You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
This commit is contained in:
@@ -197,6 +197,14 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
|
||||
status = WLAN_STATUS_REQUEST_DECLINED;
|
||||
|
||||
if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Suspend in progress. "
|
||||
"Denying ADDBA request\n");
|
||||
#endif
|
||||
goto end_no_lock;
|
||||
}
|
||||
|
||||
/* sanity check for incoming parameters:
|
||||
* check if configuration can support the BA policy
|
||||
* and if buffer size does not exceeds max value */
|
||||
|
||||
+113
-119
@@ -131,24 +131,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
|
||||
if (local->hw.ampdu_queues) {
|
||||
if (initiator) {
|
||||
/*
|
||||
* Stop the AC queue to avoid issues where we send
|
||||
* unaggregated frames already before the delba.
|
||||
*/
|
||||
ieee80211_stop_queue_by_reason(&local->hw,
|
||||
local->hw.queues + sta->tid_to_tx_q[tid],
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pretend the driver woke the queue, just in case
|
||||
* it disabled it before the session was stopped.
|
||||
*/
|
||||
ieee80211_wake_queue(
|
||||
&local->hw, local->hw.queues + sta->tid_to_tx_q[tid]);
|
||||
}
|
||||
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
||||
|
||||
@@ -158,6 +140,10 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
/* HW shall not deny going back to legacy */
|
||||
if (WARN_ON(ret)) {
|
||||
*state = HT_AGG_STATE_OPERATIONAL;
|
||||
/*
|
||||
* We may have pending packets get stuck in this case...
|
||||
* Not bothering with a workaround for now.
|
||||
*/
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -212,7 +198,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
u8 *state;
|
||||
int i, qn = -1, ret = 0;
|
||||
int ret = 0;
|
||||
u16 start_seq_num;
|
||||
|
||||
if (WARN_ON(!local->ops->ampdu_action))
|
||||
@@ -226,13 +212,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
ra, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "rejecting on voice AC\n");
|
||||
#endif
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, ra);
|
||||
@@ -257,7 +236,17 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Suspend in progress. "
|
||||
"Denying BA session request\n");
|
||||
#endif
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock(&local->ampdu_lock);
|
||||
|
||||
sdata = sta->sdata;
|
||||
|
||||
@@ -278,41 +267,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
|
||||
if (hw->ampdu_queues) {
|
||||
spin_lock(&local->queue_stop_reason_lock);
|
||||
/* reserve a new queue for this session */
|
||||
for (i = 0; i < local->hw.ampdu_queues; i++) {
|
||||
if (local->ampdu_ac_queue[i] < 0) {
|
||||
qn = i;
|
||||
local->ampdu_ac_queue[qn] =
|
||||
ieee80211_ac_from_tid(tid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&local->queue_stop_reason_lock);
|
||||
|
||||
if (qn < 0) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - "
|
||||
"queue unavailable for tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ret = -ENOSPC;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we successfully allocate the session, we can't have
|
||||
* anything going on on the queue this TID maps into, so
|
||||
* stop it for now. This is a "virtual" stop using the same
|
||||
* mechanism that drivers will use.
|
||||
*
|
||||
* XXX: queue up frames for this session in the sta_info
|
||||
* struct instead to avoid hitting all other STAs.
|
||||
*/
|
||||
ieee80211_stop_queue_by_reason(
|
||||
&local->hw, hw->queues + qn,
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
}
|
||||
/*
|
||||
* While we're asking the driver about the aggregation,
|
||||
* stop the AC queue so that we don't have to worry
|
||||
* about frames that came in while we were doing that,
|
||||
* which would require us to put them to the AC pending
|
||||
* afterwards which just makes the code more complex.
|
||||
*/
|
||||
ieee80211_stop_queue_by_reason(
|
||||
&local->hw, ieee80211_ac_from_tid(tid),
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
|
||||
/* prepare A-MPDU MLME for Tx aggregation */
|
||||
sta->ampdu_mlme.tid_tx[tid] =
|
||||
@@ -324,9 +288,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
tid);
|
||||
#endif
|
||||
ret = -ENOMEM;
|
||||
goto err_return_queue;
|
||||
goto err_wake_queue;
|
||||
}
|
||||
|
||||
skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);
|
||||
|
||||
/* Tx timer */
|
||||
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
|
||||
sta_addba_resp_timer_expired;
|
||||
@@ -351,8 +317,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
goto err_free;
|
||||
}
|
||||
sta->tid_to_tx_q[tid] = qn;
|
||||
|
||||
/* Driver vetoed or OKed, but we can take packets again now */
|
||||
ieee80211_wake_queue_by_reason(
|
||||
&local->hw, ieee80211_ac_from_tid(tid),
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
|
||||
spin_unlock(&local->ampdu_lock);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
/* send an addBA request */
|
||||
@@ -377,17 +348,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
err_free:
|
||||
kfree(sta->ampdu_mlme.tid_tx[tid]);
|
||||
sta->ampdu_mlme.tid_tx[tid] = NULL;
|
||||
err_return_queue:
|
||||
if (qn >= 0) {
|
||||
/* We failed, so start queue again right away. */
|
||||
ieee80211_wake_queue_by_reason(hw, hw->queues + qn,
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
/* give queue back to pool */
|
||||
spin_lock(&local->queue_stop_reason_lock);
|
||||
local->ampdu_ac_queue[qn] = -1;
|
||||
spin_unlock(&local->queue_stop_reason_lock);
|
||||
}
|
||||
err_wake_queue:
|
||||
ieee80211_wake_queue_by_reason(
|
||||
&local->hw, ieee80211_ac_from_tid(tid),
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
err_unlock_sta:
|
||||
spin_unlock(&local->ampdu_lock);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
@@ -395,6 +361,67 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
|
||||
|
||||
/*
|
||||
* splice packets from the STA's pending to the local pending,
|
||||
* requires a call to ieee80211_agg_splice_finish and holding
|
||||
* local->ampdu_lock across both calls.
|
||||
*/
|
||||
static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
|
||||
struct sta_info *sta, u16 tid)
|
||||
{
|
||||
unsigned long flags;
|
||||
u16 queue = ieee80211_ac_from_tid(tid);
|
||||
|
||||
ieee80211_stop_queue_by_reason(
|
||||
&local->hw, queue,
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
|
||||
if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
/* mark queue as pending, it is stopped already */
|
||||
__set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
|
||||
&local->queue_stop_reasons[queue]);
|
||||
/* copy over remaining packets */
|
||||
skb_queue_splice_tail_init(
|
||||
&sta->ampdu_mlme.tid_tx[tid]->pending,
|
||||
&local->pending[queue]);
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_agg_splice_finish(struct ieee80211_local *local,
|
||||
struct sta_info *sta, u16 tid)
|
||||
{
|
||||
u16 queue = ieee80211_ac_from_tid(tid);
|
||||
|
||||
ieee80211_wake_queue_by_reason(
|
||||
&local->hw, queue,
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
}
|
||||
|
||||
/* caller must hold sta->lock */
|
||||
static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
||||
struct sta_info *sta, u16 tid)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
|
||||
#endif
|
||||
|
||||
spin_lock(&local->ampdu_lock);
|
||||
ieee80211_agg_splice_packets(local, sta, tid);
|
||||
/*
|
||||
* NB: we rely on sta->lock being taken in the TX
|
||||
* processing here when adding to the pending queue,
|
||||
* otherwise we could only change the state of the
|
||||
* session to OPERATIONAL _here_.
|
||||
*/
|
||||
ieee80211_agg_splice_finish(local, sta, tid);
|
||||
spin_unlock(&local->ampdu_lock);
|
||||
|
||||
local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
&sta->sta, tid, NULL);
|
||||
}
|
||||
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
@@ -437,20 +464,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
|
||||
*state |= HT_ADDBA_DRV_READY_MSK;
|
||||
|
||||
if (*state == HT_AGG_STATE_OPERATIONAL) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
|
||||
#endif
|
||||
if (hw->ampdu_queues) {
|
||||
/*
|
||||
* Wake up this queue, we stopped it earlier,
|
||||
* this will in turn wake the entire AC.
|
||||
*/
|
||||
ieee80211_wake_queue_by_reason(hw,
|
||||
hw->queues + sta->tid_to_tx_q[tid],
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
}
|
||||
}
|
||||
if (*state == HT_AGG_STATE_OPERATIONAL)
|
||||
ieee80211_agg_tx_operational(local, sta, tid);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
@@ -584,22 +599,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
|
||||
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock(&local->ampdu_lock);
|
||||
|
||||
if (*state & HT_AGG_STATE_INITIATOR_MSK &&
|
||||
hw->ampdu_queues) {
|
||||
/*
|
||||
* Wake up this queue, we stopped it earlier,
|
||||
* this will in turn wake the entire AC.
|
||||
*/
|
||||
ieee80211_wake_queue_by_reason(hw,
|
||||
hw->queues + sta->tid_to_tx_q[tid],
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
}
|
||||
ieee80211_agg_splice_packets(local, sta, tid);
|
||||
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
/* from now on packets are no longer put onto sta->pending */
|
||||
sta->ampdu_mlme.addba_req_num[tid] = 0;
|
||||
kfree(sta->ampdu_mlme.tid_tx[tid]);
|
||||
sta->ampdu_mlme.tid_tx[tid] = NULL;
|
||||
|
||||
ieee80211_agg_splice_finish(local, sta, tid);
|
||||
|
||||
spin_unlock(&local->ampdu_lock);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
rcu_read_unlock();
|
||||
@@ -637,9 +649,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
{
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
u16 capab;
|
||||
u16 tid, start_seq_num;
|
||||
u16 capab, tid;
|
||||
u8 *state;
|
||||
|
||||
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
|
||||
@@ -673,26 +683,10 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
||||
|
||||
*state |= HT_ADDBA_RECEIVED_MSK;
|
||||
|
||||
if (hw->ampdu_queues && *state != curstate &&
|
||||
*state == HT_AGG_STATE_OPERATIONAL) {
|
||||
/*
|
||||
* Wake up this queue, we stopped it earlier,
|
||||
* this will in turn wake the entire AC.
|
||||
*/
|
||||
ieee80211_wake_queue_by_reason(hw,
|
||||
hw->queues + sta->tid_to_tx_q[tid],
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
}
|
||||
sta->ampdu_mlme.addba_req_num[tid] = 0;
|
||||
if (*state != curstate && *state == HT_AGG_STATE_OPERATIONAL)
|
||||
ieee80211_agg_tx_operational(local, sta, tid);
|
||||
|
||||
if (local->ops->ampdu_action) {
|
||||
(void)local->ops->ampdu_action(hw,
|
||||
IEEE80211_AMPDU_TX_RESUME,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
}
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
sta->ampdu_mlme.addba_req_num[tid] = 0;
|
||||
} else {
|
||||
sta->ampdu_mlme.addba_req_num[tid]++;
|
||||
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
|
||||
|
||||
+117
-128
@@ -540,9 +540,6 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
old = sdata->u.ap.beacon;
|
||||
|
||||
if (old)
|
||||
@@ -559,9 +556,6 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
old = sdata->u.ap.beacon;
|
||||
|
||||
if (!old)
|
||||
@@ -577,9 +571,6 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
old = sdata->u.ap.beacon;
|
||||
|
||||
if (!old)
|
||||
@@ -728,10 +719,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
int err;
|
||||
int layer2_update;
|
||||
|
||||
/* Prevent a race with changing the rate control algorithm */
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
|
||||
if (params->vlan) {
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
|
||||
|
||||
@@ -860,14 +847,8 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct sta_info *sta;
|
||||
int err;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
|
||||
return -ENOTSUPP;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, next_hop);
|
||||
if (!sta) {
|
||||
@@ -913,14 +894,8 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
|
||||
struct mesh_path *mpath;
|
||||
struct sta_info *sta;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
|
||||
return -ENOTSUPP;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, next_hop);
|
||||
@@ -989,9 +964,6 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
|
||||
return -ENOTSUPP;
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(dst, sdata);
|
||||
if (!mpath) {
|
||||
@@ -1013,9 +985,6 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
|
||||
return -ENOTSUPP;
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup_by_idx(idx, sdata);
|
||||
if (!mpath) {
|
||||
@@ -1035,8 +1004,6 @@ static int ieee80211_get_mesh_params(struct wiphy *wiphy,
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
|
||||
return -ENOTSUPP;
|
||||
memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config));
|
||||
return 0;
|
||||
}
|
||||
@@ -1054,9 +1021,6 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy,
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* Set the config options which we are interested in setting */
|
||||
conf = &(sdata->u.mesh.mshcfg);
|
||||
if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask))
|
||||
@@ -1104,9 +1068,6 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
if (params->use_cts_prot >= 0) {
|
||||
sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
|
||||
changed |= BSS_CHANGED_ERP_CTS_PROT;
|
||||
@@ -1181,91 +1142,6 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
|
||||
return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
}
|
||||
|
||||
static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata,
|
||||
u8 subtype, u8 *ies, size_t ies_len)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
switch (subtype) {
|
||||
case IEEE80211_STYPE_PROBE_REQ >> 4:
|
||||
if (local->ops->hw_scan)
|
||||
break;
|
||||
kfree(ifmgd->ie_probereq);
|
||||
ifmgd->ie_probereq = ies;
|
||||
ifmgd->ie_probereq_len = ies_len;
|
||||
return 0;
|
||||
case IEEE80211_STYPE_PROBE_RESP >> 4:
|
||||
kfree(ifmgd->ie_proberesp);
|
||||
ifmgd->ie_proberesp = ies;
|
||||
ifmgd->ie_proberesp_len = ies_len;
|
||||
return 0;
|
||||
case IEEE80211_STYPE_AUTH >> 4:
|
||||
kfree(ifmgd->ie_auth);
|
||||
ifmgd->ie_auth = ies;
|
||||
ifmgd->ie_auth_len = ies_len;
|
||||
return 0;
|
||||
case IEEE80211_STYPE_ASSOC_REQ >> 4:
|
||||
kfree(ifmgd->ie_assocreq);
|
||||
ifmgd->ie_assocreq = ies;
|
||||
ifmgd->ie_assocreq_len = ies_len;
|
||||
return 0;
|
||||
case IEEE80211_STYPE_REASSOC_REQ >> 4:
|
||||
kfree(ifmgd->ie_reassocreq);
|
||||
ifmgd->ie_reassocreq = ies;
|
||||
ifmgd->ie_reassocreq_len = ies_len;
|
||||
return 0;
|
||||
case IEEE80211_STYPE_DEAUTH >> 4:
|
||||
kfree(ifmgd->ie_deauth);
|
||||
ifmgd->ie_deauth = ies;
|
||||
ifmgd->ie_deauth_len = ies_len;
|
||||
return 0;
|
||||
case IEEE80211_STYPE_DISASSOC >> 4:
|
||||
kfree(ifmgd->ie_disassoc);
|
||||
ifmgd->ie_disassoc = ies;
|
||||
ifmgd->ie_disassoc_len = ies_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct mgmt_extra_ie_params *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
u8 *ies;
|
||||
size_t ies_len;
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
if (params->ies) {
|
||||
ies = kmemdup(params->ies, params->ies_len, GFP_KERNEL);
|
||||
if (ies == NULL)
|
||||
return -ENOMEM;
|
||||
ies_len = params->ies_len;
|
||||
} else {
|
||||
ies = NULL;
|
||||
ies_len = 0;
|
||||
}
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ret = set_mgmt_extra_ie_sta(sdata, params->subtype,
|
||||
ies, ies_len);
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
kfree(ies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ieee80211_suspend(struct wiphy *wiphy)
|
||||
{
|
||||
@@ -1287,9 +1163,6 @@ static int ieee80211_scan(struct wiphy *wiphy,
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
@@ -1300,6 +1173,119 @@ static int ieee80211_scan(struct wiphy *wiphy,
|
||||
return ieee80211_request_scan(sdata, req);
|
||||
}
|
||||
|
||||
static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_auth_request *req)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
switch (req->auth_type) {
|
||||
case NL80211_AUTHTYPE_OPEN_SYSTEM:
|
||||
sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_OPEN;
|
||||
break;
|
||||
case NL80211_AUTHTYPE_SHARED_KEY:
|
||||
sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_SHARED_KEY;
|
||||
break;
|
||||
case NL80211_AUTHTYPE_FT:
|
||||
sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_FT;
|
||||
break;
|
||||
case NL80211_AUTHTYPE_NETWORK_EAP:
|
||||
sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_LEAP;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN);
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
|
||||
|
||||
/* TODO: req->chan */
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
|
||||
|
||||
if (req->ssid) {
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
|
||||
memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
|
||||
sdata->u.mgd.ssid_len = req->ssid_len;
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
|
||||
}
|
||||
|
||||
kfree(sdata->u.mgd.sme_auth_ie);
|
||||
sdata->u.mgd.sme_auth_ie = NULL;
|
||||
sdata->u.mgd.sme_auth_ie_len = 0;
|
||||
if (req->ie) {
|
||||
sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL);
|
||||
if (sdata->u.mgd.sme_auth_ie == NULL)
|
||||
return -ENOMEM;
|
||||
memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len);
|
||||
sdata->u.mgd.sme_auth_ie_len = req->ie_len;
|
||||
}
|
||||
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
|
||||
sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE;
|
||||
ieee80211_sta_req_auth(sdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_assoc_request *req)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int ret;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 ||
|
||||
!(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED))
|
||||
return -ENOLINK; /* not authenticated */
|
||||
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
|
||||
|
||||
/* TODO: req->chan */
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
|
||||
|
||||
if (req->ssid) {
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
|
||||
memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
|
||||
sdata->u.mgd.ssid_len = req->ssid_len;
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
|
||||
} else
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
|
||||
|
||||
ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
|
||||
sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE;
|
||||
ieee80211_sta_req_auth(sdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_deauth_request *req)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
/* TODO: req->ie */
|
||||
return ieee80211_sta_deauthenticate(sdata, req->reason_code);
|
||||
}
|
||||
|
||||
static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_disassoc_request *req)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
/* TODO: req->ie */
|
||||
return ieee80211_sta_disassociate(sdata, req->reason_code);
|
||||
}
|
||||
|
||||
struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
@@ -1329,8 +1315,11 @@ struct cfg80211_ops mac80211_config_ops = {
|
||||
.change_bss = ieee80211_change_bss,
|
||||
.set_txq_params = ieee80211_set_txq_params,
|
||||
.set_channel = ieee80211_set_channel,
|
||||
.set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie,
|
||||
.suspend = ieee80211_suspend,
|
||||
.resume = ieee80211_resume,
|
||||
.scan = ieee80211_scan,
|
||||
.auth = ieee80211_auth,
|
||||
.assoc = ieee80211_assoc,
|
||||
.deauth = ieee80211_deauth,
|
||||
.disassoc = ieee80211_disassoc,
|
||||
};
|
||||
|
||||
@@ -40,6 +40,10 @@ static const struct file_operations name## _ops = { \
|
||||
local->debugfs.name = debugfs_create_file(#name, 0400, phyd, \
|
||||
local, &name## _ops);
|
||||
|
||||
#define DEBUGFS_ADD_MODE(name, mode) \
|
||||
local->debugfs.name = debugfs_create_file(#name, mode, phyd, \
|
||||
local, &name## _ops);
|
||||
|
||||
#define DEBUGFS_DEL(name) \
|
||||
debugfs_remove(local->debugfs.name); \
|
||||
local->debugfs.name = NULL;
|
||||
@@ -113,6 +117,24 @@ static const struct file_operations tsf_ops = {
|
||||
.open = mac80211_open_file_generic
|
||||
};
|
||||
|
||||
static ssize_t reset_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
|
||||
rtnl_lock();
|
||||
__ieee80211_suspend(&local->hw);
|
||||
__ieee80211_resume(&local->hw);
|
||||
rtnl_unlock();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations reset_ops = {
|
||||
.write = reset_write,
|
||||
.open = mac80211_open_file_generic,
|
||||
};
|
||||
|
||||
/* statistics stuff */
|
||||
|
||||
#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \
|
||||
@@ -254,6 +276,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
||||
DEBUGFS_ADD(total_ps_buffered);
|
||||
DEBUGFS_ADD(wep_iv);
|
||||
DEBUGFS_ADD(tsf);
|
||||
DEBUGFS_ADD_MODE(reset, 0200);
|
||||
|
||||
statsd = debugfs_create_dir("statistics", phyd);
|
||||
local->debugfs.statistics = statsd;
|
||||
@@ -308,6 +331,7 @@ void debugfs_hw_del(struct ieee80211_local *local)
|
||||
DEBUGFS_DEL(total_ps_buffered);
|
||||
DEBUGFS_DEL(wep_iv);
|
||||
DEBUGFS_DEL(tsf);
|
||||
DEBUGFS_DEL(reset);
|
||||
|
||||
DEBUGFS_STATS_DEL(transmitted_fragment_count);
|
||||
DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);
|
||||
|
||||
+2
-1
@@ -812,8 +812,9 @@ int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
ifibss->ibss_join_req = jiffies;
|
||||
ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
|
||||
set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
|
||||
|
||||
return ieee80211_sta_find_ibss(sdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
|
||||
|
||||
+38
-40
@@ -149,11 +149,6 @@ struct ieee80211_tx_data {
|
||||
|
||||
struct ieee80211_channel *channel;
|
||||
|
||||
/* Extra fragments (in addition to the first fragment
|
||||
* in skb) */
|
||||
struct sk_buff **extra_frag;
|
||||
int num_extra_frag;
|
||||
|
||||
u16 ethertype;
|
||||
unsigned int flags;
|
||||
};
|
||||
@@ -189,12 +184,6 @@ struct ieee80211_rx_data {
|
||||
u16 tkip_iv16;
|
||||
};
|
||||
|
||||
struct ieee80211_tx_stored_packet {
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff **extra_frag;
|
||||
int num_extra_frag;
|
||||
};
|
||||
|
||||
struct beacon_data {
|
||||
u8 *head, *tail;
|
||||
int head_len, tail_len;
|
||||
@@ -247,8 +236,9 @@ struct mesh_preq_queue {
|
||||
#define IEEE80211_STA_ASSOCIATED BIT(4)
|
||||
#define IEEE80211_STA_PROBEREQ_POLL BIT(5)
|
||||
#define IEEE80211_STA_CREATE_IBSS BIT(6)
|
||||
#define IEEE80211_STA_MIXED_CELL BIT(7)
|
||||
/* hole at 7, please re-use */
|
||||
#define IEEE80211_STA_WMM_ENABLED BIT(8)
|
||||
/* hole at 9, please re-use */
|
||||
#define IEEE80211_STA_AUTO_SSID_SEL BIT(10)
|
||||
#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11)
|
||||
#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
|
||||
@@ -256,6 +246,7 @@ struct mesh_preq_queue {
|
||||
#define IEEE80211_STA_TKIP_WEP_USED BIT(14)
|
||||
#define IEEE80211_STA_CSA_RECEIVED BIT(15)
|
||||
#define IEEE80211_STA_MFP_ENABLED BIT(16)
|
||||
#define IEEE80211_STA_EXT_SME BIT(17)
|
||||
/* flags for MLME request */
|
||||
#define IEEE80211_STA_REQ_SCAN 0
|
||||
#define IEEE80211_STA_REQ_DIRECT_PROBE 1
|
||||
@@ -266,12 +257,14 @@ struct mesh_preq_queue {
|
||||
#define IEEE80211_AUTH_ALG_OPEN BIT(0)
|
||||
#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
|
||||
#define IEEE80211_AUTH_ALG_LEAP BIT(2)
|
||||
#define IEEE80211_AUTH_ALG_FT BIT(3)
|
||||
|
||||
struct ieee80211_if_managed {
|
||||
struct timer_list timer;
|
||||
struct timer_list chswitch_timer;
|
||||
struct work_struct work;
|
||||
struct work_struct chswitch_work;
|
||||
struct work_struct beacon_loss_work;
|
||||
|
||||
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
|
||||
|
||||
@@ -305,6 +298,7 @@ struct ieee80211_if_managed {
|
||||
unsigned long request;
|
||||
|
||||
unsigned long last_probe;
|
||||
unsigned long last_beacon;
|
||||
|
||||
unsigned int flags;
|
||||
|
||||
@@ -321,20 +315,8 @@ struct ieee80211_if_managed {
|
||||
int wmm_last_param_set;
|
||||
|
||||
/* Extra IE data for management frames */
|
||||
u8 *ie_probereq;
|
||||
size_t ie_probereq_len;
|
||||
u8 *ie_proberesp;
|
||||
size_t ie_proberesp_len;
|
||||
u8 *ie_auth;
|
||||
size_t ie_auth_len;
|
||||
u8 *ie_assocreq;
|
||||
size_t ie_assocreq_len;
|
||||
u8 *ie_reassocreq;
|
||||
size_t ie_reassocreq_len;
|
||||
u8 *ie_deauth;
|
||||
size_t ie_deauth_len;
|
||||
u8 *ie_disassoc;
|
||||
size_t ie_disassoc_len;
|
||||
u8 *sme_auth_ie;
|
||||
size_t sme_auth_ie_len;
|
||||
};
|
||||
|
||||
enum ieee80211_ibss_flags {
|
||||
@@ -421,7 +403,6 @@ struct ieee80211_if_mesh {
|
||||
*
|
||||
* @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets
|
||||
* @IEEE80211_SDATA_PROMISC: interface is promisc
|
||||
* @IEEE80211_SDATA_USERSPACE_MLME: userspace MLME is active
|
||||
* @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode
|
||||
* @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between
|
||||
* associated stations and deliver multicast frames both
|
||||
@@ -430,9 +411,8 @@ struct ieee80211_if_mesh {
|
||||
enum ieee80211_sub_if_data_flags {
|
||||
IEEE80211_SDATA_ALLMULTI = BIT(0),
|
||||
IEEE80211_SDATA_PROMISC = BIT(1),
|
||||
IEEE80211_SDATA_USERSPACE_MLME = BIT(2),
|
||||
IEEE80211_SDATA_OPERATING_GMODE = BIT(3),
|
||||
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(4),
|
||||
IEEE80211_SDATA_OPERATING_GMODE = BIT(2),
|
||||
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
|
||||
};
|
||||
|
||||
struct ieee80211_sub_if_data {
|
||||
@@ -598,6 +578,8 @@ enum queue_stop_reason {
|
||||
IEEE80211_QUEUE_STOP_REASON_PS,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA,
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
|
||||
IEEE80211_QUEUE_STOP_REASON_PENDING,
|
||||
};
|
||||
|
||||
struct ieee80211_master_priv {
|
||||
@@ -612,12 +594,7 @@ struct ieee80211_local {
|
||||
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/* AC queue corresponding to each AMPDU queue */
|
||||
s8 ampdu_ac_queue[IEEE80211_MAX_AMPDU_QUEUES];
|
||||
unsigned int amdpu_ac_stop_refcnt[IEEE80211_MAX_AMPDU_QUEUES];
|
||||
|
||||
unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES +
|
||||
IEEE80211_MAX_AMPDU_QUEUES];
|
||||
unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
|
||||
/* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
|
||||
spinlock_t queue_stop_reason_lock;
|
||||
|
||||
@@ -654,11 +631,17 @@ struct ieee80211_local {
|
||||
struct sta_info *sta_hash[STA_HASH_SIZE];
|
||||
struct timer_list sta_cleanup;
|
||||
|
||||
unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
|
||||
unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
|
||||
struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES];
|
||||
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
|
||||
struct tasklet_struct tx_pending_tasklet;
|
||||
|
||||
/*
|
||||
* This lock is used to prevent concurrent A-MPDU
|
||||
* session start/stop processing, this thus also
|
||||
* synchronises the ->ampdu_action() callback to
|
||||
* drivers and limits it to one at a time.
|
||||
*/
|
||||
spinlock_t ampdu_lock;
|
||||
|
||||
/* number of interfaces with corresponding IFF_ flags */
|
||||
atomic_t iff_allmultis, iff_promiscs;
|
||||
|
||||
@@ -774,6 +757,7 @@ struct ieee80211_local {
|
||||
struct dentry *total_ps_buffered;
|
||||
struct dentry *wep_iv;
|
||||
struct dentry *tsf;
|
||||
struct dentry *reset;
|
||||
struct dentry *statistics;
|
||||
struct local_debugfsdentries_statsdentries {
|
||||
struct dentry *transmitted_fragment_count;
|
||||
@@ -969,7 +953,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
|
||||
char *ie, size_t len);
|
||||
const char *ie, size_t len);
|
||||
|
||||
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
|
||||
void ieee80211_scan_failed(struct ieee80211_local *local);
|
||||
@@ -1053,8 +1037,19 @@ void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
|
||||
u8 pwr_constr_elem_len);
|
||||
|
||||
/* Suspend/resume */
|
||||
#ifdef CONFIG_PM
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw);
|
||||
int __ieee80211_resume(struct ieee80211_hw *hw);
|
||||
#else
|
||||
static inline int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* utility functions/constants */
|
||||
extern void *mac80211_wiphy_privid; /* for wiphy privid */
|
||||
@@ -1081,6 +1076,9 @@ void ieee80211_dynamic_ps_timer(unsigned long data);
|
||||
void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
int powersave);
|
||||
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_hdr *hdr);
|
||||
void ieee80211_beacon_loss_work(struct work_struct *work);
|
||||
|
||||
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
|
||||
enum queue_stop_reason reason);
|
||||
|
||||
@@ -261,8 +261,7 @@ static int ieee80211_open(struct net_device *dev)
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
ieee80211_enable_keys(sdata);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
netif_carrier_off(dev);
|
||||
else
|
||||
netif_carrier_on(dev);
|
||||
@@ -478,6 +477,9 @@ static int ieee80211_stop(struct net_device *dev)
|
||||
*/
|
||||
cancel_work_sync(&sdata->u.mgd.work);
|
||||
cancel_work_sync(&sdata->u.mgd.chswitch_work);
|
||||
|
||||
cancel_work_sync(&sdata->u.mgd.beacon_loss_work);
|
||||
|
||||
/*
|
||||
* When we get here, the interface is marked down.
|
||||
* Call synchronize_rcu() to wait for the RX path
|
||||
@@ -653,13 +655,7 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
|
||||
kfree(sdata->u.mgd.extra_ie);
|
||||
kfree(sdata->u.mgd.assocreq_ies);
|
||||
kfree(sdata->u.mgd.assocresp_ies);
|
||||
kfree(sdata->u.mgd.ie_probereq);
|
||||
kfree(sdata->u.mgd.ie_proberesp);
|
||||
kfree(sdata->u.mgd.ie_auth);
|
||||
kfree(sdata->u.mgd.ie_assocreq);
|
||||
kfree(sdata->u.mgd.ie_reassocreq);
|
||||
kfree(sdata->u.mgd.ie_deauth);
|
||||
kfree(sdata->u.mgd.ie_disassoc);
|
||||
kfree(sdata->u.mgd.sme_auth_ie);
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
|
||||
+7
-18
@@ -161,12 +161,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
|
||||
if (WARN_ON(!netif_running(sdata->dev)))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
|
||||
return -EINVAL;
|
||||
|
||||
if (!local->ops->config_interface)
|
||||
return 0;
|
||||
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
@@ -183,6 +177,9 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!local->ops->config_interface)
|
||||
return 0;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
@@ -224,9 +221,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
|
||||
}
|
||||
}
|
||||
|
||||
if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
|
||||
return -EINVAL;
|
||||
|
||||
conf.changed = changed;
|
||||
|
||||
return local->ops->config_interface(local_to_hw(local),
|
||||
@@ -780,13 +774,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
setup_timer(&local->dynamic_ps_timer,
|
||||
ieee80211_dynamic_ps_timer, (unsigned long) local);
|
||||
|
||||
for (i = 0; i < IEEE80211_MAX_AMPDU_QUEUES; i++)
|
||||
local->ampdu_ac_queue[i] = -1;
|
||||
/* using an s8 won't work with more than that */
|
||||
BUILD_BUG_ON(IEEE80211_MAX_AMPDU_QUEUES > 127);
|
||||
|
||||
sta_info_init(local);
|
||||
|
||||
for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
|
||||
skb_queue_head_init(&local->pending[i]);
|
||||
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
|
||||
(unsigned long)local);
|
||||
tasklet_disable(&local->tx_pending_tasklet);
|
||||
@@ -799,6 +790,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
skb_queue_head_init(&local->skb_queue);
|
||||
skb_queue_head_init(&local->skb_queue_unreliable);
|
||||
|
||||
spin_lock_init(&local->ampdu_lock);
|
||||
|
||||
return local_to_hw(local);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_alloc_hw);
|
||||
@@ -876,10 +869,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
*/
|
||||
if (hw->queues > IEEE80211_MAX_QUEUES)
|
||||
hw->queues = IEEE80211_MAX_QUEUES;
|
||||
if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
|
||||
hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
|
||||
if (hw->queues < 4)
|
||||
hw->ampdu_queues = 0;
|
||||
|
||||
mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
|
||||
"wmaster%d", ieee80211_master_setup,
|
||||
|
||||
+180
-79
File diff suppressed because it is too large
Load Diff
+70
-8
@@ -10,6 +10,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_if_init_conf conf;
|
||||
struct sta_info *sta;
|
||||
unsigned long flags;
|
||||
|
||||
ieee80211_stop_queues_by_reason(hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
|
||||
|
||||
flush_workqueue(local->hw.workqueue);
|
||||
|
||||
@@ -17,10 +21,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
ieee80211_disable_keys(sdata);
|
||||
|
||||
/* remove STAs */
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
/* Tear down aggregation sessions */
|
||||
|
||||
if (local->ops->sta_notify) {
|
||||
rcu_read_lock();
|
||||
|
||||
if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
set_sta_flags(sta, WLAN_STA_SUSPEND);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* remove STAs */
|
||||
if (local->ops->sta_notify) {
|
||||
spin_lock_irqsave(&local->sta_lock, flags);
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data,
|
||||
@@ -29,11 +46,11 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
local->ops->sta_notify(hw, &sdata->vif,
|
||||
STA_NOTIFY_REMOVE, &sta->sta);
|
||||
}
|
||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
}
|
||||
|
||||
/* remove all interfaces */
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
netif_running(sdata->dev)) {
|
||||
@@ -61,6 +78,7 @@ int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_if_init_conf conf;
|
||||
struct sta_info *sta;
|
||||
unsigned long flags;
|
||||
int res;
|
||||
|
||||
/* restart hardware */
|
||||
@@ -72,7 +90,6 @@ int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
|
||||
/* add interfaces */
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
netif_running(sdata->dev)) {
|
||||
@@ -84,9 +101,9 @@ int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
}
|
||||
|
||||
/* add STAs back */
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
|
||||
if (local->ops->sta_notify) {
|
||||
if (local->ops->sta_notify) {
|
||||
spin_lock_irqsave(&local->sta_lock, flags);
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data,
|
||||
@@ -95,8 +112,21 @@ int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
local->ops->sta_notify(hw, &sdata->vif,
|
||||
STA_NOTIFY_ADD, &sta->sta);
|
||||
}
|
||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
}
|
||||
|
||||
/* Clear Suspend state so that ADDBA requests can be processed */
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
clear_sta_flags(sta, WLAN_STA_SUSPEND);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* add back keys */
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
if (netif_running(sdata->dev))
|
||||
@@ -113,5 +143,37 @@ int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
ieee80211_configure_filter(local);
|
||||
netif_addr_unlock_bh(local->mdev);
|
||||
|
||||
/* Finally also reconfigure all the BSS information */
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
u32 changed = ~0;
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* disable beacon change bits */
|
||||
changed &= ~IEEE80211_IFCC_BEACON;
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
WARN_ON(ieee80211_if_config(sdata, changed));
|
||||
ieee80211_bss_info_change_notify(sdata, ~0);
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
/* ignore virtual */
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case __NL80211_IFTYPE_AFTER_LAST:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ieee80211_wake_queues_by_reason(hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+4
-2
@@ -219,10 +219,12 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
|
||||
info->control.rates[i].count = 1;
|
||||
}
|
||||
|
||||
if (sta && sdata->force_unicast_rateidx > -1)
|
||||
if (sta && sdata->force_unicast_rateidx > -1) {
|
||||
info->control.rates[0].idx = sdata->force_unicast_rateidx;
|
||||
else
|
||||
} else {
|
||||
ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
|
||||
info->flags |= IEEE80211_TX_INTFL_RCALGO;
|
||||
}
|
||||
|
||||
/*
|
||||
* try to enforce the maximum rate the user wanted
|
||||
|
||||
+3
-1
@@ -44,8 +44,10 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
|
||||
struct rate_control_ref *ref = local->rate_ctrl;
|
||||
struct ieee80211_sta *ista = &sta->sta;
|
||||
void *priv_sta = sta->rate_ctrl_priv;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
||||
if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO))
|
||||
ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+16
-13
@@ -142,6 +142,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
||||
/* IEEE80211_RADIOTAP_FLAGS */
|
||||
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
|
||||
*pos |= IEEE80211_RADIOTAP_F_FCS;
|
||||
if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
|
||||
*pos |= IEEE80211_RADIOTAP_F_BADFCS;
|
||||
if (status->flag & RX_FLAG_SHORTPRE)
|
||||
*pos |= IEEE80211_RADIOTAP_F_SHORTPRE;
|
||||
pos++;
|
||||
@@ -204,9 +206,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
||||
/* ensure 2 byte alignment for the 2 byte field as required */
|
||||
if ((pos - (unsigned char *)rthdr) & 1)
|
||||
pos++;
|
||||
/* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
|
||||
if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
|
||||
*(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
|
||||
if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
|
||||
*(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADPLCP);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
@@ -849,12 +850,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
||||
* Mesh beacons will update last_rx when if they are found to
|
||||
* match the current local configuration when processed.
|
||||
*/
|
||||
sta->last_rx = jiffies;
|
||||
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
ieee80211_is_beacon(hdr->frame_control)) {
|
||||
rx->sdata->u.mgd.last_beacon = jiffies;
|
||||
} else
|
||||
sta->last_rx = jiffies;
|
||||
}
|
||||
|
||||
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_sta_rx_notify(rx->sdata, hdr);
|
||||
|
||||
sta->rx_fragments++;
|
||||
sta->rx_bytes += rx->skb->len;
|
||||
sta->last_signal = rx->status->signal;
|
||||
@@ -1876,18 +1884,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||
return RX_DROP_MONITOR;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status);
|
||||
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
|
||||
return RX_DROP_MONITOR;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
|
||||
}
|
||||
|
||||
return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status);
|
||||
return RX_DROP_MONITOR;
|
||||
}
|
||||
|
||||
static void ieee80211_rx_michael_mic_report(struct net_device *dev,
|
||||
|
||||
+75
-2
@@ -214,6 +214,66 @@ void ieee80211_scan_failed(struct ieee80211_local *local)
|
||||
local->scan_req = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* inform AP that we will go to sleep so that it will buffer the frames
|
||||
* while we scan
|
||||
*/
|
||||
static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
bool ps = false;
|
||||
|
||||
/* FIXME: what to do when local->pspolling is true? */
|
||||
|
||||
del_timer_sync(&local->dynamic_ps_timer);
|
||||
cancel_work_sync(&local->dynamic_ps_enable_work);
|
||||
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
ps = true;
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
}
|
||||
|
||||
if (!ps || !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
|
||||
/*
|
||||
* If power save was enabled, no need to send a nullfunc
|
||||
* frame because AP knows that we are sleeping. But if the
|
||||
* hardware is creating the nullfunc frame for power save
|
||||
* status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
|
||||
* enabled) and power save was enabled, the firmware just
|
||||
* sent a null frame with power save disabled. So we need
|
||||
* to send a new nullfunc frame to inform the AP that we
|
||||
* are again sleeping.
|
||||
*/
|
||||
ieee80211_send_nullfunc(local, sdata, 1);
|
||||
}
|
||||
|
||||
/* inform AP that we are awake again, unless power save is enabled */
|
||||
static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (!local->powersave)
|
||||
ieee80211_send_nullfunc(local, sdata, 0);
|
||||
else {
|
||||
/*
|
||||
* In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
|
||||
* will send a nullfunc frame with the powersave bit set
|
||||
* even though the AP already knows that we are sleeping.
|
||||
* This could be avoided by sending a null frame with power
|
||||
* save bit disabled before enabling the power save, but
|
||||
* this doesn't gain anything.
|
||||
*
|
||||
* When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
|
||||
* to send a nullfunc frame because AP already knows that
|
||||
* we are sleeping, let's just enable power save mode in
|
||||
* hardware.
|
||||
*/
|
||||
local->hw.conf.flags |= IEEE80211_CONF_PS;
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
@@ -268,7 +328,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
/* Tell AP we're back */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
|
||||
ieee80211_send_nullfunc(local, sdata, 0);
|
||||
ieee80211_scan_ps_disable(sdata);
|
||||
netif_tx_wake_all_queues(sdata->dev);
|
||||
}
|
||||
} else
|
||||
@@ -409,6 +469,19 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware/driver doesn't support hw_scan, so use software
|
||||
* scanning instead. First send a nullfunc frame with power save
|
||||
* bit on so that AP will buffer the frames for us while we are not
|
||||
* listening, then send probe requests to each channel and wait for
|
||||
* the responses. After all channels are scanned, tune back to the
|
||||
* original channel and send a nullfunc frame with power save bit
|
||||
* off to trigger the AP to send us all the buffered frames.
|
||||
*
|
||||
* Note that while local->sw_scanning is true everything else but
|
||||
* nullfunc frames and probe requests will be dropped in
|
||||
* ieee80211_tx_h_check_assoc().
|
||||
*/
|
||||
local->sw_scanning = true;
|
||||
if (local->ops->sw_scan_start)
|
||||
local->ops->sw_scan_start(local_to_hw(local));
|
||||
@@ -428,7 +501,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
ieee80211_send_nullfunc(local, sdata, 1);
|
||||
ieee80211_scan_ps_enable(sdata);
|
||||
}
|
||||
} else
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
|
||||
+5
-12
@@ -203,17 +203,6 @@ void sta_info_destroy(struct sta_info *sta)
|
||||
if (tid_rx)
|
||||
tid_rx->shutdown = true;
|
||||
|
||||
/*
|
||||
* The stop callback cannot find this station any more, but
|
||||
* it didn't complete its work -- start the queue if necessary
|
||||
*/
|
||||
if (sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_INITIATOR_MSK &&
|
||||
sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_REQ_STOP_BA_MSK &&
|
||||
local->hw.ampdu_queues)
|
||||
ieee80211_wake_queue_by_reason(&local->hw,
|
||||
local->hw.queues + sta->tid_to_tx_q[i],
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
|
||||
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
/*
|
||||
@@ -239,6 +228,11 @@ void sta_info_destroy(struct sta_info *sta)
|
||||
tid_tx = sta->ampdu_mlme.tid_tx[i];
|
||||
if (tid_tx) {
|
||||
del_timer_sync(&tid_tx->addba_resp_timer);
|
||||
/*
|
||||
* STA removed while aggregation session being
|
||||
* started? Bit odd, but purge frames anyway.
|
||||
*/
|
||||
skb_queue_purge(&tid_tx->pending);
|
||||
kfree(tid_tx);
|
||||
}
|
||||
}
|
||||
@@ -287,7 +281,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
* enable session_timer's data differentiation. refer to
|
||||
* sta_rx_agg_session_timer_expired for useage */
|
||||
sta->timer_to_tid[i] = i;
|
||||
sta->tid_to_tx_q[i] = -1;
|
||||
/* rx */
|
||||
sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
|
||||
sta->ampdu_mlme.tid_rx[i] = NULL;
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
|
||||
* frame to this station is transmitted.
|
||||
* @WLAN_STA_MFP: Management frame protection is used with this STA.
|
||||
* @WLAN_STA_SUSPEND: Set/cleared during a suspend/resume cycle.
|
||||
* Used to deny ADDBA requests (both TX and RX).
|
||||
*/
|
||||
enum ieee80211_sta_info_flags {
|
||||
WLAN_STA_AUTH = 1<<0,
|
||||
@@ -48,6 +50,7 @@ enum ieee80211_sta_info_flags {
|
||||
WLAN_STA_PSPOLL = 1<<8,
|
||||
WLAN_STA_CLEAR_PS_FILT = 1<<9,
|
||||
WLAN_STA_MFP = 1<<10,
|
||||
WLAN_STA_SUSPEND = 1<<11
|
||||
};
|
||||
|
||||
#define STA_TID_NUM 16
|
||||
@@ -70,11 +73,13 @@ enum ieee80211_sta_info_flags {
|
||||
* struct tid_ampdu_tx - TID aggregation information (Tx).
|
||||
*
|
||||
* @addba_resp_timer: timer for peer's response to addba request
|
||||
* @pending: pending frames queue -- use sta's spinlock to protect
|
||||
* @ssn: Starting Sequence Number expected to be aggregated.
|
||||
* @dialog_token: dialog token for aggregation session
|
||||
*/
|
||||
struct tid_ampdu_tx {
|
||||
struct timer_list addba_resp_timer;
|
||||
struct sk_buff_head pending;
|
||||
u16 ssn;
|
||||
u8 dialog_token;
|
||||
};
|
||||
@@ -201,7 +206,6 @@ struct sta_ampdu_mlme {
|
||||
* @tid_seq: per-TID sequence numbers for sending to this STA
|
||||
* @ampdu_mlme: A-MPDU state machine state
|
||||
* @timer_to_tid: identity mapping to ID timers
|
||||
* @tid_to_tx_q: map tid to tx queue (invalid == negative values)
|
||||
* @llid: Local link ID
|
||||
* @plid: Peer link ID
|
||||
* @reason: Cancel reason on PLINK_HOLDING state
|
||||
@@ -276,7 +280,6 @@ struct sta_info {
|
||||
*/
|
||||
struct sta_ampdu_mlme ampdu_mlme;
|
||||
u8 timer_to_tid[STA_TID_NUM];
|
||||
s8 tid_to_tx_q[STA_TID_NUM];
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
/*
|
||||
|
||||
+343
-240
File diff suppressed because it is too large
Load Diff
+30
-94
@@ -166,18 +166,13 @@ int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||||
|
||||
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
|
||||
struct sk_buff *skb = tx->skb;
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
if (tx->extra_frag) {
|
||||
struct ieee80211_hdr *fhdr;
|
||||
int i;
|
||||
for (i = 0; i < tx->num_extra_frag; i++) {
|
||||
fhdr = (struct ieee80211_hdr *)
|
||||
tx->extra_frag[i]->data;
|
||||
fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
}
|
||||
do {
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
} while ((skb = skb->next));
|
||||
}
|
||||
|
||||
int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
|
||||
@@ -344,42 +339,21 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
if (queue >= hw->queues) {
|
||||
if (local->ampdu_ac_queue[queue - hw->queues] < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* for virtual aggregation queues, we need to refcount the
|
||||
* internal mac80211 disable (multiple times!), keep track of
|
||||
* driver disable _and_ make sure the regular queue is
|
||||
* actually enabled.
|
||||
*/
|
||||
if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)
|
||||
local->amdpu_ac_stop_refcnt[queue - hw->queues]--;
|
||||
else
|
||||
__clear_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
if (local->queue_stop_reasons[queue] ||
|
||||
local->amdpu_ac_stop_refcnt[queue - hw->queues])
|
||||
return;
|
||||
|
||||
/* now go on to treat the corresponding regular queue */
|
||||
queue = local->ampdu_ac_queue[queue - hw->queues];
|
||||
reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;
|
||||
}
|
||||
if (WARN_ON(queue >= hw->queues))
|
||||
return;
|
||||
|
||||
__clear_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
if (!skb_queue_empty(&local->pending[queue]) &&
|
||||
local->queue_stop_reasons[queue] ==
|
||||
BIT(IEEE80211_QUEUE_STOP_REASON_PENDING))
|
||||
tasklet_schedule(&local->tx_pending_tasklet);
|
||||
|
||||
if (local->queue_stop_reasons[queue] != 0)
|
||||
/* someone still has this queue stopped */
|
||||
return;
|
||||
|
||||
if (test_bit(queue, local->queues_pending)) {
|
||||
set_bit(queue, local->queues_pending_run);
|
||||
tasklet_schedule(&local->tx_pending_tasklet);
|
||||
} else {
|
||||
netif_wake_subqueue(local->mdev, queue);
|
||||
}
|
||||
netif_wake_subqueue(local->mdev, queue);
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
@@ -405,29 +379,18 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
if (queue >= hw->queues) {
|
||||
if (local->ampdu_ac_queue[queue - hw->queues] < 0)
|
||||
return;
|
||||
if (WARN_ON(queue >= hw->queues))
|
||||
return;
|
||||
|
||||
/*
|
||||
* for virtual aggregation queues, we need to refcount the
|
||||
* internal mac80211 disable (multiple times!), keep track of
|
||||
* driver disable _and_ make sure the regular queue is
|
||||
* actually enabled.
|
||||
*/
|
||||
if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)
|
||||
local->amdpu_ac_stop_refcnt[queue - hw->queues]++;
|
||||
else
|
||||
__set_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
/* now go on to treat the corresponding regular queue */
|
||||
queue = local->ampdu_ac_queue[queue - hw->queues];
|
||||
reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;
|
||||
}
|
||||
/*
|
||||
* Only stop if it was previously running, this is necessary
|
||||
* for correct pending packets handling because there we may
|
||||
* start (but not wake) the queue and rely on that.
|
||||
*/
|
||||
if (!local->queue_stop_reasons[queue])
|
||||
netif_stop_subqueue(local->mdev, queue);
|
||||
|
||||
__set_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
netif_stop_subqueue(local->mdev, queue);
|
||||
}
|
||||
|
||||
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
@@ -473,15 +436,9 @@ EXPORT_SYMBOL(ieee80211_stop_queues);
|
||||
int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
unsigned long flags;
|
||||
|
||||
if (queue >= hw->queues) {
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
queue = local->ampdu_ac_queue[queue - hw->queues];
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
if (queue < 0)
|
||||
return true;
|
||||
}
|
||||
if (WARN_ON(queue >= hw->queues))
|
||||
return true;
|
||||
|
||||
return __netif_subqueue_stopped(local->mdev, queue);
|
||||
}
|
||||
@@ -496,7 +453,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
|
||||
for (i = 0; i < hw->queues; i++)
|
||||
__ieee80211_wake_queue(hw, i, reason);
|
||||
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
@@ -846,16 +803,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
const u8 *ie_auth = NULL;
|
||||
int ie_auth_len = 0;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
ie_auth_len = sdata->u.mgd.ie_auth_len;
|
||||
ie_auth = sdata->u.mgd.ie_auth;
|
||||
}
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
|
||||
sizeof(*mgmt) + 6 + extra_len + ie_auth_len);
|
||||
sizeof(*mgmt) + 6 + extra_len);
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
|
||||
"frame\n", sdata->dev->name);
|
||||
@@ -877,8 +827,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
||||
mgmt->u.auth.status_code = cpu_to_le16(0);
|
||||
if (extra)
|
||||
memcpy(skb_put(skb, extra_len), extra, extra_len);
|
||||
if (ie_auth)
|
||||
memcpy(skb_put(skb, ie_auth_len), ie_auth, ie_auth_len);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, encrypt);
|
||||
}
|
||||
@@ -891,20 +839,11 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos, *supp_rates, *esupp_rates = NULL, *extra_preq_ie = NULL;
|
||||
int i, extra_preq_ie_len = 0;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
extra_preq_ie_len = sdata->u.mgd.ie_probereq_len;
|
||||
extra_preq_ie = sdata->u.mgd.ie_probereq;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
u8 *pos, *supp_rates, *esupp_rates = NULL;
|
||||
int i;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
|
||||
ie_len + extra_preq_ie_len);
|
||||
ie_len);
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
|
||||
"request\n", sdata->dev->name);
|
||||
@@ -953,9 +892,6 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
||||
|
||||
if (ie)
|
||||
memcpy(skb_put(skb, ie_len), ie, ie_len);
|
||||
if (extra_preq_ie)
|
||||
memcpy(skb_put(skb, extra_preq_ie_len), extra_preq_ie,
|
||||
extra_preq_ie_len);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 0);
|
||||
}
|
||||
|
||||
+7
-14
@@ -329,24 +329,17 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
||||
ieee80211_tx_result
|
||||
ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
int i;
|
||||
struct sk_buff *skb;
|
||||
|
||||
ieee80211_tx_set_protected(tx);
|
||||
|
||||
if (wep_encrypt_skb(tx, tx->skb) < 0) {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
|
||||
return TX_DROP;
|
||||
}
|
||||
|
||||
if (tx->extra_frag) {
|
||||
for (i = 0; i < tx->num_extra_frag; i++) {
|
||||
if (wep_encrypt_skb(tx, tx->extra_frag[i])) {
|
||||
I802_DEBUG_INC(tx->local->
|
||||
tx_handlers_drop_wep);
|
||||
return TX_DROP;
|
||||
}
|
||||
skb = tx->skb;
|
||||
do {
|
||||
if (wep_encrypt_skb(tx, skb) < 0) {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
|
||||
return TX_DROP;
|
||||
}
|
||||
}
|
||||
} while ((skb = skb->next));
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
+15
-18
@@ -129,14 +129,12 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
|
||||
if (ret)
|
||||
return ret;
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
|
||||
ieee80211_sta_req_auth(sdata);
|
||||
return 0;
|
||||
}
|
||||
@@ -207,14 +205,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
|
||||
if (len > IEEE80211_MAX_SSID_LEN)
|
||||
return -EINVAL;
|
||||
memcpy(sdata->u.mgd.ssid, ssid, len);
|
||||
sdata->u.mgd.ssid_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data->flags)
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
|
||||
else
|
||||
@@ -224,6 +214,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
|
||||
ieee80211_sta_req_auth(sdata);
|
||||
return 0;
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
@@ -272,11 +263,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
int ret;
|
||||
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
|
||||
memcpy(sdata->u.mgd.bssid, (u8 *) &ap_addr->sa_data,
|
||||
ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
|
||||
IEEE80211_STA_AUTO_CHANNEL_SEL;
|
||||
@@ -287,6 +274,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
|
||||
ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
|
||||
ieee80211_sta_req_auth(sdata);
|
||||
return 0;
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
||||
@@ -630,7 +618,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int idx, i, alg = ALG_WEP;
|
||||
u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
int remove = 0;
|
||||
int remove = 0, ret;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
@@ -656,11 +644,20 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ieee80211_set_encryption(
|
||||
ret = ieee80211_set_encryption(
|
||||
sdata, bcaddr,
|
||||
idx, alg, remove,
|
||||
!sdata->default_key,
|
||||
keybuf, erq->length);
|
||||
|
||||
if (!ret) {
|
||||
if (remove)
|
||||
sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED;
|
||||
else
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user