mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1699 commits) bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL. vlan: Calling vlan_hwaccel_do_receive() is always valid. tproxy: use the interface primary IP address as a default value for --on-ip tproxy: added IPv6 support to the socket match cxgb3: function namespace cleanup tproxy: added IPv6 support to the TPROXY target tproxy: added IPv6 socket lookup function to nf_tproxy_core be2net: Changes to use only priority codes allowed by f/w tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled tproxy: added tproxy sockopt interface in the IPV6 layer tproxy: added udp6_lib_lookup function tproxy: added const specifiers to udp lookup functions tproxy: split off ipv6 defragmentation to a separate module l2tp: small cleanup nf_nat: restrict ICMP translation for embedded header can: mcp251x: fix generation of error frames can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set can-raw: add msg_flags to distinguish local traffic 9p: client code cleanup rds: make local functions/variables static ... Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and drivers/net/wireless/ath/ath9k/debug.c as per David
This commit is contained in:
commit
5f05647dd8
1341 changed files with 157282 additions and 84033 deletions
|
|
@ -138,10 +138,8 @@ struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
|
|||
struct crypto_cipher *tfm;
|
||||
|
||||
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
return NULL;
|
||||
|
||||
crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
|
||||
if (!IS_ERR(tfm))
|
||||
crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
|
||||
|
||||
return tfm;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,10 +119,8 @@ struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[])
|
|||
struct crypto_cipher *tfm;
|
||||
|
||||
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
return NULL;
|
||||
|
||||
crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN);
|
||||
if (!IS_ERR(tfm))
|
||||
crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN);
|
||||
|
||||
return tfm;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,20 +81,21 @@ 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);
|
||||
|
||||
del_timer_sync(&tid_rx->session_timer);
|
||||
del_timer_sync(&tid_rx->reorder_timer);
|
||||
|
||||
call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -120,6 +121,20 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
|
|||
ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
|
||||
}
|
||||
|
||||
static void sta_rx_agg_reorder_timer_expired(unsigned long data)
|
||||
{
|
||||
u8 *ptid = (u8 *)data;
|
||||
u8 *timer_to_id = ptid - *ptid;
|
||||
struct sta_info *sta = container_of(timer_to_id, struct sta_info,
|
||||
timer_to_tid[0]);
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock(&sta->lock);
|
||||
ieee80211_release_reorder_timeout(sta, *ptid);
|
||||
spin_unlock(&sta->lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
|
||||
u8 dialog_token, u16 status, u16 policy,
|
||||
u16 buf_size, u16 timeout)
|
||||
|
|
@ -251,11 +266,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
goto end;
|
||||
}
|
||||
|
||||
spin_lock_init(&tid_agg_rx->reorder_lock);
|
||||
|
||||
/* rx timer */
|
||||
tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
|
||||
tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer(&tid_agg_rx->session_timer);
|
||||
|
||||
/* rx reorder timer */
|
||||
tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
|
||||
tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer(&tid_agg_rx->reorder_timer);
|
||||
|
||||
/* prepare reordering buffer */
|
||||
tid_agg_rx->reorder_buf =
|
||||
kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
@ -185,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,
|
||||
|
|
@ -577,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);
|
||||
|
||||
|
|
@ -672,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);
|
||||
|
||||
|
|
@ -772,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:
|
||||
|
|
|
|||
|
|
@ -19,33 +19,6 @@
|
|||
#include "rate.h"
|
||||
#include "mesh.h"
|
||||
|
||||
static bool nl80211_type_check(enum nl80211_iftype type)
|
||||
{
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
#endif
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool nl80211_params_check(enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
if (!nl80211_type_check(type))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
struct vif_params *params)
|
||||
|
|
@ -55,9 +28,6 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
int err;
|
||||
|
||||
if (!nl80211_params_check(type, params))
|
||||
return -EINVAL;
|
||||
|
||||
err = ieee80211_if_add(local, name, &dev, type, params);
|
||||
if (err || type != NL80211_IFTYPE_MONITOR || !flags)
|
||||
return err;
|
||||
|
|
@ -82,12 +52,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
|
|||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
int ret;
|
||||
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
return -EBUSY;
|
||||
|
||||
if (!nl80211_params_check(type, params))
|
||||
return -EINVAL;
|
||||
|
||||
ret = ieee80211_if_change_type(sdata, type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -104,54 +68,71 @@ 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;
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sta_info *sta = NULL;
|
||||
enum ieee80211_key_alg alg;
|
||||
struct ieee80211_key *key;
|
||||
int err;
|
||||
|
||||
if (!netif_running(dev))
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return -ENETDOWN;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
/* reject WEP and TKIP keys if WEP failed to initialize */
|
||||
switch (params->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
alg = ALG_WEP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
alg = ALG_TKIP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
alg = ALG_CCMP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
alg = ALG_AES_CMAC;
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
if (IS_ERR(sdata->local->wep_tx_tfm))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* reject WEP and TKIP keys if WEP failed to initialize */
|
||||
if ((alg == ALG_WEP || alg == ALG_TKIP) &&
|
||||
IS_ERR(sdata->local->wep_tx_tfm))
|
||||
return -EINVAL;
|
||||
key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
|
||||
params->key, params->seq_len, params->seq);
|
||||
if (IS_ERR(key))
|
||||
return PTR_ERR(key);
|
||||
|
||||
key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,
|
||||
params->seq_len, params->seq);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
if (pairwise)
|
||||
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
|
||||
|
||||
mutex_lock(&sdata->local->sta_mtx);
|
||||
|
||||
|
|
@ -164,9 +145,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
ieee80211_key_link(key, sdata, sta);
|
||||
err = ieee80211_key_link(key, sdata, sta);
|
||||
if (err)
|
||||
ieee80211_key_free(sdata->local, key);
|
||||
|
||||
err = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
|
||||
|
|
@ -174,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;
|
||||
|
|
@ -191,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;
|
||||
|
|
@ -216,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))
|
||||
{
|
||||
|
|
@ -224,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;
|
||||
|
|
@ -238,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];
|
||||
|
||||
|
|
@ -247,10 +240,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
switch (key->conf.alg) {
|
||||
case ALG_TKIP:
|
||||
params.cipher = WLAN_CIPHER_SUITE_TKIP;
|
||||
params.cipher = key->conf.cipher;
|
||||
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
iv32 = key->u.tkip.tx.iv32;
|
||||
iv16 = key->u.tkip.tx.iv16;
|
||||
|
||||
|
|
@ -268,8 +261,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
params.seq = seq;
|
||||
params.seq_len = 6;
|
||||
break;
|
||||
case ALG_CCMP:
|
||||
params.cipher = WLAN_CIPHER_SUITE_CCMP;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
seq[0] = key->u.ccmp.tx_pn[5];
|
||||
seq[1] = key->u.ccmp.tx_pn[4];
|
||||
seq[2] = key->u.ccmp.tx_pn[3];
|
||||
|
|
@ -279,14 +271,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
params.seq = seq;
|
||||
params.seq_len = 6;
|
||||
break;
|
||||
case ALG_WEP:
|
||||
if (key->conf.keylen == 5)
|
||||
params.cipher = WLAN_CIPHER_SUITE_WEP40;
|
||||
else
|
||||
params.cipher = WLAN_CIPHER_SUITE_WEP104;
|
||||
break;
|
||||
case ALG_AES_CMAC:
|
||||
params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
seq[0] = key->u.aes_cmac.tx_pn[5];
|
||||
seq[1] = key->u.aes_cmac.tx_pn[4];
|
||||
seq[2] = key->u.aes_cmac.tx_pn[3];
|
||||
|
|
@ -342,13 +327,19 @@ 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_BITRATE;
|
||||
STATION_INFO_TX_RETRIES |
|
||||
STATION_INFO_TX_FAILED |
|
||||
STATION_INFO_TX_BITRATE |
|
||||
STATION_INFO_RX_DROP_MISC;
|
||||
|
||||
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
|
||||
sinfo->rx_bytes = sta->rx_bytes;
|
||||
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;
|
||||
sinfo->rx_dropped_misc = sta->rx_dropped;
|
||||
|
||||
if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
|
||||
(sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
|
||||
|
|
@ -634,6 +625,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
|
|||
struct sta_info *sta,
|
||||
struct station_parameters *params)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 rates;
|
||||
int i, j;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
|
@ -642,7 +634,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
|
|||
|
||||
sband = local->hw.wiphy->bands[local->oper_channel->band];
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_irqsave(&sta->flaglock, flags);
|
||||
mask = params->sta_flags_mask;
|
||||
set = params->sta_flags_set;
|
||||
|
||||
|
|
@ -669,7 +661,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
|
|||
if (set & BIT(NL80211_STA_FLAG_MFP))
|
||||
sta->flags |= WLAN_STA_MFP;
|
||||
}
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_irqrestore(&sta->flaglock, flags);
|
||||
|
||||
/*
|
||||
* cfg80211 validates this (1-2007) and allows setting the AID
|
||||
|
|
@ -1143,9 +1135,9 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
|
|||
p.uapsd = false;
|
||||
|
||||
if (drv_conf_tx(local, params->queue, &p)) {
|
||||
printk(KERN_DEBUG "%s: failed to set TX queue "
|
||||
"parameters for queue %d\n",
|
||||
wiphy_name(local->hw.wiphy), params->queue);
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"failed to set TX queue parameters for queue %d\n",
|
||||
params->queue);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1207,15 +1199,26 @@ static int ieee80211_scan(struct wiphy *wiphy,
|
|||
struct net_device *dev,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
||||
(sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon))
|
||||
switch (ieee80211_vif_type_p2p(&sdata->vif)) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (sdata->local->ops->hw_scan)
|
||||
break;
|
||||
/* FIXME: implement NoA while scanning in software */
|
||||
return -EOPNOTSUPP;
|
||||
case NL80211_IFTYPE_AP:
|
||||
if (sdata->u.ap.beacon)
|
||||
return -EOPNOTSUPP;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return ieee80211_request_scan(sdata, req);
|
||||
}
|
||||
|
|
@ -1362,7 +1365,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);
|
||||
|
||||
|
|
@ -1411,7 +1414,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;
|
||||
}
|
||||
|
|
@ -1541,11 +1544,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
|
|||
return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
|
||||
}
|
||||
|
||||
static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
bool channel_type_valid,
|
||||
const u8 *buf, size_t len, u64 *cookie)
|
||||
static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
bool channel_type_valid,
|
||||
const u8 *buf, size_t len, u64 *cookie)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
|
@ -1566,7 +1569,11 @@ static int ieee80211_action(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);
|
||||
|
|
@ -1575,8 +1582,7 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
|
|||
return -ENOLINK;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
|
||||
flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -1598,6 +1604,23 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u16 frame_type, bool reg)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
|
||||
if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
|
||||
return;
|
||||
|
||||
if (reg)
|
||||
local->probe_req_reg++;
|
||||
else
|
||||
local->probe_req_reg--;
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->reconfig_filter);
|
||||
}
|
||||
|
||||
struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
|
|
@ -1647,6 +1670,7 @@ struct cfg80211_ops mac80211_config_ops = {
|
|||
.set_bitrate_mask = ieee80211_set_bitrate_mask,
|
||||
.remain_on_channel = ieee80211_remain_on_channel,
|
||||
.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
|
||||
.action = ieee80211_action,
|
||||
.mgmt_tx = ieee80211_mgmt_tx,
|
||||
.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
|
||||
.mgmt_frame_register = ieee80211_mgmt_frame_register,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local,
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&local->iflist_mtx));
|
||||
lockdep_assert_held(&local->iflist_mtx);
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata == ignore)
|
||||
|
|
|
|||
|
|
@ -86,13 +86,15 @@ static ssize_t tsf_write(struct file *file,
|
|||
if (strncmp(buf, "reset", 5) == 0) {
|
||||
if (local->ops->reset_tsf) {
|
||||
drv_reset_tsf(local);
|
||||
printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy));
|
||||
wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
|
||||
}
|
||||
} else {
|
||||
tsf = simple_strtoul(buf, NULL, 0);
|
||||
if (local->ops->set_tsf) {
|
||||
drv_set_tsf(local, tsf);
|
||||
printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf);
|
||||
wiphy_info(local->hw.wiphy,
|
||||
"debugfs set TSF to %#018llx\n", tsf);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -375,7 +377,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
|||
if (!phyd)
|
||||
return;
|
||||
|
||||
local->debugfs.stations = debugfs_create_dir("stations", phyd);
|
||||
local->debugfs.keys = debugfs_create_dir("keys", phyd);
|
||||
|
||||
DEBUGFS_ADD(frequency);
|
||||
|
|
|
|||
|
|
@ -66,26 +66,13 @@ static ssize_t key_algorithm_read(struct file *file,
|
|||
char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char *alg;
|
||||
char buf[15];
|
||||
struct ieee80211_key *key = file->private_data;
|
||||
u32 c = key->conf.cipher;
|
||||
|
||||
switch (key->conf.alg) {
|
||||
case ALG_WEP:
|
||||
alg = "WEP\n";
|
||||
break;
|
||||
case ALG_TKIP:
|
||||
alg = "TKIP\n";
|
||||
break;
|
||||
case ALG_CCMP:
|
||||
alg = "CCMP\n";
|
||||
break;
|
||||
case ALG_AES_CMAC:
|
||||
alg = "AES-128-CMAC\n";
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg));
|
||||
sprintf(buf, "%.2x-%.2x-%.2x:%d\n",
|
||||
c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
|
||||
}
|
||||
KEY_OPS(algorithm);
|
||||
|
||||
|
|
@ -97,21 +84,22 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
|
|||
int len;
|
||||
struct ieee80211_key *key = file->private_data;
|
||||
|
||||
switch (key->conf.alg) {
|
||||
case ALG_WEP:
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
len = scnprintf(buf, sizeof(buf), "\n");
|
||||
break;
|
||||
case ALG_TKIP:
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
|
||||
key->u.tkip.tx.iv32,
|
||||
key->u.tkip.tx.iv16);
|
||||
break;
|
||||
case ALG_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
tpn = key->u.ccmp.tx_pn;
|
||||
len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
|
||||
tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
|
||||
break;
|
||||
case ALG_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
tpn = key->u.aes_cmac.tx_pn;
|
||||
len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
|
||||
tpn[0], tpn[1], tpn[2], tpn[3], tpn[4],
|
||||
|
|
@ -132,11 +120,12 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
|
|||
int i, len;
|
||||
const u8 *rpn;
|
||||
|
||||
switch (key->conf.alg) {
|
||||
case ALG_WEP:
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
len = scnprintf(buf, sizeof(buf), "\n");
|
||||
break;
|
||||
case ALG_TKIP:
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
"%08x %04x\n",
|
||||
|
|
@ -144,7 +133,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
|
|||
key->u.tkip.rx[i].iv16);
|
||||
len = p - buf;
|
||||
break;
|
||||
case ALG_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) {
|
||||
rpn = key->u.ccmp.rx_pn[i];
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
|
|
@ -154,7 +143,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
|
|||
}
|
||||
len = p - buf;
|
||||
break;
|
||||
case ALG_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
rpn = key->u.aes_cmac.rx_pn;
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
"%02x%02x%02x%02x%02x%02x\n",
|
||||
|
|
@ -176,11 +165,11 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf,
|
|||
char buf[20];
|
||||
int len;
|
||||
|
||||
switch (key->conf.alg) {
|
||||
case ALG_CCMP:
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
|
||||
break;
|
||||
case ALG_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
len = scnprintf(buf, sizeof(buf), "%u\n",
|
||||
key->u.aes_cmac.replays);
|
||||
break;
|
||||
|
|
@ -198,8 +187,8 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
|
|||
char buf[20];
|
||||
int len;
|
||||
|
||||
switch (key->conf.alg) {
|
||||
case ALG_AES_CMAC:
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
len = scnprintf(buf, sizeof(buf), "%u\n",
|
||||
key->u.aes_cmac.icverrors);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -410,6 +410,9 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
|
|||
sprintf(buf, "netdev:%s", sdata->name);
|
||||
sdata->debugfs.dir = debugfs_create_dir(buf,
|
||||
sdata->local->hw.wiphy->debugfsdir);
|
||||
if (sdata->debugfs.dir)
|
||||
sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
|
||||
sdata->debugfs.dir);
|
||||
add_files(sdata);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -198,7 +198,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;
|
||||
}
|
||||
|
||||
|
|
@ -302,7 +303,7 @@ STA_OPS(ht_capa);
|
|||
|
||||
void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
||||
{
|
||||
struct dentry *stations_dir = sta->local->debugfs.stations;
|
||||
struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations;
|
||||
u8 mac[3*ETH_ALEN];
|
||||
|
||||
sta->debugfs.add_has_run = true;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,20 @@ static inline int drv_add_interface(struct ieee80211_local *local,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int drv_change_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type, bool p2p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
|
||||
trace_drv_change_interface(local, sdata, type, p2p);
|
||||
ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_remove_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,12 +25,14 @@ static inline void trace_ ## name(proto) {}
|
|||
#define STA_PR_FMT " sta:%pM"
|
||||
#define STA_PR_ARG __entry->sta_addr
|
||||
|
||||
#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
|
||||
#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
|
||||
__field(bool, p2p) \
|
||||
__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
|
||||
#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
|
||||
#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
|
||||
__entry->p2p = sdata->vif.p2p; \
|
||||
__assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
|
||||
#define VIF_PR_FMT " vif:%s(%d)"
|
||||
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type
|
||||
#define VIF_PR_FMT " vif:%s(%d%s)"
|
||||
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
|
||||
|
||||
/*
|
||||
* Tracing for driver callbacks.
|
||||
|
|
@ -136,6 +138,34 @@ TRACE_EVENT(drv_add_interface,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_change_interface,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type, bool p2p),
|
||||
|
||||
TP_ARGS(local, sdata, type, p2p),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(u32, new_type)
|
||||
__field(bool, new_p2p)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->new_type = type;
|
||||
__entry->new_p2p = p2p;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT " new type:%d%s",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type,
|
||||
__entry->new_p2p ? "/p2p" : ""
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_remove_interface,
|
||||
TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
|
||||
|
||||
|
|
@ -336,7 +366,7 @@ TRACE_EVENT(drv_set_key,
|
|||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
STA_ENTRY
|
||||
__field(enum ieee80211_key_alg, alg)
|
||||
__field(u32, cipher)
|
||||
__field(u8, hw_key_idx)
|
||||
__field(u8, flags)
|
||||
__field(s8, keyidx)
|
||||
|
|
@ -346,7 +376,7 @@ TRACE_EVENT(drv_set_key,
|
|||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
STA_ASSIGN;
|
||||
__entry->alg = key->alg;
|
||||
__entry->cipher = key->cipher;
|
||||
__entry->flags = key->flags;
|
||||
__entry->keyidx = key->keyidx;
|
||||
__entry->hw_key_idx = key->hw_key_idx;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -265,3 +268,33 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_request_smps_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
container_of(work, struct ieee80211_sub_if_data,
|
||||
u.mgd.request_smps_work);
|
||||
|
||||
mutex_lock(&sdata->u.mgd.mtx);
|
||||
__ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode);
|
||||
mutex_unlock(&sdata->u.mgd.mtx);
|
||||
}
|
||||
|
||||
void ieee80211_request_smps(struct ieee80211_vif *vif,
|
||||
enum ieee80211_smps_mode smps_mode)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
|
||||
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
|
||||
return;
|
||||
|
||||
if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
|
||||
sdata->u.mgd.driver_smps_mode = smps_mode;
|
||||
|
||||
ieee80211_queue_work(&sdata->local->hw,
|
||||
&sdata->u.mgd.request_smps_work);
|
||||
}
|
||||
/* this might change ... don't want non-open drivers using it */
|
||||
EXPORT_SYMBOL_GPL(ieee80211_request_smps);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -427,8 +448,8 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
|||
return NULL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
|
||||
wiphy_name(local->hw.wiphy), addr, sdata->name);
|
||||
wiphy_debug(local->hw.wiphy, "Adding new IBSS station %pM (dev=%s)\n",
|
||||
addr, sdata->name);
|
||||
#endif
|
||||
|
||||
sta = sta_info_alloc(sdata, addr, gfp);
|
||||
|
|
@ -920,12 +941,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
|
||||
sdata->u.ibss.ssid_len = params->ssid_len;
|
||||
|
||||
mutex_unlock(&sdata->u.ibss.mtx);
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
|
||||
mutex_unlock(&sdata->u.ibss.mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -980,7 +1003,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
mutex_unlock(&sdata->u.ibss.mtx);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,12 +50,6 @@ struct ieee80211_local;
|
|||
* increased memory use (about 2 kB of RAM per entry). */
|
||||
#define IEEE80211_FRAGMENT_MAX 4
|
||||
|
||||
/*
|
||||
* Time after which we ignore scan results and no longer report/use
|
||||
* them in any way.
|
||||
*/
|
||||
#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
|
||||
|
||||
#define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024))
|
||||
|
||||
#define IEEE80211_DEFAULT_UAPSD_QUEUES \
|
||||
|
|
@ -165,12 +159,37 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
|
|||
#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u)
|
||||
#define RX_QUEUED ((__force ieee80211_rx_result) 3u)
|
||||
|
||||
#define IEEE80211_RX_IN_SCAN BIT(0)
|
||||
/* frame is destined to interface currently processed (incl. multicast frames) */
|
||||
#define IEEE80211_RX_RA_MATCH BIT(1)
|
||||
#define IEEE80211_RX_AMSDU BIT(2)
|
||||
#define IEEE80211_RX_FRAGMENTED BIT(3)
|
||||
/* only add flags here that do not change with subframes of an aMPDU */
|
||||
/**
|
||||
* enum ieee80211_packet_rx_flags - packet RX flags
|
||||
* @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed
|
||||
* (incl. multicast frames)
|
||||
* @IEEE80211_RX_IN_SCAN: received while scanning
|
||||
* @IEEE80211_RX_FRAGMENTED: fragmented frame
|
||||
* @IEEE80211_RX_AMSDU: a-MSDU packet
|
||||
* @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed
|
||||
*
|
||||
* These are per-frame flags that are attached to a frame in the
|
||||
* @rx_flags field of &struct ieee80211_rx_status.
|
||||
*/
|
||||
enum ieee80211_packet_rx_flags {
|
||||
IEEE80211_RX_IN_SCAN = BIT(0),
|
||||
IEEE80211_RX_RA_MATCH = BIT(1),
|
||||
IEEE80211_RX_FRAGMENTED = BIT(2),
|
||||
IEEE80211_RX_AMSDU = BIT(3),
|
||||
IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_rx_flags - RX data flags
|
||||
*
|
||||
* @IEEE80211_RX_CMNTR: received on cooked monitor already
|
||||
*
|
||||
* These flags are used across handling multiple interfaces
|
||||
* for a single frame.
|
||||
*/
|
||||
enum ieee80211_rx_flags {
|
||||
IEEE80211_RX_CMNTR = BIT(0),
|
||||
};
|
||||
|
||||
struct ieee80211_rx_data {
|
||||
struct sk_buff *skb;
|
||||
|
|
@ -343,10 +362,14 @@ struct ieee80211_if_managed {
|
|||
unsigned long timers_running; /* used for quiesce/restart */
|
||||
bool powersave; /* powersave requested for this iface */
|
||||
enum ieee80211_smps_mode req_smps, /* requested smps mode */
|
||||
ap_smps; /* smps mode AP thinks we're in */
|
||||
ap_smps, /* smps mode AP thinks we're in */
|
||||
driver_smps_mode; /* smps mode request */
|
||||
|
||||
struct work_struct request_smps_work;
|
||||
|
||||
unsigned int flags;
|
||||
|
||||
bool beacon_crc_valid;
|
||||
u32 beacon_crc;
|
||||
|
||||
enum {
|
||||
|
|
@ -370,6 +393,13 @@ struct ieee80211_if_managed {
|
|||
*/
|
||||
int ave_beacon_signal;
|
||||
|
||||
/*
|
||||
* Number of Beacon frames used in ave_beacon_signal. This can be used
|
||||
* to avoid generating less reliable cqm events that would be based
|
||||
* only on couple of received frames.
|
||||
*/
|
||||
unsigned int count_beacon_signal;
|
||||
|
||||
/*
|
||||
* Last Beacon frame signal strength average (ave_beacon_signal / 16)
|
||||
* that triggered a cqm event. 0 indicates that no event has been
|
||||
|
|
@ -474,6 +504,19 @@ enum ieee80211_sub_if_data_flags {
|
|||
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_sdata_state_bits - virtual interface state bits
|
||||
* @SDATA_STATE_RUNNING: virtual interface is up & running; this
|
||||
* mirrors netif_running() but is separate for interface type
|
||||
* change handling while the interface is up
|
||||
* @SDATA_STATE_OFFCHANNEL: This interface is currently in offchannel
|
||||
* mode, so queues are stopped
|
||||
*/
|
||||
enum ieee80211_sdata_state_bits {
|
||||
SDATA_STATE_RUNNING,
|
||||
SDATA_STATE_OFFCHANNEL,
|
||||
};
|
||||
|
||||
struct ieee80211_sub_if_data {
|
||||
struct list_head list;
|
||||
|
||||
|
|
@ -487,6 +530,8 @@ struct ieee80211_sub_if_data {
|
|||
|
||||
unsigned int flags;
|
||||
|
||||
unsigned long state;
|
||||
|
||||
int drop_unencrypted;
|
||||
|
||||
char name[IFNAMSIZ];
|
||||
|
|
@ -497,17 +542,20 @@ struct ieee80211_sub_if_data {
|
|||
*/
|
||||
bool ht_opmode_valid;
|
||||
|
||||
/* to detect idle changes */
|
||||
bool old_idle;
|
||||
|
||||
/* Fragment table for host-based reassembly */
|
||||
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;
|
||||
|
||||
u16 sequence_number;
|
||||
__be16 control_port_protocol;
|
||||
bool control_port_no_encrypt;
|
||||
|
||||
struct work_struct work;
|
||||
struct sk_buff_head skb_queue;
|
||||
|
|
@ -539,6 +587,7 @@ struct ieee80211_sub_if_data {
|
|||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
struct {
|
||||
struct dentry *dir;
|
||||
struct dentry *subdir_stations;
|
||||
struct dentry *default_key;
|
||||
struct dentry *default_mgmt_key;
|
||||
} debugfs;
|
||||
|
|
@ -595,11 +644,17 @@ enum queue_stop_reason {
|
|||
* determine if we are on the operating channel or not
|
||||
* @SCAN_OFF_CHANNEL: We're off our operating channel for scanning,
|
||||
* gets only set in conjunction with SCAN_SW_SCANNING
|
||||
* @SCAN_COMPLETED: Set for our scan work function when the driver reported
|
||||
* that the scan completed.
|
||||
* @SCAN_ABORTED: Set for our scan work function when the driver reported
|
||||
* a scan complete for an aborted scan.
|
||||
*/
|
||||
enum {
|
||||
SCAN_SW_SCANNING,
|
||||
SCAN_HW_SCANNING,
|
||||
SCAN_OFF_CHANNEL,
|
||||
SCAN_COMPLETED,
|
||||
SCAN_ABORTED,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -634,7 +689,6 @@ struct ieee80211_local {
|
|||
/*
|
||||
* work stuff, potentially off-channel (in the future)
|
||||
*/
|
||||
struct mutex work_mtx;
|
||||
struct list_head work_list;
|
||||
struct timer_list work_timer;
|
||||
struct work_struct work_work;
|
||||
|
|
@ -653,9 +707,13 @@ struct ieee80211_local {
|
|||
int open_count;
|
||||
int monitors, cooked_mntrs;
|
||||
/* number of interfaces with corresponding FIF_ flags */
|
||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
|
||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
|
||||
fif_probe_req;
|
||||
int probe_req_reg;
|
||||
unsigned int filter_flags; /* FIF_* */
|
||||
|
||||
bool wiphy_ciphers_allocated;
|
||||
|
||||
/* protects the aggregated multicast list and filter calls */
|
||||
spinlock_t filter_lock;
|
||||
|
||||
|
|
@ -746,9 +804,10 @@ struct ieee80211_local {
|
|||
*/
|
||||
struct mutex key_mtx;
|
||||
|
||||
/* mutex for scan and work locking */
|
||||
struct mutex mtx;
|
||||
|
||||
/* Scanning and BSS list */
|
||||
struct mutex scan_mtx;
|
||||
unsigned long scanning;
|
||||
struct cfg80211_ssid scan_ssid;
|
||||
struct cfg80211_scan_request *int_scan_req;
|
||||
|
|
@ -866,10 +925,14 @@ struct ieee80211_local {
|
|||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
struct local_debugfsdentries {
|
||||
struct dentry *rcdir;
|
||||
struct dentry *stations;
|
||||
struct dentry *keys;
|
||||
} debugfs;
|
||||
#endif
|
||||
|
||||
/* dummy netdev for use w/ NAPI */
|
||||
struct net_device napi_dev;
|
||||
|
||||
struct napi_struct napi;
|
||||
};
|
||||
|
||||
static inline struct ieee80211_sub_if_data *
|
||||
|
|
@ -1003,6 +1066,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
|
|||
void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
/* IBSS code */
|
||||
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
|
||||
|
|
@ -1068,10 +1133,12 @@ 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)
|
||||
{
|
||||
return netif_running(sdata->dev);
|
||||
return test_bit(SDATA_STATE_RUNNING, &sdata->state);
|
||||
}
|
||||
|
||||
/* tx handling */
|
||||
|
|
@ -1105,12 +1172,13 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
|||
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps, const u8 *da,
|
||||
const u8 *bssid);
|
||||
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);
|
||||
|
|
@ -1124,13 +1192,16 @@ 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);
|
||||
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
|
||||
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
|
||||
|
||||
/* Spectrum management */
|
||||
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
@ -1146,6 +1217,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw);
|
|||
|
||||
static inline int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
|
||||
"%s: resume with hardware scan still in progress\n",
|
||||
wiphy_name(hw->wiphy));
|
||||
|
||||
return ieee80211_reconfig(hw_to_local(hw));
|
||||
}
|
||||
#else
|
||||
|
|
@ -1208,7 +1285,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
|||
const u8 *key, u8 key_len, u8 key_idx);
|
||||
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
const u8 *ie, size_t ie_len,
|
||||
enum ieee80211_band band);
|
||||
enum ieee80211_band band, u32 rate_mask,
|
||||
u8 channel);
|
||||
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len);
|
||||
|
|
@ -1221,8 +1299,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
|
||||
|
|
@ -94,21 +95,14 @@ static inline int identical_mac_addr_allowed(int type1, int type2)
|
|||
type2 == NL80211_IFTYPE_AP_VLAN));
|
||||
}
|
||||
|
||||
static int ieee80211_open(struct net_device *dev)
|
||||
static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_sub_if_data *nsdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
u32 changed = 0;
|
||||
int res;
|
||||
u32 hw_reconf_flags = 0;
|
||||
u8 null_addr[ETH_ALEN] = {0};
|
||||
struct ieee80211_sub_if_data *nsdata;
|
||||
struct net_device *dev = sdata->dev;
|
||||
|
||||
/* fail early if user set an invalid address */
|
||||
if (compare_ether_addr(dev->dev_addr, null_addr) &&
|
||||
!is_valid_ether_addr(dev->dev_addr))
|
||||
return -EADDRNOTAVAIL;
|
||||
ASSERT_RTNL();
|
||||
|
||||
/* we hold the RTNL here so can safely walk the list */
|
||||
list_for_each_entry(nsdata, &local->interfaces, list) {
|
||||
|
|
@ -125,7 +119,7 @@ static int ieee80211_open(struct net_device *dev)
|
|||
* belonging to the same hardware. Then, however, we're
|
||||
* faced with having to adopt two different TSF timers...
|
||||
*/
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
if (iftype == NL80211_IFTYPE_ADHOC &&
|
||||
nsdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
return -EBUSY;
|
||||
|
||||
|
|
@ -139,19 +133,56 @@ static int ieee80211_open(struct net_device *dev)
|
|||
/*
|
||||
* check whether it may have the same address
|
||||
*/
|
||||
if (!identical_mac_addr_allowed(sdata->vif.type,
|
||||
if (!identical_mac_addr_allowed(iftype,
|
||||
nsdata->vif.type))
|
||||
return -ENOTUNIQ;
|
||||
|
||||
/*
|
||||
* can only add VLANs to enabled APs
|
||||
*/
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
||||
if (iftype == NL80211_IFTYPE_AP_VLAN &&
|
||||
nsdata->vif.type == NL80211_IFTYPE_AP)
|
||||
sdata->bss = &nsdata->u.ap;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* checks should be in ieee80211_check_concurrent_iface.
|
||||
*/
|
||||
static int ieee80211_do_open(struct net_device *dev, bool coming_up)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
u32 changed = 0;
|
||||
int res;
|
||||
u32 hw_reconf_flags = 0;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_WDS:
|
||||
if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
|
||||
|
|
@ -177,7 +208,9 @@ static int ieee80211_open(struct net_device *dev)
|
|||
/* no special treatment */
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case __NL80211_IFTYPE_AFTER_LAST:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
/* cannot happen */
|
||||
WARN_ON(1);
|
||||
break;
|
||||
|
|
@ -187,39 +220,30 @@ static int ieee80211_open(struct net_device *dev)
|
|||
res = drv_start(local);
|
||||
if (res)
|
||||
goto err_del_bss;
|
||||
if (local->ops->napi_poll)
|
||||
napi_enable(&local->napi);
|
||||
/* we're brought up, everything changes */
|
||||
hw_reconf_flags = ~0;
|
||||
ieee80211_led_radio(local, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check all interfaces and copy the hopefully now-present
|
||||
* MAC address to those that have the special null one.
|
||||
* Copy the hopefully now-present MAC address to
|
||||
* this interface, if it has the special null one.
|
||||
*/
|
||||
list_for_each_entry(nsdata, &local->interfaces, list) {
|
||||
struct net_device *ndev = nsdata->dev;
|
||||
if (is_zero_ether_addr(dev->dev_addr)) {
|
||||
memcpy(dev->dev_addr,
|
||||
local->hw.wiphy->perm_addr,
|
||||
ETH_ALEN);
|
||||
memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
|
||||
|
||||
/*
|
||||
* No need to check running since we do not allow
|
||||
* it to start up with this invalid address.
|
||||
*/
|
||||
if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
|
||||
memcpy(ndev->dev_addr,
|
||||
local->hw.wiphy->perm_addr,
|
||||
ETH_ALEN);
|
||||
memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
|
||||
if (!is_valid_ether_addr(dev->dev_addr)) {
|
||||
if (!local->open_count)
|
||||
drv_stop(local);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the MAC address for this device.
|
||||
*/
|
||||
if (!is_valid_ether_addr(dev->dev_addr)) {
|
||||
if (!local->open_count)
|
||||
drv_stop(local);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
/* no need to tell driver */
|
||||
|
|
@ -237,25 +261,17 @@ static int ieee80211_open(struct net_device *dev)
|
|||
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);
|
||||
break;
|
||||
default:
|
||||
res = drv_add_interface(local, &sdata->vif);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
if (coming_up) {
|
||||
res = drv_add_interface(local, &sdata->vif);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
local->fif_other_bss++;
|
||||
|
|
@ -264,8 +280,11 @@ static int ieee80211_open(struct net_device *dev)
|
|||
ieee80211_start_mesh(sdata);
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
local->fif_pspoll++;
|
||||
local->fif_probe_req++;
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
||||
local->fif_probe_req++;
|
||||
}
|
||||
|
||||
changed |= ieee80211_reset_erp_info(sdata);
|
||||
|
|
@ -277,6 +296,8 @@ static int ieee80211_open(struct net_device *dev)
|
|||
netif_carrier_on(dev);
|
||||
}
|
||||
|
||||
set_bit(SDATA_STATE_RUNNING, &sdata->state);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_WDS) {
|
||||
/* Create STA entry for the WDS peer */
|
||||
sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
|
||||
|
|
@ -294,6 +315,8 @@ static int ieee80211_open(struct net_device *dev)
|
|||
/* STA has been freed */
|
||||
goto err_del_interface;
|
||||
}
|
||||
|
||||
rate_control_rate_init(sta);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -307,9 +330,13 @@ static int ieee80211_open(struct net_device *dev)
|
|||
if (sdata->flags & IEEE80211_SDATA_PROMISC)
|
||||
atomic_inc(&local->iff_promiscs);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
hw_reconf_flags |= __ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (coming_up)
|
||||
local->open_count++;
|
||||
|
||||
local->open_count++;
|
||||
if (hw_reconf_flags) {
|
||||
ieee80211_hw_config(local, hw_reconf_flags);
|
||||
/*
|
||||
|
|
@ -334,22 +361,42 @@ static int ieee80211_open(struct net_device *dev)
|
|||
sdata->bss = NULL;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
list_del(&sdata->u.vlan.list);
|
||||
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ieee80211_stop(struct net_device *dev)
|
||||
static int ieee80211_open(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
int err;
|
||||
|
||||
/* fail early if user set an invalid address */
|
||||
if (!is_zero_ether_addr(dev->dev_addr) &&
|
||||
!is_valid_ether_addr(dev->dev_addr))
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return ieee80211_do_open(dev, true);
|
||||
}
|
||||
|
||||
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
bool going_down)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb, *tmp;
|
||||
u32 hw_reconf_flags = 0;
|
||||
int i;
|
||||
|
||||
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
|
||||
|
||||
/*
|
||||
* Stop TX on this interface first.
|
||||
*/
|
||||
netif_tx_stop_all_queues(dev);
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
|
||||
/*
|
||||
* Purge work for this interface.
|
||||
|
|
@ -366,12 +413,9 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
* (because if we remove a STA after ops->remove_interface()
|
||||
* the driver will have removed the vif info already!)
|
||||
*
|
||||
* We could relax this and only unlink the stations from the
|
||||
* hash table and list but keep them on a per-sdata list that
|
||||
* will be inserted back again when the interface is brought
|
||||
* up again, but I don't currently see a use case for that,
|
||||
* except with WDS which gets a STA entry created when it is
|
||||
* brought up.
|
||||
* This is relevant only in AP, WDS and mesh modes, since in
|
||||
* all other modes we've already removed all stations when
|
||||
* disconnecting etc.
|
||||
*/
|
||||
sta_info_flush(local, sdata);
|
||||
|
||||
|
|
@ -387,14 +431,19 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
if (sdata->flags & IEEE80211_SDATA_PROMISC)
|
||||
atomic_dec(&local->iff_promiscs);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
local->fif_pspoll--;
|
||||
local->fif_probe_req--;
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
||||
local->fif_probe_req--;
|
||||
}
|
||||
|
||||
netif_addr_lock_bh(dev);
|
||||
netif_addr_lock_bh(sdata->dev);
|
||||
spin_lock_bh(&local->filter_lock);
|
||||
__hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len);
|
||||
__hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
|
||||
sdata->dev->addr_len);
|
||||
spin_unlock_bh(&local->filter_lock);
|
||||
netif_addr_unlock_bh(dev);
|
||||
netif_addr_unlock_bh(sdata->dev);
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
|
||||
|
|
@ -406,11 +455,21 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
struct ieee80211_sub_if_data *vlan, *tmpsdata;
|
||||
struct beacon_data *old_beacon = sdata->u.ap.beacon;
|
||||
|
||||
/* sdata_running will return false, so this will disable */
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
/* remove beacon */
|
||||
rcu_assign_pointer(sdata->u.ap.beacon, NULL);
|
||||
synchronize_rcu();
|
||||
kfree(old_beacon);
|
||||
|
||||
/* free all potentially still buffered bcast frames */
|
||||
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
|
||||
local->total_ps_buffered--;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* down all dependent devices, that is VLANs */
|
||||
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
|
||||
u.vlan.list)
|
||||
|
|
@ -418,7 +477,8 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
WARN_ON(!list_empty(&sdata->u.ap.vlans));
|
||||
}
|
||||
|
||||
local->open_count--;
|
||||
if (going_down)
|
||||
local->open_count--;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
|
|
@ -437,40 +497,9 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
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_STATION:
|
||||
del_timer_sync(&sdata->u.mgd.chswitch_timer);
|
||||
del_timer_sync(&sdata->u.mgd.timer);
|
||||
del_timer_sync(&sdata->u.mgd.conn_mon_timer);
|
||||
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
|
||||
/*
|
||||
* If any of the timers fired while we waited for it, it will
|
||||
* have queued its work. Now the work will be running again
|
||||
* but will not rearm the timer again because it checks
|
||||
* whether the interface is running, which, at this point,
|
||||
* it no longer is.
|
||||
*/
|
||||
cancel_work_sync(&sdata->u.mgd.chswitch_work);
|
||||
cancel_work_sync(&sdata->u.mgd.monitor_work);
|
||||
cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
|
||||
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
del_timer_sync(&sdata->u.ibss.timer);
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
/* other_bss and allmulti are always set on mesh
|
||||
|
|
@ -498,27 +527,34 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
ieee80211_scan_cancel(local);
|
||||
|
||||
/*
|
||||
* Disable beaconing for AP and mesh, IBSS can't
|
||||
* still be joined to a network at this point.
|
||||
* Disable beaconing here for mesh only, AP and IBSS
|
||||
* are already taken care of.
|
||||
*/
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
BSS_CHANGED_BEACON_ENABLED);
|
||||
}
|
||||
|
||||
/* free all remaining keys, there shouldn't be any */
|
||||
/*
|
||||
* Free all remaining keys, there shouldn't be any,
|
||||
* except maybe group keys in AP more or WDS?
|
||||
*/
|
||||
ieee80211_free_keys(sdata);
|
||||
drv_remove_interface(local, &sdata->vif);
|
||||
|
||||
if (going_down)
|
||||
drv_remove_interface(local, &sdata->vif);
|
||||
}
|
||||
|
||||
sdata->bss = NULL;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
hw_reconf_flags |= __ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
|
||||
if (local->open_count == 0) {
|
||||
if (local->ops->napi_poll)
|
||||
napi_disable(&local->napi);
|
||||
ieee80211_clear_tx_pending(local);
|
||||
ieee80211_stop_device(local);
|
||||
|
||||
|
|
@ -541,6 +577,13 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
}
|
||||
|
||||
static int ieee80211_stop(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
ieee80211_do_stop(sdata, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -585,8 +628,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct beacon_data *beacon;
|
||||
struct sk_buff *skb;
|
||||
int flushed;
|
||||
int i;
|
||||
|
||||
|
|
@ -599,37 +640,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
|
|||
__skb_queue_purge(&sdata->fragments[i].skb_list);
|
||||
sdata->fragment_next = 0;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
beacon = sdata->u.ap.beacon;
|
||||
rcu_assign_pointer(sdata->u.ap.beacon, NULL);
|
||||
synchronize_rcu();
|
||||
kfree(beacon);
|
||||
|
||||
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
|
||||
local->total_ps_buffered--;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
mesh_rmc_free(sdata);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (WARN_ON(sdata->u.ibss.presp))
|
||||
kfree_skb(sdata->u.ibss.presp);
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case __NL80211_IFTYPE_AFTER_LAST:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
mesh_rmc_free(sdata);
|
||||
|
||||
flushed = sta_info_flush(local, sdata);
|
||||
WARN_ON(flushed);
|
||||
|
|
@ -791,7 +803,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) {
|
||||
|
|
@ -844,9 +857,13 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* and set some type-dependent values */
|
||||
sdata->vif.type = type;
|
||||
sdata->vif.p2p = false;
|
||||
sdata->dev->netdev_ops = &ieee80211_dataif_ops;
|
||||
sdata->wdev.iftype = type;
|
||||
|
||||
sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
|
||||
sdata->control_port_no_encrypt = false;
|
||||
|
||||
/* only monitor differs */
|
||||
sdata->dev->type = ARPHRD_ETHER;
|
||||
|
||||
|
|
@ -854,10 +871,20 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
|||
INIT_WORK(&sdata->work, ieee80211_iface_work);
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
type = NL80211_IFTYPE_AP;
|
||||
sdata->vif.type = type;
|
||||
sdata->vif.p2p = true;
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_AP:
|
||||
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
|
||||
INIT_LIST_HEAD(&sdata->u.ap.vlans);
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
type = NL80211_IFTYPE_STATION;
|
||||
sdata->vif.type = type;
|
||||
sdata->vif.p2p = true;
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ieee80211_sta_setup_sdata(sdata);
|
||||
break;
|
||||
|
|
@ -878,7 +905,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
|||
case NL80211_IFTYPE_AP_VLAN:
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case __NL80211_IFTYPE_AFTER_LAST:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
|
@ -886,12 +913,85 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_debugfs_add_netdev(sdata);
|
||||
}
|
||||
|
||||
static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int ret, err;
|
||||
enum nl80211_iftype internal_type = type;
|
||||
bool p2p = false;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!local->ops->change_interface)
|
||||
return -EBUSY;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
/*
|
||||
* Could maybe also all others here?
|
||||
* Just not sure how that interacts
|
||||
* with the RX/config path e.g. for
|
||||
* mesh.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
/*
|
||||
* Could probably support everything
|
||||
* but WDS here (WDS do_open can fail
|
||||
* under memory pressure, which this
|
||||
* code isn't prepared to handle).
|
||||
*/
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
p2p = true;
|
||||
internal_type = NL80211_IFTYPE_STATION;
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
p2p = true;
|
||||
internal_type = NL80211_IFTYPE_AP;
|
||||
break;
|
||||
default:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = ieee80211_check_concurrent_iface(sdata, internal_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ieee80211_do_stop(sdata, false);
|
||||
|
||||
ieee80211_teardown_sdata(sdata->dev);
|
||||
|
||||
ret = drv_change_interface(local, sdata, internal_type, p2p);
|
||||
if (ret)
|
||||
type = sdata->vif.type;
|
||||
|
||||
ieee80211_setup_sdata(sdata, type);
|
||||
|
||||
err = ieee80211_do_open(sdata->dev, false);
|
||||
WARN(err, "type change: do_open returned %d", err);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (type == sdata->vif.type)
|
||||
if (type == ieee80211_vif_type_p2p(&sdata->vif))
|
||||
return 0;
|
||||
|
||||
/* Setting ad-hoc mode on non-IBSS channel is not supported. */
|
||||
|
|
@ -899,18 +999,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
|||
type == NL80211_IFTYPE_ADHOC)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* We could, here, on changes between IBSS/STA/MESH modes,
|
||||
* invoke an MLME function instead that disassociates etc.
|
||||
* and goes into the requested mode.
|
||||
*/
|
||||
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
return -EBUSY;
|
||||
|
||||
/* Purge and reset type-dependent state. */
|
||||
ieee80211_teardown_sdata(sdata->dev);
|
||||
ieee80211_setup_sdata(sdata, type);
|
||||
if (ieee80211_sdata_running(sdata)) {
|
||||
ret = ieee80211_runtime_change_iftype(sdata, type);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* Purge and reset type-dependent state. */
|
||||
ieee80211_teardown_sdata(sdata->dev);
|
||||
ieee80211_setup_sdata(sdata, type);
|
||||
}
|
||||
|
||||
/* reset some values that shouldn't be kept across type changes */
|
||||
sdata->vif.bss_conf.basic_rates =
|
||||
|
|
@ -1167,8 +1264,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local,
|
|||
return 0;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: device no longer idle - %s\n",
|
||||
wiphy_name(local->hw.wiphy), reason);
|
||||
wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason);
|
||||
#endif
|
||||
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
|
||||
|
|
@ -1181,8 +1277,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
|
|||
return 0;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: device now idle\n",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
wiphy_debug(local->hw.wiphy, "device now idle\n");
|
||||
#endif
|
||||
|
||||
drv_flush(local, false);
|
||||
|
|
@ -1195,28 +1290,61 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int count = 0;
|
||||
bool working = false, scanning = false;
|
||||
struct ieee80211_work *wk;
|
||||
|
||||
if (!list_empty(&local->work_list))
|
||||
return ieee80211_idle_off(local, "working");
|
||||
|
||||
if (local->scanning)
|
||||
return ieee80211_idle_off(local, "scanning");
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
|
||||
!lockdep_is_held(&local->iflist_mtx));
|
||||
#endif
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
if (!ieee80211_sdata_running(sdata)) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
sdata->old_idle = sdata->vif.bss_conf.idle;
|
||||
|
||||
/* do not count disabled managed interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!sdata->u.mgd.associated)
|
||||
!sdata->u.mgd.associated) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
/* do not count unused IBSS interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
!sdata->u.ibss.ssid_len)
|
||||
!sdata->u.ibss.ssid_len) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
/* count everything else */
|
||||
count++;
|
||||
}
|
||||
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
working = true;
|
||||
wk->sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
|
||||
if (local->scan_sdata) {
|
||||
scanning = true;
|
||||
local->scan_sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata->old_idle == sdata->vif.bss_conf.idle)
|
||||
continue;
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
||||
}
|
||||
|
||||
if (working)
|
||||
return ieee80211_idle_off(local, "working");
|
||||
if (scanning)
|
||||
return ieee80211_idle_off(local, "scanning");
|
||||
if (!count)
|
||||
return ieee80211_idle_on(local);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
|||
|
||||
static void assert_key_lock(struct ieee80211_local *local)
|
||||
{
|
||||
WARN_ON(!mutex_is_locked(&local->key_mtx));
|
||||
lockdep_assert_held(&local->key_mtx);
|
||||
}
|
||||
|
||||
static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
|
||||
|
|
@ -60,7 +60,7 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_sta *sta;
|
||||
|
|
@ -69,12 +69,20 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
|||
might_sleep();
|
||||
|
||||
if (!key->local->ops->set_key)
|
||||
return;
|
||||
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,
|
||||
|
|
@ -83,14 +91,28 @@ static void 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)
|
||||
printk(KERN_ERR "mac80211-%s: failed to set key "
|
||||
"(%d, %pM) to hardware (%d)\n",
|
||||
wiphy_name(key->local->hw.wiphy),
|
||||
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
|
||||
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:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
||||
|
|
@ -121,14 +143,33 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
|||
sta, &key->conf);
|
||||
|
||||
if (ret)
|
||||
printk(KERN_ERR "mac80211-%s: failed to remove key "
|
||||
"(%d, %pM) from hardware (%d)\n",
|
||||
wiphy_name(key->local->hw.wiphy),
|
||||
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
|
||||
wiphy_err(key->local->hw.wiphy,
|
||||
"failed to remove key (%d, %pM) from hardware (%d)\n",
|
||||
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -184,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)
|
||||
{
|
||||
|
|
@ -192,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);
|
||||
|
||||
|
|
@ -227,20 +275,18 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
|
||||
int idx,
|
||||
size_t key_len,
|
||||
struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
||||
const u8 *key_data,
|
||||
size_t seq_len, const u8 *seq)
|
||||
{
|
||||
struct ieee80211_key *key;
|
||||
int i, j;
|
||||
int i, j, err;
|
||||
|
||||
BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS);
|
||||
|
||||
key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
|
||||
if (!key)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/*
|
||||
* Default to software encryption; we'll later upload the
|
||||
|
|
@ -249,15 +295,16 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
|
|||
key->conf.flags = 0;
|
||||
key->flags = 0;
|
||||
|
||||
key->conf.alg = alg;
|
||||
key->conf.cipher = cipher;
|
||||
key->conf.keyidx = idx;
|
||||
key->conf.keylen = key_len;
|
||||
switch (alg) {
|
||||
case ALG_WEP:
|
||||
switch (cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
key->conf.iv_len = WEP_IV_LEN;
|
||||
key->conf.icv_len = WEP_ICV_LEN;
|
||||
break;
|
||||
case ALG_TKIP:
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
key->conf.iv_len = TKIP_IV_LEN;
|
||||
key->conf.icv_len = TKIP_ICV_LEN;
|
||||
if (seq) {
|
||||
|
|
@ -269,7 +316,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
|
|||
}
|
||||
}
|
||||
break;
|
||||
case ALG_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
key->conf.iv_len = CCMP_HDR_LEN;
|
||||
key->conf.icv_len = CCMP_MIC_LEN;
|
||||
if (seq) {
|
||||
|
|
@ -278,42 +325,38 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
|
|||
key->u.ccmp.rx_pn[i][j] =
|
||||
seq[CCMP_PN_LEN - j - 1];
|
||||
}
|
||||
break;
|
||||
case ALG_AES_CMAC:
|
||||
key->conf.iv_len = 0;
|
||||
key->conf.icv_len = sizeof(struct ieee80211_mmie);
|
||||
if (seq)
|
||||
for (j = 0; j < 6; j++)
|
||||
key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
|
||||
break;
|
||||
}
|
||||
memcpy(key->conf.key, key_data, key_len);
|
||||
INIT_LIST_HEAD(&key->list);
|
||||
|
||||
if (alg == ALG_CCMP) {
|
||||
/*
|
||||
* Initialize AES key state here as an optimization so that
|
||||
* it does not need to be initialized for every packet.
|
||||
*/
|
||||
key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data);
|
||||
if (!key->u.ccmp.tfm) {
|
||||
if (IS_ERR(key->u.ccmp.tfm)) {
|
||||
err = PTR_ERR(key->u.ccmp.tfm);
|
||||
kfree(key);
|
||||
return NULL;
|
||||
key = ERR_PTR(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (alg == ALG_AES_CMAC) {
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
key->conf.iv_len = 0;
|
||||
key->conf.icv_len = sizeof(struct ieee80211_mmie);
|
||||
if (seq)
|
||||
for (j = 0; j < 6; j++)
|
||||
key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
|
||||
/*
|
||||
* Initialize AES key state here as an optimization so that
|
||||
* it does not need to be initialized for every packet.
|
||||
*/
|
||||
key->u.aes_cmac.tfm =
|
||||
ieee80211_aes_cmac_key_setup(key_data);
|
||||
if (!key->u.aes_cmac.tfm) {
|
||||
if (IS_ERR(key->u.aes_cmac.tfm)) {
|
||||
err = PTR_ERR(key->u.aes_cmac.tfm);
|
||||
kfree(key);
|
||||
return NULL;
|
||||
key = ERR_PTR(err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
memcpy(key->conf.key, key_data, key_len);
|
||||
INIT_LIST_HEAD(&key->list);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
|
@ -326,9 +369,9 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
|
|||
if (key->local)
|
||||
ieee80211_key_disable_hw_accel(key);
|
||||
|
||||
if (key->conf.alg == ALG_CCMP)
|
||||
if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
|
||||
ieee80211_aes_key_free(key->u.ccmp.tfm);
|
||||
if (key->conf.alg == ALG_AES_CMAC)
|
||||
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
|
||||
ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
|
||||
if (key->local)
|
||||
ieee80211_debugfs_key_remove(key);
|
||||
|
|
@ -336,12 +379,13 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
|
|||
kfree(key);
|
||||
}
|
||||
|
||||
void ieee80211_key_link(struct ieee80211_key *key,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta)
|
||||
int ieee80211_key_link(struct ieee80211_key *key,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_key *old_key;
|
||||
int idx;
|
||||
int idx, ret;
|
||||
bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
|
||||
|
||||
BUG_ON(!sdata);
|
||||
BUG_ON(!key);
|
||||
|
|
@ -358,13 +402,6 @@ void 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;
|
||||
|
|
@ -386,19 +423,23 @@ void 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);
|
||||
|
||||
ieee80211_key_enable_hw_accel(key);
|
||||
ret = ieee80211_key_enable_hw_accel(key);
|
||||
|
||||
mutex_unlock(&sdata->local->key_mtx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ieee80211_key_free(struct ieee80211_key *key)
|
||||
|
|
@ -408,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
|
||||
|
|
@ -123,18 +126,16 @@ struct ieee80211_key {
|
|||
struct ieee80211_key_conf conf;
|
||||
};
|
||||
|
||||
struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
|
||||
int idx,
|
||||
size_t key_len,
|
||||
struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
||||
const u8 *key_data,
|
||||
size_t seq_len, const u8 *seq);
|
||||
/*
|
||||
* Insert a key into data structures (sdata, sta if necessary)
|
||||
* to make it used, free old key.
|
||||
*/
|
||||
void ieee80211_key_link(struct ieee80211_key *key,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta);
|
||||
int __must_check ieee80211_key_link(struct ieee80211_key *key,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta);
|
||||
void ieee80211_key_free(struct ieee80211_local *local,
|
||||
struct ieee80211_key *key);
|
||||
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
|
|||
if (local->monitors || local->scanning)
|
||||
new_flags |= FIF_BCN_PRBRESP_PROMISC;
|
||||
|
||||
if (local->fif_probe_req || local->probe_req_reg)
|
||||
new_flags |= FIF_PROBE_REQ;
|
||||
|
||||
if (local->fif_fcsfail)
|
||||
new_flags |= FIF_FCSFAIL;
|
||||
|
||||
|
|
@ -99,16 +102,19 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
|||
int ret = 0;
|
||||
int power;
|
||||
enum nl80211_channel_type channel_type;
|
||||
u32 offchannel_flag;
|
||||
|
||||
might_sleep();
|
||||
|
||||
scan_chan = local->scan_channel;
|
||||
|
||||
offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
|
||||
if (scan_chan) {
|
||||
chan = scan_chan;
|
||||
channel_type = NL80211_CHAN_NO_HT;
|
||||
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
|
||||
} else if (local->tmp_channel) {
|
||||
} else if (local->tmp_channel &&
|
||||
local->oper_channel != local->tmp_channel) {
|
||||
chan = scan_chan = local->tmp_channel;
|
||||
channel_type = local->tmp_channel_type;
|
||||
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
|
||||
|
|
@ -117,8 +123,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
|||
channel_type = local->_oper_channel_type;
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
|
||||
}
|
||||
offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
|
||||
|
||||
if (chan != local->hw.conf.channel ||
|
||||
if (offchannel_flag || chan != local->hw.conf.channel ||
|
||||
channel_type != local->hw.conf.channel_type) {
|
||||
local->hw.conf.channel = chan;
|
||||
local->hw.conf.channel_type = channel_type;
|
||||
|
|
@ -197,6 +204,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 {
|
||||
|
|
@ -207,6 +216,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:
|
||||
|
|
@ -291,7 +301,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();
|
||||
}
|
||||
|
|
@ -302,7 +321,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
|
|||
|
||||
trace_api_restart_hw(local);
|
||||
|
||||
/* use this reason, __ieee80211_resume will unblock it */
|
||||
/* use this reason, ieee80211_reconfig will unblock it */
|
||||
ieee80211_stop_queues_by_reason(hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
|
||||
|
||||
|
|
@ -316,7 +335,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);
|
||||
}
|
||||
|
||||
|
|
@ -336,9 +355,6 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
|
|||
struct ieee80211_if_managed *ifmgd;
|
||||
int c = 0;
|
||||
|
||||
if (!netif_running(ndev))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* Make sure it's our interface that got changed */
|
||||
if (!wdev)
|
||||
return NOTIFY_DONE;
|
||||
|
|
@ -349,11 +365,14 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
|
|||
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
|
||||
bss_conf = &sdata->vif.bss_conf;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* ARP filtering is only supported in managed mode */
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
idev = sdata->dev->ip_ptr;
|
||||
idev = __in_dev_get_rtnl(sdata->dev);
|
||||
if (!idev)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
|
|
@ -390,6 +409,80 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
container_of(napi, struct ieee80211_local, napi);
|
||||
|
||||
return local->ops->napi_poll(&local->hw, budget);
|
||||
}
|
||||
|
||||
void ieee80211_napi_schedule(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
napi_schedule(&local->napi);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_napi_schedule);
|
||||
|
||||
void ieee80211_napi_complete(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
napi_complete(&local->napi);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_napi_complete);
|
||||
|
||||
/* There isn't a lot of sense in it, but you can transmit anything you like */
|
||||
static const struct ieee80211_txrx_stypes
|
||||
ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
[NL80211_IFTYPE_ADHOC] = {
|
||||
.tx = 0xffff,
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_STATION] = {
|
||||
.tx = 0xffff,
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_AP] = {
|
||||
.tx = 0xffff,
|
||||
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
|
||||
BIT(IEEE80211_STYPE_AUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_ACTION >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_AP_VLAN] = {
|
||||
/* copy AP */
|
||||
.tx = 0xffff,
|
||||
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
|
||||
BIT(IEEE80211_STYPE_AUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_ACTION >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_P2P_CLIENT] = {
|
||||
.tx = 0xffff,
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_P2P_GO] = {
|
||||
.tx = 0xffff,
|
||||
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
|
||||
BIT(IEEE80211_STYPE_AUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_ACTION >> 4),
|
||||
},
|
||||
};
|
||||
|
||||
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
const struct ieee80211_ops *ops)
|
||||
{
|
||||
|
|
@ -419,6 +512,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
if (!wiphy)
|
||||
return NULL;
|
||||
|
||||
wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes;
|
||||
|
||||
wiphy->flags |= WIPHY_FLAG_NETNS_OK |
|
||||
WIPHY_FLAG_4ADDR_AP |
|
||||
WIPHY_FLAG_4ADDR_STATION;
|
||||
|
|
@ -444,6 +539,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;
|
||||
|
|
@ -455,7 +551,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
__hw_addr_init(&local->mc_list);
|
||||
|
||||
mutex_init(&local->iflist_mtx);
|
||||
mutex_init(&local->scan_mtx);
|
||||
mutex_init(&local->mtx);
|
||||
|
||||
mutex_init(&local->key_mtx);
|
||||
spin_lock_init(&local->filter_lock);
|
||||
|
|
@ -494,6 +590,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
skb_queue_head_init(&local->skb_queue);
|
||||
skb_queue_head_init(&local->skb_queue_unreliable);
|
||||
|
||||
/* init dummy netdev for use w/ NAPI */
|
||||
init_dummy_netdev(&local->napi_dev);
|
||||
|
||||
return local_to_hw(local);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_alloc_hw);
|
||||
|
|
@ -506,6 +605,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
int channels, max_bitrates;
|
||||
bool supp_ht;
|
||||
static const u32 cipher_suites[] = {
|
||||
/* keep WEP first, it may be removed below */
|
||||
WLAN_CIPHER_SUITE_WEP40,
|
||||
WLAN_CIPHER_SUITE_WEP104,
|
||||
WLAN_CIPHER_SUITE_TKIP,
|
||||
|
|
@ -515,6 +615,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
|
||||
|
|
@ -554,6 +657,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
/* mac80211 always supports monitor */
|
||||
local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
|
||||
|
||||
#ifndef CONFIG_MAC80211_MESH
|
||||
/* mesh depends on Kconfig, but drivers should set it if they want */
|
||||
local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
#endif
|
||||
|
||||
/* mac80211 supports control port protocol changing */
|
||||
local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
|
||||
local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
|
||||
|
|
@ -589,10 +700,41 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
if (local->hw.wiphy->max_scan_ie_len)
|
||||
local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
|
||||
|
||||
local->hw.wiphy->cipher_suites = cipher_suites;
|
||||
local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
|
||||
if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
|
||||
local->hw.wiphy->n_cipher_suites--;
|
||||
/* Set up cipher suites unless driver already did */
|
||||
if (!local->hw.wiphy->cipher_suites) {
|
||||
local->hw.wiphy->cipher_suites = cipher_suites;
|
||||
local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
|
||||
if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
|
||||
local->hw.wiphy->n_cipher_suites--;
|
||||
}
|
||||
if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
|
||||
if (local->hw.wiphy->cipher_suites == cipher_suites) {
|
||||
local->hw.wiphy->cipher_suites += 2;
|
||||
local->hw.wiphy->n_cipher_suites -= 2;
|
||||
} else {
|
||||
u32 *suites;
|
||||
int r, w = 0;
|
||||
|
||||
/* Filter out WEP */
|
||||
|
||||
suites = kmemdup(
|
||||
local->hw.wiphy->cipher_suites,
|
||||
sizeof(u32) * local->hw.wiphy->n_cipher_suites,
|
||||
GFP_KERNEL);
|
||||
if (!suites)
|
||||
return -ENOMEM;
|
||||
for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
|
||||
u32 suite = local->hw.wiphy->cipher_suites[r];
|
||||
if (suite == WLAN_CIPHER_SUITE_WEP40 ||
|
||||
suite == WLAN_CIPHER_SUITE_WEP104)
|
||||
continue;
|
||||
suites[w++] = suite;
|
||||
}
|
||||
local->hw.wiphy->cipher_suites = suites;
|
||||
local->hw.wiphy->n_cipher_suites = w;
|
||||
local->wiphy_ciphers_allocated = true;
|
||||
}
|
||||
}
|
||||
|
||||
result = wiphy_register(local->hw.wiphy);
|
||||
if (result < 0)
|
||||
|
|
@ -641,16 +783,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
|
||||
result = ieee80211_wep_init(local);
|
||||
if (result < 0)
|
||||
printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
|
||||
wiphy_name(local->hw.wiphy), result);
|
||||
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
|
||||
result);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
result = ieee80211_init_rate_ctrl_alg(local,
|
||||
hw->rate_control_algorithm);
|
||||
if (result < 0) {
|
||||
printk(KERN_DEBUG "%s: Failed to initialize rate control "
|
||||
"algorithm\n", wiphy_name(local->hw.wiphy));
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"Failed to initialize rate control algorithm\n");
|
||||
goto fail_rate;
|
||||
}
|
||||
|
||||
|
|
@ -659,8 +801,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
result = ieee80211_if_add(local, "wlan%d", NULL,
|
||||
NL80211_IFTYPE_STATION, NULL);
|
||||
if (result)
|
||||
printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
wiphy_warn(local->hw.wiphy,
|
||||
"Failed to add default virtual iface\n");
|
||||
}
|
||||
|
||||
rtnl_unlock();
|
||||
|
|
@ -683,6 +825,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
goto fail_ifa;
|
||||
#endif
|
||||
|
||||
netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
|
||||
local->hw.napi_weight);
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
|
|
@ -703,6 +848,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
fail_workqueue:
|
||||
wiphy_unregister(local->hw.wiphy);
|
||||
fail_wiphy_register:
|
||||
if (local->wiphy_ciphers_allocated)
|
||||
kfree(local->hw.wiphy->cipher_suites);
|
||||
kfree(local->int_scan_req);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -738,6 +885,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
|||
*/
|
||||
del_timer_sync(&local->work_timer);
|
||||
|
||||
cancel_work_sync(&local->restart_work);
|
||||
cancel_work_sync(&local->reconfig_filter);
|
||||
|
||||
ieee80211_clear_tx_pending(local);
|
||||
|
|
@ -746,8 +894,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
|||
|
||||
if (skb_queue_len(&local->skb_queue) ||
|
||||
skb_queue_len(&local->skb_queue_unreliable))
|
||||
printk(KERN_WARNING "%s: skb_queue not empty\n",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
|
||||
skb_queue_purge(&local->skb_queue);
|
||||
skb_queue_purge(&local->skb_queue_unreliable);
|
||||
|
||||
|
|
@ -764,7 +911,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
|
|||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
mutex_destroy(&local->iflist_mtx);
|
||||
mutex_destroy(&local->scan_mtx);
|
||||
mutex_destroy(&local->mtx);
|
||||
|
||||
if (local->wiphy_ciphers_allocated)
|
||||
kfree(local->hw.wiphy->cipher_suites);
|
||||
|
||||
wiphy_free(local->hw.wiphy);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
|||
enum plink_event event;
|
||||
enum plink_frame_type ftype;
|
||||
size_t baselen;
|
||||
bool deactivated;
|
||||
bool deactivated, matches_local = true;
|
||||
u8 ie_len;
|
||||
u8 *baseaddr;
|
||||
__le16 plid, llid, reason;
|
||||
|
|
@ -487,6 +487,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
|||
/* Now we will figure out the appropriate event... */
|
||||
event = PLINK_UNDEFINED;
|
||||
if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) {
|
||||
matches_local = false;
|
||||
switch (ftype) {
|
||||
case PLINK_OPEN:
|
||||
event = OPN_RJCT;
|
||||
|
|
@ -498,7 +499,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
|||
/* avoid warning */
|
||||
break;
|
||||
}
|
||||
spin_lock_bh(&sta->lock);
|
||||
}
|
||||
|
||||
if (!sta && !matches_local) {
|
||||
rcu_read_unlock();
|
||||
reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
|
||||
llid = 0;
|
||||
mesh_plink_frame_tx(sdata, PLINK_CLOSE, mgmt->sa, llid,
|
||||
plid, reason);
|
||||
return;
|
||||
} else if (!sta) {
|
||||
/* ftype == PLINK_OPEN */
|
||||
u32 rates;
|
||||
|
|
@ -522,7 +531,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
|||
}
|
||||
event = OPN_ACPT;
|
||||
spin_lock_bh(&sta->lock);
|
||||
} else {
|
||||
} else if (matches_local) {
|
||||
spin_lock_bh(&sta->lock);
|
||||
switch (ftype) {
|
||||
case PLINK_OPEN:
|
||||
|
|
@ -564,6 +573,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
|||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
spin_lock_bh(&sta->lock);
|
||||
}
|
||||
|
||||
mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@
|
|||
*/
|
||||
#define IEEE80211_SIGNAL_AVE_WEIGHT 3
|
||||
|
||||
/*
|
||||
* How many Beacon frames need to have been used in average signal strength
|
||||
* before starting to indicate signal change events.
|
||||
*/
|
||||
#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
|
||||
|
||||
#define TMR_RUNNING_TIMER 0
|
||||
#define TMR_RUNNING_CHANSW 1
|
||||
|
||||
|
|
@ -86,7 +92,7 @@ enum rx_mgmt_action {
|
|||
/* utils */
|
||||
static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
|
||||
{
|
||||
WARN_ON(!mutex_is_locked(&ifmgd->mtx));
|
||||
lockdep_assert_held(&ifmgd->mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -109,7 +115,7 @@ static void run_again(struct ieee80211_if_managed *ifmgd,
|
|||
mod_timer(&ifmgd->timer, timeout);
|
||||
}
|
||||
|
||||
static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata)
|
||||
void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER)
|
||||
return;
|
||||
|
|
@ -118,6 +124,19 @@ static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata)
|
|||
round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME));
|
||||
}
|
||||
|
||||
void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
|
||||
return;
|
||||
|
||||
mod_timer(&sdata->u.mgd.conn_mon_timer,
|
||||
round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
|
||||
|
||||
ifmgd->probe_send_count = 0;
|
||||
}
|
||||
|
||||
static int ecw2cw(int ecw)
|
||||
{
|
||||
return (1 << ecw) - 1;
|
||||
|
|
@ -778,16 +797,17 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|||
params.uapsd = uapsd;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
|
||||
"cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
|
||||
wiphy_name(local->hw.wiphy), queue, aci, acm,
|
||||
params.aifs, params.cw_min, params.cw_max, params.txop,
|
||||
params.uapsd);
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"WMM queue=%d aci=%d acm=%d aifs=%d "
|
||||
"cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
|
||||
queue, aci, acm,
|
||||
params.aifs, params.cw_min, params.cw_max,
|
||||
params.txop, params.uapsd);
|
||||
#endif
|
||||
if (drv_conf_tx(local, queue, ¶ms))
|
||||
printk(KERN_DEBUG "%s: failed to set TX queue "
|
||||
"parameters for queue %d\n",
|
||||
wiphy_name(local->hw.wiphy), queue);
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"failed to set TX queue parameters for queue %d\n",
|
||||
queue);
|
||||
}
|
||||
|
||||
/* enable WMM or activate new settings */
|
||||
|
|
@ -860,14 +880,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
|||
sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
|
||||
IEEE80211_STA_BEACON_POLL);
|
||||
|
||||
/*
|
||||
* Always handle WMM once after association regardless
|
||||
* of the first value the AP uses. Setting -1 here has
|
||||
* that effect because the AP values is an unsigned
|
||||
* 4-bit value.
|
||||
*/
|
||||
sdata->u.mgd.wmm_last_param_set = -1;
|
||||
|
||||
ieee80211_led_assoc(local, 1);
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
|
||||
|
|
@ -901,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);
|
||||
|
|
@ -909,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;
|
||||
|
|
@ -948,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);
|
||||
|
||||
|
|
@ -990,6 +1002,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (remove_sta)
|
||||
sta_info_destroy_addr(sdata, bssid);
|
||||
|
||||
del_timer_sync(&sdata->u.mgd.conn_mon_timer);
|
||||
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
|
||||
del_timer_sync(&sdata->u.mgd.timer);
|
||||
del_timer_sync(&sdata->u.mgd.chswitch_timer);
|
||||
}
|
||||
|
||||
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
@ -1006,21 +1023,26 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
|
|||
if (is_multicast_ether_addr(hdr->addr1))
|
||||
return;
|
||||
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
|
||||
return;
|
||||
|
||||
mod_timer(&sdata->u.mgd.conn_mon_timer,
|
||||
round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
|
||||
ieee80211_sta_reset_conn_monitor(sdata);
|
||||
}
|
||||
|
||||
static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
const u8 *ssid;
|
||||
u8 *dst = ifmgd->associated->bssid;
|
||||
u8 unicast_limit = max(1, IEEE80211_MAX_PROBE_TRIES - 3);
|
||||
|
||||
/*
|
||||
* Try sending broadcast probe requests for the last three
|
||||
* probe requests after the first ones failed since some
|
||||
* buggy APs only support broadcast probe requests.
|
||||
*/
|
||||
if (ifmgd->probe_send_count >= unicast_limit)
|
||||
dst = NULL;
|
||||
|
||||
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
|
||||
ieee80211_send_probe_req(sdata, ifmgd->associated->bssid,
|
||||
ssid + 2, ssid[1], NULL, 0);
|
||||
ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0);
|
||||
|
||||
ifmgd->probe_send_count++;
|
||||
ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
|
||||
|
|
@ -1102,9 +1124,12 @@ 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_recalc_idle(local);
|
||||
ieee80211_set_disassoc(sdata, true, true);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
/*
|
||||
* must be outside lock due to cfg80211,
|
||||
* but that's not a problem.
|
||||
|
|
@ -1172,8 +1197,10 @@ 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);
|
||||
|
||||
return RX_MGMT_CFG80211_DEAUTH;
|
||||
}
|
||||
|
|
@ -1202,8 +1229,10 @@ 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);
|
||||
return RX_MGMT_CFG80211_DISASSOC;
|
||||
}
|
||||
|
||||
|
|
@ -1262,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;
|
||||
|
|
@ -1298,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
|
||||
|
|
@ -1330,6 +1359,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Always handle WMM once after association regardless
|
||||
* of the first value the AP uses. Setting -1 here has
|
||||
* that effect because the AP values is an unsigned
|
||||
* 4-bit value.
|
||||
*/
|
||||
ifmgd->wmm_last_param_set = -1;
|
||||
|
||||
if (elems.wmm_param)
|
||||
ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
|
||||
elems.wmm_param_len);
|
||||
|
|
@ -1362,7 +1399,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
|
|||
* Also start the timer that will detect beacon loss.
|
||||
*/
|
||||
ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
|
||||
mod_beacon_timer(sdata);
|
||||
ieee80211_sta_reset_beacon_monitor(sdata);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1465,7 +1502,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
* we have or will be receiving any beacons or data, so let's
|
||||
* schedule the timers again, just in case.
|
||||
*/
|
||||
mod_beacon_timer(sdata);
|
||||
ieee80211_sta_reset_beacon_monitor(sdata);
|
||||
|
||||
mod_timer(&ifmgd->conn_mon_timer,
|
||||
round_jiffies_up(jiffies +
|
||||
|
|
@ -1540,15 +1577,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->last_beacon_signal = rx_status->signal;
|
||||
if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
|
||||
ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
|
||||
ifmgd->ave_beacon_signal = rx_status->signal;
|
||||
ifmgd->ave_beacon_signal = rx_status->signal * 16;
|
||||
ifmgd->last_cqm_event_signal = 0;
|
||||
ifmgd->count_beacon_signal = 1;
|
||||
} else {
|
||||
ifmgd->ave_beacon_signal =
|
||||
(IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
|
||||
(16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
|
||||
ifmgd->ave_beacon_signal) / 16;
|
||||
ifmgd->count_beacon_signal++;
|
||||
}
|
||||
if (bss_conf->cqm_rssi_thold &&
|
||||
ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
|
||||
!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
|
||||
int sig = ifmgd->ave_beacon_signal / 16;
|
||||
int last_event = ifmgd->last_cqm_event_signal;
|
||||
|
|
@ -1588,7 +1628,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
* Push the beacon loss detection into the future since
|
||||
* we are processing a beacon from the AP just now.
|
||||
*/
|
||||
mod_beacon_timer(sdata);
|
||||
ieee80211_sta_reset_beacon_monitor(sdata);
|
||||
|
||||
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
|
||||
ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
|
||||
|
|
@ -1599,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);
|
||||
|
||||
|
|
@ -1630,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;
|
||||
|
|
@ -1751,7 +1792,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_work *wk;
|
||||
|
||||
mutex_lock(&local->work_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
if (wk->sdata != sdata)
|
||||
continue;
|
||||
|
|
@ -1783,7 +1824,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
free_work(wk);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&local->work_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
|
||||
}
|
||||
|
|
@ -1823,10 +1864,12 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "No probe response from AP %pM"
|
||||
" after %dms, try %d\n", bssid,
|
||||
(1000 * IEEE80211_PROBE_WAIT)/HZ,
|
||||
ifmgd->probe_send_count);
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"%s: No probe response from AP %pM"
|
||||
" after %dms, try %d\n",
|
||||
sdata->name,
|
||||
bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ,
|
||||
ifmgd->probe_send_count);
|
||||
#endif
|
||||
ieee80211_mgd_probe_ap_send(sdata);
|
||||
} else {
|
||||
|
|
@ -1836,12 +1879,16 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
|||
*/
|
||||
ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
|
||||
IEEE80211_STA_BEACON_POLL);
|
||||
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_recalc_idle(local);
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"%s: No probe response from AP %pM"
|
||||
" after %dms, disconnecting.\n",
|
||||
sdata->name,
|
||||
bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
|
||||
ieee80211_set_disassoc(sdata, true, true);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
/*
|
||||
* must be outside lock due to cfg80211,
|
||||
* but that's not a problem.
|
||||
|
|
@ -1917,6 +1964,8 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
|
|||
* time -- the code here is properly synchronised.
|
||||
*/
|
||||
|
||||
cancel_work_sync(&ifmgd->request_smps_work);
|
||||
|
||||
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
|
||||
if (del_timer_sync(&ifmgd->timer))
|
||||
set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
|
||||
|
|
@ -1952,6 +2001,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
|
|||
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
|
||||
INIT_WORK(&ifmgd->beacon_connection_loss_work,
|
||||
ieee80211_beacon_connection_loss_work);
|
||||
INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
|
||||
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
|
||||
(unsigned long) sdata);
|
||||
setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
|
||||
|
|
@ -2158,7 +2208,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);
|
||||
|
||||
|
|
@ -2169,6 +2219,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 ||
|
||||
|
|
@ -2249,6 +2301,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
else
|
||||
ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
|
||||
|
||||
sdata->control_port_protocol = req->crypto.control_port_ethertype;
|
||||
sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
|
||||
|
||||
ieee80211_add_work(wk);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2267,7 +2322,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 {
|
||||
|
|
@ -2275,7 +2330,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
mutex_lock(&local->work_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
if (wk->sdata != sdata)
|
||||
continue;
|
||||
|
|
@ -2294,7 +2349,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
free_work(wk);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&local->work_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
/*
|
||||
* If somebody requests authentication and we haven't
|
||||
|
|
@ -2319,7 +2374,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
if (assoc_bss)
|
||||
sta_info_destroy_addr(sdata, bssid);
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2348,7 +2405,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);
|
||||
|
||||
|
|
@ -2357,7 +2414,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
cookie, !req->local_state_change);
|
||||
sta_info_destroy_addr(sdata, bssid);
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,16 @@
|
|||
static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
local->offchannel_ps_enabled = false;
|
||||
|
||||
/* FIXME: what to do when local->pspolling is true? */
|
||||
|
||||
del_timer_sync(&local->dynamic_ps_timer);
|
||||
del_timer_sync(&ifmgd->bcn_mon_timer);
|
||||
del_timer_sync(&ifmgd->conn_mon_timer);
|
||||
|
||||
cancel_work_sync(&local->dynamic_ps_enable_work);
|
||||
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
|
|
@ -85,6 +89,9 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
|
|||
mod_timer(&local->dynamic_ps_timer, jiffies +
|
||||
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
|
||||
}
|
||||
|
||||
ieee80211_sta_reset_beacon_monitor(sdata);
|
||||
ieee80211_sta_reset_conn_monitor(sdata);
|
||||
}
|
||||
|
||||
void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
|
||||
|
|
@ -112,8 +119,10 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
|
|||
* used from user space controlled off-channel operations.
|
||||
*/
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR) {
|
||||
set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
|
@ -131,6 +140,7 @@ void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
|
|||
continue;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
if (sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_enable(sdata);
|
||||
|
|
@ -155,8 +165,20 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
|
|||
ieee80211_offchannel_ps_disable(sdata);
|
||||
}
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
|
||||
/*
|
||||
* This may wake up queues even though the driver
|
||||
* currently has them stopped. This is not very
|
||||
* likely, since the driver won't have gotten any
|
||||
* (or hardly any) new packets while we weren't
|
||||
* on the right channel, and even if it happens
|
||||
* it will at most lead to queueing up one more
|
||||
* packet per queue in mac80211 rather than on
|
||||
* the interface qdisc.
|
||||
*/
|
||||
netif_tx_wake_all_queues(sdata->dev);
|
||||
}
|
||||
|
||||
/* re-enable beaconing */
|
||||
if (enable_beaconing &&
|
||||
|
|
|
|||
|
|
@ -45,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) {
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
|
|||
|
||||
fc = hdr->frame_control;
|
||||
|
||||
return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
|
||||
return (info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc);
|
||||
}
|
||||
|
||||
static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx)
|
||||
|
|
@ -369,8 +369,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
|
|||
|
||||
ref = rate_control_alloc(name, local);
|
||||
if (!ref) {
|
||||
printk(KERN_WARNING "%s: Failed to select rate control "
|
||||
"algorithm\n", wiphy_name(local->hw.wiphy));
|
||||
wiphy_warn(local->hw.wiphy,
|
||||
"Failed to select rate control algorithm\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
|
@ -381,9 +381,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
|
|||
sta_info_flush(local, NULL);
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: Selected rate control "
|
||||
"algorithm '%s'\n", wiphy_name(local->hw.wiphy),
|
||||
ref->ops->name);
|
||||
wiphy_debug(local->hw.wiphy, "Selected rate control algorithm '%s'\n",
|
||||
ref->ops->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -397,8 +397,9 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
|||
!(info->flags & IEEE80211_TX_STAT_AMPDU))
|
||||
return;
|
||||
|
||||
if (!info->status.ampdu_len) {
|
||||
info->status.ampdu_ack_len = 1;
|
||||
if (!(info->flags & IEEE80211_TX_STAT_AMPDU)) {
|
||||
info->status.ampdu_ack_len =
|
||||
(info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0);
|
||||
info->status.ampdu_len = 1;
|
||||
}
|
||||
|
||||
|
|
@ -426,7 +427,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
|||
group = minstrel_ht_get_group_idx(&ar[i]);
|
||||
rate = &mi->groups[group].rates[ar[i].idx % 8];
|
||||
|
||||
if (last && (info->flags & IEEE80211_TX_STAT_ACK))
|
||||
if (last)
|
||||
rate->success += info->status.ampdu_ack_len;
|
||||
|
||||
rate->attempts += ar[i].count * info->status.ampdu_len;
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
|
|||
file_info->next_entry = (file_info->next_entry + 1) %
|
||||
RC_PID_EVENT_RING_SIZE;
|
||||
|
||||
/* Print information about the event. Note that userpace needs to
|
||||
/* Print information about the event. Note that userspace needs to
|
||||
* provide large enough buffers. */
|
||||
length = length < RC_PID_PRINT_BUF_SIZE ?
|
||||
length : RC_PID_PRINT_BUF_SIZE;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -242,20 +242,19 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
|
|||
local->hw_scan_req->n_channels = n_chans;
|
||||
|
||||
ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
|
||||
req->ie, req->ie_len, band);
|
||||
req->ie, req->ie_len, band, (u32) -1,
|
||||
0);
|
||||
local->hw_scan_req->ie_len = ielen;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
trace_api_scan_completed(local, aborted);
|
||||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
/*
|
||||
* It's ok to abort a not-yet-running scan (that
|
||||
|
|
@ -266,17 +265,13 @@ 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->scan_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->scan_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);
|
||||
|
|
@ -290,26 +285,42 @@ 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->scan_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);
|
||||
ieee80211_queue_work(&local->hw, &local->work_work);
|
||||
}
|
||||
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
trace_api_scan_completed(local, aborted);
|
||||
|
||||
set_bit(SCAN_COMPLETED, &local->scanning);
|
||||
if (aborted)
|
||||
set_bit(SCAN_ABORTED, &local->scanning);
|
||||
ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_scan_completed);
|
||||
|
||||
static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
||||
|
|
@ -353,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;
|
||||
|
||||
|
|
@ -434,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;
|
||||
|
|
@ -445,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
|
||||
|
|
@ -522,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,
|
||||
|
|
@ -638,20 +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;
|
||||
bool aborted, hw_scan, finish;
|
||||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
if (!sdata || !local->scan_req) {
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
return;
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
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->scan_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;
|
||||
|
|
@ -661,21 +664,21 @@ void ieee80211_scan_work(struct work_struct *work)
|
|||
local->scan_sdata = NULL;
|
||||
|
||||
rc = __ieee80211_start_scan(sdata, req);
|
||||
mutex_unlock(&local->scan_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->scan_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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -685,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);
|
||||
|
|
@ -704,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,
|
||||
|
|
@ -711,9 +731,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
int res;
|
||||
|
||||
mutex_lock(&sdata->local->scan_mtx);
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
res = __ieee80211_start_scan(sdata, req);
|
||||
mutex_unlock(&sdata->local->scan_mtx);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -726,7 +746,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
|
|||
int ret = -EBUSY;
|
||||
enum ieee80211_band band;
|
||||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
/* busy scanning */
|
||||
if (local->scan_req)
|
||||
|
|
@ -761,25 +781,44 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
|
||||
unlock:
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
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->scan_mtx);
|
||||
abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
|
||||
(!local->scanning && local->scan_req);
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning);
|
||||
if (abortscan)
|
||||
ieee80211_scan_completed(&local->hw, true);
|
||||
finish = __ieee80211_scan_completed(&local->hw, true, false);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
|
|||
lockdep_is_held(&local->sta_mtx));
|
||||
while (sta) {
|
||||
if ((sta->sdata == sdata ||
|
||||
sta->sdata->bss == sdata->bss) &&
|
||||
(sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
|
||||
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
|
||||
break;
|
||||
sta = rcu_dereference_check(sta->hnext,
|
||||
|
|
@ -174,8 +174,7 @@ static void __sta_info_free(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Destroyed STA %pM\n",
|
||||
wiphy_name(local->hw.wiphy), sta->sta.addr);
|
||||
wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
|
||||
kfree(sta);
|
||||
|
|
@ -262,8 +261,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Allocated STA %pM\n",
|
||||
wiphy_name(local->hw.wiphy), sta->sta.addr);
|
||||
wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
|
|
@ -282,7 +280,7 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
|
|||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&local->sta_mtx));
|
||||
lockdep_assert_held(&local->sta_mtx);
|
||||
|
||||
/* notify driver */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
|
|
@ -300,8 +298,9 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
|
|||
sta->uploaded = true;
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
if (async)
|
||||
printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n",
|
||||
wiphy_name(local->hw.wiphy), sta->sta.addr);
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"Finished adding IBSS STA %pM\n",
|
||||
sta->sta.addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -411,8 +410,8 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
|
|||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Added IBSS STA %pM\n",
|
||||
wiphy_name(local->hw.wiphy), sta->sta.addr);
|
||||
wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
|
||||
sta->sta.addr);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->sta_finish_work);
|
||||
|
|
@ -459,8 +458,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Inserted STA %pM\n",
|
||||
wiphy_name(local->hw.wiphy), sta->sta.addr);
|
||||
wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
|
||||
/* move reference to rcu-protected */
|
||||
|
|
@ -618,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();
|
||||
|
||||
|
|
@ -635,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);
|
||||
|
|
@ -646,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;
|
||||
|
||||
|
|
@ -690,8 +688,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Removed STA %pM\n",
|
||||
wiphy_name(local->hw.wiphy), sta->sta.addr);
|
||||
wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
cancel_work_sync(&sta->drv_unblock_wk);
|
||||
|
||||
|
|
@ -841,13 +838,20 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
|
|||
mutex_unlock(&local->sta_mtx);
|
||||
}
|
||||
|
||||
struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
|
||||
const u8 *addr)
|
||||
struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
|
||||
const u8 *addr,
|
||||
const u8 *localaddr)
|
||||
{
|
||||
struct sta_info *sta, *nxt;
|
||||
|
||||
/* Just return a random station ... first in list ... */
|
||||
/*
|
||||
* Just return a random station if localaddr is NULL
|
||||
* ... first in list.
|
||||
*/
|
||||
for_each_sta_info(hw_to_local(hw), addr, sta, nxt) {
|
||||
if (localaddr &&
|
||||
compare_ether_addr(sta->sdata->vif.addr, localaddr) != 0)
|
||||
continue;
|
||||
if (!sta->uploaded)
|
||||
return NULL;
|
||||
return &sta->sta;
|
||||
|
|
@ -855,7 +859,7 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
|
|||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
|
||||
EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_ifaddr);
|
||||
|
||||
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
|
||||
const u8 *addr)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -103,6 +105,7 @@ struct tid_ampdu_tx {
|
|||
* @reorder_buf: buffer to reorder incoming aggregated MPDUs
|
||||
* @reorder_time: jiffies when skb was added
|
||||
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
|
||||
* @reorder_timer: releases expired frames from the reorder buffer.
|
||||
* @head_seq_num: head sequence number in reordering buffer.
|
||||
* @stored_mpdu_num: number of MPDUs in reordering buffer
|
||||
* @ssn: Starting Sequence Number expected to be aggregated.
|
||||
|
|
@ -110,20 +113,25 @@ struct tid_ampdu_tx {
|
|||
* @timeout: reset timer value (in TUs).
|
||||
* @dialog_token: dialog token for aggregation session
|
||||
* @rcu_head: RCU head used for freeing this struct
|
||||
* @reorder_lock: serializes access to reorder buffer, see below.
|
||||
*
|
||||
* This structure is protected by RCU and the per-station
|
||||
* spinlock. Assignments to the array holding it must hold
|
||||
* the spinlock, only the RX path can access it under RCU
|
||||
* lock-free. The RX path, since it is single-threaded,
|
||||
* can even modify the structure without locking since the
|
||||
* only other modifications to it are done when the struct
|
||||
* can not yet or no longer be found by the RX path.
|
||||
* the spinlock.
|
||||
*
|
||||
* The @reorder_lock is used to protect the variables and
|
||||
* arrays such as @reorder_buf, @reorder_time, @head_seq_num,
|
||||
* @stored_mpdu_num and @reorder_time from being corrupted by
|
||||
* concurrent access of the RX path and the expired frame
|
||||
* release timer.
|
||||
*/
|
||||
struct tid_ampdu_rx {
|
||||
struct rcu_head rcu_head;
|
||||
spinlock_t reorder_lock;
|
||||
struct sk_buff **reorder_buf;
|
||||
unsigned long *reorder_time;
|
||||
struct timer_list session_timer;
|
||||
struct timer_list reorder_timer;
|
||||
u16 head_seq_num;
|
||||
u16 stored_mpdu_num;
|
||||
u16 ssn;
|
||||
|
|
@ -191,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
|
||||
|
|
@ -246,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;
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
|
|||
info->control.vif = &sta->sdata->vif;
|
||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING |
|
||||
IEEE80211_TX_INTFL_RETRANSMISSION;
|
||||
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
|
||||
|
||||
sta->tx_filtered_count++;
|
||||
|
||||
|
|
@ -114,11 +115,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
|
|||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: dropped TX filtered frame, "
|
||||
"queue_len=%d PS=%d @%lu\n",
|
||||
wiphy_name(local->hw.wiphy),
|
||||
skb_queue_len(&sta->tx_filtered),
|
||||
!!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
|
||||
skb_queue_len(&sta->tx_filtered),
|
||||
!!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
|
||||
#endif
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
@ -296,7 +296,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
|
||||
cfg80211_action_tx_status(
|
||||
cfg80211_mgmt_tx_status(
|
||||
skb->dev, (unsigned long) skb, skb->data, skb->len,
|
||||
!!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
@ -351,8 +354,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
|
|||
|
||||
local->total_ps_buffered = total;
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
|
||||
wiphy_name(local->hw.wiphy), purged);
|
||||
wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n",
|
||||
purged);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -508,6 +511,18 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
|
|||
return ieee80211_tx_h_multicast_ps_buf(tx);
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
|
||||
if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol &&
|
||||
tx->sdata->control_port_no_encrypt))
|
||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
|
|
@ -517,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) &&
|
||||
|
|
@ -527,7 +542,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|||
else if ((key = rcu_dereference(tx->sdata->default_key)))
|
||||
tx->key = key;
|
||||
else if (tx->sdata->drop_unencrypted &&
|
||||
(tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) &&
|
||||
(tx->skb->protocol != tx->sdata->control_port_protocol) &&
|
||||
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
|
||||
(!ieee80211_is_robust_mgmt_frame(hdr) ||
|
||||
(ieee80211_is_action(hdr->frame_control) &&
|
||||
|
|
@ -543,15 +558,16 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|||
tx->key->tx_rx_count++;
|
||||
/* TODO: add threshold stuff again */
|
||||
|
||||
switch (tx->key->conf.alg) {
|
||||
case ALG_WEP:
|
||||
switch (tx->key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
if (ieee80211_is_auth(hdr->frame_control))
|
||||
break;
|
||||
case ALG_TKIP:
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
if (!ieee80211_is_data_present(hdr->frame_control))
|
||||
tx->key = NULL;
|
||||
break;
|
||||
case ALG_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
if (!ieee80211_is_data_present(hdr->frame_control) &&
|
||||
!ieee80211_use_mfp(hdr->frame_control, tx->sta,
|
||||
tx->skb))
|
||||
|
|
@ -561,7 +577,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|||
IEEE80211_KEY_FLAG_SW_MGMT) &&
|
||||
ieee80211_is_mgmt(hdr->frame_control);
|
||||
break;
|
||||
case ALG_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
if (!ieee80211_is_mgmt(hdr->frame_control))
|
||||
tx->key = NULL;
|
||||
break;
|
||||
|
|
@ -946,22 +962,31 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
|
|||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
|
||||
if (!tx->key)
|
||||
return TX_CONTINUE;
|
||||
|
||||
switch (tx->key->conf.alg) {
|
||||
case ALG_WEP:
|
||||
switch (tx->key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
return ieee80211_crypto_wep_encrypt(tx);
|
||||
case ALG_TKIP:
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
return ieee80211_crypto_tkip_encrypt(tx);
|
||||
case ALG_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
return ieee80211_crypto_ccmp_encrypt(tx);
|
||||
case ALG_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
return ieee80211_crypto_aes_cmac_encrypt(tx);
|
||||
default:
|
||||
/* handle hw-only algorithm */
|
||||
if (info->control.hw_key) {
|
||||
ieee80211_tx_set_protected(tx);
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* not reached */
|
||||
WARN_ON(1);
|
||||
return TX_DROP;
|
||||
}
|
||||
|
||||
|
|
@ -1339,6 +1364,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
|||
CALL_TXH(ieee80211_tx_h_dynamic_ps);
|
||||
CALL_TXH(ieee80211_tx_h_check_assoc);
|
||||
CALL_TXH(ieee80211_tx_h_ps_buf);
|
||||
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
|
||||
CALL_TXH(ieee80211_tx_h_select_key);
|
||||
if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
|
||||
CALL_TXH(ieee80211_tx_h_rate_ctrl);
|
||||
|
|
@ -1511,8 +1537,8 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
|
|||
I802_DEBUG_INC(local->tx_expand_skb_head);
|
||||
|
||||
if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
|
||||
printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"failed to reallocate TX buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -1586,6 +1612,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
return;
|
||||
}
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
info->control.vif = &sdata->vif;
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
|
|
@ -1699,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
u16 ethertype, hdrlen, meshhdrlen = 0;
|
||||
__le16 fc;
|
||||
struct ieee80211_hdr hdr;
|
||||
struct ieee80211s_hdr mesh_hdr;
|
||||
struct ieee80211s_hdr mesh_hdr __maybe_unused;
|
||||
const u8 *encaps_data;
|
||||
int encaps_len, skip_header_bytes;
|
||||
int nh_pos, h_pos;
|
||||
|
|
@ -1816,7 +1843,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
#endif
|
||||
case NL80211_IFTYPE_STATION:
|
||||
memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
|
||||
if (sdata->u.mgd.use_4addr &&
|
||||
cpu_to_be16(ethertype) != sdata->control_port_protocol) {
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
|
||||
/* RA TA DA SA */
|
||||
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
|
||||
|
|
@ -1869,7 +1897,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
unlikely(!is_multicast_ether_addr(hdr.addr1) &&
|
||||
!(sta_flags & WLAN_STA_AUTHORIZED) &&
|
||||
!(ethertype == ETH_P_PAE &&
|
||||
!(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
|
||||
compare_ether_addr(sdata->vif.addr,
|
||||
skb->data + ETH_ALEN) == 0))) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
|
|
@ -2068,8 +2096,7 @@ void ieee80211_tx_pending(unsigned long data)
|
|||
|
||||
if (skb_queue_empty(&local->pending[i]))
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
netif_tx_wake_queue(
|
||||
netdev_get_tx_queue(sdata->dev, i));
|
||||
netif_wake_subqueue(sdata->dev, i);
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -283,8 +283,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
|
|||
|
||||
if (skb_queue_empty(&local->pending[queue])) {
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
|
||||
continue;
|
||||
netif_wake_subqueue(sdata->dev, queue);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
} else
|
||||
tasklet_schedule(&local->tx_pending_tasklet);
|
||||
|
|
@ -323,7 +326,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
|
|||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue));
|
||||
netif_stop_subqueue(sdata->dev, queue);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
@ -471,16 +474,10 @@ void ieee80211_iterate_active_interfaces(
|
|||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
switch (sdata->vif.type) {
|
||||
case __NL80211_IFTYPE_AFTER_LAST:
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
continue;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
|
|
@ -505,16 +502,10 @@ void ieee80211_iterate_active_interfaces_atomic(
|
|||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
switch (sdata->vif.type) {
|
||||
case __NL80211_IFTYPE_AFTER_LAST:
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
continue;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
|
|
@ -904,26 +895,34 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
const u8 *ie, size_t ie_len,
|
||||
enum ieee80211_band band)
|
||||
enum ieee80211_band band, u32 rate_mask,
|
||||
u8 channel)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
u8 *pos;
|
||||
size_t offset = 0, noffset;
|
||||
int supp_rates_len, i;
|
||||
u8 rates[32];
|
||||
int num_rates;
|
||||
int ext_rates_len;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
|
||||
pos = buffer;
|
||||
|
||||
supp_rates_len = min_t(int, sband->n_bitrates, 8);
|
||||
num_rates = 0;
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
if ((BIT(i) & rate_mask) == 0)
|
||||
continue; /* skip rate */
|
||||
rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5);
|
||||
}
|
||||
|
||||
supp_rates_len = min_t(int, num_rates, 8);
|
||||
|
||||
*pos++ = WLAN_EID_SUPP_RATES;
|
||||
*pos++ = supp_rates_len;
|
||||
|
||||
for (i = 0; i < supp_rates_len; i++) {
|
||||
int rate = sband->bitrates[i].bitrate;
|
||||
*pos++ = (u8) (rate / 5);
|
||||
}
|
||||
memcpy(pos, rates, supp_rates_len);
|
||||
pos += supp_rates_len;
|
||||
|
||||
/* insert "request information" if in custom IEs */
|
||||
if (ie && ie_len) {
|
||||
|
|
@ -941,14 +940,18 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
|||
offset = noffset;
|
||||
}
|
||||
|
||||
if (sband->n_bitrates > i) {
|
||||
ext_rates_len = num_rates - supp_rates_len;
|
||||
if (ext_rates_len > 0) {
|
||||
*pos++ = WLAN_EID_EXT_SUPP_RATES;
|
||||
*pos++ = sband->n_bitrates - i;
|
||||
*pos++ = ext_rates_len;
|
||||
memcpy(pos, rates + supp_rates_len, ext_rates_len);
|
||||
pos += ext_rates_len;
|
||||
}
|
||||
|
||||
for (; i < sband->n_bitrates; i++) {
|
||||
int rate = sband->bitrates[i].bitrate;
|
||||
*pos++ = (u8) (rate / 5);
|
||||
}
|
||||
if (channel && sband->band == IEEE80211_BAND_2GHZ) {
|
||||
*pos++ = WLAN_EID_DS_PARAMS;
|
||||
*pos++ = 1;
|
||||
*pos++ = channel;
|
||||
}
|
||||
|
||||
/* insert custom IEs that go before HT */
|
||||
|
|
@ -1017,6 +1020,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
|||
struct ieee80211_mgmt *mgmt;
|
||||
size_t buf_len;
|
||||
u8 *buf;
|
||||
u8 chan;
|
||||
|
||||
/* FIXME: come up with a proper value */
|
||||
buf = kmalloc(200 + ie_len, GFP_KERNEL);
|
||||
|
|
@ -1026,8 +1030,14 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
|||
return;
|
||||
}
|
||||
|
||||
chan = ieee80211_frequency_to_channel(
|
||||
local->hw.conf.channel->center_freq);
|
||||
|
||||
buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
|
||||
local->hw.conf.channel->band);
|
||||
local->hw.conf.channel->band,
|
||||
sdata->rc_rateidx_mask
|
||||
[local->hw.conf.channel->band],
|
||||
chan);
|
||||
|
||||
skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
|
||||
ssid, ssid_len,
|
||||
|
|
@ -1189,7 +1199,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
/* ignore virtual */
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case __NL80211_IFTYPE_AFTER_LAST:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1209,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);
|
||||
}
|
||||
|
||||
|
|
@ -1285,17 +1297,13 @@ 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)
|
||||
WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx));
|
||||
|
||||
WARN_ON(!mutex_is_locked(&local->iflist_mtx));
|
||||
lockdep_assert_held(&local->iflist_mtx);
|
||||
|
||||
/*
|
||||
* This function could be improved to handle multiple
|
||||
|
|
@ -1308,22 +1316,12 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
|
|||
*/
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!netif_running(sdata->dev))
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
|
|||
struct ieee80211_key *key)
|
||||
{
|
||||
u32 klen;
|
||||
u8 *rc4key;
|
||||
u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
|
||||
u8 keyidx;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
unsigned int hdrlen;
|
||||
|
|
@ -240,15 +240,11 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
|
|||
|
||||
keyidx = skb->data[hdrlen + 3] >> 6;
|
||||
|
||||
if (!key || keyidx != key->conf.keyidx || key->conf.alg != ALG_WEP)
|
||||
if (!key || keyidx != key->conf.keyidx)
|
||||
return -1;
|
||||
|
||||
klen = 3 + key->conf.keylen;
|
||||
|
||||
rc4key = kmalloc(klen, GFP_ATOMIC);
|
||||
if (!rc4key)
|
||||
return -1;
|
||||
|
||||
/* Prepend 24-bit IV to RC4 key */
|
||||
memcpy(rc4key, skb->data + hdrlen, 3);
|
||||
|
||||
|
|
@ -260,8 +256,6 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
|
|||
len))
|
||||
ret = -1;
|
||||
|
||||
kfree(rc4key);
|
||||
|
||||
/* Trim ICV */
|
||||
skb_trim(skb, skb->len - WEP_ICV_LEN);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ enum work_action {
|
|||
/* utils */
|
||||
static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
|
||||
{
|
||||
WARN_ON(!mutex_is_locked(&local->work_mtx));
|
||||
lockdep_assert_held(&local->mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -757,7 +757,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
|
|||
mgmt = (struct ieee80211_mgmt *) skb->data;
|
||||
fc = le16_to_cpu(mgmt->frame_control);
|
||||
|
||||
mutex_lock(&local->work_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
const u8 *bssid = NULL;
|
||||
|
|
@ -833,7 +833,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
|
|||
WARN(1, "unexpected: %d", rma);
|
||||
}
|
||||
|
||||
mutex_unlock(&local->work_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (rma != WORK_ACT_DONE)
|
||||
goto out;
|
||||
|
|
@ -845,9 +845,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
|
|||
case WORK_DONE_REQUEUE:
|
||||
synchronize_rcu();
|
||||
wk->started = false; /* restart */
|
||||
mutex_lock(&local->work_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
list_add_tail(&wk->list, &local->work_list);
|
||||
mutex_unlock(&local->work_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -888,9 +888,9 @@ static void ieee80211_work_work(struct work_struct *work)
|
|||
while ((skb = skb_dequeue(&local->work_skb_queue)))
|
||||
ieee80211_work_rx_queued_mgmt(local, skb);
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
mutex_lock(&local->work_mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
|
||||
bool started = wk->started;
|
||||
|
|
@ -995,20 +995,16 @@ static void ieee80211_work_work(struct work_struct *work)
|
|||
run_again(local, jiffies + HZ/2);
|
||||
}
|
||||
|
||||
mutex_lock(&local->scan_mtx);
|
||||
|
||||
if (list_empty(&local->work_list) && local->scan_req &&
|
||||
!local->scanning)
|
||||
ieee80211_queue_delayed_work(&local->hw,
|
||||
&local->scan_work,
|
||||
round_jiffies_relative(0));
|
||||
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
|
||||
mutex_unlock(&local->work_mtx);
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
list_for_each_entry_safe(wk, tmp, &free_work, list) {
|
||||
wk->done(wk, NULL);
|
||||
list_del(&wk->list);
|
||||
|
|
@ -1035,16 +1031,15 @@ void ieee80211_add_work(struct ieee80211_work *wk)
|
|||
wk->started = false;
|
||||
|
||||
local = wk->sdata->local;
|
||||
mutex_lock(&local->work_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
list_add_tail(&wk->list, &local->work_list);
|
||||
mutex_unlock(&local->work_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->work_work);
|
||||
}
|
||||
|
||||
void ieee80211_work_init(struct ieee80211_local *local)
|
||||
{
|
||||
mutex_init(&local->work_mtx);
|
||||
INIT_LIST_HEAD(&local->work_list);
|
||||
setup_timer(&local->work_timer, ieee80211_work_timer,
|
||||
(unsigned long)local);
|
||||
|
|
@ -1057,7 +1052,7 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_work *wk;
|
||||
|
||||
mutex_lock(&local->work_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
if (wk->sdata != sdata)
|
||||
continue;
|
||||
|
|
@ -1065,19 +1060,19 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
|
|||
wk->started = true;
|
||||
wk->timeout = jiffies;
|
||||
}
|
||||
mutex_unlock(&local->work_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
/* run cleanups etc. */
|
||||
ieee80211_work_work(&local->work_work);
|
||||
|
||||
mutex_lock(&local->work_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
if (wk->sdata != sdata)
|
||||
continue;
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&local->work_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
@ -1163,7 +1158,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_work *wk, *tmp;
|
||||
bool found = false;
|
||||
|
||||
mutex_lock(&local->work_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
|
||||
if ((unsigned long) wk == cookie) {
|
||||
wk->timeout = jiffies;
|
||||
|
|
@ -1171,7 +1166,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
|
|||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&local->work_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (!found)
|
||||
return -ENOENT;
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
|
|||
int tail;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
|
||||
!ieee80211_is_data_present(hdr->frame_control))
|
||||
if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
|
||||
skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control))
|
||||
return TX_CONTINUE;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
|
@ -94,7 +94,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
|||
if (status->flag & RX_FLAG_MMIC_STRIPPED)
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
|
||||
if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
|
||||
!ieee80211_has_protected(hdr->frame_control) ||
|
||||
!ieee80211_is_data_present(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
|
@ -117,7 +117,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
|||
key = &rx->key->conf.key[key_offset];
|
||||
michael_mic(key, hdr, data, data_len, mic);
|
||||
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
|
||||
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
||||
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
|
||||
|
|
@ -221,19 +221,13 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
|
|||
if (!rx->sta || skb->len - hdrlen < 12)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
if (status->flag & RX_FLAG_DECRYPTED) {
|
||||
if (status->flag & RX_FLAG_IV_STRIPPED) {
|
||||
/*
|
||||
* Hardware took care of all processing, including
|
||||
* replay protection, and stripped the ICV/IV so
|
||||
* we cannot do any checks here.
|
||||
*/
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
/* let TKIP code verify IV, but skip decryption */
|
||||
/*
|
||||
* Let TKIP code verify IV, but skip decryption.
|
||||
* In the case where hardware checks the IV as well,
|
||||
* we don't even get here, see ieee80211_rx_h_decrypt()
|
||||
*/
|
||||
if (status->flag & RX_FLAG_DECRYPTED)
|
||||
hwaccel = 1;
|
||||
}
|
||||
|
||||
res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
|
||||
key, skb->data + hdrlen,
|
||||
|
|
@ -447,10 +441,6 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
|
|||
if (!rx->sta || data_len < 0)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
if ((status->flag & RX_FLAG_DECRYPTED) &&
|
||||
(status->flag & RX_FLAG_IV_STRIPPED))
|
||||
return RX_CONTINUE;
|
||||
|
||||
ccmp_hdr2pn(pn, skb->data + hdrlen);
|
||||
|
||||
queue = ieee80211_is_mgmt(hdr->frame_control) ?
|
||||
|
|
@ -564,10 +554,6 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
|
|||
if (!ieee80211_is_mgmt(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if ((status->flag & RX_FLAG_DECRYPTED) &&
|
||||
(status->flag & RX_FLAG_IV_STRIPPED))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (skb->len < 24 + sizeof(*mmie))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue