Ejemplo n.º 1
0
/*
 * 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 (!(sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK))
		return;

	if (WARN(!sta->ampdu_mlme.tid_tx[tid],
		 "TID %d gone but expected when splicing aggregates from"
		 "the pending queue\n", tid))
		return;

	if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
		/* 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);
	}
}
Ejemplo n.º 2
0
ieee80211_stop_queue_agg(struct ieee80211_local *local, int tid)
{
	int queue = ieee80211_ac_from_tid(tid);

	if (atomic_inc_return(&local->agg_queue_stop[queue]) == 1)
		ieee80211_stop_queue_by_reason(
			&local->hw, queue,
			IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
	__acquire(agg_queue);
}
Ejemplo n.º 3
0
ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
{
    int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];

    if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
        ieee80211_stop_queue_by_reason(
            &sdata->local->hw, queue,
            IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
    __acquire(agg_queue);
}
Ejemplo n.º 4
0
ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
{
	int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];

	/* we do refcounting here, so don't use the queue reason refcounting */

	if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
		ieee80211_stop_queue_by_reason(
			&sdata->local->hw, queue,
			IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
			false);
	__acquire(agg_queue);
}
Ejemplo n.º 5
0
/*
 * 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);
	}
}
Ejemplo n.º 6
0
int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct sta_info *sta;
	struct ieee80211_sub_if_data *sdata;
	u8 *state;
	int ret = 0;
	u16 start_seq_num;

	if (WARN_ON(!local->ops->ampdu_action))
		return -EINVAL;

	if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
		return -EINVAL;

#ifdef CONFIG_MAC80211_HT_DEBUG
	printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
	       ra, tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */

	rcu_read_lock();

	sta = sta_info_get(local, ra);
	if (!sta) {
#ifdef CONFIG_MAC80211_HT_DEBUG
		printk(KERN_DEBUG "Could not find the station\n");
#endif
		ret = -ENOENT;
		goto unlock;
	}

	/*
	 * The aggregation code is not prepared to handle
	 * anything but STA/AP due to the BSSID handling.
	 * IBSS could work in the code but isn't supported
	 * by drivers or the standard.
	 */
	if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
	    sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
	    sta->sdata->vif.type != NL80211_IFTYPE_AP) {
		ret = -EINVAL;
		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;

	/* we have tried too many times, receiver does not want A-MPDU */
	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
		ret = -EBUSY;
		goto err_unlock_sta;
	}

	state = &sta->ampdu_mlme.tid_state_tx[tid];
	/* check if the TID is not in aggregation flow already */
	if (*state != HT_AGG_STATE_IDLE) {
#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 */
		ret = -EAGAIN;
		goto err_unlock_sta;
	}

	/*
	 * 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] =
			kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
	if (!sta->ampdu_mlme.tid_tx[tid]) {
#ifdef CONFIG_MAC80211_HT_DEBUG
		if (net_ratelimit())
			printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
					tid);
#endif
		ret = -ENOMEM;
		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;
	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
			(unsigned long)&sta->timer_to_tid[tid];
	init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);

	/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
	 * call back right away, it must see that the flow has begun */
	*state |= HT_ADDBA_REQUESTED_MSK;

	start_seq_num = sta->tid_seq[tid];

	ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START,
			       &sta->sta, tid, &start_seq_num);

	if (ret) {
#ifdef CONFIG_MAC80211_HT_DEBUG
		printk(KERN_DEBUG "BA request denied - HW unavailable for"
					" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
		*state = HT_AGG_STATE_IDLE;
		goto err_free;
	}

	/* 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 */
	sta->ampdu_mlme.dialog_token_allocator++;
	sta->ampdu_mlme.tid_tx[tid]->dialog_token =
			sta->ampdu_mlme.dialog_token_allocator;
	sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;

	ieee80211_send_addba_request(sta->sdata, ra, tid,
			 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
			 sta->ampdu_mlme.tid_tx[tid]->ssn,
			 0x40, 5000);
	sta->ampdu_mlme.addba_req_num[tid]++;
	/* activate the timer for the recipient's addBA response */
	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
				jiffies + ADDBA_RESP_INTERVAL;
	add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
#ifdef CONFIG_MAC80211_HT_DEBUG
	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
#endif
	goto unlock;

 err_free:
	kfree(sta->ampdu_mlme.tid_tx[tid]);
	sta->ampdu_mlme.tid_tx[tid] = NULL;
 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();
	return ret;
}