From: Johannes Berg Date: Tue, 4 Oct 2016 07:22:19 +0000 (+0200) Subject: Merge remote-tracking branch 'net-next/master' into mac80211-next X-Git-Tag: v4.9-rc1~127^2~1^2 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Flinux.git;a=commitdiff_plain;h=1e1430d5282bc3a572465ef3261eea793d98a653 Merge remote-tracking branch 'net-next/master' into mac80211-next Resolve the merge conflict between Felix's/my and Toke's patches coming into the tree through net and mac80211-next respectively. Most of Felix's changes go away due to Toke's new infrastructure work, my patch changes to "goto begin" (the label wasn't there before) instead of returning NULL so flow control towards drivers is preserved better. Signed-off-by: Johannes Berg --- 1e1430d5282bc3a572465ef3261eea793d98a653 diff --cc net/mac80211/sta_info.c index 167bff078bdd,011880d633b4..78e9ecbc96e6 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@@ -1647,7 -1638,10 +1636,8 @@@ ieee80211_sta_ps_deliver_response(struc return; for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { - if (!(tids & BIT(tid)) || txq_has_queue(sta->sta.txq[tid])) - struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); - + if (!(driver_release_tids & BIT(tid)) || - txqi->tin.backlog_packets) ++ txq_has_queue(sta->sta.txq[tid])) continue; sta_info_recalc_tim(sta); diff --cc net/mac80211/tx.c index 0ea1b0d02186,1ff08be90a98..1c56abc49627 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@@ -3374,90 -3316,6 +3374,94 @@@ static bool ieee80211_xmit_fast(struct return true; } +struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = container_of(txq, struct txq_info, txq); + struct ieee80211_hdr *hdr; + struct sk_buff *skb = NULL; + struct fq *fq = &local->fq; + struct fq_tin *tin = &txqi->tin; + struct ieee80211_tx_info *info; + struct ieee80211_tx_data tx; + ieee80211_tx_result r; + + spin_lock_bh(&fq->lock); + + if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) + goto out; + + /* Make sure fragments stay together. */ + skb = __skb_dequeue(&txqi->frags); + if (skb) + goto out; + +begin: + skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func); + if (!skb) + goto out; + + ieee80211_set_skb_vif(skb, txqi); + + hdr = (struct ieee80211_hdr *)skb->data; + info = IEEE80211_SKB_CB(skb); + + memset(&tx, 0, sizeof(tx)); + __skb_queue_head_init(&tx.skbs); + tx.local = local; + tx.skb = skb; + tx.sdata = vif_to_sdata(info->control.vif); + + if (txq->sta) + tx.sta = container_of(txq->sta, struct sta_info, sta); + + /* + * The key can be removed while the packet was queued, so need to call + * this here to get the current key. + */ + r = ieee80211_tx_h_select_key(&tx); + if (r != TX_CONTINUE) { + ieee80211_free_txskb(&local->hw, skb); + goto begin; + } + + if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { + struct sta_info *sta = container_of(txq->sta, struct sta_info, + sta); + u8 pn_offs = 0; + + if (tx.key && + (tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) + pn_offs = ieee80211_hdrlen(hdr->frame_control); + + ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, + tx.key, skb); + } else { + if (invoke_tx_handlers_late(&tx)) + goto begin; + + skb = __skb_dequeue(&tx.skbs); + + if (!skb_queue_empty(&tx.skbs)) + skb_queue_splice_tail(&tx.skbs, &txqi->frags); + } + ++ if (skb && skb_has_frag_list(skb) && ++ !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) { ++ if (skb_linearize(skb)) { ++ ieee80211_free_txskb(&local->hw, skb); ++ goto begin; ++ } ++ } ++ +out: + spin_unlock_bh(&fq->lock); + - if (skb && skb_has_frag_list(skb) && - !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) - skb_linearize(skb); - + return skb; +} +EXPORT_SYMBOL(ieee80211_tx_dequeue); + void __ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev, u32 info_flags)