Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem

This commit is contained in:
John W. Linville 2012-06-12 14:25:04 -04:00
commit 0440507bbc
219 changed files with 12126 additions and 7378 deletions

View file

@ -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 \

View file

@ -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);

View file

@ -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;
}

View file

@ -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,

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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,

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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));
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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 &&

View file

@ -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
/*

View file

@ -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;
}

View file

@ -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");

View file

@ -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 */

View file

@ -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))

View file

@ -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;
}