mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
commit
0440507bbc
219 changed files with 12126 additions and 7378 deletions
|
|
@ -9,7 +9,6 @@ mac80211-y := \
|
|||
scan.o offchannel.o \
|
||||
ht.o agg-tx.o agg-rx.o \
|
||||
ibss.o \
|
||||
work.o \
|
||||
iface.o \
|
||||
rate.o \
|
||||
michael.o \
|
||||
|
|
|
|||
|
|
@ -74,18 +74,15 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
|||
|
||||
RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG
|
||||
"Rx BA session stop requested for %pM tid %u %s reason: %d\n",
|
||||
sta->sta.addr, tid,
|
||||
initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
|
||||
(int)reason);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ht_vdbg("Rx BA session stop requested for %pM tid %u %s reason: %d\n",
|
||||
sta->sta.addr, tid,
|
||||
initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
|
||||
(int)reason);
|
||||
|
||||
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL, 0))
|
||||
printk(KERN_DEBUG "HW problem - can not stop rx "
|
||||
"aggregation for tid %d\n", tid);
|
||||
pr_debug("HW problem - can not stop rx aggregation for tid %d\n",
|
||||
tid);
|
||||
|
||||
/* check if this is a self generated aggregation halt */
|
||||
if (initiator == WLAN_BACK_RECIPIENT && tx)
|
||||
|
|
@ -160,9 +157,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
|
|||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
|
||||
#endif
|
||||
ht_vdbg("rx session timer expired on tid %d\n", (u16)*ptid);
|
||||
|
||||
set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
|
||||
ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
|
||||
}
|
||||
|
|
@ -249,10 +245,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
status = WLAN_STATUS_REQUEST_DECLINED;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Suspend in progress. "
|
||||
"Denying ADDBA request\n");
|
||||
#endif
|
||||
ht_vdbg("Suspend in progress - Denying ADDBA request\n");
|
||||
goto end_no_lock;
|
||||
}
|
||||
|
||||
|
|
@ -324,10 +317,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
|
||||
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num, 0);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
ht_vdbg("Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
if (ret) {
|
||||
kfree(tid_agg_rx->reorder_buf);
|
||||
kfree(tid_agg_rx->reorder_time);
|
||||
|
|
|
|||
|
|
@ -184,10 +184,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
|||
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
|
||||
sta->sta.addr, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ht_vdbg("Tx BA session stop requested for %pM tid %u\n",
|
||||
sta->sta.addr, tid);
|
||||
|
||||
del_timer_sync(&tid_tx->addba_resp_timer);
|
||||
del_timer_sync(&tid_tx->session_timer);
|
||||
|
|
@ -253,17 +251,12 @@ static void sta_addba_resp_timer_expired(unsigned long data)
|
|||
if (!tid_tx ||
|
||||
test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
|
||||
rcu_read_unlock();
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "timer expired on tid %d but we are not "
|
||||
"(or no longer) expecting addBA response there\n",
|
||||
ht_vdbg("timer expired on tid %d but we are not (or no longer) expecting addBA response there\n",
|
||||
tid);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
|
||||
#endif
|
||||
ht_vdbg("addBA response timer expired on tid %d\n", tid);
|
||||
|
||||
ieee80211_stop_tx_ba_session(&sta->sta, tid);
|
||||
rcu_read_unlock();
|
||||
|
|
@ -372,10 +365,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
|||
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num, 0);
|
||||
if (ret) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - HW unavailable for"
|
||||
" tid %d\n", tid);
|
||||
#endif
|
||||
ht_vdbg("BA request denied - HW unavailable for tid %d\n", tid);
|
||||
spin_lock_bh(&sta->lock);
|
||||
ieee80211_agg_splice_packets(sdata, tid_tx, tid);
|
||||
ieee80211_assign_tid_tx(sta, tid, NULL);
|
||||
|
|
@ -388,9 +378,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
|||
|
||||
/* activate the timer for the recipient's addBA response */
|
||||
mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
|
||||
#endif
|
||||
ht_vdbg("activated addBA response timer on tid %d\n", tid);
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
|
||||
|
|
@ -437,9 +425,7 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
|
|||
|
||||
rcu_read_unlock();
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
|
||||
#endif
|
||||
ht_vdbg("tx session timer expired on tid %d\n", (u16)*ptid);
|
||||
|
||||
ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
|
||||
}
|
||||
|
|
@ -463,10 +449,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
|||
(local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
|
||||
pubsta->addr, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ht_vdbg("Open BA session requested for %pM tid %u\n",
|
||||
pubsta->addr, tid);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
||||
|
|
@ -476,10 +460,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
|||
return -EINVAL;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA sessions blocked. "
|
||||
"Denying BA session request\n");
|
||||
#endif
|
||||
ht_vdbg("BA sessions blocked - Denying BA session request\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -497,10 +478,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
|||
*/
|
||||
if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
!sta->sta.ht_cap.ht_supported) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - IBSS STA %pM"
|
||||
"does not advertise HT support\n", pubsta->addr);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ht_vdbg("BA request denied - IBSS STA %pM does not advertise HT support\n",
|
||||
pubsta->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -520,12 +499,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
|||
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES &&
|
||||
time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
|
||||
HT_AGG_RETRIES_PERIOD)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - "
|
||||
"waiting a grace period after %d failed requests "
|
||||
"on tid %u\n",
|
||||
sta->ampdu_mlme.addba_req_num[tid], tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ht_vdbg("BA request denied - waiting a grace period after %d failed requests on tid %u\n",
|
||||
sta->ampdu_mlme.addba_req_num[tid], tid);
|
||||
ret = -EBUSY;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
|
|
@ -533,10 +508,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
|||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
/* check if the TID is not in aggregation flow already */
|
||||
if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - session is not "
|
||||
"idle on tid %u\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ht_vdbg("BA request denied - session is not idle on tid %u\n",
|
||||
tid);
|
||||
ret = -EAGAIN;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
|
|
@ -591,9 +564,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
|||
|
||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
|
||||
#endif
|
||||
ht_vdbg("Aggregation is on for tid %d\n", tid);
|
||||
|
||||
drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
|
|
@ -627,10 +598,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
|
|||
trace_api_start_tx_ba_cb(sdata, ra, tid);
|
||||
|
||||
if (tid >= STA_TID_NUM) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
|
||||
tid, STA_TID_NUM);
|
||||
#endif
|
||||
ht_vdbg("Bad TID value: tid = %d (>= %d)\n", tid, STA_TID_NUM);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -638,9 +606,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
|
|||
sta = sta_info_get_bss(sdata, ra);
|
||||
if (!sta) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
|
||||
#endif
|
||||
ht_vdbg("Could not find station: %pM\n", ra);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -648,9 +614,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
|
|||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
|
||||
if (WARN_ON(!tid_tx)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "addBA was not requested!\n");
|
||||
#endif
|
||||
ht_vdbg("addBA was not requested!\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
|
@ -750,25 +714,17 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
|
|||
trace_api_stop_tx_ba_cb(sdata, ra, tid);
|
||||
|
||||
if (tid >= STA_TID_NUM) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
|
||||
tid, STA_TID_NUM);
|
||||
#endif
|
||||
ht_vdbg("Bad TID value: tid = %d (>= %d)\n", tid, STA_TID_NUM);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
|
||||
ra, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ht_vdbg("Stopping Tx BA session for %pM tid %d\n", ra, tid);
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
sta = sta_info_get_bss(sdata, ra);
|
||||
if (!sta) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
|
||||
#endif
|
||||
ht_vdbg("Could not find station: %pM\n", ra);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
|
@ -777,9 +733,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
|
|||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
|
||||
if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
|
||||
#endif
|
||||
ht_vdbg("unexpected callback to A-MPDU stop\n");
|
||||
goto unlock_sta;
|
||||
}
|
||||
|
||||
|
|
@ -855,17 +809,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
|||
goto out;
|
||||
|
||||
if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
|
||||
#endif
|
||||
ht_vdbg("wrong addBA response token, tid %d\n", tid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
del_timer_sync(&tid_tx->addba_resp_timer);
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
|
||||
#endif
|
||||
ht_vdbg("switched off addBA timer for tid %d\n", tid);
|
||||
|
||||
/*
|
||||
* addba_resp_timer may have fired before we got here, and
|
||||
|
|
@ -874,11 +824,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
|||
*/
|
||||
if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
|
||||
test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG
|
||||
"got addBA resp for tid %d but we already gave up\n",
|
||||
tid);
|
||||
#endif
|
||||
ht_vdbg("got addBA resp for tid %d but we already gave up\n",
|
||||
tid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -674,6 +674,48 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ieee80211_set_channel(struct wiphy *wiphy,
|
||||
struct net_device *netdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata = NULL;
|
||||
|
||||
if (netdev)
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
|
||||
|
||||
switch (ieee80211_get_channel_mode(local, NULL)) {
|
||||
case CHAN_MODE_HOPPING:
|
||||
return -EBUSY;
|
||||
case CHAN_MODE_FIXED:
|
||||
if (local->oper_channel != chan)
|
||||
return -EBUSY;
|
||||
if (!sdata && local->_oper_channel_type == channel_type)
|
||||
return 0;
|
||||
break;
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ieee80211_set_channel_type(local, sdata, channel_type))
|
||||
return -EBUSY;
|
||||
|
||||
local->oper_channel = chan;
|
||||
|
||||
/* auto-detects changes */
|
||||
ieee80211_hw_config(local, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
|
||||
}
|
||||
|
||||
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *resp, size_t resp_len)
|
||||
{
|
||||
|
|
@ -788,6 +830,11 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (old)
|
||||
return -EALREADY;
|
||||
|
||||
err = ieee80211_set_channel(wiphy, dev, params->channel,
|
||||
params->channel_type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Apply control port protocol, this allows us to
|
||||
* not encrypt dynamic WEP control frames.
|
||||
|
|
@ -1558,6 +1605,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
|
|||
err = copy_mesh_setup(ifmsh, setup);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ieee80211_set_channel(wiphy, dev, setup->channel,
|
||||
setup->channel_type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ieee80211_start_mesh(sdata);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1677,55 +1730,6 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_set_channel(struct wiphy *wiphy,
|
||||
struct net_device *netdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata = NULL;
|
||||
struct ieee80211_channel *old_oper;
|
||||
enum nl80211_channel_type old_oper_type;
|
||||
enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT;
|
||||
|
||||
if (netdev)
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
|
||||
|
||||
switch (ieee80211_get_channel_mode(local, NULL)) {
|
||||
case CHAN_MODE_HOPPING:
|
||||
return -EBUSY;
|
||||
case CHAN_MODE_FIXED:
|
||||
if (local->oper_channel != chan)
|
||||
return -EBUSY;
|
||||
if (!sdata && local->_oper_channel_type == channel_type)
|
||||
return 0;
|
||||
break;
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
|
||||
if (sdata)
|
||||
old_vif_oper_type = sdata->vif.bss_conf.channel_type;
|
||||
old_oper_type = local->_oper_channel_type;
|
||||
|
||||
if (!ieee80211_set_channel_type(local, sdata, channel_type))
|
||||
return -EBUSY;
|
||||
|
||||
old_oper = local->oper_channel;
|
||||
local->oper_channel = chan;
|
||||
|
||||
/* Update driver if changes were actually made. */
|
||||
if ((old_oper != local->oper_channel) ||
|
||||
(old_oper_type != local->_oper_channel_type))
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
|
||||
if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
old_vif_oper_type != sdata->vif.bss_conf.channel_type)
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ieee80211_suspend(struct wiphy *wiphy,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
|
|
@ -2108,35 +2112,171 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local,
|
||||
struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type chantype,
|
||||
unsigned int duration, u64 *cookie)
|
||||
static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration, u64 *cookie,
|
||||
struct sk_buff *txskb)
|
||||
{
|
||||
struct ieee80211_roc_work *roc, *tmp;
|
||||
bool queued = false;
|
||||
int ret;
|
||||
u32 random_cookie;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
if (local->hw_roc_cookie)
|
||||
return -EBUSY;
|
||||
/* must be nonzero */
|
||||
random_cookie = random32() | 1;
|
||||
roc = kzalloc(sizeof(*roc), GFP_KERNEL);
|
||||
if (!roc)
|
||||
return -ENOMEM;
|
||||
|
||||
*cookie = random_cookie;
|
||||
local->hw_roc_dev = dev;
|
||||
local->hw_roc_cookie = random_cookie;
|
||||
local->hw_roc_channel = chan;
|
||||
local->hw_roc_channel_type = chantype;
|
||||
local->hw_roc_duration = duration;
|
||||
ret = drv_remain_on_channel(local, chan, chantype, duration);
|
||||
if (ret) {
|
||||
local->hw_roc_channel = NULL;
|
||||
local->hw_roc_cookie = 0;
|
||||
roc->chan = channel;
|
||||
roc->chan_type = channel_type;
|
||||
roc->duration = duration;
|
||||
roc->req_duration = duration;
|
||||
roc->frame = txskb;
|
||||
roc->mgmt_tx_cookie = (unsigned long)txskb;
|
||||
roc->sdata = sdata;
|
||||
INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
|
||||
INIT_LIST_HEAD(&roc->dependents);
|
||||
|
||||
/* if there's one pending or we're scanning, queue this one */
|
||||
if (!list_empty(&local->roc_list) || local->scanning)
|
||||
goto out_check_combine;
|
||||
|
||||
/* if not HW assist, just queue & schedule work */
|
||||
if (!local->ops->remain_on_channel) {
|
||||
ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
|
||||
goto out_queue;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* otherwise actually kick it off here (for error handling) */
|
||||
|
||||
/*
|
||||
* If the duration is zero, then the driver
|
||||
* wouldn't actually do anything. Set it to
|
||||
* 10 for now.
|
||||
*
|
||||
* TODO: cancel the off-channel operation
|
||||
* when we get the SKB's TX status and
|
||||
* the wait time was zero before.
|
||||
*/
|
||||
if (!duration)
|
||||
duration = 10;
|
||||
|
||||
ret = drv_remain_on_channel(local, channel, channel_type, duration);
|
||||
if (ret) {
|
||||
kfree(roc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
roc->started = true;
|
||||
goto out_queue;
|
||||
|
||||
out_check_combine:
|
||||
list_for_each_entry(tmp, &local->roc_list, list) {
|
||||
if (tmp->chan != channel || tmp->chan_type != channel_type)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Extend this ROC if possible:
|
||||
*
|
||||
* If it hasn't started yet, just increase the duration
|
||||
* and add the new one to the list of dependents.
|
||||
*/
|
||||
if (!tmp->started) {
|
||||
list_add_tail(&roc->list, &tmp->dependents);
|
||||
tmp->duration = max(tmp->duration, roc->duration);
|
||||
queued = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If it has already started, it's more difficult ... */
|
||||
if (local->ops->remain_on_channel) {
|
||||
unsigned long j = jiffies;
|
||||
|
||||
/*
|
||||
* In the offloaded ROC case, if it hasn't begun, add
|
||||
* this new one to the dependent list to be handled
|
||||
* when the the master one begins. If it has begun,
|
||||
* check that there's still a minimum time left and
|
||||
* if so, start this one, transmitting the frame, but
|
||||
* add it to the list directly after this one with a
|
||||
* a reduced time so we'll ask the driver to execute
|
||||
* it right after finishing the previous one, in the
|
||||
* hope that it'll also be executed right afterwards,
|
||||
* effectively extending the old one.
|
||||
* If there's no minimum time left, just add it to the
|
||||
* normal list.
|
||||
*/
|
||||
if (!tmp->hw_begun) {
|
||||
list_add_tail(&roc->list, &tmp->dependents);
|
||||
queued = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (time_before(j + IEEE80211_ROC_MIN_LEFT,
|
||||
tmp->hw_start_time +
|
||||
msecs_to_jiffies(tmp->duration))) {
|
||||
int new_dur;
|
||||
|
||||
ieee80211_handle_roc_started(roc);
|
||||
|
||||
new_dur = roc->duration -
|
||||
jiffies_to_msecs(tmp->hw_start_time +
|
||||
msecs_to_jiffies(
|
||||
tmp->duration) -
|
||||
j);
|
||||
|
||||
if (new_dur > 0) {
|
||||
/* add right after tmp */
|
||||
list_add(&roc->list, &tmp->list);
|
||||
} else {
|
||||
list_add_tail(&roc->list,
|
||||
&tmp->dependents);
|
||||
}
|
||||
queued = true;
|
||||
}
|
||||
} else if (del_timer_sync(&tmp->work.timer)) {
|
||||
unsigned long new_end;
|
||||
|
||||
/*
|
||||
* In the software ROC case, cancel the timer, if
|
||||
* that fails then the finish work is already
|
||||
* queued/pending and thus we queue the new ROC
|
||||
* normally, if that succeeds then we can extend
|
||||
* the timer duration and TX the frame (if any.)
|
||||
*/
|
||||
|
||||
list_add_tail(&roc->list, &tmp->dependents);
|
||||
queued = true;
|
||||
|
||||
new_end = jiffies + msecs_to_jiffies(roc->duration);
|
||||
|
||||
/* ok, it was started & we canceled timer */
|
||||
if (time_after(new_end, tmp->work.timer.expires))
|
||||
mod_timer(&tmp->work.timer, new_end);
|
||||
else
|
||||
add_timer(&tmp->work.timer);
|
||||
|
||||
ieee80211_handle_roc_started(roc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out_queue:
|
||||
if (!queued)
|
||||
list_add_tail(&roc->list, &local->roc_list);
|
||||
|
||||
/*
|
||||
* cookie is either the roc (for normal roc)
|
||||
* or the SKB (for mgmt TX)
|
||||
*/
|
||||
if (txskb)
|
||||
*cookie = (unsigned long)txskb;
|
||||
else
|
||||
*cookie = (unsigned long)roc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_remain_on_channel(struct wiphy *wiphy,
|
||||
|
|
@ -2148,42 +2288,64 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (local->ops->remain_on_channel) {
|
||||
int ret;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ret = ieee80211_remain_on_channel_hw(local, dev,
|
||||
chan, channel_type,
|
||||
duration, cookie);
|
||||
local->hw_roc_for_tx = false;
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
|
||||
duration, cookie);
|
||||
}
|
||||
|
||||
static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
|
||||
u64 cookie)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
|
||||
duration, cookie, NULL);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (local->hw_roc_cookie != cookie)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ieee80211_cancel_roc(struct ieee80211_local *local,
|
||||
u64 cookie, bool mgmt_tx)
|
||||
{
|
||||
struct ieee80211_roc_work *roc, *tmp, *found = NULL;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
|
||||
if (!mgmt_tx && (unsigned long)roc != cookie)
|
||||
continue;
|
||||
else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
|
||||
continue;
|
||||
|
||||
found = roc;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
mutex_unlock(&local->mtx);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = drv_cancel_remain_on_channel(local);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (local->ops->remain_on_channel) {
|
||||
if (found->started) {
|
||||
ret = drv_cancel_remain_on_channel(local);
|
||||
if (WARN_ON_ONCE(ret)) {
|
||||
mutex_unlock(&local->mtx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
local->hw_roc_cookie = 0;
|
||||
local->hw_roc_channel = NULL;
|
||||
list_del(&found->list);
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
ieee80211_run_deferred_scan(local);
|
||||
ieee80211_start_next_roc(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
ieee80211_roc_notify_destroy(found);
|
||||
} else {
|
||||
/* work may be pending so use it all the time */
|
||||
found->abort = true;
|
||||
ieee80211_queue_delayed_work(&local->hw, &found->work, 0);
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
/* work will clean up etc */
|
||||
flush_delayed_work(&found->work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2195,39 +2357,7 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
|
|||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (local->ops->cancel_remain_on_channel) {
|
||||
int ret;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
|
||||
}
|
||||
|
||||
static enum work_done_result
|
||||
ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb)
|
||||
{
|
||||
/*
|
||||
* Use the data embedded in the work struct for reporting
|
||||
* here so if the driver mangled the SKB before dropping
|
||||
* it (which is the only way we really should get here)
|
||||
* then we don't report mangled data.
|
||||
*
|
||||
* If there was no wait time, then by the time we get here
|
||||
* the driver will likely not have reported the status yet,
|
||||
* so in that case userspace will have to deal with it.
|
||||
*/
|
||||
|
||||
if (wk->offchan_tx.wait && !wk->offchan_tx.status)
|
||||
cfg80211_mgmt_tx_status(wk->sdata->dev,
|
||||
(unsigned long) wk->offchan_tx.frame,
|
||||
wk->data, wk->data_len, false, GFP_KERNEL);
|
||||
|
||||
return WORK_DONE_DESTROY;
|
||||
return ieee80211_cancel_roc(local, cookie, false);
|
||||
}
|
||||
|
||||
static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
|
@ -2241,10 +2371,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_work *wk;
|
||||
const struct ieee80211_mgmt *mgmt = (void *)buf;
|
||||
bool need_offchan = false;
|
||||
u32 flags;
|
||||
bool is_offchan = false;
|
||||
int ret;
|
||||
|
||||
if (dont_wait_for_ack)
|
||||
flags = IEEE80211_TX_CTL_NO_ACK;
|
||||
|
|
@ -2252,33 +2382,28 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
|||
flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
|
||||
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
|
||||
/* Check that we are on the requested channel for transmission */
|
||||
if (chan != local->tmp_channel &&
|
||||
chan != local->oper_channel)
|
||||
is_offchan = true;
|
||||
if (channel_type_valid &&
|
||||
(channel_type != local->tmp_channel_type &&
|
||||
channel_type != local->_oper_channel_type))
|
||||
is_offchan = true;
|
||||
|
||||
if (chan == local->hw_roc_channel) {
|
||||
/* TODO: check channel type? */
|
||||
is_offchan = false;
|
||||
flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
|
||||
}
|
||||
|
||||
if (no_cck)
|
||||
flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
|
||||
|
||||
if (is_offchan && !offchan)
|
||||
return -EBUSY;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (!sdata->vif.bss_conf.ibss_joined)
|
||||
need_offchan = true;
|
||||
/* fall through */
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
!sdata->u.mesh.mesh_id_len)
|
||||
need_offchan = true;
|
||||
/* fall through */
|
||||
#endif
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||
!ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
!rcu_access_pointer(sdata->bss->beacon))
|
||||
need_offchan = true;
|
||||
if (!ieee80211_is_action(mgmt->frame_control) ||
|
||||
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
|
||||
break;
|
||||
|
|
@ -2290,103 +2415,60 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
|||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (!sdata->u.mgd.associated)
|
||||
need_offchan = true;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
/* Check if the operating channel is the requested channel */
|
||||
if (!need_offchan) {
|
||||
need_offchan = chan != local->oper_channel;
|
||||
if (channel_type_valid &&
|
||||
channel_type != local->_oper_channel_type)
|
||||
need_offchan = true;
|
||||
}
|
||||
|
||||
if (need_offchan && !offchan) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unlock;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
|
||||
memcpy(skb_put(skb, len), buf, len);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags = flags;
|
||||
|
||||
if (flags & IEEE80211_TX_CTL_TX_OFFCHAN)
|
||||
IEEE80211_SKB_CB(skb)->hw_queue =
|
||||
local->hw.offchannel_tx_hw_queue;
|
||||
|
||||
skb->dev = sdata->dev;
|
||||
|
||||
*cookie = (unsigned long) skb;
|
||||
if (!need_offchan) {
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (is_offchan && local->ops->remain_on_channel) {
|
||||
unsigned int duration;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
/*
|
||||
* If the duration is zero, then the driver
|
||||
* wouldn't actually do anything. Set it to
|
||||
* 100 for now.
|
||||
*
|
||||
* TODO: cancel the off-channel operation
|
||||
* when we get the SKB's TX status and
|
||||
* the wait time was zero before.
|
||||
*/
|
||||
duration = 100;
|
||||
if (wait)
|
||||
duration = wait;
|
||||
ret = ieee80211_remain_on_channel_hw(local, dev, chan,
|
||||
channel_type,
|
||||
duration, cookie);
|
||||
if (ret) {
|
||||
kfree_skb(skb);
|
||||
mutex_unlock(&local->mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
local->hw_roc_for_tx = true;
|
||||
local->hw_roc_duration = wait;
|
||||
|
||||
/*
|
||||
* queue up frame for transmission after
|
||||
* ieee80211_ready_on_channel call
|
||||
*/
|
||||
|
||||
/* modify cookie to prevent API mismatches */
|
||||
*cookie ^= 2;
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
|
||||
if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
|
||||
IEEE80211_SKB_CB(skb)->hw_queue =
|
||||
local->hw.offchannel_tx_hw_queue;
|
||||
local->hw_roc_skb = skb;
|
||||
local->hw_roc_skb_for_status = skb;
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can transmit right away if the channel was the
|
||||
* right one and there's no wait involved... If a
|
||||
* wait is involved, we might otherwise not be on
|
||||
* the right channel for long enough!
|
||||
*/
|
||||
if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) {
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL);
|
||||
if (!wk) {
|
||||
/* This will handle all kinds of coalescing and immediate TX */
|
||||
ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
|
||||
wait, cookie, skb);
|
||||
if (ret)
|
||||
kfree_skb(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wk->type = IEEE80211_WORK_OFFCHANNEL_TX;
|
||||
wk->chan = chan;
|
||||
wk->chan_type = channel_type;
|
||||
wk->sdata = sdata;
|
||||
wk->done = ieee80211_offchan_tx_done;
|
||||
wk->offchan_tx.frame = skb;
|
||||
wk->offchan_tx.wait = wait;
|
||||
wk->data_len = len;
|
||||
memcpy(wk->data, buf, len);
|
||||
|
||||
ieee80211_add_work(wk);
|
||||
return 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&local->mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
|
||||
|
|
@ -2395,45 +2477,8 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_work *wk;
|
||||
int ret = -ENOENT;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
if (local->ops->cancel_remain_on_channel) {
|
||||
cookie ^= 2;
|
||||
ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
|
||||
|
||||
if (ret == 0) {
|
||||
kfree_skb(local->hw_roc_skb);
|
||||
local->hw_roc_skb = NULL;
|
||||
local->hw_roc_skb_for_status = NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
if (wk->sdata != sdata)
|
||||
continue;
|
||||
|
||||
if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
|
||||
continue;
|
||||
|
||||
if (cookie != (unsigned long) wk->offchan_tx.frame)
|
||||
continue;
|
||||
|
||||
wk->timeout = jiffies;
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->work_work);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ret;
|
||||
return ieee80211_cancel_roc(local, cookie, true);
|
||||
}
|
||||
|
||||
static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
|
||||
|
|
@ -2677,7 +2722,7 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
|||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
|
||||
printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer);
|
||||
pr_debug("TDLS mgmt action %d peer %pM\n", action_code, peer);
|
||||
#endif
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
|
||||
|
|
@ -2788,7 +2833,7 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
|
|||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
|
||||
printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer);
|
||||
pr_debug("TDLS oper %d peer %pM\n", oper, peer);
|
||||
#endif
|
||||
|
||||
switch (oper) {
|
||||
|
|
@ -2933,7 +2978,7 @@ struct cfg80211_ops mac80211_config_ops = {
|
|||
#endif
|
||||
.change_bss = ieee80211_change_bss,
|
||||
.set_txq_params = ieee80211_set_txq_params,
|
||||
.set_channel = ieee80211_set_channel,
|
||||
.set_monitor_channel = ieee80211_set_monitor_channel,
|
||||
.suspend = ieee80211_suspend,
|
||||
.resume = ieee80211_resume,
|
||||
.scan = ieee80211_scan,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local,
|
|||
if (!sdata->u.ap.beacon)
|
||||
continue;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (!sdata->wdev.mesh_id_len)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -607,6 +607,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
|
|||
MESHPARAMS_ADD(min_discovery_timeout);
|
||||
MESHPARAMS_ADD(dot11MeshHWMPRootMode);
|
||||
MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
|
||||
MESHPARAMS_ADD(dot11MeshForwarding);
|
||||
MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
|
||||
MESHPARAMS_ADD(rssi_threshold);
|
||||
MESHPARAMS_ADD(ht_opmode);
|
||||
|
|
@ -685,6 +686,6 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
sprintf(buf, "netdev:%s", sdata->name);
|
||||
if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
|
||||
printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
|
||||
pr_err("mac80211: debugfs: failed to rename debugfs "
|
||||
"dir to %s\n", buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,8 +82,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
local->oper_channel = chan;
|
||||
channel_type = ifibss->channel_type;
|
||||
if (channel_type > NL80211_CHAN_HT20 &&
|
||||
!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
|
||||
if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
|
||||
channel_type = NL80211_CHAN_HT20;
|
||||
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
|
||||
/* can only fail due to HT40+/- mismatch */
|
||||
|
|
@ -281,11 +280,8 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
|
|||
if (sta_info_insert_rcu(sta))
|
||||
return sta_info_get(sdata, addr);
|
||||
if (auth) {
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM"
|
||||
"(auth_transaction=1)\n", sdata->vif.addr,
|
||||
sdata->u.ibss.bssid, addr);
|
||||
#endif
|
||||
ibss_vdbg("TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
|
||||
sdata->vif.addr, sdata->u.ibss.bssid, addr);
|
||||
ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0,
|
||||
addr, sdata->u.ibss.bssid, NULL, 0, 0);
|
||||
}
|
||||
|
|
@ -355,11 +351,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
|
||||
return;
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: RX Auth SA=%pM DA=%pM BSSID=%pM."
|
||||
"(auth_transaction=%d)\n",
|
||||
sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);
|
||||
#endif
|
||||
ibss_vdbg("%s: RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n",
|
||||
sdata->name, mgmt->sa, mgmt->da, mgmt->bssid,
|
||||
auth_transaction);
|
||||
sta_info_destroy_addr(sdata, mgmt->sa);
|
||||
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);
|
||||
rcu_read_unlock();
|
||||
|
|
@ -422,15 +416,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
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_resp (0x%x -> 0x%x)\n",
|
||||
sdata->name, sta->sta.addr,
|
||||
prev_rates,
|
||||
sta->sta.supp_rates[band]);
|
||||
#endif
|
||||
ibss_vdbg("%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]);
|
||||
rates_updated = true;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -545,22 +534,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
rx_timestamp = drv_get_tsf(local, sdata);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
|
||||
"%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
|
||||
mgmt->sa, mgmt->bssid,
|
||||
(unsigned long long)rx_timestamp,
|
||||
(unsigned long long)beacon_timestamp,
|
||||
(unsigned long long)(rx_timestamp - beacon_timestamp),
|
||||
jiffies);
|
||||
#endif
|
||||
ibss_vdbg("RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
|
||||
mgmt->sa, mgmt->bssid,
|
||||
(unsigned long long)rx_timestamp,
|
||||
(unsigned long long)beacon_timestamp,
|
||||
(unsigned long long)(rx_timestamp - beacon_timestamp),
|
||||
jiffies);
|
||||
|
||||
if (beacon_timestamp > rx_timestamp) {
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: beacon TSF higher than "
|
||||
"local TSF - IBSS merge with BSSID %pM\n",
|
||||
sdata->name, mgmt->bssid);
|
||||
#endif
|
||||
ibss_vdbg("%s: beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n",
|
||||
sdata->name, mgmt->bssid);
|
||||
ieee80211_sta_join_ibss(sdata, bss);
|
||||
supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
|
||||
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
|
||||
|
|
@ -662,8 +645,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
if (ifibss->fixed_channel)
|
||||
return;
|
||||
|
||||
printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
|
||||
"IBSS networks with same SSID (merge)\n", sdata->name);
|
||||
pr_debug("%s: No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n",
|
||||
sdata->name);
|
||||
|
||||
ieee80211_request_internal_scan(sdata,
|
||||
ifibss->ssid, ifibss->ssid_len, NULL);
|
||||
|
|
@ -691,8 +674,8 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
bssid[0] |= 0x02;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
|
||||
sdata->name, bssid);
|
||||
pr_debug("%s: Creating new IBSS network, BSSID %pM\n",
|
||||
sdata->name, bssid);
|
||||
|
||||
capability = WLAN_CAPABILITY_IBSS;
|
||||
|
||||
|
|
@ -723,10 +706,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
lockdep_assert_held(&ifibss->mtx);
|
||||
|
||||
active_ibss = ieee80211_sta_active_ibss(sdata);
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
|
||||
sdata->name, active_ibss);
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
ibss_vdbg("%s: sta_find_ibss (active_ibss=%d)\n",
|
||||
sdata->name, active_ibss);
|
||||
|
||||
if (active_ibss)
|
||||
return;
|
||||
|
|
@ -749,29 +730,23 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
struct ieee80211_bss *bss;
|
||||
|
||||
bss = (void *)cbss->priv;
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG " sta_find_ibss: selected %pM current "
|
||||
"%pM\n", cbss->bssid, ifibss->bssid);
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
|
||||
printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
|
||||
" based on configured SSID\n",
|
||||
sdata->name, cbss->bssid);
|
||||
ibss_vdbg(" sta_find_ibss: selected %pM current %pM\n",
|
||||
cbss->bssid, ifibss->bssid);
|
||||
pr_debug("%s: Selected IBSS BSSID %pM based on configured SSID\n",
|
||||
sdata->name, cbss->bssid);
|
||||
|
||||
ieee80211_sta_join_ibss(sdata, bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG " did not try to join ibss\n");
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
ibss_vdbg(" did not try to join ibss\n");
|
||||
|
||||
/* Selected IBSS not found in current scan results - try to scan */
|
||||
if (time_after(jiffies, ifibss->last_scan_completed +
|
||||
IEEE80211_SCAN_INTERVAL)) {
|
||||
printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
|
||||
"join\n", sdata->name);
|
||||
pr_debug("%s: Trigger new scan to find an IBSS to join\n",
|
||||
sdata->name);
|
||||
|
||||
ieee80211_request_internal_scan(sdata,
|
||||
ifibss->ssid, ifibss->ssid_len,
|
||||
|
|
@ -785,9 +760,9 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
ieee80211_sta_create_ibss(sdata);
|
||||
return;
|
||||
}
|
||||
printk(KERN_DEBUG "%s: IBSS not allowed on"
|
||||
" %d MHz\n", sdata->name,
|
||||
local->hw.conf.channel->center_freq);
|
||||
pr_debug("%s: IBSS not allowed on %d MHz\n",
|
||||
sdata->name,
|
||||
local->hw.conf.channel->center_freq);
|
||||
|
||||
/* No IBSS found - decrease scan interval and continue
|
||||
* scanning. */
|
||||
|
|
@ -822,12 +797,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
tx_last_beacon = drv_tx_last_beacon(local);
|
||||
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
|
||||
" (tx_last_beacon=%d)\n",
|
||||
sdata->name, mgmt->sa, mgmt->da,
|
||||
mgmt->bssid, tx_last_beacon);
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
ibss_vdbg("%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n",
|
||||
sdata->name, mgmt->sa, mgmt->da,
|
||||
mgmt->bssid, tx_last_beacon);
|
||||
|
||||
if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
|
||||
return;
|
||||
|
|
@ -840,11 +812,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
pos = mgmt->u.probe_req.variable;
|
||||
if (pos[0] != WLAN_EID_SSID ||
|
||||
pos + 2 + pos[1] > end) {
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
|
||||
"from %pM\n",
|
||||
sdata->name, mgmt->sa);
|
||||
#endif
|
||||
ibss_vdbg("%s: Invalid SSID IE in ProbeReq from %pM\n",
|
||||
sdata->name, mgmt->sa);
|
||||
return;
|
||||
}
|
||||
if (pos[1] != 0 &&
|
||||
|
|
@ -861,10 +830,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
resp = (struct ieee80211_mgmt *) skb->data;
|
||||
memcpy(resp->da, mgmt->sa, ETH_ALEN);
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
|
||||
sdata->name, resp->da);
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
ibss_vdbg("%s: Sending ProbeResp to %pM\n", sdata->name, resp->da);
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,55 +317,30 @@ struct mesh_preq_queue {
|
|||
u8 flags;
|
||||
};
|
||||
|
||||
enum ieee80211_work_type {
|
||||
IEEE80211_WORK_ABORT,
|
||||
IEEE80211_WORK_REMAIN_ON_CHANNEL,
|
||||
IEEE80211_WORK_OFFCHANNEL_TX,
|
||||
};
|
||||
#if HZ/100 == 0
|
||||
#define IEEE80211_ROC_MIN_LEFT 1
|
||||
#else
|
||||
#define IEEE80211_ROC_MIN_LEFT (HZ/100)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum work_done_result - indicates what to do after work was done
|
||||
*
|
||||
* @WORK_DONE_DESTROY: This work item is no longer needed, destroy.
|
||||
* @WORK_DONE_REQUEUE: This work item was reset to be reused, and
|
||||
* should be requeued.
|
||||
*/
|
||||
enum work_done_result {
|
||||
WORK_DONE_DESTROY,
|
||||
WORK_DONE_REQUEUE,
|
||||
};
|
||||
|
||||
struct ieee80211_work {
|
||||
struct ieee80211_roc_work {
|
||||
struct list_head list;
|
||||
struct list_head dependents;
|
||||
|
||||
struct rcu_head rcu_head;
|
||||
struct delayed_work work;
|
||||
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
enum work_done_result (*done)(struct ieee80211_work *wk,
|
||||
struct sk_buff *skb);
|
||||
|
||||
struct ieee80211_channel *chan;
|
||||
enum nl80211_channel_type chan_type;
|
||||
|
||||
unsigned long timeout;
|
||||
enum ieee80211_work_type type;
|
||||
bool started, abort, hw_begun, notified;
|
||||
|
||||
bool started;
|
||||
unsigned long hw_start_time;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u32 duration;
|
||||
} remain;
|
||||
struct {
|
||||
struct sk_buff *frame;
|
||||
u32 wait;
|
||||
bool status;
|
||||
} offchan_tx;
|
||||
};
|
||||
|
||||
size_t data_len;
|
||||
u8 data[];
|
||||
u32 duration, req_duration;
|
||||
struct sk_buff *frame;
|
||||
u64 mgmt_tx_cookie;
|
||||
};
|
||||
|
||||
/* flags used in struct ieee80211_if_managed.flags */
|
||||
|
|
@ -399,7 +374,6 @@ struct ieee80211_mgd_auth_data {
|
|||
struct ieee80211_mgd_assoc_data {
|
||||
struct cfg80211_bss *bss;
|
||||
const u8 *supp_rates;
|
||||
const u8 *ht_operation_ie;
|
||||
|
||||
unsigned long timeout;
|
||||
int tries;
|
||||
|
|
@ -414,6 +388,8 @@ struct ieee80211_mgd_assoc_data {
|
|||
bool sent_assoc;
|
||||
bool synced;
|
||||
|
||||
u8 ap_ht_param;
|
||||
|
||||
size_t ie_len;
|
||||
u8 ie[];
|
||||
};
|
||||
|
|
@ -846,13 +822,6 @@ struct ieee80211_local {
|
|||
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/*
|
||||
* work stuff, potentially off-channel (in the future)
|
||||
*/
|
||||
struct list_head work_list;
|
||||
struct timer_list work_timer;
|
||||
struct work_struct work_work;
|
||||
|
||||
/*
|
||||
* private workqueue to mac80211. mac80211 makes this accessible
|
||||
* via ieee80211_queue_work()
|
||||
|
|
@ -1087,14 +1056,12 @@ struct ieee80211_local {
|
|||
} debugfs;
|
||||
#endif
|
||||
|
||||
struct ieee80211_channel *hw_roc_channel;
|
||||
struct net_device *hw_roc_dev;
|
||||
struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status;
|
||||
/*
|
||||
* Remain-on-channel support
|
||||
*/
|
||||
struct list_head roc_list;
|
||||
struct work_struct hw_roc_start, hw_roc_done;
|
||||
enum nl80211_channel_type hw_roc_channel_type;
|
||||
unsigned int hw_roc_duration;
|
||||
u32 hw_roc_cookie;
|
||||
bool hw_roc_for_tx;
|
||||
unsigned long hw_roc_start_time;
|
||||
|
||||
struct idr ack_status_frames;
|
||||
spinlock_t ack_status_lock;
|
||||
|
|
@ -1290,7 +1257,12 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
|
|||
bool offchannel_ps_enable);
|
||||
void ieee80211_offchannel_return(struct ieee80211_local *local,
|
||||
bool offchannel_ps_disable);
|
||||
void ieee80211_hw_roc_setup(struct ieee80211_local *local);
|
||||
void ieee80211_roc_setup(struct ieee80211_local *local);
|
||||
void ieee80211_start_next_roc(struct ieee80211_local *local);
|
||||
void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc);
|
||||
void ieee80211_sw_roc_work(struct work_struct *work);
|
||||
void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
|
||||
|
||||
/* interface handling */
|
||||
int ieee80211_iface_init(void);
|
||||
|
|
@ -1500,18 +1472,6 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
|||
enum nl80211_channel_type channel_type,
|
||||
u16 prot_mode);
|
||||
|
||||
/* internal work items */
|
||||
void ieee80211_work_init(struct ieee80211_local *local);
|
||||
void ieee80211_add_work(struct ieee80211_work *wk);
|
||||
void free_work(struct ieee80211_work *wk);
|
||||
void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration, u64 *cookie);
|
||||
int ieee80211_wk_cancel_remain_on_channel(
|
||||
struct ieee80211_sub_if_data *sdata, u64 cookie);
|
||||
|
||||
/* channel management */
|
||||
enum ieee80211_chan_mode {
|
||||
CHAN_MODE_UNDEFINED,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
|
||||
pr_debug("%s: setting MTU %d\n", dev->name, new_mtu);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
dev->mtu = new_mtu;
|
||||
return 0;
|
||||
|
|
@ -528,10 +528,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
|
||||
/*
|
||||
* Purge work for this interface.
|
||||
*/
|
||||
ieee80211_work_purge(sdata);
|
||||
ieee80211_roc_purge(sdata);
|
||||
|
||||
/*
|
||||
* Remove all stations associated with this interface.
|
||||
|
|
@ -637,18 +634,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_configure_filter(local);
|
||||
break;
|
||||
default:
|
||||
mutex_lock(&local->mtx);
|
||||
if (local->hw_roc_dev == sdata->dev &&
|
||||
local->hw_roc_channel) {
|
||||
/* ignore return value since this is racy */
|
||||
drv_cancel_remain_on_channel(local);
|
||||
ieee80211_queue_work(&local->hw, &local->hw_roc_done);
|
||||
}
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
flush_work(&local->hw_roc_start);
|
||||
flush_work(&local->hw_roc_done);
|
||||
|
||||
flush_work(&sdata->work);
|
||||
/*
|
||||
* When we get here, the interface is marked down.
|
||||
|
|
@ -1238,7 +1223,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
|
|||
|
||||
if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {
|
||||
/* not a contiguous mask ... not handled now! */
|
||||
printk(KERN_DEBUG "not contiguous\n");
|
||||
pr_debug("not contiguous\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1364,6 +1349,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
sdata->u.mgd.use_4addr = params->use_4addr;
|
||||
}
|
||||
|
||||
ndev->features |= local->hw.netdev_features;
|
||||
|
||||
ret = register_netdevice(ndev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
|
@ -1454,9 +1441,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int count = 0;
|
||||
bool working = false, scanning = false, hw_roc = false;
|
||||
struct ieee80211_work *wk;
|
||||
bool working = false, scanning = false;
|
||||
unsigned int led_trig_start = 0, led_trig_stop = 0;
|
||||
struct ieee80211_roc_work *roc;
|
||||
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
|
||||
|
|
@ -1491,9 +1478,11 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
|||
count++;
|
||||
}
|
||||
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
working = true;
|
||||
wk->sdata->vif.bss_conf.idle = false;
|
||||
if (!local->ops->remain_on_channel) {
|
||||
list_for_each_entry(roc, &local->roc_list, list) {
|
||||
working = true;
|
||||
roc->sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (local->scan_sdata &&
|
||||
|
|
@ -1502,9 +1491,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
|||
local->scan_sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
|
||||
if (local->hw_roc_channel)
|
||||
hw_roc = true;
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
|
|
@ -1516,7 +1502,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
|||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
||||
}
|
||||
|
||||
if (working || scanning || hw_roc)
|
||||
if (working || scanning)
|
||||
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
|
||||
else
|
||||
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
|
||||
|
|
@ -1528,8 +1514,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
|||
|
||||
ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
|
||||
|
||||
if (hw_roc)
|
||||
return ieee80211_idle_off(local, "hw remain-on-channel");
|
||||
if (working)
|
||||
return ieee80211_idle_off(local, "working");
|
||||
if (scanning)
|
||||
|
|
|
|||
|
|
@ -625,8 +625,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
|
||||
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
|
||||
|
||||
ieee80211_work_init(local);
|
||||
|
||||
INIT_WORK(&local->restart_work, ieee80211_restart_work);
|
||||
|
||||
INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
|
||||
|
|
@ -669,7 +667,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
|
||||
ieee80211_led_names(local);
|
||||
|
||||
ieee80211_hw_roc_setup(local);
|
||||
ieee80211_roc_setup(local);
|
||||
|
||||
return &local->hw;
|
||||
}
|
||||
|
|
@ -682,6 +680,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
enum ieee80211_band band;
|
||||
int channels, max_bitrates;
|
||||
bool supp_ht;
|
||||
netdev_features_t feature_whitelist;
|
||||
static const u32 cipher_suites[] = {
|
||||
/* keep WEP first, it may be removed below */
|
||||
WLAN_CIPHER_SUITE_WEP40,
|
||||
|
|
@ -708,6 +707,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
|
||||
return -EINVAL;
|
||||
|
||||
/* Only HW csum features are currently compatible with mac80211 */
|
||||
feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
|
||||
NETIF_F_HW_CSUM;
|
||||
if (WARN_ON(hw->netdev_features & ~feature_whitelist))
|
||||
return -EINVAL;
|
||||
|
||||
if (hw->max_report_rates == 0)
|
||||
hw->max_report_rates = hw->max_rates;
|
||||
|
||||
|
|
@ -1009,12 +1014,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
|||
|
||||
rtnl_unlock();
|
||||
|
||||
/*
|
||||
* Now all work items will be gone, but the
|
||||
* timer might still be armed, so delete it
|
||||
*/
|
||||
del_timer_sync(&local->work_timer);
|
||||
|
||||
cancel_work_sync(&local->restart_work);
|
||||
cancel_work_sync(&local->reconfig_filter);
|
||||
|
||||
|
|
|
|||
|
|
@ -524,8 +524,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
|
|||
bool free_plinks;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: running mesh housekeeping\n",
|
||||
sdata->name);
|
||||
pr_debug("%s: running mesh housekeeping\n", sdata->name);
|
||||
#endif
|
||||
|
||||
ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
|
||||
#define mhwmp_dbg(fmt, args...) \
|
||||
printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
|
||||
pr_debug("Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
|
||||
#else
|
||||
#define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#include "mesh.h"
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
|
||||
#define mpath_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
|
||||
#define mpath_dbg(fmt, args...) pr_debug(fmt, ##args)
|
||||
#else
|
||||
#define mpath_dbg(fmt, args...) do { (void)(0); } while (0)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#include "mesh.h"
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
|
||||
#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
|
||||
#define mpl_dbg(fmt, args...) pr_debug(fmt, ##args)
|
||||
#else
|
||||
#define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG
|
||||
#define msync_dbg(fmt, args...) \
|
||||
printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args)
|
||||
pr_debug("Mesh sync (%s): " fmt "\n", sdata->name, ##args)
|
||||
#else
|
||||
#define msync_dbg(fmt, args...) do { (void)(0); } while (0)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -258,12 +258,11 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
|
|||
}
|
||||
|
||||
static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, const u8 *ht_oper_ie,
|
||||
struct sk_buff *skb, u8 ap_ht_param,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_channel *channel,
|
||||
enum ieee80211_smps_mode smps)
|
||||
{
|
||||
struct ieee80211_ht_operation *ht_oper;
|
||||
u8 *pos;
|
||||
u32 flags = channel->flags;
|
||||
u16 cap;
|
||||
|
|
@ -271,21 +270,13 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
|
||||
|
||||
if (!ht_oper_ie)
|
||||
return;
|
||||
|
||||
if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation))
|
||||
return;
|
||||
|
||||
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
|
||||
ieee80211_apply_htcap_overrides(sdata, &ht_cap);
|
||||
|
||||
ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2);
|
||||
|
||||
/* determine capability flags */
|
||||
cap = ht_cap.cap;
|
||||
|
||||
switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
||||
switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
||||
if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
|
||||
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
|
|
@ -509,7 +500,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
|
||||
ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie,
|
||||
ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
|
||||
sband, local->oper_channel, ifmgd->ap_smps);
|
||||
|
||||
/* if present, add any custom non-vendor IEs that go after HT */
|
||||
|
|
@ -939,11 +930,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!list_empty(&local->work_list)) {
|
||||
local->ps_sdata = NULL;
|
||||
goto change;
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
|
@ -1016,7 +1002,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
|||
local->ps_sdata = NULL;
|
||||
}
|
||||
|
||||
change:
|
||||
ieee80211_change_ps(local);
|
||||
}
|
||||
|
||||
|
|
@ -1585,6 +1570,8 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
|
|||
net_dbg_ratelimited("%s: detected beacon loss from AP - sending probe request\n",
|
||||
sdata->name);
|
||||
#endif
|
||||
ieee80211_cqm_rssi_notify(&sdata->vif,
|
||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);
|
||||
|
||||
/*
|
||||
* The driver/our work has already reported this event or the
|
||||
|
|
@ -1667,8 +1654,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
|
||||
|
||||
printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n",
|
||||
sdata->name, bssid);
|
||||
pr_debug("%s: Connection to AP %pM lost\n", sdata->name, bssid);
|
||||
|
||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
||||
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
|
||||
|
|
@ -1802,9 +1788,10 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
|
|||
return RX_MGMT_NONE;
|
||||
|
||||
if (status_code != WLAN_STATUS_SUCCESS) {
|
||||
printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n",
|
||||
sdata->name, mgmt->sa, status_code);
|
||||
goto out;
|
||||
pr_debug("%s: %pM denied authentication (status %d)\n",
|
||||
sdata->name, mgmt->sa, status_code);
|
||||
ieee80211_destroy_auth_data(sdata, false);
|
||||
return RX_MGMT_CFG80211_RX_AUTH;
|
||||
}
|
||||
|
||||
switch (ifmgd->auth_data->algorithm) {
|
||||
|
|
@ -1825,8 +1812,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
|
|||
return RX_MGMT_NONE;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
|
||||
out:
|
||||
pr_debug("%s: authenticated\n", sdata->name);
|
||||
ifmgd->auth_data->done = true;
|
||||
ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
|
||||
run_again(ifmgd, ifmgd->auth_data->timeout);
|
||||
|
|
@ -1839,8 +1825,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
|
|||
goto out_err;
|
||||
}
|
||||
if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
|
||||
printk(KERN_DEBUG "%s: failed moving %pM to auth\n",
|
||||
sdata->name, bssid);
|
||||
pr_debug("%s: failed moving %pM to auth\n", sdata->name, bssid);
|
||||
goto out_err;
|
||||
}
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
|
|
@ -1874,8 +1859,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
|
||||
|
||||
printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
|
||||
sdata->name, bssid, reason_code);
|
||||
pr_debug("%s: deauthenticated from %pM (Reason: %u)\n",
|
||||
sdata->name, bssid, reason_code);
|
||||
|
||||
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
|
||||
|
||||
|
|
@ -1905,8 +1890,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
|
||||
|
||||
printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
|
||||
sdata->name, mgmt->sa, reason_code);
|
||||
pr_debug("%s: disassociated from %pM (Reason: %u)\n",
|
||||
sdata->name, mgmt->sa, reason_code);
|
||||
|
||||
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
|
||||
|
||||
|
|
@ -1998,17 +1983,15 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
|
||||
|
||||
if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
|
||||
printk(KERN_DEBUG
|
||||
"%s: invalid AID value 0x%x; bits 15:14 not set\n",
|
||||
sdata->name, aid);
|
||||
pr_debug("%s: invalid AID value 0x%x; bits 15:14 not set\n",
|
||||
sdata->name, aid);
|
||||
aid &= ~(BIT(15) | BIT(14));
|
||||
|
||||
ifmgd->broken_ap = false;
|
||||
|
||||
if (aid == 0 || aid > IEEE80211_MAX_AID) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: invalid AID value %d (out of range), turn off PS\n",
|
||||
sdata->name, aid);
|
||||
pr_debug("%s: invalid AID value %d (out of range), turn off PS\n",
|
||||
sdata->name, aid);
|
||||
aid = 0;
|
||||
ifmgd->broken_ap = true;
|
||||
}
|
||||
|
|
@ -2017,8 +2000,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
|
||||
|
||||
if (!elems.supp_rates) {
|
||||
printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
|
||||
sdata->name);
|
||||
pr_debug("%s: no SuppRates element in AssocResp\n",
|
||||
sdata->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2058,9 +2041,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
|
||||
err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
||||
if (err) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: failed to move station %pM to desired state\n",
|
||||
sdata->name, sta->sta.addr);
|
||||
pr_debug("%s: failed to move station %pM to desired state\n",
|
||||
sdata->name, sta->sta.addr);
|
||||
WARN_ON(__sta_info_destroy(sta));
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
return false;
|
||||
|
|
@ -2143,10 +2125,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
|
||||
|
||||
printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
|
||||
"status=%d aid=%d)\n",
|
||||
sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
|
||||
capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
|
||||
pr_debug("%s: RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
|
||||
sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
|
||||
capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
|
||||
|
||||
pos = mgmt->u.assoc_resp.variable;
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
|
||||
|
|
@ -2157,9 +2138,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
u32 tu, ms;
|
||||
tu = get_unaligned_le32(elems.timeout_int + 1);
|
||||
ms = tu * 1024 / 1000;
|
||||
printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
|
||||
"comeback duration %u TU (%u ms)\n",
|
||||
sdata->name, mgmt->sa, tu, ms);
|
||||
pr_debug("%s: %pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
|
||||
sdata->name, mgmt->sa, tu, ms);
|
||||
assoc_data->timeout = jiffies + msecs_to_jiffies(ms);
|
||||
if (ms > IEEE80211_ASSOC_TIMEOUT)
|
||||
run_again(ifmgd, assoc_data->timeout);
|
||||
|
|
@ -2169,11 +2149,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
*bss = assoc_data->bss;
|
||||
|
||||
if (status_code != WLAN_STATUS_SUCCESS) {
|
||||
printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n",
|
||||
sdata->name, mgmt->sa, status_code);
|
||||
pr_debug("%s: %pM denied association (code=%d)\n",
|
||||
sdata->name, mgmt->sa, status_code);
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
} else {
|
||||
printk(KERN_DEBUG "%s: associated\n", sdata->name);
|
||||
pr_debug("%s: associated\n", sdata->name);
|
||||
|
||||
if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
|
||||
/* oops -- internal error -- send timeout for now */
|
||||
|
|
@ -2281,7 +2261,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
|
||||
/* got probe response, continue with auth */
|
||||
printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
|
||||
pr_debug("%s: direct probe responded\n", sdata->name);
|
||||
ifmgd->auth_data->tries = 0;
|
||||
ifmgd->auth_data->timeout = jiffies;
|
||||
run_again(ifmgd, ifmgd->auth_data->timeout);
|
||||
|
|
@ -2645,8 +2625,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
|
|||
auth_data->tries++;
|
||||
|
||||
if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
|
||||
printk(KERN_DEBUG "%s: authentication with %pM timed out\n",
|
||||
sdata->name, auth_data->bss->bssid);
|
||||
pr_debug("%s: authentication with %pM timed out\n",
|
||||
sdata->name, auth_data->bss->bssid);
|
||||
|
||||
/*
|
||||
* Most likely AP is not in the range so remove the
|
||||
|
|
@ -2658,9 +2638,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
|
||||
if (auth_data->bss->proberesp_ies) {
|
||||
printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n",
|
||||
sdata->name, auth_data->bss->bssid, auth_data->tries,
|
||||
IEEE80211_AUTH_MAX_TRIES);
|
||||
pr_debug("%s: send auth to %pM (try %d/%d)\n",
|
||||
sdata->name, auth_data->bss->bssid, auth_data->tries,
|
||||
IEEE80211_AUTH_MAX_TRIES);
|
||||
|
||||
auth_data->expected_transaction = 2;
|
||||
ieee80211_send_auth(sdata, 1, auth_data->algorithm,
|
||||
|
|
@ -2670,9 +2650,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
|
|||
} else {
|
||||
const u8 *ssidie;
|
||||
|
||||
printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n",
|
||||
sdata->name, auth_data->bss->bssid, auth_data->tries,
|
||||
IEEE80211_AUTH_MAX_TRIES);
|
||||
pr_debug("%s: direct probe to %pM (try %d/%i)\n",
|
||||
sdata->name, auth_data->bss->bssid, auth_data->tries,
|
||||
IEEE80211_AUTH_MAX_TRIES);
|
||||
|
||||
ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
|
||||
if (!ssidie)
|
||||
|
|
@ -2700,8 +2680,8 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
assoc_data->tries++;
|
||||
if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
|
||||
printk(KERN_DEBUG "%s: association with %pM timed out\n",
|
||||
sdata->name, assoc_data->bss->bssid);
|
||||
pr_debug("%s: association with %pM timed out\n",
|
||||
sdata->name, assoc_data->bss->bssid);
|
||||
|
||||
/*
|
||||
* Most likely AP is not in the range so remove the
|
||||
|
|
@ -2712,9 +2692,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n",
|
||||
sdata->name, assoc_data->bss->bssid, assoc_data->tries,
|
||||
IEEE80211_ASSOC_MAX_TRIES);
|
||||
pr_debug("%s: associate with %pM (try %d/%d)\n",
|
||||
sdata->name, assoc_data->bss->bssid, assoc_data->tries,
|
||||
IEEE80211_ASSOC_MAX_TRIES);
|
||||
ieee80211_send_assoc(sdata);
|
||||
|
||||
assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
|
||||
|
|
@ -3085,13 +3065,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
|||
* since we look at probe response/beacon data here
|
||||
* it should be OK.
|
||||
*/
|
||||
printk(KERN_DEBUG
|
||||
"%s: Wrong control channel: center-freq: %d"
|
||||
" ht-cfreq: %d ht->primary_chan: %d"
|
||||
" band: %d. Disabling HT.\n",
|
||||
sdata->name, cbss->channel->center_freq,
|
||||
ht_cfreq, ht_oper->primary_chan,
|
||||
cbss->channel->band);
|
||||
pr_debug("%s: Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
|
||||
sdata->name, cbss->channel->center_freq,
|
||||
ht_cfreq, ht_oper->primary_chan,
|
||||
cbss->channel->band);
|
||||
ht_oper = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -3115,9 +3092,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
|||
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
|
||||
/* can only fail due to HT40+/- mismatch */
|
||||
channel_type = NL80211_CHAN_HT20;
|
||||
printk(KERN_DEBUG
|
||||
"%s: disabling 40 MHz due to multi-vif mismatch\n",
|
||||
sdata->name);
|
||||
pr_debug("%s: disabling 40 MHz due to multi-vif mismatch\n",
|
||||
sdata->name);
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
|
||||
WARN_ON(!ieee80211_set_channel_type(local, sdata,
|
||||
channel_type));
|
||||
|
|
@ -3146,9 +3122,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
|||
* we can connect -- with a warning.
|
||||
*/
|
||||
if (!basic_rates && min_rate_index >= 0) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: No basic rates, using min rate instead.\n",
|
||||
sdata->name);
|
||||
pr_debug("%s: No basic rates, using min rate instead\n",
|
||||
sdata->name);
|
||||
basic_rates = BIT(min_rate_index);
|
||||
}
|
||||
|
||||
|
|
@ -3174,9 +3149,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
|||
err = sta_info_insert(sta);
|
||||
sta = NULL;
|
||||
if (err) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: failed to insert STA entry for the AP (error %d)\n",
|
||||
sdata->name, err);
|
||||
pr_debug("%s: failed to insert STA entry for the AP (error %d)\n",
|
||||
sdata->name, err);
|
||||
return err;
|
||||
}
|
||||
} else
|
||||
|
|
@ -3254,8 +3228,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
|||
if (ifmgd->associated)
|
||||
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
|
||||
|
||||
printk(KERN_DEBUG "%s: authenticate with %pM\n",
|
||||
sdata->name, req->bss->bssid);
|
||||
pr_debug("%s: authenticate with %pM\n", sdata->name, req->bss->bssid);
|
||||
|
||||
err = ieee80211_prep_connection(sdata, req->bss, false);
|
||||
if (err)
|
||||
|
|
@ -3290,7 +3263,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_bss *bss = (void *)req->bss->priv;
|
||||
struct ieee80211_mgd_assoc_data *assoc_data;
|
||||
struct ieee80211_supported_band *sband;
|
||||
const u8 *ssidie;
|
||||
const u8 *ssidie, *ht_ie;
|
||||
int i, err;
|
||||
|
||||
ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
|
||||
|
|
@ -3338,11 +3311,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
* We can set this to true for non-11n hardware, that'll be checked
|
||||
* separately along with the peer capabilities.
|
||||
*/
|
||||
for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
|
||||
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 ||
|
||||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
|
||||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
|
||||
netdev_info(sdata->dev,
|
||||
"disabling HT due to WEP/TKIP use\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (req->flags & ASSOC_REQ_DISABLE_HT)
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
|
||||
|
|
@ -3350,8 +3327,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
/* Also disable HT if we don't support it or the AP doesn't use WMM */
|
||||
sband = local->hw.wiphy->bands[req->bss->channel->band];
|
||||
if (!sband->ht_cap.ht_supported ||
|
||||
local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used)
|
||||
local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
|
||||
netdev_info(sdata->dev,
|
||||
"disabling HT as WMM/QoS is not supported\n");
|
||||
}
|
||||
|
||||
memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
|
||||
memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
|
||||
|
|
@ -3377,8 +3357,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
(local->hw.queues >= IEEE80211_NUM_ACS);
|
||||
assoc_data->supp_rates = bss->supp_rates;
|
||||
assoc_data->supp_rates_len = bss->supp_rates_len;
|
||||
assoc_data->ht_operation_ie =
|
||||
ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
|
||||
|
||||
ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
|
||||
if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
|
||||
assoc_data->ap_ht_param =
|
||||
((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
|
||||
else
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
|
||||
|
||||
if (bss->wmm_used && bss->uapsd_supported &&
|
||||
(sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
|
||||
|
|
@ -3425,8 +3410,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
* Wait up to one beacon interval ...
|
||||
* should this be more if we miss one?
|
||||
*/
|
||||
printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
|
||||
sdata->name, ifmgd->bssid);
|
||||
pr_debug("%s: waiting for beacon from %pM\n",
|
||||
sdata->name, ifmgd->bssid);
|
||||
assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
|
||||
} else {
|
||||
assoc_data->have_beacon = true;
|
||||
|
|
@ -3445,8 +3430,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
corrupt_type = "beacon";
|
||||
} else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
|
||||
corrupt_type = "probe response";
|
||||
printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n",
|
||||
sdata->name, corrupt_type);
|
||||
pr_debug("%s: associating with AP with corrupt %s\n",
|
||||
sdata->name, corrupt_type);
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
|
@ -3475,9 +3460,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG
|
||||
"%s: deauthenticating from %pM by local choice (reason=%d)\n",
|
||||
sdata->name, req->bssid, req->reason_code);
|
||||
pr_debug("%s: deauthenticating from %pM by local choice (reason=%d)\n",
|
||||
sdata->name, req->bssid, req->reason_code);
|
||||
|
||||
if (ifmgd->associated &&
|
||||
ether_addr_equal(ifmgd->associated->bssid, req->bssid))
|
||||
|
|
@ -3519,8 +3503,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
return -ENOLINK;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
|
||||
sdata->name, req->bss->bssid, req->reason_code);
|
||||
pr_debug("%s: disassociating from %pM by local choice (reason=%d)\n",
|
||||
sdata->name, req->bss->bssid, req->reason_code);
|
||||
|
||||
memcpy(bssid, req->bss->bssid, ETH_ALEN);
|
||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
|
||||
|
|
@ -3561,10 +3545,3 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
|
|||
cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
|
||||
|
||||
unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
return sdata->dev->operstate;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_get_operstate);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-trace.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
/*
|
||||
* Tell our hardware to disable PS.
|
||||
|
|
@ -181,34 +182,58 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
|
|||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
|
||||
{
|
||||
if (roc->notified)
|
||||
return;
|
||||
|
||||
if (roc->mgmt_tx_cookie) {
|
||||
if (!WARN_ON(!roc->frame)) {
|
||||
ieee80211_tx_skb(roc->sdata, roc->frame);
|
||||
roc->frame = NULL;
|
||||
}
|
||||
} else {
|
||||
cfg80211_ready_on_channel(roc->sdata->dev, (unsigned long)roc,
|
||||
roc->chan, roc->chan_type,
|
||||
roc->req_duration, GFP_KERNEL);
|
||||
}
|
||||
|
||||
roc->notified = true;
|
||||
}
|
||||
|
||||
static void ieee80211_hw_roc_start(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, hw_roc_start);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_roc_work *roc, *dep, *tmp;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
if (!local->hw_roc_channel) {
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
if (list_empty(&local->roc_list))
|
||||
goto out_unlock;
|
||||
|
||||
roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
|
||||
list);
|
||||
|
||||
if (!roc->started)
|
||||
goto out_unlock;
|
||||
|
||||
roc->hw_begun = true;
|
||||
roc->hw_start_time = local->hw_roc_start_time;
|
||||
|
||||
ieee80211_handle_roc_started(roc);
|
||||
list_for_each_entry_safe(dep, tmp, &roc->dependents, list) {
|
||||
ieee80211_handle_roc_started(dep);
|
||||
|
||||
if (dep->duration > roc->duration) {
|
||||
u32 dur = dep->duration;
|
||||
dep->duration = dur - roc->duration;
|
||||
roc->duration = dur;
|
||||
list_del(&dep->list);
|
||||
list_add(&dep->list, &roc->list);
|
||||
}
|
||||
}
|
||||
|
||||
if (local->hw_roc_skb) {
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev);
|
||||
ieee80211_tx_skb(sdata, local->hw_roc_skb);
|
||||
local->hw_roc_skb = NULL;
|
||||
} else {
|
||||
cfg80211_ready_on_channel(local->hw_roc_dev,
|
||||
local->hw_roc_cookie,
|
||||
local->hw_roc_channel,
|
||||
local->hw_roc_channel_type,
|
||||
local->hw_roc_duration,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
|
|
@ -216,52 +241,179 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw)
|
|||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
local->hw_roc_start_time = jiffies;
|
||||
|
||||
trace_api_ready_on_channel(local);
|
||||
|
||||
ieee80211_queue_work(hw, &local->hw_roc_start);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
|
||||
|
||||
void ieee80211_start_next_roc(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_roc_work *roc;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
if (list_empty(&local->roc_list)) {
|
||||
ieee80211_run_deferred_scan(local);
|
||||
return;
|
||||
}
|
||||
|
||||
roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
|
||||
list);
|
||||
|
||||
if (local->ops->remain_on_channel) {
|
||||
int ret, duration = roc->duration;
|
||||
|
||||
/* XXX: duplicated, see ieee80211_start_roc_work() */
|
||||
if (!duration)
|
||||
duration = 10;
|
||||
|
||||
ret = drv_remain_on_channel(local, roc->chan,
|
||||
roc->chan_type,
|
||||
duration);
|
||||
|
||||
roc->started = true;
|
||||
|
||||
if (ret) {
|
||||
wiphy_warn(local->hw.wiphy,
|
||||
"failed to start next HW ROC (%d)\n", ret);
|
||||
/*
|
||||
* queue the work struct again to avoid recursion
|
||||
* when multiple failures occur
|
||||
*/
|
||||
ieee80211_remain_on_channel_expired(&local->hw);
|
||||
}
|
||||
} else {
|
||||
/* delay it a bit */
|
||||
ieee80211_queue_delayed_work(&local->hw, &roc->work,
|
||||
round_jiffies_relative(HZ/2));
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
|
||||
{
|
||||
struct ieee80211_roc_work *dep, *tmp;
|
||||
|
||||
/* was never transmitted */
|
||||
if (roc->frame) {
|
||||
cfg80211_mgmt_tx_status(roc->sdata->dev,
|
||||
(unsigned long)roc->frame,
|
||||
roc->frame->data, roc->frame->len,
|
||||
false, GFP_KERNEL);
|
||||
kfree_skb(roc->frame);
|
||||
}
|
||||
|
||||
if (!roc->mgmt_tx_cookie)
|
||||
cfg80211_remain_on_channel_expired(roc->sdata->dev,
|
||||
(unsigned long)roc,
|
||||
roc->chan, roc->chan_type,
|
||||
GFP_KERNEL);
|
||||
|
||||
list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
|
||||
ieee80211_roc_notify_destroy(dep);
|
||||
|
||||
kfree(roc);
|
||||
}
|
||||
|
||||
void ieee80211_sw_roc_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_roc_work *roc =
|
||||
container_of(work, struct ieee80211_roc_work, work.work);
|
||||
struct ieee80211_sub_if_data *sdata = roc->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
if (roc->abort)
|
||||
goto finish;
|
||||
|
||||
if (WARN_ON(list_empty(&local->roc_list)))
|
||||
goto out_unlock;
|
||||
|
||||
if (WARN_ON(roc != list_first_entry(&local->roc_list,
|
||||
struct ieee80211_roc_work,
|
||||
list)))
|
||||
goto out_unlock;
|
||||
|
||||
if (!roc->started) {
|
||||
struct ieee80211_roc_work *dep;
|
||||
|
||||
/* start this ROC */
|
||||
|
||||
/* switch channel etc */
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
local->tmp_channel = roc->chan;
|
||||
local->tmp_channel_type = roc->chan_type;
|
||||
ieee80211_hw_config(local, 0);
|
||||
|
||||
/* tell userspace or send frame */
|
||||
ieee80211_handle_roc_started(roc);
|
||||
list_for_each_entry(dep, &roc->dependents, list)
|
||||
ieee80211_handle_roc_started(dep);
|
||||
|
||||
/* if it was pure TX, just finish right away */
|
||||
if (!roc->duration)
|
||||
goto finish;
|
||||
|
||||
roc->started = true;
|
||||
ieee80211_queue_delayed_work(&local->hw, &roc->work,
|
||||
msecs_to_jiffies(roc->duration));
|
||||
} else {
|
||||
/* finish this ROC */
|
||||
finish:
|
||||
list_del(&roc->list);
|
||||
ieee80211_roc_notify_destroy(roc);
|
||||
|
||||
if (roc->started) {
|
||||
drv_flush(local, false);
|
||||
|
||||
local->tmp_channel = NULL;
|
||||
ieee80211_hw_config(local, 0);
|
||||
|
||||
ieee80211_offchannel_return(local, true);
|
||||
}
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
ieee80211_start_next_roc(local);
|
||||
ieee80211_run_deferred_scan(local);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
static void ieee80211_hw_roc_done(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, hw_roc_done);
|
||||
struct ieee80211_roc_work *roc;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
if (!local->hw_roc_channel) {
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
}
|
||||
if (list_empty(&local->roc_list))
|
||||
goto out_unlock;
|
||||
|
||||
/* was never transmitted */
|
||||
if (local->hw_roc_skb) {
|
||||
u64 cookie;
|
||||
roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
|
||||
list);
|
||||
|
||||
cookie = local->hw_roc_cookie ^ 2;
|
||||
if (!roc->started)
|
||||
goto out_unlock;
|
||||
|
||||
cfg80211_mgmt_tx_status(local->hw_roc_dev, cookie,
|
||||
local->hw_roc_skb->data,
|
||||
local->hw_roc_skb->len, false,
|
||||
GFP_KERNEL);
|
||||
list_del(&roc->list);
|
||||
|
||||
kfree_skb(local->hw_roc_skb);
|
||||
local->hw_roc_skb = NULL;
|
||||
local->hw_roc_skb_for_status = NULL;
|
||||
}
|
||||
ieee80211_roc_notify_destroy(roc);
|
||||
|
||||
if (!local->hw_roc_for_tx)
|
||||
cfg80211_remain_on_channel_expired(local->hw_roc_dev,
|
||||
local->hw_roc_cookie,
|
||||
local->hw_roc_channel,
|
||||
local->hw_roc_channel_type,
|
||||
GFP_KERNEL);
|
||||
/* if there's another roc, start it now */
|
||||
ieee80211_start_next_roc(local);
|
||||
|
||||
local->hw_roc_channel = NULL;
|
||||
local->hw_roc_cookie = 0;
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
/* or scan maybe */
|
||||
ieee80211_run_deferred_scan(local);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
|
|
@ -275,8 +427,48 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
|
||||
|
||||
void ieee80211_hw_roc_setup(struct ieee80211_local *local)
|
||||
void ieee80211_roc_setup(struct ieee80211_local *local)
|
||||
{
|
||||
INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);
|
||||
INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done);
|
||||
INIT_LIST_HEAD(&local->roc_list);
|
||||
}
|
||||
|
||||
void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_roc_work *roc, *tmp;
|
||||
LIST_HEAD(tmp_list);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
|
||||
if (roc->sdata != sdata)
|
||||
continue;
|
||||
|
||||
if (roc->started && local->ops->remain_on_channel) {
|
||||
/* can race, so ignore return value */
|
||||
drv_cancel_remain_on_channel(local);
|
||||
}
|
||||
|
||||
list_move_tail(&roc->list, &tmp_list);
|
||||
roc->abort = true;
|
||||
}
|
||||
|
||||
ieee80211_start_next_roc(local);
|
||||
ieee80211_run_deferred_scan(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
|
||||
if (local->ops->remain_on_channel) {
|
||||
list_del(&roc->list);
|
||||
ieee80211_roc_notify_destroy(roc);
|
||||
} else {
|
||||
ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
|
||||
|
||||
/* work will clean up etc */
|
||||
flush_delayed_work(&roc->work);
|
||||
}
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(!list_empty(&tmp_list));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
int err = drv_suspend(local, wowlan);
|
||||
if (err < 0) {
|
||||
local->quiescing = false;
|
||||
local->wowlan = false;
|
||||
return err;
|
||||
} else if (err > 0) {
|
||||
WARN_ON(err != 1);
|
||||
|
|
|
|||
|
|
@ -1137,22 +1137,22 @@ static void ap_sta_ps_start(struct sta_info *sta)
|
|||
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
|
||||
sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
pr_debug("%s: STA %pM aid %d enters power save mode\n",
|
||||
sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
}
|
||||
|
||||
static void ap_sta_ps_end(struct sta_info *sta)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
|
||||
sta->sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
pr_debug("%s: STA %pM aid %d exits power save mode\n",
|
||||
sta->sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
|
||||
sta->sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
pr_debug("%s: STA %pM aid %d driver-ps-blocked\n",
|
||||
sta->sdata->name, sta->sta.addr, sta->sta.aid);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
return;
|
||||
}
|
||||
|
|
@ -1387,12 +1387,10 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
|
|||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
struct ieee80211_hdr *hdr =
|
||||
(struct ieee80211_hdr *) entry->skb_list.next->data;
|
||||
printk(KERN_DEBUG "%s: RX reassembly removed oldest "
|
||||
"fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
|
||||
"addr1=%pM addr2=%pM\n",
|
||||
sdata->name, idx,
|
||||
jiffies - entry->first_frag_time, entry->seq,
|
||||
entry->last_frag, hdr->addr1, hdr->addr2);
|
||||
pr_debug("%s: RX reassembly removed oldest fragment entry (idx=%d age=%lu seq=%d last_frag=%d addr1=%pM addr2=%pM\n",
|
||||
sdata->name, idx,
|
||||
jiffies - entry->first_frag_time, entry->seq,
|
||||
entry->last_frag, hdr->addr1, hdr->addr2);
|
||||
#endif
|
||||
__skb_queue_purge(&entry->skb_list);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
|
|||
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);
|
||||
ieee80211_start_next_roc(local);
|
||||
}
|
||||
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
|
|
@ -375,7 +375,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
|||
static bool ieee80211_can_scan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
if (!list_empty(&local->work_list))
|
||||
if (!list_empty(&local->roc_list))
|
||||
return false;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
|
|
|
|||
|
|
@ -333,9 +333,8 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n",
|
||||
sdata->name, sta->sta.addr, state + 1, err);
|
||||
pr_debug("%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n",
|
||||
sdata->name, sta->sta.addr, state + 1, err);
|
||||
err = 0;
|
||||
}
|
||||
|
||||
|
|
@ -619,8 +618,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
|
|||
|
||||
local->total_ps_buffered--;
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
|
||||
sta->sta.addr);
|
||||
pr_debug("Buffered frame expired (STA %pM)\n", sta->sta.addr);
|
||||
#endif
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
|
@ -889,10 +887,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
|
|||
continue;
|
||||
|
||||
if (time_after(jiffies, sta->last_rx + exp_time)) {
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: expiring inactive STA %pM\n",
|
||||
sdata->name, sta->sta.addr);
|
||||
#endif
|
||||
ibss_vdbg("%s: expiring inactive STA %pM\n",
|
||||
sdata->name, sta->sta.addr);
|
||||
WARN_ON(__sta_info_destroy(sta));
|
||||
}
|
||||
}
|
||||
|
|
@ -991,9 +987,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
|||
sta_info_recalc_tim(sta);
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
|
||||
"since STA not sleeping anymore\n", sdata->name,
|
||||
sta->sta.addr, sta->sta.aid, filtered, buffered);
|
||||
pr_debug("%s: STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n",
|
||||
sdata->name, sta->sta.addr, sta->sta.aid, filtered, buffered);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
}
|
||||
|
||||
|
|
@ -1385,8 +1380,8 @@ int sta_info_move_state(struct sta_info *sta,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: moving STA %pM to state %d\n",
|
||||
sta->sdata->name, sta->sta.addr, new_state);
|
||||
pr_debug("%s: moving STA %pM to state %d\n",
|
||||
sta->sdata->name, sta->sta.addr, new_state);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -520,36 +520,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
|
||||
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
|
||||
u64 cookie = (unsigned long)skb;
|
||||
acked = info->flags & IEEE80211_TX_STAT_ACK;
|
||||
|
||||
if (ieee80211_is_nullfunc(hdr->frame_control) ||
|
||||
ieee80211_is_qos_nullfunc(hdr->frame_control)) {
|
||||
acked = info->flags & IEEE80211_TX_STAT_ACK;
|
||||
|
||||
ieee80211_is_qos_nullfunc(hdr->frame_control))
|
||||
cfg80211_probe_status(skb->dev, hdr->addr1,
|
||||
cookie, acked, GFP_ATOMIC);
|
||||
} else {
|
||||
struct ieee80211_work *wk;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(wk, &local->work_list, list) {
|
||||
if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
|
||||
continue;
|
||||
if (wk->offchan_tx.frame != skb)
|
||||
continue;
|
||||
wk->offchan_tx.status = true;
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (local->hw_roc_skb_for_status == skb) {
|
||||
cookie = local->hw_roc_cookie ^ 2;
|
||||
local->hw_roc_skb_for_status = NULL;
|
||||
}
|
||||
|
||||
else
|
||||
cfg80211_mgmt_tx_status(
|
||||
skb->dev, cookie, skb->data, skb->len,
|
||||
!!(info->flags & IEEE80211_TX_STAT_ACK),
|
||||
GFP_ATOMIC);
|
||||
}
|
||||
acked, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
if (unlikely(info->ack_frame_id)) {
|
||||
|
|
@ -589,7 +569,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
/* send frame to monitor interfaces now */
|
||||
rtap_len = ieee80211_tx_radiotap_len(info);
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
|
||||
printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
|
||||
pr_err("ieee80211_tx_status: headroom too small\n");
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -263,12 +263,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
|
|||
#ifdef CONFIG_MAC80211_TKIP_DEBUG
|
||||
{
|
||||
int i;
|
||||
printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
|
||||
pr_debug("TKIP decrypt: data(len=%zd)", payload_len);
|
||||
for (i = 0; i < payload_len; i++)
|
||||
printk(" %02x", payload[i]);
|
||||
printk("\n");
|
||||
printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
|
||||
iv16, iv32);
|
||||
pr_debug("TKIP decrypt: iv16=%04x iv32=%08x\n", iv16, iv32);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -283,11 +282,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
|
|||
(iv32 == key->u.tkip.rx[queue].iv32 &&
|
||||
iv16 <= key->u.tkip.rx[queue].iv16))) {
|
||||
#ifdef CONFIG_MAC80211_TKIP_DEBUG
|
||||
printk(KERN_DEBUG "TKIP replay detected for RX frame from "
|
||||
"%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
|
||||
ta,
|
||||
iv32, iv16, key->u.tkip.rx[queue].iv32,
|
||||
key->u.tkip.rx[queue].iv16);
|
||||
pr_debug("TKIP replay detected for RX frame from %pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
|
||||
ta, iv32, iv16,
|
||||
key->u.tkip.rx[queue].iv32,
|
||||
key->u.tkip.rx[queue].iv16);
|
||||
#endif
|
||||
return TKIP_DECRYPT_REPLAY;
|
||||
}
|
||||
|
|
@ -306,13 +304,12 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
|
|||
{
|
||||
int i;
|
||||
u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY;
|
||||
printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM"
|
||||
" TK=", ta);
|
||||
pr_debug("TKIP decrypt: Phase1 TA=%pM TK=", ta);
|
||||
for (i = 0; i < 16; i++)
|
||||
printk("%02x ",
|
||||
key->conf.key[key_offset + i]);
|
||||
printk("\n");
|
||||
printk(KERN_DEBUG "TKIP decrypt: P1K=");
|
||||
pr_debug("TKIP decrypt: P1K=");
|
||||
for (i = 0; i < 5; i++)
|
||||
printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
|
||||
printk("\n");
|
||||
|
|
@ -336,7 +333,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
|
|||
#ifdef CONFIG_MAC80211_TKIP_DEBUG
|
||||
{
|
||||
int i;
|
||||
printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
|
||||
pr_debug("TKIP decrypt: Phase2 rc4key=");
|
||||
for (i = 0; i < 16; i++)
|
||||
printk("%02x ", rc4key[i]);
|
||||
printk("\n");
|
||||
|
|
|
|||
|
|
@ -297,9 +297,8 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
|||
if (unlikely(!assoc &&
|
||||
ieee80211_is_data(hdr->frame_control))) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: dropped data frame to not "
|
||||
"associated station %pM\n",
|
||||
tx->sdata->name, hdr->addr1);
|
||||
pr_debug("%s: dropped data frame to not associated station %pM\n",
|
||||
tx->sdata->name, hdr->addr1);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
|
||||
return TX_DROP;
|
||||
|
|
@ -467,8 +466,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
|
||||
sta->sta.addr, sta->sta.aid, ac);
|
||||
pr_debug("STA %pM aid %d: PS buffer for AC %d\n",
|
||||
sta->sta.addr, sta->sta.aid, ac);
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
|
||||
purge_old_ps_buffers(tx->local);
|
||||
|
|
@ -502,9 +501,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
|||
}
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||
else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: STA %pM in PS mode, but polling/in SP -> send frame\n",
|
||||
tx->sdata->name, sta->sta.addr);
|
||||
pr_debug("%s: STA %pM in PS mode, but polling/in SP -> send frame\n",
|
||||
tx->sdata->name, sta->sta.addr);
|
||||
}
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
||||
|
||||
|
|
|
|||
|
|
@ -804,7 +804,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_queue_params qparam;
|
||||
int ac;
|
||||
bool use_11b;
|
||||
bool use_11b, enable_qos;
|
||||
int aCWmin, aCWmax;
|
||||
|
||||
if (!local->ops->conf_tx)
|
||||
|
|
@ -818,6 +818,13 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
|||
use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
|
||||
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
|
||||
|
||||
/*
|
||||
* By default disable QoS in STA mode for old access points, which do
|
||||
* not support 802.11e. New APs will provide proper queue parameters,
|
||||
* that we will configure later.
|
||||
*/
|
||||
enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
/* Set defaults according to 802.11-2007 Table 7-37 */
|
||||
aCWmax = 1023;
|
||||
|
|
@ -826,38 +833,47 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
|||
else
|
||||
aCWmin = 15;
|
||||
|
||||
switch (ac) {
|
||||
case IEEE80211_AC_BK:
|
||||
if (enable_qos) {
|
||||
switch (ac) {
|
||||
case IEEE80211_AC_BK:
|
||||
qparam.cw_max = aCWmax;
|
||||
qparam.cw_min = aCWmin;
|
||||
qparam.txop = 0;
|
||||
qparam.aifs = 7;
|
||||
break;
|
||||
/* never happens but let's not leave undefined */
|
||||
default:
|
||||
case IEEE80211_AC_BE:
|
||||
qparam.cw_max = aCWmax;
|
||||
qparam.cw_min = aCWmin;
|
||||
qparam.txop = 0;
|
||||
qparam.aifs = 3;
|
||||
break;
|
||||
case IEEE80211_AC_VI:
|
||||
qparam.cw_max = aCWmin;
|
||||
qparam.cw_min = (aCWmin + 1) / 2 - 1;
|
||||
if (use_11b)
|
||||
qparam.txop = 6016/32;
|
||||
else
|
||||
qparam.txop = 3008/32;
|
||||
qparam.aifs = 2;
|
||||
break;
|
||||
case IEEE80211_AC_VO:
|
||||
qparam.cw_max = (aCWmin + 1) / 2 - 1;
|
||||
qparam.cw_min = (aCWmin + 1) / 4 - 1;
|
||||
if (use_11b)
|
||||
qparam.txop = 3264/32;
|
||||
else
|
||||
qparam.txop = 1504/32;
|
||||
qparam.aifs = 2;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Confiure old 802.11b/g medium access rules. */
|
||||
qparam.cw_max = aCWmax;
|
||||
qparam.cw_min = aCWmin;
|
||||
qparam.txop = 0;
|
||||
qparam.aifs = 7;
|
||||
break;
|
||||
default: /* never happens but let's not leave undefined */
|
||||
case IEEE80211_AC_BE:
|
||||
qparam.cw_max = aCWmax;
|
||||
qparam.cw_min = aCWmin;
|
||||
qparam.txop = 0;
|
||||
qparam.aifs = 3;
|
||||
break;
|
||||
case IEEE80211_AC_VI:
|
||||
qparam.cw_max = aCWmin;
|
||||
qparam.cw_min = (aCWmin + 1) / 2 - 1;
|
||||
if (use_11b)
|
||||
qparam.txop = 6016/32;
|
||||
else
|
||||
qparam.txop = 3008/32;
|
||||
qparam.aifs = 2;
|
||||
break;
|
||||
case IEEE80211_AC_VO:
|
||||
qparam.cw_max = (aCWmin + 1) / 2 - 1;
|
||||
qparam.cw_min = (aCWmin + 1) / 4 - 1;
|
||||
if (use_11b)
|
||||
qparam.txop = 3264/32;
|
||||
else
|
||||
qparam.txop = 1504/32;
|
||||
qparam.aifs = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
qparam.uapsd = false;
|
||||
|
|
@ -866,12 +882,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
|||
drv_conf_tx(local, sdata, ac, &qparam);
|
||||
}
|
||||
|
||||
/* after reinitialize QoS TX queues setting to default,
|
||||
* disable QoS at all */
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
|
||||
sdata->vif.bss_conf.qos =
|
||||
sdata->vif.type != NL80211_IFTYPE_STATION;
|
||||
sdata->vif.bss_conf.qos = enable_qos;
|
||||
if (bss_notify)
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
BSS_CHANGED_QOS);
|
||||
|
|
@ -1267,14 +1279,19 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
/* add STAs back */
|
||||
mutex_lock(&local->sta_mtx);
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
if (sta->uploaded) {
|
||||
enum ieee80211_sta_state state;
|
||||
enum ieee80211_sta_state state;
|
||||
|
||||
for (state = IEEE80211_STA_NOTEXIST;
|
||||
state < sta->sta_state; state++)
|
||||
WARN_ON(drv_sta_state(local, sta->sdata, sta,
|
||||
state, state + 1));
|
||||
}
|
||||
if (!sta->uploaded)
|
||||
continue;
|
||||
|
||||
/* AP-mode stations will be added later */
|
||||
if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
continue;
|
||||
|
||||
for (state = IEEE80211_STA_NOTEXIST;
|
||||
state < sta->sta_state; state++)
|
||||
WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
|
||||
state + 1));
|
||||
}
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
|
|
@ -1371,6 +1388,24 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
}
|
||||
}
|
||||
|
||||
/* APs are now beaconing, add back stations */
|
||||
mutex_lock(&local->sta_mtx);
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
enum ieee80211_sta_state state;
|
||||
|
||||
if (!sta->uploaded)
|
||||
continue;
|
||||
|
||||
if (sta->sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
continue;
|
||||
|
||||
for (state = IEEE80211_STA_NOTEXIST;
|
||||
state < sta->sta_state; state++)
|
||||
WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
|
||||
state + 1));
|
||||
}
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
/* add back keys */
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
|
|
|
|||
|
|
@ -1,370 +0,0 @@
|
|||
/*
|
||||
* mac80211 work implementation
|
||||
*
|
||||
* Copyright 2003-2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright 2004, Instant802 Networks, Inc.
|
||||
* Copyright 2005, Devicescape Software, Inc.
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "rate.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
enum work_action {
|
||||
WORK_ACT_NONE,
|
||||
WORK_ACT_TIMEOUT,
|
||||
};
|
||||
|
||||
|
||||
/* utils */
|
||||
static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
|
||||
{
|
||||
lockdep_assert_held(&local->mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can have multiple work items (and connection probing)
|
||||
* scheduling this timer, but we need to take care to only
|
||||
* reschedule it when it should fire _earlier_ than it was
|
||||
* asked for before, or if it's not pending right now. This
|
||||
* function ensures that. Note that it then is required to
|
||||
* run this function for all timeouts after the first one
|
||||
* has happened -- the work that runs from this timer will
|
||||
* do that.
|
||||
*/
|
||||
static void run_again(struct ieee80211_local *local,
|
||||
unsigned long timeout)
|
||||
{
|
||||
ASSERT_WORK_MTX(local);
|
||||
|
||||
if (!timer_pending(&local->work_timer) ||
|
||||
time_before(timeout, local->work_timer.expires))
|
||||
mod_timer(&local->work_timer, timeout);
|
||||
}
|
||||
|
||||
void free_work(struct ieee80211_work *wk)
|
||||
{
|
||||
kfree_rcu(wk, rcu_head);
|
||||
}
|
||||
|
||||
static enum work_action __must_check
|
||||
ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
|
||||
{
|
||||
/*
|
||||
* First time we run, do nothing -- the generic code will
|
||||
* have switched to the right channel etc.
|
||||
*/
|
||||
if (!wk->started) {
|
||||
wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
|
||||
|
||||
cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
|
||||
wk->chan, wk->chan_type,
|
||||
wk->remain.duration, GFP_KERNEL);
|
||||
|
||||
return WORK_ACT_NONE;
|
||||
}
|
||||
|
||||
return WORK_ACT_TIMEOUT;
|
||||
}
|
||||
|
||||
static enum work_action __must_check
|
||||
ieee80211_offchannel_tx(struct ieee80211_work *wk)
|
||||
{
|
||||
if (!wk->started) {
|
||||
wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
|
||||
|
||||
/*
|
||||
* After this, offchan_tx.frame remains but now is no
|
||||
* longer a valid pointer -- we still need it as the
|
||||
* cookie for canceling this work/status matching.
|
||||
*/
|
||||
ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
|
||||
|
||||
return WORK_ACT_NONE;
|
||||
}
|
||||
|
||||
return WORK_ACT_TIMEOUT;
|
||||
}
|
||||
|
||||
static void ieee80211_work_timer(unsigned long data)
|
||||
{
|
||||
struct ieee80211_local *local = (void *) data;
|
||||
|
||||
if (local->quiescing)
|
||||
return;
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->work_work);
|
||||
}
|
||||
|
||||
static void ieee80211_work_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, work_work);
|
||||
struct ieee80211_work *wk, *tmp;
|
||||
LIST_HEAD(free_work);
|
||||
enum work_action rma;
|
||||
bool remain_off_channel = false;
|
||||
|
||||
/*
|
||||
* ieee80211_queue_work() should have picked up most cases,
|
||||
* here we'll pick the rest.
|
||||
*/
|
||||
if (WARN(local->suspended, "work scheduled while going to suspend\n"))
|
||||
return;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
if (local->scanning) {
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
|
||||
bool started = wk->started;
|
||||
|
||||
/* mark work as started if it's on the current off-channel */
|
||||
if (!started && local->tmp_channel &&
|
||||
wk->chan == local->tmp_channel &&
|
||||
wk->chan_type == local->tmp_channel_type) {
|
||||
started = true;
|
||||
wk->timeout = jiffies;
|
||||
}
|
||||
|
||||
if (!started && !local->tmp_channel) {
|
||||
ieee80211_offchannel_stop_vifs(local, true);
|
||||
|
||||
local->tmp_channel = wk->chan;
|
||||
local->tmp_channel_type = wk->chan_type;
|
||||
|
||||
ieee80211_hw_config(local, 0);
|
||||
|
||||
started = true;
|
||||
wk->timeout = jiffies;
|
||||
}
|
||||
|
||||
/* don't try to work with items that aren't started */
|
||||
if (!started)
|
||||
continue;
|
||||
|
||||
if (time_is_after_jiffies(wk->timeout)) {
|
||||
/*
|
||||
* This work item isn't supposed to be worked on
|
||||
* right now, but take care to adjust the timer
|
||||
* properly.
|
||||
*/
|
||||
run_again(local, wk->timeout);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (wk->type) {
|
||||
default:
|
||||
WARN_ON(1);
|
||||
/* nothing */
|
||||
rma = WORK_ACT_NONE;
|
||||
break;
|
||||
case IEEE80211_WORK_ABORT:
|
||||
rma = WORK_ACT_TIMEOUT;
|
||||
break;
|
||||
case IEEE80211_WORK_REMAIN_ON_CHANNEL:
|
||||
rma = ieee80211_remain_on_channel_timeout(wk);
|
||||
break;
|
||||
case IEEE80211_WORK_OFFCHANNEL_TX:
|
||||
rma = ieee80211_offchannel_tx(wk);
|
||||
break;
|
||||
}
|
||||
|
||||
wk->started = started;
|
||||
|
||||
switch (rma) {
|
||||
case WORK_ACT_NONE:
|
||||
/* might have changed the timeout */
|
||||
run_again(local, wk->timeout);
|
||||
break;
|
||||
case WORK_ACT_TIMEOUT:
|
||||
list_del_rcu(&wk->list);
|
||||
synchronize_rcu();
|
||||
list_add(&wk->list, &free_work);
|
||||
break;
|
||||
default:
|
||||
WARN(1, "unexpected: %d", rma);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
if (!wk->started)
|
||||
continue;
|
||||
if (wk->chan != local->tmp_channel ||
|
||||
wk->chan_type != local->tmp_channel_type)
|
||||
continue;
|
||||
remain_off_channel = true;
|
||||
}
|
||||
|
||||
if (!remain_off_channel && local->tmp_channel) {
|
||||
local->tmp_channel = NULL;
|
||||
ieee80211_hw_config(local, 0);
|
||||
|
||||
ieee80211_offchannel_return(local, true);
|
||||
|
||||
/* give connection some time to breathe */
|
||||
run_again(local, jiffies + HZ/2);
|
||||
}
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
ieee80211_run_deferred_scan(local);
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
list_for_each_entry_safe(wk, tmp, &free_work, list) {
|
||||
wk->done(wk, NULL);
|
||||
list_del(&wk->list);
|
||||
kfree(wk);
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_add_work(struct ieee80211_work *wk)
|
||||
{
|
||||
struct ieee80211_local *local;
|
||||
|
||||
if (WARN_ON(!wk->chan))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!wk->sdata))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!wk->done))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
|
||||
return;
|
||||
|
||||
wk->started = false;
|
||||
|
||||
local = wk->sdata->local;
|
||||
mutex_lock(&local->mtx);
|
||||
list_add_tail(&wk->list, &local->work_list);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->work_work);
|
||||
}
|
||||
|
||||
void ieee80211_work_init(struct ieee80211_local *local)
|
||||
{
|
||||
INIT_LIST_HEAD(&local->work_list);
|
||||
setup_timer(&local->work_timer, ieee80211_work_timer,
|
||||
(unsigned long)local);
|
||||
INIT_WORK(&local->work_work, ieee80211_work_work);
|
||||
}
|
||||
|
||||
void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_work *wk;
|
||||
bool cleanup = false;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry(wk, &local->work_list, list) {
|
||||
if (wk->sdata != sdata)
|
||||
continue;
|
||||
cleanup = true;
|
||||
wk->type = IEEE80211_WORK_ABORT;
|
||||
wk->started = true;
|
||||
wk->timeout = jiffies;
|
||||
}
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
/* run cleanups etc. */
|
||||
if (cleanup)
|
||||
ieee80211_work_work(&local->work_work);
|
||||
|
||||
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->mtx);
|
||||
}
|
||||
|
||||
static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
/*
|
||||
* We are done serving the remain-on-channel command.
|
||||
*/
|
||||
cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
|
||||
wk->chan, wk->chan_type,
|
||||
GFP_KERNEL);
|
||||
|
||||
return WORK_DONE_DESTROY;
|
||||
}
|
||||
|
||||
int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration, u64 *cookie)
|
||||
{
|
||||
struct ieee80211_work *wk;
|
||||
|
||||
wk = kzalloc(sizeof(*wk), GFP_KERNEL);
|
||||
if (!wk)
|
||||
return -ENOMEM;
|
||||
|
||||
wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
|
||||
wk->chan = chan;
|
||||
wk->chan_type = channel_type;
|
||||
wk->sdata = sdata;
|
||||
wk->done = ieee80211_remain_done;
|
||||
|
||||
wk->remain.duration = duration;
|
||||
|
||||
*cookie = (unsigned long) wk;
|
||||
|
||||
ieee80211_add_work(wk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
|
||||
u64 cookie)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_work *wk, *tmp;
|
||||
bool found = false;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
|
||||
if ((unsigned long) wk == cookie) {
|
||||
wk->timeout = jiffies;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (!found)
|
||||
return -ENOENT;
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->work_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue