1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e2ebc74dSJohannes Berg /*
3e2ebc74dSJohannes Berg * Copyright 2002-2005, Instant802 Networks, Inc.
4e2ebc74dSJohannes Berg * Copyright 2005-2006, Devicescape Software, Inc.
5e2ebc74dSJohannes Berg * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
6e2ebc74dSJohannes Berg * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
7d98ad83eSJohannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH
8e700e44fSJohannes Berg * Copyright (C) 2018-2024 Intel Corporation
9e2ebc74dSJohannes Berg *
10e2ebc74dSJohannes Berg * Transmit and frame generation functions.
11e2ebc74dSJohannes Berg */
12e2ebc74dSJohannes Berg
13e2ebc74dSJohannes Berg #include <linux/kernel.h>
14e2ebc74dSJohannes Berg #include <linux/slab.h>
15e2ebc74dSJohannes Berg #include <linux/skbuff.h>
16ebceec86SMichael Braun #include <linux/if_vlan.h>
17e2ebc74dSJohannes Berg #include <linux/etherdevice.h>
18e2ebc74dSJohannes Berg #include <linux/bitmap.h>
19d4e46a3dSJohannes Berg #include <linux/rcupdate.h>
20bc3b2d7fSPaul Gortmaker #include <linux/export.h>
21881d966bSEric W. Biederman #include <net/net_namespace.h>
22e2ebc74dSJohannes Berg #include <net/ieee80211_radiotap.h>
23e2ebc74dSJohannes Berg #include <net/cfg80211.h>
24e2ebc74dSJohannes Berg #include <net/mac80211.h>
255caa328eSMichal Kazior #include <net/codel.h>
265caa328eSMichal Kazior #include <net/codel_impl.h>
27e2ebc74dSJohannes Berg #include <asm/unaligned.h>
28fa962b92SMichal Kazior #include <net/fq_impl.h>
29d457a0e3SEric Dumazet #include <net/gso.h>
30e2ebc74dSJohannes Berg
31e2ebc74dSJohannes Berg #include "ieee80211_i.h"
3224487981SJohannes Berg #include "driver-ops.h"
332c8dccc7SJohannes Berg #include "led.h"
3433b64eb2SLuis Carlos Cobo #include "mesh.h"
35e2ebc74dSJohannes Berg #include "wep.h"
36e2ebc74dSJohannes Berg #include "wpa.h"
37e2ebc74dSJohannes Berg #include "wme.h"
382c8dccc7SJohannes Berg #include "rate.h"
39e2ebc74dSJohannes Berg
40e2ebc74dSJohannes Berg /* misc utils */
41e2ebc74dSJohannes Berg
ieee80211_duration(struct ieee80211_tx_data * tx,struct sk_buff * skb,int group_addr,int next_frag_len)42252b86c4SJohannes Berg static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
43252b86c4SJohannes Berg struct sk_buff *skb, int group_addr,
44e2ebc74dSJohannes Berg int next_frag_len)
45e2ebc74dSJohannes Berg {
462103dec1SSimon Wunderlich int rate, mrate, erp, dur, i, shift = 0;
472e92e6f2SJohannes Berg struct ieee80211_rate *txrate;
48e2ebc74dSJohannes Berg struct ieee80211_local *local = tx->local;
498318d78aSJohannes Berg struct ieee80211_supported_band *sband;
50358c8d9dSHarvey Harrison struct ieee80211_hdr *hdr;
51252b86c4SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
522103dec1SSimon Wunderlich struct ieee80211_chanctx_conf *chanctx_conf;
532103dec1SSimon Wunderlich u32 rate_flags = 0;
542103dec1SSimon Wunderlich
5595cd470cSFelix Fietkau /* assume HW handles this */
5695cd470cSFelix Fietkau if (tx->rate.flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
5795cd470cSFelix Fietkau return 0;
5895cd470cSFelix Fietkau
592103dec1SSimon Wunderlich rcu_read_lock();
60d0a9123eSJohannes Berg chanctx_conf = rcu_dereference(tx->sdata->vif.bss_conf.chanctx_conf);
612103dec1SSimon Wunderlich if (chanctx_conf) {
622103dec1SSimon Wunderlich shift = ieee80211_chandef_get_shift(&chanctx_conf->def);
632103dec1SSimon Wunderlich rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
642103dec1SSimon Wunderlich }
652103dec1SSimon Wunderlich rcu_read_unlock();
66e6a9854bSJohannes Berg
67e6a9854bSJohannes Berg /* uh huh? */
680d528d85SFelix Fietkau if (WARN_ON_ONCE(tx->rate.idx < 0))
69e6a9854bSJohannes Berg return 0;
70e2ebc74dSJohannes Berg
712d56577bSJohannes Berg sband = local->hw.wiphy->bands[info->band];
720d528d85SFelix Fietkau txrate = &sband->bitrates[tx->rate.idx];
738318d78aSJohannes Berg
748318d78aSJohannes Berg erp = txrate->flags & IEEE80211_RATE_ERP_G;
75e2ebc74dSJohannes Berg
7689b8c02aSThomas Pedersen /* device is expected to do this */
7789b8c02aSThomas Pedersen if (sband->band == NL80211_BAND_S1GHZ)
7889b8c02aSThomas Pedersen return 0;
7989b8c02aSThomas Pedersen
80e2ebc74dSJohannes Berg /*
81e2ebc74dSJohannes Berg * data and mgmt (except PS Poll):
82e2ebc74dSJohannes Berg * - during CFP: 32768
83e2ebc74dSJohannes Berg * - during contention period:
84e2ebc74dSJohannes Berg * if addr1 is group address: 0
85e2ebc74dSJohannes Berg * if more fragments = 0 and addr1 is individual address: time to
86e2ebc74dSJohannes Berg * transmit one ACK plus SIFS
87e2ebc74dSJohannes Berg * if more fragments = 1 and addr1 is individual address: time to
88e2ebc74dSJohannes Berg * transmit next fragment plus 2 x ACK plus 3 x SIFS
89e2ebc74dSJohannes Berg *
90e2ebc74dSJohannes Berg * IEEE 802.11, 9.6:
91e2ebc74dSJohannes Berg * - control response frame (CTS or ACK) shall be transmitted using the
92e2ebc74dSJohannes Berg * same rate as the immediately previous frame in the frame exchange
93e2ebc74dSJohannes Berg * sequence, if this rate belongs to the PHY mandatory rates, or else
94e2ebc74dSJohannes Berg * at the highest possible rate belonging to the PHY rates in the
95e2ebc74dSJohannes Berg * BSSBasicRateSet
96e2ebc74dSJohannes Berg */
97252b86c4SJohannes Berg hdr = (struct ieee80211_hdr *)skb->data;
98358c8d9dSHarvey Harrison if (ieee80211_is_ctl(hdr->frame_control)) {
99e2ebc74dSJohannes Berg /* TODO: These control frames are not currently sent by
100ccd7b362SJohannes Berg * mac80211, but should they be implemented, this function
101e2ebc74dSJohannes Berg * needs to be updated to support duration field calculation.
102e2ebc74dSJohannes Berg *
103e2ebc74dSJohannes Berg * RTS: time needed to transmit pending data/mgmt frame plus
104e2ebc74dSJohannes Berg * one CTS frame plus one ACK frame plus 3 x SIFS
105e2ebc74dSJohannes Berg * CTS: duration of immediately previous RTS minus time
106e2ebc74dSJohannes Berg * required to transmit CTS and its SIFS
107e2ebc74dSJohannes Berg * ACK: 0 if immediately previous directed data/mgmt had
108e2ebc74dSJohannes Berg * more=0, with more=1 duration in ACK frame is duration
109e2ebc74dSJohannes Berg * from previous frame minus time needed to transmit ACK
110e2ebc74dSJohannes Berg * and its SIFS
111e2ebc74dSJohannes Berg * PS Poll: BIT(15) | BIT(14) | aid
112e2ebc74dSJohannes Berg */
113e2ebc74dSJohannes Berg return 0;
114e2ebc74dSJohannes Berg }
115e2ebc74dSJohannes Berg
116e2ebc74dSJohannes Berg /* data/mgmt */
117e2ebc74dSJohannes Berg if (0 /* FIX: data/mgmt during CFP */)
11803f93c3dSJohannes Berg return cpu_to_le16(32768);
119e2ebc74dSJohannes Berg
120e2ebc74dSJohannes Berg if (group_addr) /* Group address as the destination - no ACK */
121e2ebc74dSJohannes Berg return 0;
122e2ebc74dSJohannes Berg
123e2ebc74dSJohannes Berg /* Individual destination address:
124e2ebc74dSJohannes Berg * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes)
125e2ebc74dSJohannes Berg * CTS and ACK frames shall be transmitted using the highest rate in
126e2ebc74dSJohannes Berg * basic rate set that is less than or equal to the rate of the
127e2ebc74dSJohannes Berg * immediately previous frame and that is using the same modulation
128e2ebc74dSJohannes Berg * (CCK or OFDM). If no basic rate set matches with these requirements,
129e2ebc74dSJohannes Berg * the highest mandatory rate of the PHY that is less than or equal to
130e2ebc74dSJohannes Berg * the rate of the previous frame is used.
131e2ebc74dSJohannes Berg * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
132e2ebc74dSJohannes Berg */
133e2ebc74dSJohannes Berg rate = -1;
1348318d78aSJohannes Berg /* use lowest available if everything fails */
1358318d78aSJohannes Berg mrate = sband->bitrates[0].bitrate;
1368318d78aSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) {
1378318d78aSJohannes Berg struct ieee80211_rate *r = &sband->bitrates[i];
1388318d78aSJohannes Berg
1398318d78aSJohannes Berg if (r->bitrate > txrate->bitrate)
140e2ebc74dSJohannes Berg break;
141e2ebc74dSJohannes Berg
1422103dec1SSimon Wunderlich if ((rate_flags & r->flags) != rate_flags)
1432103dec1SSimon Wunderlich continue;
1442103dec1SSimon Wunderlich
145bda3933aSJohannes Berg if (tx->sdata->vif.bss_conf.basic_rates & BIT(i))
1462103dec1SSimon Wunderlich rate = DIV_ROUND_UP(r->bitrate, 1 << shift);
147e2ebc74dSJohannes Berg
1488318d78aSJohannes Berg switch (sband->band) {
14963fa0426SSrinivasan Raju case NL80211_BAND_2GHZ:
15063fa0426SSrinivasan Raju case NL80211_BAND_LC: {
1518318d78aSJohannes Berg u32 flag;
15239eac2deSJohannes Berg if (tx->sdata->deflink.operating_11g_mode)
1538318d78aSJohannes Berg flag = IEEE80211_RATE_MANDATORY_G;
1548318d78aSJohannes Berg else
1558318d78aSJohannes Berg flag = IEEE80211_RATE_MANDATORY_B;
1568318d78aSJohannes Berg if (r->flags & flag)
1578318d78aSJohannes Berg mrate = r->bitrate;
1588318d78aSJohannes Berg break;
1598318d78aSJohannes Berg }
16057fbcce3SJohannes Berg case NL80211_BAND_5GHZ:
161c5b9a7f8SArend van Spriel case NL80211_BAND_6GHZ:
1628318d78aSJohannes Berg if (r->flags & IEEE80211_RATE_MANDATORY_A)
1638318d78aSJohannes Berg mrate = r->bitrate;
1648318d78aSJohannes Berg break;
165df78a0c0SThomas Pedersen case NL80211_BAND_S1GHZ:
16657fbcce3SJohannes Berg case NL80211_BAND_60GHZ:
1673a0c52a6SVladimir Kondratiev /* TODO, for now fall through */
16857fbcce3SJohannes Berg case NUM_NL80211_BANDS:
1698318d78aSJohannes Berg WARN_ON(1);
1708318d78aSJohannes Berg break;
1718318d78aSJohannes Berg }
172e2ebc74dSJohannes Berg }
173e2ebc74dSJohannes Berg if (rate == -1) {
174e2ebc74dSJohannes Berg /* No matching basic rate found; use highest suitable mandatory
175e2ebc74dSJohannes Berg * PHY rate */
1762103dec1SSimon Wunderlich rate = DIV_ROUND_UP(mrate, 1 << shift);
177e2ebc74dSJohannes Berg }
178e2ebc74dSJohannes Berg
1796674f210SSimon Wunderlich /* Don't calculate ACKs for QoS Frames with NoAck Policy set */
1806674f210SSimon Wunderlich if (ieee80211_is_data_qos(hdr->frame_control) &&
181c26a0e10SClaudio Pisa *(ieee80211_get_qos_ctl(hdr)) & IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
1826674f210SSimon Wunderlich dur = 0;
1836674f210SSimon Wunderlich else
184e2ebc74dSJohannes Berg /* Time needed to transmit ACK
185e2ebc74dSJohannes Berg * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
186e2ebc74dSJohannes Berg * to closest integer */
1874ee73f33SMichal Kazior dur = ieee80211_frame_duration(sband->band, 10, rate, erp,
188438b61b7SSimon Wunderlich tx->sdata->vif.bss_conf.use_short_preamble,
189438b61b7SSimon Wunderlich shift);
190e2ebc74dSJohannes Berg
191e2ebc74dSJohannes Berg if (next_frag_len) {
192e2ebc74dSJohannes Berg /* Frame is fragmented: duration increases with time needed to
193e2ebc74dSJohannes Berg * transmit next fragment plus ACK and 2 x SIFS. */
194e2ebc74dSJohannes Berg dur *= 2; /* ACK + SIFS */
195e2ebc74dSJohannes Berg /* next fragment */
1964ee73f33SMichal Kazior dur += ieee80211_frame_duration(sband->band, next_frag_len,
1978318d78aSJohannes Berg txrate->bitrate, erp,
198438b61b7SSimon Wunderlich tx->sdata->vif.bss_conf.use_short_preamble,
199438b61b7SSimon Wunderlich shift);
200e2ebc74dSJohannes Berg }
201e2ebc74dSJohannes Berg
20203f93c3dSJohannes Berg return cpu_to_le16(dur);
203e2ebc74dSJohannes Berg }
204e2ebc74dSJohannes Berg
205e2ebc74dSJohannes Berg /* tx handlers */
2065c1b98a5SKalle Valo static ieee80211_tx_result debug_noinline
ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data * tx)2075c1b98a5SKalle Valo ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
2085c1b98a5SKalle Valo {
2095c1b98a5SKalle Valo struct ieee80211_local *local = tx->local;
2100c74211dSKalle Valo struct ieee80211_if_managed *ifmgd;
21194a5b3acSAndrei Otcheretianski struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
2125c1b98a5SKalle Valo
2135c1b98a5SKalle Valo /* driver doesn't support power save */
21430686bf7SJohannes Berg if (!ieee80211_hw_check(&local->hw, SUPPORTS_PS))
2155c1b98a5SKalle Valo return TX_CONTINUE;
2165c1b98a5SKalle Valo
2175c1b98a5SKalle Valo /* hardware does dynamic power save */
21830686bf7SJohannes Berg if (ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
2195c1b98a5SKalle Valo return TX_CONTINUE;
2205c1b98a5SKalle Valo
2215c1b98a5SKalle Valo /* dynamic power save disabled */
2225c1b98a5SKalle Valo if (local->hw.conf.dynamic_ps_timeout <= 0)
2235c1b98a5SKalle Valo return TX_CONTINUE;
2245c1b98a5SKalle Valo
2255c1b98a5SKalle Valo /* we are scanning, don't enable power save */
2265c1b98a5SKalle Valo if (local->scanning)
2275c1b98a5SKalle Valo return TX_CONTINUE;
2285c1b98a5SKalle Valo
2295c1b98a5SKalle Valo if (!local->ps_sdata)
2305c1b98a5SKalle Valo return TX_CONTINUE;
2315c1b98a5SKalle Valo
2325c1b98a5SKalle Valo /* No point if we're going to suspend */
2335c1b98a5SKalle Valo if (local->quiescing)
2345c1b98a5SKalle Valo return TX_CONTINUE;
2355c1b98a5SKalle Valo
2360c74211dSKalle Valo /* dynamic ps is supported only in managed mode */
2370c74211dSKalle Valo if (tx->sdata->vif.type != NL80211_IFTYPE_STATION)
2380c74211dSKalle Valo return TX_CONTINUE;
2390c74211dSKalle Valo
24094a5b3acSAndrei Otcheretianski if (unlikely(info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK))
24194a5b3acSAndrei Otcheretianski return TX_CONTINUE;
24294a5b3acSAndrei Otcheretianski
2430c74211dSKalle Valo ifmgd = &tx->sdata->u.mgd;
2440c74211dSKalle Valo
2450c74211dSKalle Valo /*
2460c74211dSKalle Valo * Don't wakeup from power save if u-apsd is enabled, voip ac has
2470c74211dSKalle Valo * u-apsd enabled and the frame is in voip class. This effectively
2480c74211dSKalle Valo * means that even if all access categories have u-apsd enabled, in
2490c74211dSKalle Valo * practise u-apsd is only used with the voip ac. This is a
2500c74211dSKalle Valo * workaround for the case when received voip class packets do not
2510c74211dSKalle Valo * have correct qos tag for some reason, due the network or the
2520c74211dSKalle Valo * peer application.
2530c74211dSKalle Valo *
254dc41e4d4SEliad Peller * Note: ifmgd->uapsd_queues access is racy here. If the value is
2550c74211dSKalle Valo * changed via debugfs, user needs to reassociate manually to have
2560c74211dSKalle Valo * everything in sync.
2570c74211dSKalle Valo */
2584875d30dSJohannes Berg if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) &&
2594875d30dSJohannes Berg (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) &&
2604875d30dSJohannes Berg skb_get_queue_mapping(tx->skb) == IEEE80211_AC_VO)
2610c74211dSKalle Valo return TX_CONTINUE;
2620c74211dSKalle Valo
2635c1b98a5SKalle Valo if (local->hw.conf.flags & IEEE80211_CONF_PS) {
2645c1b98a5SKalle Valo ieee80211_stop_queues_by_reason(&local->hw,
265445ea4e8SJohannes Berg IEEE80211_MAX_QUEUE_MAP,
266cca07b00SLuciano Coelho IEEE80211_QUEUE_STOP_REASON_PS,
267cca07b00SLuciano Coelho false);
268db28569aSVivek Natarajan ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
2695c1b98a5SKalle Valo ieee80211_queue_work(&local->hw,
2705c1b98a5SKalle Valo &local->dynamic_ps_disable_work);
2715c1b98a5SKalle Valo }
2725c1b98a5SKalle Valo
2735db1c07cSLuciano Coelho /* Don't restart the timer if we're not disassociated */
2745db1c07cSLuciano Coelho if (!ifmgd->associated)
2755db1c07cSLuciano Coelho return TX_CONTINUE;
2765db1c07cSLuciano Coelho
2775c1b98a5SKalle Valo mod_timer(&local->dynamic_ps_timer, jiffies +
2785c1b98a5SKalle Valo msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
2795c1b98a5SKalle Valo
2805c1b98a5SKalle Valo return TX_CONTINUE;
2815c1b98a5SKalle Valo }
282e2ebc74dSJohannes Berg
283d9e8a70fSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_check_assoc(struct ieee80211_tx_data * tx)2845cf121c3SJohannes Berg ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
285e2ebc74dSJohannes Berg {
286358c8d9dSHarvey Harrison
287e039fa4aSJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
288e039fa4aSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
289c2c98fdeSJohannes Berg bool assoc = false;
290e2ebc74dSJohannes Berg
291e039fa4aSJohannes Berg if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
2929ae54c84SJohannes Berg return TX_CONTINUE;
29358d4185eSJohannes Berg
294b23b025fSBen Greear if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) &&
295b23b025fSBen Greear test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) &&
296a9a6ffffSKalle Valo !ieee80211_is_probe_req(hdr->frame_control) &&
29730b2f0beSThomas Pedersen !ieee80211_is_any_nullfunc(hdr->frame_control))
298a9a6ffffSKalle Valo /*
299a9a6ffffSKalle Valo * When software scanning only nullfunc frames (to notify
300a9a6ffffSKalle Valo * the sleep state to the AP) and probe requests (for the
301a9a6ffffSKalle Valo * active scan) are allowed, all other frames should not be
302a9a6ffffSKalle Valo * sent and we should not get here, but if we do
303a9a6ffffSKalle Valo * nonetheless, drop them to avoid sending them
304a9a6ffffSKalle Valo * off-channel. See the link below and
305a9a6ffffSKalle Valo * ieee80211_start_scan() for more.
306a9a6ffffSKalle Valo *
307a9a6ffffSKalle Valo * http://article.gmane.org/gmane.linux.kernel.wireless.general/30089
308a9a6ffffSKalle Valo */
3099ae54c84SJohannes Berg return TX_DROP;
310e2ebc74dSJohannes Berg
311239281f8SRostislav Lisovy if (tx->sdata->vif.type == NL80211_IFTYPE_OCB)
312239281f8SRostislav Lisovy return TX_CONTINUE;
313239281f8SRostislav Lisovy
3145cf121c3SJohannes Berg if (tx->flags & IEEE80211_TX_PS_BUFFERED)
3159ae54c84SJohannes Berg return TX_CONTINUE;
316e2ebc74dSJohannes Berg
317c2c98fdeSJohannes Berg if (tx->sta)
318c2c98fdeSJohannes Berg assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
319e2ebc74dSJohannes Berg
3205cf121c3SJohannes Berg if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
321c2c98fdeSJohannes Berg if (unlikely(!assoc &&
322358c8d9dSHarvey Harrison ieee80211_is_data(hdr->frame_control))) {
323e2ebc74dSJohannes Berg #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
324bdcbd8e0SJohannes Berg sdata_info(tx->sdata,
325bdcbd8e0SJohannes Berg "dropped data frame to not associated station %pM\n",
326bdcbd8e0SJohannes Berg hdr->addr1);
327bdcbd8e0SJohannes Berg #endif
328e2ebc74dSJohannes Berg I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
3299ae54c84SJohannes Berg return TX_DROP;
330e2ebc74dSJohannes Berg }
33172f15d53SMichael Braun } else if (unlikely(ieee80211_is_data(hdr->frame_control) &&
33272f15d53SMichael Braun ieee80211_vif_get_num_mcast_if(tx->sdata) == 0)) {
333e2ebc74dSJohannes Berg /*
334e2ebc74dSJohannes Berg * No associated STAs - no need to send multicast
335e2ebc74dSJohannes Berg * frames.
336e2ebc74dSJohannes Berg */
3379ae54c84SJohannes Berg return TX_DROP;
338e2ebc74dSJohannes Berg }
339e2ebc74dSJohannes Berg
3409ae54c84SJohannes Berg return TX_CONTINUE;
341e2ebc74dSJohannes Berg }
342e2ebc74dSJohannes Berg
343e2ebc74dSJohannes Berg /* This function is called whenever the AP is about to exceed the maximum limit
344e2ebc74dSJohannes Berg * of buffered frames for power saving STAs. This situation should not really
345e2ebc74dSJohannes Berg * happen often during normal operation, so dropping the oldest buffered packet
346e2ebc74dSJohannes Berg * from each queue should be OK to make some room for new frames. */
purge_old_ps_buffers(struct ieee80211_local * local)347e2ebc74dSJohannes Berg static void purge_old_ps_buffers(struct ieee80211_local *local)
348e2ebc74dSJohannes Berg {
349e2ebc74dSJohannes Berg int total = 0, purged = 0;
350e2ebc74dSJohannes Berg struct sk_buff *skb;
351e2ebc74dSJohannes Berg struct ieee80211_sub_if_data *sdata;
352e2ebc74dSJohannes Berg struct sta_info *sta;
353e2ebc74dSJohannes Berg
35479010420SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) {
355d012a605SMarco Porsch struct ps_data *ps;
356d012a605SMarco Porsch
357d012a605SMarco Porsch if (sdata->vif.type == NL80211_IFTYPE_AP)
358d012a605SMarco Porsch ps = &sdata->u.ap.ps;
3593f52b7e3SMarco Porsch else if (ieee80211_vif_is_mesh(&sdata->vif))
3603f52b7e3SMarco Porsch ps = &sdata->u.mesh.ps;
361d012a605SMarco Porsch else
362e2ebc74dSJohannes Berg continue;
363d012a605SMarco Porsch
364d012a605SMarco Porsch skb = skb_dequeue(&ps->bc_buf);
365e2ebc74dSJohannes Berg if (skb) {
366e2ebc74dSJohannes Berg purged++;
3676b07d9caSFelix Fietkau ieee80211_free_txskb(&local->hw, skb);
368e2ebc74dSJohannes Berg }
369d012a605SMarco Porsch total += skb_queue_len(&ps->bc_buf);
370e2ebc74dSJohannes Berg }
371e2ebc74dSJohannes Berg
372948d887dSJohannes Berg /*
373948d887dSJohannes Berg * Drop one frame from each station from the lowest-priority
374948d887dSJohannes Berg * AC that has frames at all.
375948d887dSJohannes Berg */
376d0709a65SJohannes Berg list_for_each_entry_rcu(sta, &local->sta_list, list) {
377948d887dSJohannes Berg int ac;
378948d887dSJohannes Berg
379948d887dSJohannes Berg for (ac = IEEE80211_AC_BK; ac >= IEEE80211_AC_VO; ac--) {
380948d887dSJohannes Berg skb = skb_dequeue(&sta->ps_tx_buf[ac]);
381948d887dSJohannes Berg total += skb_queue_len(&sta->ps_tx_buf[ac]);
382e2ebc74dSJohannes Berg if (skb) {
383e2ebc74dSJohannes Berg purged++;
384c3e7724bSFelix Fietkau ieee80211_free_txskb(&local->hw, skb);
385948d887dSJohannes Berg break;
386e2ebc74dSJohannes Berg }
387948d887dSJohannes Berg }
388e2ebc74dSJohannes Berg }
389d0709a65SJohannes Berg
390e2ebc74dSJohannes Berg local->total_ps_buffered = total;
391bdcbd8e0SJohannes Berg ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged);
392e2ebc74dSJohannes Berg }
393e2ebc74dSJohannes Berg
3949ae54c84SJohannes Berg static ieee80211_tx_result
ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data * tx)3955cf121c3SJohannes Berg ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
396e2ebc74dSJohannes Berg {
397e039fa4aSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
398358c8d9dSHarvey Harrison struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
399d012a605SMarco Porsch struct ps_data *ps;
400e039fa4aSJohannes Berg
4017d54d0ddSJohannes Berg /*
4027d54d0ddSJohannes Berg * broadcast/multicast frame
4037d54d0ddSJohannes Berg *
4043f52b7e3SMarco Porsch * If any of the associated/peer stations is in power save mode,
4057d54d0ddSJohannes Berg * the frame is buffered to be sent after DTIM beacon frame.
4067d54d0ddSJohannes Berg * This is done either by the hardware or us.
4077d54d0ddSJohannes Berg */
4087d54d0ddSJohannes Berg
4093f52b7e3SMarco Porsch /* powersaving STAs currently only in AP/VLAN/mesh mode */
410d012a605SMarco Porsch if (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
411d012a605SMarco Porsch tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
4123e122be0SJohannes Berg if (!tx->sdata->bss)
4133e122be0SJohannes Berg return TX_CONTINUE;
4143e122be0SJohannes Berg
415d012a605SMarco Porsch ps = &tx->sdata->bss->ps;
4163f52b7e3SMarco Porsch } else if (ieee80211_vif_is_mesh(&tx->sdata->vif)) {
4173f52b7e3SMarco Porsch ps = &tx->sdata->u.mesh.ps;
418d012a605SMarco Porsch } else {
419d012a605SMarco Porsch return TX_CONTINUE;
420d012a605SMarco Porsch }
421d012a605SMarco Porsch
422d012a605SMarco Porsch
4233e122be0SJohannes Berg /* no buffering for ordered frames */
424358c8d9dSHarvey Harrison if (ieee80211_has_order(hdr->frame_control))
4259ae54c84SJohannes Berg return TX_CONTINUE;
4267d54d0ddSJohannes Berg
42708b99399SJohannes Berg if (ieee80211_is_probe_req(hdr->frame_control))
42808b99399SJohannes Berg return TX_CONTINUE;
42908b99399SJohannes Berg
43030686bf7SJohannes Berg if (ieee80211_hw_check(&tx->local->hw, QUEUE_CONTROL))
431f4d57941SJohannes Berg info->hw_queue = tx->sdata->vif.cab_queue;
432f4d57941SJohannes Berg
4339ec1190dSFelix Fietkau /* no stations in PS mode and no buffered packets */
4349ec1190dSFelix Fietkau if (!atomic_read(&ps->num_sta_ps) && skb_queue_empty(&ps->bc_buf))
4359ae54c84SJohannes Berg return TX_CONTINUE;
4367d54d0ddSJohannes Berg
43762b1208eSJohannes Berg info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
43862b1208eSJohannes Berg
43962b517cbSJohannes Berg /* device releases frame after DTIM beacon */
44030686bf7SJohannes Berg if (!ieee80211_hw_check(&tx->local->hw, HOST_BROADCAST_PS_BUFFERING))
44162b1208eSJohannes Berg return TX_CONTINUE;
44262b1208eSJohannes Berg
4437d54d0ddSJohannes Berg /* buffered in mac80211 */
444e2ebc74dSJohannes Berg if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
445e2ebc74dSJohannes Berg purge_old_ps_buffers(tx->local);
44662b1208eSJohannes Berg
447d012a605SMarco Porsch if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) {
448bdcbd8e0SJohannes Berg ps_dbg(tx->sdata,
449bdcbd8e0SJohannes Berg "BC TX buffer full - dropping the oldest frame\n");
4506b07d9caSFelix Fietkau ieee80211_free_txskb(&tx->local->hw, skb_dequeue(&ps->bc_buf));
451e2ebc74dSJohannes Berg } else
452e2ebc74dSJohannes Berg tx->local->total_ps_buffered++;
45362b1208eSJohannes Berg
454d012a605SMarco Porsch skb_queue_tail(&ps->bc_buf, tx->skb);
45562b1208eSJohannes Berg
4569ae54c84SJohannes Berg return TX_QUEUED;
457e2ebc74dSJohannes Berg }
458e2ebc74dSJohannes Berg
ieee80211_use_mfp(__le16 fc,struct sta_info * sta,struct sk_buff * skb)459fb733336SJouni Malinen static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
460fb733336SJouni Malinen struct sk_buff *skb)
461fb733336SJouni Malinen {
462fb733336SJouni Malinen if (!ieee80211_is_mgmt(fc))
463fb733336SJouni Malinen return 0;
464fb733336SJouni Malinen
465c2c98fdeSJohannes Berg if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
466fb733336SJouni Malinen return 0;
467fb733336SJouni Malinen
468d8ca16dbSJohannes Berg if (!ieee80211_is_robust_mgmt_frame(skb))
469fb733336SJouni Malinen return 0;
470fb733336SJouni Malinen
471fb733336SJouni Malinen return 1;
472fb733336SJouni Malinen }
473fb733336SJouni Malinen
4749ae54c84SJohannes Berg static ieee80211_tx_result
ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data * tx)4755cf121c3SJohannes Berg ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
476e2ebc74dSJohannes Berg {
477e2ebc74dSJohannes Berg struct sta_info *sta = tx->sta;
478e039fa4aSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
47908b99399SJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
4803393a608SJuuso Oikarinen struct ieee80211_local *local = tx->local;
481e2ebc74dSJohannes Berg
48202f2f1a9SJohannes Berg if (unlikely(!sta))
4839ae54c84SJohannes Berg return TX_CONTINUE;
484e2ebc74dSJohannes Berg
485c2c98fdeSJohannes Berg if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
4865ac2e350SJohannes Berg test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
4875ac2e350SJohannes Berg test_sta_flag(sta, WLAN_STA_PS_DELIVER)) &&
48802f2f1a9SJohannes Berg !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
489948d887dSJohannes Berg int ac = skb_get_queue_mapping(tx->skb);
490948d887dSJohannes Berg
49108b99399SJohannes Berg if (ieee80211_is_mgmt(hdr->frame_control) &&
4922c9abe65SJohannes Berg !ieee80211_is_bufferable_mmpdu(tx->skb)) {
49308b99399SJohannes Berg info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
49408b99399SJohannes Berg return TX_CONTINUE;
49508b99399SJohannes Berg }
49608b99399SJohannes Berg
497bdcbd8e0SJohannes Berg ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n",
498948d887dSJohannes Berg sta->sta.addr, sta->sta.aid, ac);
499e2ebc74dSJohannes Berg if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
500e2ebc74dSJohannes Berg purge_old_ps_buffers(tx->local);
5011d147bfaSEmmanuel Grumbach
5021d147bfaSEmmanuel Grumbach /* sync with ieee80211_sta_ps_deliver_wakeup */
5031d147bfaSEmmanuel Grumbach spin_lock(&sta->ps_lock);
5041d147bfaSEmmanuel Grumbach /*
5051d147bfaSEmmanuel Grumbach * STA woke up the meantime and all the frames on ps_tx_buf have
5061d147bfaSEmmanuel Grumbach * been queued to pending queue. No reordering can happen, go
5071d147bfaSEmmanuel Grumbach * ahead and Tx the packet.
5081d147bfaSEmmanuel Grumbach */
5091d147bfaSEmmanuel Grumbach if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
5105ac2e350SJohannes Berg !test_sta_flag(sta, WLAN_STA_PS_DRIVER) &&
5115ac2e350SJohannes Berg !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
5121d147bfaSEmmanuel Grumbach spin_unlock(&sta->ps_lock);
5131d147bfaSEmmanuel Grumbach return TX_CONTINUE;
5141d147bfaSEmmanuel Grumbach }
5151d147bfaSEmmanuel Grumbach
516948d887dSJohannes Berg if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
517948d887dSJohannes Berg struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
518bdcbd8e0SJohannes Berg ps_dbg(tx->sdata,
519bdcbd8e0SJohannes Berg "STA %pM TX buffer for AC %d full - dropping oldest frame\n",
520bdcbd8e0SJohannes Berg sta->sta.addr, ac);
521c3e7724bSFelix Fietkau ieee80211_free_txskb(&local->hw, old);
522e2ebc74dSJohannes Berg } else
523e2ebc74dSJohannes Berg tx->local->total_ps_buffered++;
524004c872eSJohannes Berg
525e039fa4aSJohannes Berg info->control.jiffies = jiffies;
5265061b0c2SJohannes Berg info->control.vif = &tx->sdata->vif;
527cc20ff2cSFelix Fietkau info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
52803c8c06fSJohannes Berg info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
529948d887dSJohannes Berg skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
5301d147bfaSEmmanuel Grumbach spin_unlock(&sta->ps_lock);
5313393a608SJuuso Oikarinen
5323393a608SJuuso Oikarinen if (!timer_pending(&local->sta_cleanup))
5333393a608SJuuso Oikarinen mod_timer(&local->sta_cleanup,
5343393a608SJuuso Oikarinen round_jiffies(jiffies +
5353393a608SJuuso Oikarinen STA_INFO_CLEANUP_INTERVAL));
5363393a608SJuuso Oikarinen
537c868cb35SJohannes Berg /*
538c868cb35SJohannes Berg * We queued up some frames, so the TIM bit might
539c868cb35SJohannes Berg * need to be set, recalculate it.
540c868cb35SJohannes Berg */
541c868cb35SJohannes Berg sta_info_recalc_tim(sta);
542c868cb35SJohannes Berg
5439ae54c84SJohannes Berg return TX_QUEUED;
544bdcbd8e0SJohannes Berg } else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
545bdcbd8e0SJohannes Berg ps_dbg(tx->sdata,
546bdcbd8e0SJohannes Berg "STA %pM in PS mode, but polling/in SP -> send frame\n",
547bdcbd8e0SJohannes Berg sta->sta.addr);
548e2ebc74dSJohannes Berg }
549e2ebc74dSJohannes Berg
5509ae54c84SJohannes Berg return TX_CONTINUE;
551e2ebc74dSJohannes Berg }
552e2ebc74dSJohannes Berg
553d9e8a70fSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_ps_buf(struct ieee80211_tx_data * tx)5545cf121c3SJohannes Berg ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
555e2ebc74dSJohannes Berg {
5565cf121c3SJohannes Berg if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
5579ae54c84SJohannes Berg return TX_CONTINUE;
558e2ebc74dSJohannes Berg
5595cf121c3SJohannes Berg if (tx->flags & IEEE80211_TX_UNICAST)
560e2ebc74dSJohannes Berg return ieee80211_tx_h_unicast_ps_buf(tx);
561e2ebc74dSJohannes Berg else
562e2ebc74dSJohannes Berg return ieee80211_tx_h_multicast_ps_buf(tx);
563e2ebc74dSJohannes Berg }
564e2ebc74dSJohannes Berg
565d9e8a70fSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data * tx)566a621fa4dSJohannes Berg ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
567a621fa4dSJohannes Berg {
568a621fa4dSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
569a621fa4dSJohannes Berg
570af61a165SJohannes Berg if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol)) {
571af61a165SJohannes Berg if (tx->sdata->control_port_no_encrypt)
572a621fa4dSJohannes Berg info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
573af61a165SJohannes Berg info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
5749c1c98a3SJouni Malinen info->flags |= IEEE80211_TX_CTL_USE_MINRATE;
575af61a165SJohannes Berg }
576a621fa4dSJohannes Berg
577a621fa4dSJohannes Berg return TX_CONTINUE;
578a621fa4dSJohannes Berg }
579a621fa4dSJohannes Berg
580ccdde7c7SJohannes Berg static struct ieee80211_key *
ieee80211_select_link_key(struct ieee80211_tx_data * tx)581ccdde7c7SJohannes Berg ieee80211_select_link_key(struct ieee80211_tx_data *tx)
582ccdde7c7SJohannes Berg {
583ccdde7c7SJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
584ccdde7c7SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
585ccdde7c7SJohannes Berg struct ieee80211_link_data *link;
586ccdde7c7SJohannes Berg unsigned int link_id;
587ccdde7c7SJohannes Berg
588ccdde7c7SJohannes Berg link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK);
589ccdde7c7SJohannes Berg if (link_id == IEEE80211_LINK_UNSPECIFIED) {
590ccdde7c7SJohannes Berg link = &tx->sdata->deflink;
591ccdde7c7SJohannes Berg } else {
592ccdde7c7SJohannes Berg link = rcu_dereference(tx->sdata->link[link_id]);
593ccdde7c7SJohannes Berg if (!link)
594ccdde7c7SJohannes Berg return NULL;
595ccdde7c7SJohannes Berg }
596ccdde7c7SJohannes Berg
5971d10575bSMukesh Sisodiya if (ieee80211_is_group_privacy_action(tx->skb))
598ccdde7c7SJohannes Berg return rcu_dereference(link->default_multicast_key);
5991d10575bSMukesh Sisodiya else if (ieee80211_is_mgmt(hdr->frame_control) &&
6001d10575bSMukesh Sisodiya is_multicast_ether_addr(hdr->addr1) &&
6011d10575bSMukesh Sisodiya ieee80211_is_robust_mgmt_frame(tx->skb))
6021d10575bSMukesh Sisodiya return rcu_dereference(link->default_mgmt_key);
6031d10575bSMukesh Sisodiya else if (is_multicast_ether_addr(hdr->addr1))
6041d10575bSMukesh Sisodiya return rcu_dereference(link->default_multicast_key);
605ccdde7c7SJohannes Berg
606ccdde7c7SJohannes Berg return NULL;
607ccdde7c7SJohannes Berg }
608ccdde7c7SJohannes Berg
609a621fa4dSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_select_key(struct ieee80211_tx_data * tx)6105cf121c3SJohannes Berg ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
611e2ebc74dSJohannes Berg {
61246e6de15SJohannes Berg struct ieee80211_key *key;
613e039fa4aSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
614358c8d9dSHarvey Harrison struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
615d4e46a3dSJohannes Berg
616a0761a30SJohannes Berg if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) {
617e2ebc74dSJohannes Berg tx->key = NULL;
618a0761a30SJohannes Berg return TX_CONTINUE;
619a0761a30SJohannes Berg }
620a0761a30SJohannes Berg
621a0761a30SJohannes Berg if (tx->sta &&
6222475b1ccSMax Stepanov (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
623d4e46a3dSJohannes Berg tx->key = key;
624ccdde7c7SJohannes Berg else if ((key = ieee80211_select_link_key(tx)))
625f7e0104cSJohannes Berg tx->key = key;
626f7e0104cSJohannes Berg else if (!is_multicast_ether_addr(hdr->addr1) &&
627f7e0104cSJohannes Berg (key = rcu_dereference(tx->sdata->default_unicast_key)))
628d4e46a3dSJohannes Berg tx->key = key;
629e8f4fb7cSJohannes Berg else
63046e6de15SJohannes Berg tx->key = NULL;
631e2ebc74dSJohannes Berg
632e2ebc74dSJohannes Berg if (tx->key) {
633813d7669SJohannes Berg bool skip_hw = false;
634813d7669SJohannes Berg
635011bfcc4SJohannes Berg /* TODO: add threshold stuff again */
636176e4f84SJohannes Berg
63797359d12SJohannes Berg switch (tx->key->conf.cipher) {
63897359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP40:
63997359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP104:
64097359d12SJohannes Berg case WLAN_CIPHER_SUITE_TKIP:
641358c8d9dSHarvey Harrison if (!ieee80211_is_data_present(hdr->frame_control))
642176e4f84SJohannes Berg tx->key = NULL;
643176e4f84SJohannes Berg break;
64497359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP:
6452b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256:
64600b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP:
64700b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256:
648fb733336SJouni Malinen if (!ieee80211_is_data_present(hdr->frame_control) &&
649fb733336SJouni Malinen !ieee80211_use_mfp(hdr->frame_control, tx->sta,
65046f6b060SMasashi Honma tx->skb) &&
65146f6b060SMasashi Honma !ieee80211_is_group_privacy_action(tx->skb))
652fb733336SJouni Malinen tx->key = NULL;
6533b43a187SKalle Valo else
654813d7669SJohannes Berg skip_hw = (tx->key->conf.flags &
655e548c49eSJohannes Berg IEEE80211_KEY_FLAG_SW_MGMT_TX) &&
656813d7669SJohannes Berg ieee80211_is_mgmt(hdr->frame_control);
657fb733336SJouni Malinen break;
65897359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC:
65956c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256:
6608ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128:
6618ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256:
6623cfcf6acSJouni Malinen if (!ieee80211_is_mgmt(hdr->frame_control))
6633cfcf6acSJouni Malinen tx->key = NULL;
6643cfcf6acSJouni Malinen break;
665e2ebc74dSJohannes Berg }
666813d7669SJohannes Berg
667e54faf29SJohannes Berg if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED &&
66861304336SWen Gong !ieee80211_is_deauth(hdr->frame_control)) &&
66961304336SWen Gong tx->skb->protocol != tx->sdata->control_port_protocol)
67095acac61SJohannes Berg return TX_DROP;
67195acac61SJohannes Berg
672f12553ebSJohannes Berg if (!skip_hw && tx->key &&
673382b1655SJohannes Berg tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
674813d7669SJohannes Berg info->control.hw_key = &tx->key->conf;
6752463ec86SFelix Fietkau } else if (ieee80211_is_data_present(hdr->frame_control) && tx->sta &&
676a0761a30SJohannes Berg test_sta_flag(tx->sta, WLAN_STA_USES_ENCRYPTION)) {
677a0761a30SJohannes Berg return TX_DROP;
678176e4f84SJohannes Berg }
679176e4f84SJohannes Berg
6809ae54c84SJohannes Berg return TX_CONTINUE;
681e2ebc74dSJohannes Berg }
682e2ebc74dSJohannes Berg
683d9e8a70fSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data * tx)6845cf121c3SJohannes Berg ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
685e2ebc74dSJohannes Berg {
686e039fa4aSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
687e6a9854bSJohannes Berg struct ieee80211_hdr *hdr = (void *)tx->skb->data;
688e6a9854bSJohannes Berg struct ieee80211_supported_band *sband;
689a2c40249SShanyu Zhao u32 len;
690e6a9854bSJohannes Berg struct ieee80211_tx_rate_control txrc;
6910d528d85SFelix Fietkau struct ieee80211_sta_rates *ratetbl = NULL;
6923187ba0cSRyder Lee bool encap = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
693c2c98fdeSJohannes Berg bool assoc = false;
694e6a9854bSJohannes Berg
695e6a9854bSJohannes Berg memset(&txrc, 0, sizeof(txrc));
6968318d78aSJohannes Berg
6972d56577bSJohannes Berg sband = tx->local->hw.wiphy->bands[info->band];
698e2ebc74dSJohannes Berg
699a2c40249SShanyu Zhao len = min_t(u32, tx->skb->len + FCS_LEN,
700b9a5f8caSJouni Malinen tx->local->hw.wiphy->frag_threshold);
70158d4185eSJohannes Berg
702e6a9854bSJohannes Berg /* set up the tx rate control struct we give the RC algo */
703005e472bSJohannes Berg txrc.hw = &tx->local->hw;
704e6a9854bSJohannes Berg txrc.sband = sband;
705e6a9854bSJohannes Berg txrc.bss_conf = &tx->sdata->vif.bss_conf;
706e6a9854bSJohannes Berg txrc.skb = tx->skb;
707e6a9854bSJohannes Berg txrc.reported_rate.idx = -1;
7080cfadb49SJohannes Berg
709*d54455a3SPing-Ke Shih if (unlikely(info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)) {
7100cfadb49SJohannes Berg txrc.rate_idx_mask = ~0;
7110cfadb49SJohannes Berg } else {
7122d56577bSJohannes Berg txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band];
7132ffbe6d3SFelix Fietkau
7142ffbe6d3SFelix Fietkau if (tx->sdata->rc_has_mcs_mask[info->band])
7152ffbe6d3SFelix Fietkau txrc.rate_idx_mcs_mask =
7162ffbe6d3SFelix Fietkau tx->sdata->rc_rateidx_mcs_mask[info->band];
7170cfadb49SJohannes Berg }
7182ffbe6d3SFelix Fietkau
7198f0729b1SFelix Fietkau txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
7204bb62344SChun-Yeow Yeoh tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
7215765f9f6SBertold Van den Bergh tx->sdata->vif.type == NL80211_IFTYPE_ADHOC ||
7225765f9f6SBertold Van den Bergh tx->sdata->vif.type == NL80211_IFTYPE_OCB);
72358d4185eSJohannes Berg
724e6a9854bSJohannes Berg /* set up RTS protection if desired */
725b9a5f8caSJouni Malinen if (len > tx->local->hw.wiphy->rts_threshold) {
7260d528d85SFelix Fietkau txrc.rts = true;
727e2ebc74dSJohannes Berg }
728e6a9854bSJohannes Berg
7290d528d85SFelix Fietkau info->control.use_rts = txrc.rts;
730991fec09SFelix Fietkau info->control.use_cts_prot = tx->sdata->vif.bss_conf.use_cts_prot;
731991fec09SFelix Fietkau
732e6a9854bSJohannes Berg /*
733e6a9854bSJohannes Berg * Use short preamble if the BSS can handle it, but not for
734e6a9854bSJohannes Berg * management frames unless we know the receiver can handle
735e6a9854bSJohannes Berg * that -- the management frame might be to a station that
736e6a9854bSJohannes Berg * just wants a probe response.
737e6a9854bSJohannes Berg */
738e6a9854bSJohannes Berg if (tx->sdata->vif.bss_conf.use_short_preamble &&
7393187ba0cSRyder Lee (ieee80211_is_tx_data(tx->skb) ||
740c2c98fdeSJohannes Berg (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
7410d528d85SFelix Fietkau txrc.short_preamble = true;
7420d528d85SFelix Fietkau
7430d528d85SFelix Fietkau info->control.short_preamble = txrc.short_preamble;
744e6a9854bSJohannes Berg
745dfdfc2beSSven Eckelmann /* don't ask rate control when rate already injected via radiotap */
746dfdfc2beSSven Eckelmann if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)
747dfdfc2beSSven Eckelmann return TX_CONTINUE;
748dfdfc2beSSven Eckelmann
749c2c98fdeSJohannes Berg if (tx->sta)
750c2c98fdeSJohannes Berg assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
751e6a9854bSJohannes Berg
752b770b43eSLuis R. Rodriguez /*
753b770b43eSLuis R. Rodriguez * Lets not bother rate control if we're associated and cannot
754b770b43eSLuis R. Rodriguez * talk to the sta. This should not happen.
755b770b43eSLuis R. Rodriguez */
756c2c98fdeSJohannes Berg if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
757b770b43eSLuis R. Rodriguez !rate_usable_index_exists(sband, &tx->sta->sta),
758b770b43eSLuis R. Rodriguez "%s: Dropped data frame as no usable bitrate found while "
759b770b43eSLuis R. Rodriguez "scanning and associated. Target station: "
760b770b43eSLuis R. Rodriguez "%pM on %d GHz band\n",
7613187ba0cSRyder Lee tx->sdata->name,
7623187ba0cSRyder Lee encap ? ((struct ethhdr *)hdr)->h_dest : hdr->addr1,
7632d56577bSJohannes Berg info->band ? 5 : 2))
764b770b43eSLuis R. Rodriguez return TX_DROP;
765b770b43eSLuis R. Rodriguez
766b770b43eSLuis R. Rodriguez /*
767b770b43eSLuis R. Rodriguez * If we're associated with the sta at this point we know we can at
768b770b43eSLuis R. Rodriguez * least send the frame at the lowest bit rate.
769b770b43eSLuis R. Rodriguez */
770e6a9854bSJohannes Berg rate_control_get_rate(tx->sdata, tx->sta, &txrc);
771e6a9854bSJohannes Berg
7720d528d85SFelix Fietkau if (tx->sta && !info->control.skip_table)
7730d528d85SFelix Fietkau ratetbl = rcu_dereference(tx->sta->sta.rates);
7740d528d85SFelix Fietkau
7750d528d85SFelix Fietkau if (unlikely(info->control.rates[0].idx < 0)) {
7760d528d85SFelix Fietkau if (ratetbl) {
7770d528d85SFelix Fietkau struct ieee80211_tx_rate rate = {
7780d528d85SFelix Fietkau .idx = ratetbl->rate[0].idx,
7790d528d85SFelix Fietkau .flags = ratetbl->rate[0].flags,
7800d528d85SFelix Fietkau .count = ratetbl->rate[0].count
7810d528d85SFelix Fietkau };
7820d528d85SFelix Fietkau
7830d528d85SFelix Fietkau if (ratetbl->rate[0].idx < 0)
784e6a9854bSJohannes Berg return TX_DROP;
785e6a9854bSJohannes Berg
7860d528d85SFelix Fietkau tx->rate = rate;
7870d528d85SFelix Fietkau } else {
7880d528d85SFelix Fietkau return TX_DROP;
7890d528d85SFelix Fietkau }
7900d528d85SFelix Fietkau } else {
7910d528d85SFelix Fietkau tx->rate = info->control.rates[0];
7920d528d85SFelix Fietkau }
7930d528d85SFelix Fietkau
794c1ce5a74SHelmut Schaa if (txrc.reported_rate.idx < 0) {
7950d528d85SFelix Fietkau txrc.reported_rate = tx->rate;
7963187ba0cSRyder Lee if (tx->sta && ieee80211_is_tx_data(tx->skb))
797046d2e7cSSriram R tx->sta->deflink.tx_stats.last_rate = txrc.reported_rate;
798c1ce5a74SHelmut Schaa } else if (tx->sta)
799046d2e7cSSriram R tx->sta->deflink.tx_stats.last_rate = txrc.reported_rate;
800e6a9854bSJohannes Berg
8010d528d85SFelix Fietkau if (ratetbl)
8020d528d85SFelix Fietkau return TX_CONTINUE;
8030d528d85SFelix Fietkau
804e6a9854bSJohannes Berg if (unlikely(!info->control.rates[0].count))
805e6a9854bSJohannes Berg info->control.rates[0].count = 1;
806e6a9854bSJohannes Berg
8079955151dSGábor Stefanik if (WARN_ON_ONCE((info->control.rates[0].count > 1) &&
8089955151dSGábor Stefanik (info->flags & IEEE80211_TX_CTL_NO_ACK)))
8099955151dSGábor Stefanik info->control.rates[0].count = 1;
8109955151dSGábor Stefanik
8119ae54c84SJohannes Berg return TX_CONTINUE;
812e2ebc74dSJohannes Berg }
813e2ebc74dSJohannes Berg
ieee80211_tx_next_seq(struct sta_info * sta,int tid)814ba8c3d6fSFelix Fietkau static __le16 ieee80211_tx_next_seq(struct sta_info *sta, int tid)
815ba8c3d6fSFelix Fietkau {
816ba8c3d6fSFelix Fietkau u16 *seq = &sta->tid_seq[tid];
817ba8c3d6fSFelix Fietkau __le16 ret = cpu_to_le16(*seq);
818ba8c3d6fSFelix Fietkau
819ba8c3d6fSFelix Fietkau /* Increase the sequence number. */
820ba8c3d6fSFelix Fietkau *seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ;
821ba8c3d6fSFelix Fietkau
822ba8c3d6fSFelix Fietkau return ret;
823ba8c3d6fSFelix Fietkau }
824ba8c3d6fSFelix Fietkau
825d9e8a70fSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_sequence(struct ieee80211_tx_data * tx)826f591fa5dSJohannes Berg ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
827f591fa5dSJohannes Berg {
828f591fa5dSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
829f591fa5dSJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
830f591fa5dSJohannes Berg int tid;
831f591fa5dSJohannes Berg
83225d834e1SJohannes Berg /*
83325d834e1SJohannes Berg * Packet injection may want to control the sequence
83425d834e1SJohannes Berg * number, if we have no matching interface then we
83525d834e1SJohannes Berg * neither assign one ourselves nor ask the driver to.
83625d834e1SJohannes Berg */
8375061b0c2SJohannes Berg if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR))
83825d834e1SJohannes Berg return TX_CONTINUE;
83925d834e1SJohannes Berg
840f591fa5dSJohannes Berg if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
841f591fa5dSJohannes Berg return TX_CONTINUE;
842f591fa5dSJohannes Berg
843f591fa5dSJohannes Berg if (ieee80211_hdrlen(hdr->frame_control) < 24)
844f591fa5dSJohannes Berg return TX_CONTINUE;
845f591fa5dSJohannes Berg
84649a59543SJohannes Berg if (ieee80211_is_qos_nullfunc(hdr->frame_control))
84749a59543SJohannes Berg return TX_CONTINUE;
84849a59543SJohannes Berg
84929c3e95fSMathy Vanhoef if (info->control.flags & IEEE80211_TX_CTRL_NO_SEQNO)
85029c3e95fSMathy Vanhoef return TX_CONTINUE;
85129c3e95fSMathy Vanhoef
852963d0e8dSJohannes Berg /* SNS11 from 802.11be 10.3.2.14 */
853963d0e8dSJohannes Berg if (unlikely(is_multicast_ether_addr(hdr->addr1) &&
854f1871abdSIlan Peer ieee80211_vif_is_mld(info->control.vif) &&
855963d0e8dSJohannes Berg info->control.vif->type == NL80211_IFTYPE_AP)) {
856963d0e8dSJohannes Berg if (info->control.flags & IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX)
857963d0e8dSJohannes Berg tx->sdata->mld_mcast_seq += 0x10;
858963d0e8dSJohannes Berg hdr->seq_ctrl = cpu_to_le16(tx->sdata->mld_mcast_seq);
859963d0e8dSJohannes Berg return TX_CONTINUE;
860963d0e8dSJohannes Berg }
861963d0e8dSJohannes Berg
86294778280SJohannes Berg /*
86394778280SJohannes Berg * Anything but QoS data that has a sequence number field
86494778280SJohannes Berg * (is long enough) gets a sequence number from the global
865c4c205f3SBob Copeland * counter. QoS data frames with a multicast destination
866c4c205f3SBob Copeland * also use the global counter (802.11-2012 9.3.2.10).
86794778280SJohannes Berg */
868c4c205f3SBob Copeland if (!ieee80211_is_data_qos(hdr->frame_control) ||
869c4c205f3SBob Copeland is_multicast_ether_addr(hdr->addr1)) {
87094778280SJohannes Berg /* driver should assign sequence number */
871f591fa5dSJohannes Berg info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
87294778280SJohannes Berg /* for pure STA mode without beacons, we can do it */
87394778280SJohannes Berg hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
87494778280SJohannes Berg tx->sdata->sequence_number += 0x10;
87579c892b8SJohannes Berg if (tx->sta)
876046d2e7cSSriram R tx->sta->deflink.tx_stats.msdu[IEEE80211_NUM_TIDS]++;
877f591fa5dSJohannes Berg return TX_CONTINUE;
878f591fa5dSJohannes Berg }
879f591fa5dSJohannes Berg
880f591fa5dSJohannes Berg /*
881f591fa5dSJohannes Berg * This should be true for injected/management frames only, for
882f591fa5dSJohannes Berg * management frames we have set the IEEE80211_TX_CTL_ASSIGN_SEQ
883f591fa5dSJohannes Berg * above since they are not QoS-data frames.
884f591fa5dSJohannes Berg */
885f591fa5dSJohannes Berg if (!tx->sta)
886f591fa5dSJohannes Berg return TX_CONTINUE;
887f591fa5dSJohannes Berg
888f591fa5dSJohannes Berg /* include per-STA, per-TID sequence counter */
889a1f2ba04SSara Sharon tid = ieee80211_get_tid(hdr);
890046d2e7cSSriram R tx->sta->deflink.tx_stats.msdu[tid]++;
891f591fa5dSJohannes Berg
892ba8c3d6fSFelix Fietkau hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid);
893f591fa5dSJohannes Berg
894f591fa5dSJohannes Berg return TX_CONTINUE;
895f591fa5dSJohannes Berg }
896f591fa5dSJohannes Berg
ieee80211_fragment(struct ieee80211_tx_data * tx,struct sk_buff * skb,int hdrlen,int frag_threshold)897252b86c4SJohannes Berg static int ieee80211_fragment(struct ieee80211_tx_data *tx,
8982de8e0d9SJohannes Berg struct sk_buff *skb, int hdrlen,
8992de8e0d9SJohannes Berg int frag_threshold)
9002de8e0d9SJohannes Berg {
901252b86c4SJohannes Berg struct ieee80211_local *local = tx->local;
902a1a3fcecSJohannes Berg struct ieee80211_tx_info *info;
903252b86c4SJohannes Berg struct sk_buff *tmp;
9042de8e0d9SJohannes Berg int per_fragm = frag_threshold - hdrlen - FCS_LEN;
9052de8e0d9SJohannes Berg int pos = hdrlen + per_fragm;
9062de8e0d9SJohannes Berg int rem = skb->len - hdrlen - per_fragm;
9072de8e0d9SJohannes Berg
9082de8e0d9SJohannes Berg if (WARN_ON(rem < 0))
9092de8e0d9SJohannes Berg return -EINVAL;
9102de8e0d9SJohannes Berg
911252b86c4SJohannes Berg /* first fragment was already added to queue by caller */
912252b86c4SJohannes Berg
9132de8e0d9SJohannes Berg while (rem) {
9142de8e0d9SJohannes Berg int fraglen = per_fragm;
9152de8e0d9SJohannes Berg
9162de8e0d9SJohannes Berg if (fraglen > rem)
9172de8e0d9SJohannes Berg fraglen = rem;
9182de8e0d9SJohannes Berg rem -= fraglen;
9192de8e0d9SJohannes Berg tmp = dev_alloc_skb(local->tx_headroom +
9202de8e0d9SJohannes Berg frag_threshold +
92123a5f0afSJohannes Berg IEEE80211_ENCRYPT_HEADROOM +
9222de8e0d9SJohannes Berg IEEE80211_ENCRYPT_TAILROOM);
9232de8e0d9SJohannes Berg if (!tmp)
9242de8e0d9SJohannes Berg return -ENOMEM;
925252b86c4SJohannes Berg
926252b86c4SJohannes Berg __skb_queue_tail(&tx->skbs, tmp);
927252b86c4SJohannes Berg
9282475b1ccSMax Stepanov skb_reserve(tmp,
92923a5f0afSJohannes Berg local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);
9302475b1ccSMax Stepanov
9312de8e0d9SJohannes Berg /* copy control information */
9322de8e0d9SJohannes Berg memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
933a1a3fcecSJohannes Berg
934a1a3fcecSJohannes Berg info = IEEE80211_SKB_CB(tmp);
935a1a3fcecSJohannes Berg info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
936a1a3fcecSJohannes Berg IEEE80211_TX_CTL_FIRST_FRAGMENT);
937a1a3fcecSJohannes Berg
938a1a3fcecSJohannes Berg if (rem)
939a1a3fcecSJohannes Berg info->flags |= IEEE80211_TX_CTL_MORE_FRAMES;
940a1a3fcecSJohannes Berg
9412de8e0d9SJohannes Berg skb_copy_queue_mapping(tmp, skb);
9422de8e0d9SJohannes Berg tmp->priority = skb->priority;
9432de8e0d9SJohannes Berg tmp->dev = skb->dev;
9442de8e0d9SJohannes Berg
9452de8e0d9SJohannes Berg /* copy header and data */
94659ae1d12SJohannes Berg skb_put_data(tmp, skb->data, hdrlen);
94759ae1d12SJohannes Berg skb_put_data(tmp, skb->data + pos, fraglen);
9482de8e0d9SJohannes Berg
9492de8e0d9SJohannes Berg pos += fraglen;
9502de8e0d9SJohannes Berg }
9512de8e0d9SJohannes Berg
952252b86c4SJohannes Berg /* adjust first fragment's length */
953338f977fSJohannes Berg skb_trim(skb, hdrlen + per_fragm);
9542de8e0d9SJohannes Berg return 0;
9552de8e0d9SJohannes Berg }
9562de8e0d9SJohannes Berg
957f591fa5dSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_fragment(struct ieee80211_tx_data * tx)958e2454948SJohannes Berg ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
959e2454948SJohannes Berg {
9602de8e0d9SJohannes Berg struct sk_buff *skb = tx->skb;
9612de8e0d9SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
9622de8e0d9SJohannes Berg struct ieee80211_hdr *hdr = (void *)skb->data;
963b9a5f8caSJouni Malinen int frag_threshold = tx->local->hw.wiphy->frag_threshold;
9642de8e0d9SJohannes Berg int hdrlen;
9652de8e0d9SJohannes Berg int fragnum;
966e2454948SJohannes Berg
967252b86c4SJohannes Berg /* no matter what happens, tx->skb moves to tx->skbs */
968252b86c4SJohannes Berg __skb_queue_tail(&tx->skbs, skb);
969252b86c4SJohannes Berg tx->skb = NULL;
970252b86c4SJohannes Berg
971a26eb27aSJohannes Berg if (info->flags & IEEE80211_TX_CTL_DONTFRAG)
972a26eb27aSJohannes Berg return TX_CONTINUE;
973a26eb27aSJohannes Berg
974f3fe4e93SSara Sharon if (ieee80211_hw_check(&tx->local->hw, SUPPORTS_TX_FRAG))
975e2454948SJohannes Berg return TX_CONTINUE;
976e2454948SJohannes Berg
977eefce91aSJohannes Berg /*
978eefce91aSJohannes Berg * Warn when submitting a fragmented A-MPDU frame and drop it.
9793b8d81e0SJohannes Berg * This scenario is handled in ieee80211_tx_prepare but extra
9808d5e0d58SRon Rindjunsky * caution taken here as fragmented ampdu may cause Tx stop.
981eefce91aSJohannes Berg */
9828b30b1feSSujith if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
983eefce91aSJohannes Berg return TX_DROP;
984eefce91aSJohannes Berg
985065e9605SHarvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control);
986e2454948SJohannes Berg
987a26eb27aSJohannes Berg /* internal error, why isn't DONTFRAG set? */
9888ccd8f21SJohannes Berg if (WARN_ON(skb->len + FCS_LEN <= frag_threshold))
9892de8e0d9SJohannes Berg return TX_DROP;
990e2454948SJohannes Berg
9912de8e0d9SJohannes Berg /*
9922de8e0d9SJohannes Berg * Now fragment the frame. This will allocate all the fragments and
9932de8e0d9SJohannes Berg * chain them (using skb as the first fragment) to skb->next.
9942de8e0d9SJohannes Berg * During transmission, we will remove the successfully transmitted
9952de8e0d9SJohannes Berg * fragments from this list. When the low-level driver rejects one
9962de8e0d9SJohannes Berg * of the fragments then we will simply pretend to accept the skb
9972de8e0d9SJohannes Berg * but store it away as pending.
9982de8e0d9SJohannes Berg */
999252b86c4SJohannes Berg if (ieee80211_fragment(tx, skb, hdrlen, frag_threshold))
10002de8e0d9SJohannes Berg return TX_DROP;
1001e2454948SJohannes Berg
10022de8e0d9SJohannes Berg /* update duration/seq/flags of fragments */
10032de8e0d9SJohannes Berg fragnum = 0;
1004252b86c4SJohannes Berg
1005252b86c4SJohannes Berg skb_queue_walk(&tx->skbs, skb) {
10062de8e0d9SJohannes Berg const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
1007e2454948SJohannes Berg
10082de8e0d9SJohannes Berg hdr = (void *)skb->data;
10092de8e0d9SJohannes Berg info = IEEE80211_SKB_CB(skb);
1010e6a9854bSJohannes Berg
1011252b86c4SJohannes Berg if (!skb_queue_is_last(&tx->skbs, skb)) {
10122de8e0d9SJohannes Berg hdr->frame_control |= morefrags;
1013e6a9854bSJohannes Berg /*
1014e6a9854bSJohannes Berg * No multi-rate retries for fragmented frames, that
1015e6a9854bSJohannes Berg * would completely throw off the NAV at other STAs.
1016e6a9854bSJohannes Berg */
1017e6a9854bSJohannes Berg info->control.rates[1].idx = -1;
1018e6a9854bSJohannes Berg info->control.rates[2].idx = -1;
1019e6a9854bSJohannes Berg info->control.rates[3].idx = -1;
1020e3e1a0bcSThomas Huehn BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4);
1021e6a9854bSJohannes Berg info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
10222de8e0d9SJohannes Berg } else {
10232de8e0d9SJohannes Berg hdr->frame_control &= ~morefrags;
1024e6a9854bSJohannes Berg }
10252de8e0d9SJohannes Berg hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG);
10262de8e0d9SJohannes Berg fragnum++;
1027252b86c4SJohannes Berg }
1028e2454948SJohannes Berg
1029e2454948SJohannes Berg return TX_CONTINUE;
1030e2454948SJohannes Berg }
1031e2454948SJohannes Berg
1032d9e8a70fSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_stats(struct ieee80211_tx_data * tx)1033feff1f2fSJohannes Berg ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
1034feff1f2fSJohannes Berg {
1035252b86c4SJohannes Berg struct sk_buff *skb;
1036560d2682SJohannes Berg int ac = -1;
1037feff1f2fSJohannes Berg
1038feff1f2fSJohannes Berg if (!tx->sta)
1039feff1f2fSJohannes Berg return TX_CONTINUE;
1040feff1f2fSJohannes Berg
1041252b86c4SJohannes Berg skb_queue_walk(&tx->skbs, skb) {
1042560d2682SJohannes Berg ac = skb_get_queue_mapping(skb);
1043046d2e7cSSriram R tx->sta->deflink.tx_stats.bytes[ac] += skb->len;
1044252b86c4SJohannes Berg }
1045560d2682SJohannes Berg if (ac >= 0)
1046046d2e7cSSriram R tx->sta->deflink.tx_stats.packets[ac]++;
1047feff1f2fSJohannes Berg
1048feff1f2fSJohannes Berg return TX_CONTINUE;
1049feff1f2fSJohannes Berg }
1050feff1f2fSJohannes Berg
1051feff1f2fSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_encrypt(struct ieee80211_tx_data * tx)1052e2454948SJohannes Berg ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
1053e2454948SJohannes Berg {
1054e2454948SJohannes Berg if (!tx->key)
1055e2454948SJohannes Berg return TX_CONTINUE;
1056e2454948SJohannes Berg
105797359d12SJohannes Berg switch (tx->key->conf.cipher) {
105897359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP40:
105997359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP104:
1060e2454948SJohannes Berg return ieee80211_crypto_wep_encrypt(tx);
106197359d12SJohannes Berg case WLAN_CIPHER_SUITE_TKIP:
1062e2454948SJohannes Berg return ieee80211_crypto_tkip_encrypt(tx);
106397359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP:
10642b2ba0dbSJouni Malinen return ieee80211_crypto_ccmp_encrypt(
10652b2ba0dbSJouni Malinen tx, IEEE80211_CCMP_MIC_LEN);
10662b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256:
10672b2ba0dbSJouni Malinen return ieee80211_crypto_ccmp_encrypt(
10682b2ba0dbSJouni Malinen tx, IEEE80211_CCMP_256_MIC_LEN);
106997359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC:
10703cfcf6acSJouni Malinen return ieee80211_crypto_aes_cmac_encrypt(tx);
107156c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256:
107256c52da2SJouni Malinen return ieee80211_crypto_aes_cmac_256_encrypt(tx);
10738ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128:
10748ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256:
10758ade538bSJouni Malinen return ieee80211_crypto_aes_gmac_encrypt(tx);
107600b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP:
107700b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256:
107800b9cfa3SJouni Malinen return ieee80211_crypto_gcmp_encrypt(tx);
1079e2454948SJohannes Berg }
1080e2454948SJohannes Berg
1081e2454948SJohannes Berg return TX_DROP;
1082e2454948SJohannes Berg }
1083e2454948SJohannes Berg
1084d9e8a70fSJohannes Berg static ieee80211_tx_result debug_noinline
ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data * tx)108503f93c3dSJohannes Berg ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
108603f93c3dSJohannes Berg {
1087252b86c4SJohannes Berg struct sk_buff *skb;
10882de8e0d9SJohannes Berg struct ieee80211_hdr *hdr;
10892de8e0d9SJohannes Berg int next_len;
10902de8e0d9SJohannes Berg bool group_addr;
109103f93c3dSJohannes Berg
1092252b86c4SJohannes Berg skb_queue_walk(&tx->skbs, skb) {
10932de8e0d9SJohannes Berg hdr = (void *) skb->data;
10947e0aae47SJouni Malinen if (unlikely(ieee80211_is_pspoll(hdr->frame_control)))
10957e0aae47SJouni Malinen break; /* must not overwrite AID */
1096252b86c4SJohannes Berg if (!skb_queue_is_last(&tx->skbs, skb)) {
1097252b86c4SJohannes Berg struct sk_buff *next = skb_queue_next(&tx->skbs, skb);
1098252b86c4SJohannes Berg next_len = next->len;
1099252b86c4SJohannes Berg } else
1100252b86c4SJohannes Berg next_len = 0;
11012de8e0d9SJohannes Berg group_addr = is_multicast_ether_addr(hdr->addr1);
110203f93c3dSJohannes Berg
11032de8e0d9SJohannes Berg hdr->duration_id =
1104252b86c4SJohannes Berg ieee80211_duration(tx, skb, group_addr, next_len);
1105252b86c4SJohannes Berg }
110603f93c3dSJohannes Berg
110703f93c3dSJohannes Berg return TX_CONTINUE;
110803f93c3dSJohannes Berg }
110903f93c3dSJohannes Berg
1110e2ebc74dSJohannes Berg /* actual transmit path */
1111e2ebc74dSJohannes Berg
ieee80211_tx_prep_agg(struct ieee80211_tx_data * tx,struct sk_buff * skb,struct ieee80211_tx_info * info,struct tid_ampdu_tx * tid_tx,int tid)1112a622ab72SJohannes Berg static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
1113a622ab72SJohannes Berg struct sk_buff *skb,
1114a622ab72SJohannes Berg struct ieee80211_tx_info *info,
1115a622ab72SJohannes Berg struct tid_ampdu_tx *tid_tx,
1116a622ab72SJohannes Berg int tid)
1117a622ab72SJohannes Berg {
1118a622ab72SJohannes Berg bool queued = false;
1119285fa695SNikolay Martynov bool reset_agg_timer = false;
1120aa454580SHelmut Schaa struct sk_buff *purge_skb = NULL;
1121a622ab72SJohannes Berg
1122a622ab72SJohannes Berg if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
1123285fa695SNikolay Martynov reset_agg_timer = true;
11240ab33703SJohannes Berg } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
11250ab33703SJohannes Berg /*
11260ab33703SJohannes Berg * nothing -- this aggregation session is being started
11270ab33703SJohannes Berg * but that might still fail with the driver
11280ab33703SJohannes Berg */
1129ba8c3d6fSFelix Fietkau } else if (!tx->sta->sta.txq[tid]) {
1130a622ab72SJohannes Berg spin_lock(&tx->sta->lock);
1131a622ab72SJohannes Berg /*
1132a622ab72SJohannes Berg * Need to re-check now, because we may get here
1133a622ab72SJohannes Berg *
1134a622ab72SJohannes Berg * 1) in the window during which the setup is actually
1135a622ab72SJohannes Berg * already done, but not marked yet because not all
1136a622ab72SJohannes Berg * packets are spliced over to the driver pending
1137a622ab72SJohannes Berg * queue yet -- if this happened we acquire the lock
1138a622ab72SJohannes Berg * either before or after the splice happens, but
1139a622ab72SJohannes Berg * need to recheck which of these cases happened.
1140a622ab72SJohannes Berg *
1141a622ab72SJohannes Berg * 2) during session teardown, if the OPERATIONAL bit
1142a622ab72SJohannes Berg * was cleared due to the teardown but the pointer
1143a622ab72SJohannes Berg * hasn't been assigned NULL yet (or we loaded it
1144a622ab72SJohannes Berg * before it was assigned) -- in this case it may
1145a622ab72SJohannes Berg * now be NULL which means we should just let the
1146a622ab72SJohannes Berg * packet pass through because splicing the frames
1147a622ab72SJohannes Berg * back is already done.
1148a622ab72SJohannes Berg */
114940b275b6SJohannes Berg tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid);
1150a622ab72SJohannes Berg
1151a622ab72SJohannes Berg if (!tid_tx) {
1152a622ab72SJohannes Berg /* do nothing, let packet pass through */
1153a622ab72SJohannes Berg } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
1154285fa695SNikolay Martynov reset_agg_timer = true;
1155a622ab72SJohannes Berg } else {
1156a622ab72SJohannes Berg queued = true;
1157f6d4671aSEmmanuel Grumbach if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) {
1158f6d4671aSEmmanuel Grumbach clear_sta_flag(tx->sta, WLAN_STA_SP);
1159f6d4671aSEmmanuel Grumbach ps_dbg(tx->sta->sdata,
1160f6d4671aSEmmanuel Grumbach "STA %pM aid %d: SP frame queued, close the SP w/o telling the peer\n",
1161f6d4671aSEmmanuel Grumbach tx->sta->sta.addr, tx->sta->sta.aid);
1162f6d4671aSEmmanuel Grumbach }
1163a622ab72SJohannes Berg info->control.vif = &tx->sdata->vif;
1164cc20ff2cSFelix Fietkau info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
1165facde7f3SEmmanuel Grumbach info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
1166a622ab72SJohannes Berg __skb_queue_tail(&tid_tx->pending, skb);
1167aa454580SHelmut Schaa if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
1168aa454580SHelmut Schaa purge_skb = __skb_dequeue(&tid_tx->pending);
1169a622ab72SJohannes Berg }
1170a622ab72SJohannes Berg spin_unlock(&tx->sta->lock);
1171aa454580SHelmut Schaa
1172aa454580SHelmut Schaa if (purge_skb)
1173c3e7724bSFelix Fietkau ieee80211_free_txskb(&tx->local->hw, purge_skb);
1174a622ab72SJohannes Berg }
1175a622ab72SJohannes Berg
1176285fa695SNikolay Martynov /* reset session timer */
1177914eac24SSara Sharon if (reset_agg_timer)
117812d3952fSFelix Fietkau tid_tx->last_tx = jiffies;
1179285fa695SNikolay Martynov
1180a622ab72SJohannes Berg return queued;
1181a622ab72SJohannes Berg }
1182a622ab72SJohannes Berg
ieee80211_aggr_check(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct sk_buff * skb)11838b0f5cb6SFelix Fietkau void ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
11848b0f5cb6SFelix Fietkau struct sta_info *sta, struct sk_buff *skb)
11851a791550SFelix Fietkau {
11861a791550SFelix Fietkau struct rate_control_ref *ref = sdata->local->rate_ctrl;
11871a791550SFelix Fietkau u16 tid;
11881a791550SFelix Fietkau
11891a791550SFelix Fietkau if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
11901a791550SFelix Fietkau return;
11911a791550SFelix Fietkau
1192046d2e7cSSriram R if (!sta || !sta->sta.deflink.ht_cap.ht_supported ||
11931a791550SFelix Fietkau !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
11941a791550SFelix Fietkau skb->protocol == sdata->control_port_protocol)
11951a791550SFelix Fietkau return;
11961a791550SFelix Fietkau
11971a791550SFelix Fietkau tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
11981a791550SFelix Fietkau if (likely(sta->ampdu_mlme.tid_tx[tid]))
11991a791550SFelix Fietkau return;
12001a791550SFelix Fietkau
12011a791550SFelix Fietkau ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
12021a791550SFelix Fietkau }
12031a791550SFelix Fietkau
120458d4185eSJohannes Berg /*
120558d4185eSJohannes Berg * initialises @tx
12067c10770fSJohannes Berg * pass %NULL for the station if unknown, a valid pointer if known
12077c10770fSJohannes Berg * or an ERR_PTR() if the station is known not to exist
120858d4185eSJohannes Berg */
12099ae54c84SJohannes Berg static ieee80211_tx_result
ieee80211_tx_prepare(struct ieee80211_sub_if_data * sdata,struct ieee80211_tx_data * tx,struct sta_info * sta,struct sk_buff * skb)12103b8d81e0SJohannes Berg ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
12113b8d81e0SJohannes Berg struct ieee80211_tx_data *tx,
12127c10770fSJohannes Berg struct sta_info *sta, struct sk_buff *skb)
1213e2ebc74dSJohannes Berg {
12143b8d81e0SJohannes Berg struct ieee80211_local *local = sdata->local;
121558d4185eSJohannes Berg struct ieee80211_hdr *hdr;
1216e039fa4aSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
12171a791550SFelix Fietkau bool aggr_check = false;
121868f2b517SJohannes Berg int tid;
1219e2ebc74dSJohannes Berg
1220e2ebc74dSJohannes Berg memset(tx, 0, sizeof(*tx));
1221e2ebc74dSJohannes Berg tx->skb = skb;
1222e2ebc74dSJohannes Berg tx->local = local;
12233b8d81e0SJohannes Berg tx->sdata = sdata;
1224252b86c4SJohannes Berg __skb_queue_head_init(&tx->skbs);
1225e2ebc74dSJohannes Berg
1226cd8ffc80SJohannes Berg /*
1227cd8ffc80SJohannes Berg * If this flag is set to true anywhere, and we get here,
1228cd8ffc80SJohannes Berg * we are doing the needed processing, so remove the flag
1229cd8ffc80SJohannes Berg * now.
1230cd8ffc80SJohannes Berg */
1231cc20ff2cSFelix Fietkau info->control.flags &= ~IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
1232cd8ffc80SJohannes Berg
123358d4185eSJohannes Berg hdr = (struct ieee80211_hdr *) skb->data;
123458d4185eSJohannes Berg
12357c10770fSJohannes Berg if (likely(sta)) {
12367c10770fSJohannes Berg if (!IS_ERR(sta))
12377c10770fSJohannes Berg tx->sta = sta;
12387c10770fSJohannes Berg } else {
12393f0e0b22SFelix Fietkau if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
1240f14543eeSFelix Fietkau tx->sta = rcu_dereference(sdata->u.vlan.sta);
12417c10770fSJohannes Berg if (!tx->sta && sdata->wdev.use_4addr)
12423f0e0b22SFelix Fietkau return TX_DROP;
124310cb8e61SMarkus Theil } else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
1244b4d57adbSFelix Fietkau tx->sta = sta_info_get_bss(sdata, hdr->addr1);
12453f0e0b22SFelix Fietkau }
12461a791550SFelix Fietkau if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) {
1247abe60632SJohannes Berg tx->sta = sta_info_get(sdata, hdr->addr1);
12481a791550SFelix Fietkau aggr_check = true;
12491a791550SFelix Fietkau }
12507c10770fSJohannes Berg }
125158d4185eSJohannes Berg
1252cd8ffc80SJohannes Berg if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
125349a59543SJohannes Berg !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
125430686bf7SJohannes Berg ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
125530686bf7SJohannes Berg !ieee80211_hw_check(&local->hw, TX_AMPDU_SETUP_IN_HW)) {
1256cd8ffc80SJohannes Berg struct tid_ampdu_tx *tid_tx;
1257cd8ffc80SJohannes Berg
1258a1f2ba04SSara Sharon tid = ieee80211_get_tid(hdr);
1259a622ab72SJohannes Berg tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
12601a791550SFelix Fietkau if (!tid_tx && aggr_check) {
12611a791550SFelix Fietkau ieee80211_aggr_check(sdata, tx->sta, skb);
12621a791550SFelix Fietkau tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
12631a791550SFelix Fietkau }
12641a791550SFelix Fietkau
1265a622ab72SJohannes Berg if (tid_tx) {
1266a622ab72SJohannes Berg bool queued;
1267a622ab72SJohannes Berg
1268a622ab72SJohannes Berg queued = ieee80211_tx_prep_agg(tx, skb, info,
1269a622ab72SJohannes Berg tid_tx, tid);
1270cd8ffc80SJohannes Berg
1271cd8ffc80SJohannes Berg if (unlikely(queued))
1272cd8ffc80SJohannes Berg return TX_QUEUED;
12738b30b1feSSujith }
1274a622ab72SJohannes Berg }
12758b30b1feSSujith
1276badffb72SJiri Slaby if (is_multicast_ether_addr(hdr->addr1)) {
12775cf121c3SJohannes Berg tx->flags &= ~IEEE80211_TX_UNICAST;
1278e039fa4aSJohannes Berg info->flags |= IEEE80211_TX_CTL_NO_ACK;
12796fd67e93SSimon Wunderlich } else
12805cf121c3SJohannes Berg tx->flags |= IEEE80211_TX_UNICAST;
128158d4185eSJohannes Berg
1282a26eb27aSJohannes Berg if (!(info->flags & IEEE80211_TX_CTL_DONTFRAG)) {
1283a26eb27aSJohannes Berg if (!(tx->flags & IEEE80211_TX_UNICAST) ||
1284a26eb27aSJohannes Berg skb->len + FCS_LEN <= local->hw.wiphy->frag_threshold ||
1285a26eb27aSJohannes Berg info->flags & IEEE80211_TX_CTL_AMPDU)
1286a26eb27aSJohannes Berg info->flags |= IEEE80211_TX_CTL_DONTFRAG;
128758d4185eSJohannes Berg }
128858d4185eSJohannes Berg
1289e2ebc74dSJohannes Berg if (!tx->sta)
1290e039fa4aSJohannes Berg info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
1291f7418bc1SFelix Fietkau else if (test_and_clear_sta_flag(tx->sta, WLAN_STA_CLEAR_PS_FILT)) {
1292e039fa4aSJohannes Berg info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
1293f7418bc1SFelix Fietkau ieee80211_check_fast_xmit(tx->sta);
1294f7418bc1SFelix Fietkau }
129558d4185eSJohannes Berg
1296e039fa4aSJohannes Berg info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT;
1297e2ebc74dSJohannes Berg
12989ae54c84SJohannes Berg return TX_CONTINUE;
1299e2ebc74dSJohannes Berg }
1300e2ebc74dSJohannes Berg
ieee80211_get_txq(struct ieee80211_local * local,struct ieee80211_vif * vif,struct sta_info * sta,struct sk_buff * skb)130180a83cfcSMichal Kazior static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
1302ba8c3d6fSFelix Fietkau struct ieee80211_vif *vif,
1303dbef5362SMichal Kazior struct sta_info *sta,
1304ba8c3d6fSFelix Fietkau struct sk_buff *skb)
1305ba8c3d6fSFelix Fietkau {
1306ba8c3d6fSFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1307ba8c3d6fSFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1308ba8c3d6fSFelix Fietkau struct ieee80211_txq *txq = NULL;
1309ba8c3d6fSFelix Fietkau
1310c3732a7bSFelix Fietkau if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
1311c3732a7bSFelix Fietkau (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
131280a83cfcSMichal Kazior return NULL;
1313ba8c3d6fSFelix Fietkau
1314cc20ff2cSFelix Fietkau if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
131550ff477aSJohn Crispin unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
1316adf8ed01SJohannes Berg if ((!ieee80211_is_mgmt(hdr->frame_control) ||
13172c9abe65SJohannes Berg ieee80211_is_bufferable_mmpdu(skb) ||
13180eeb2b67SSara Sharon vif->type == NL80211_IFTYPE_STATION) &&
1319adf8ed01SJohannes Berg sta && sta->uploaded) {
1320adf8ed01SJohannes Berg /*
1321adf8ed01SJohannes Berg * This will be NULL if the driver didn't set the
1322adf8ed01SJohannes Berg * opt-in hardware flag.
1323adf8ed01SJohannes Berg */
1324adf8ed01SJohannes Berg txq = sta->sta.txq[IEEE80211_NUM_TIDS];
1325adf8ed01SJohannes Berg }
1326adf8ed01SJohannes Berg } else if (sta) {
1327ba8c3d6fSFelix Fietkau u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
1328ba8c3d6fSFelix Fietkau
1329dbef5362SMichal Kazior if (!sta->uploaded)
1330dbef5362SMichal Kazior return NULL;
1331dbef5362SMichal Kazior
1332dbef5362SMichal Kazior txq = sta->sta.txq[tid];
133394450963SAlexander Wetzel } else {
1334ba8c3d6fSFelix Fietkau txq = vif->txq;
1335ba8c3d6fSFelix Fietkau }
1336ba8c3d6fSFelix Fietkau
1337ba8c3d6fSFelix Fietkau if (!txq)
133880a83cfcSMichal Kazior return NULL;
1339ba8c3d6fSFelix Fietkau
134080a83cfcSMichal Kazior return to_txq_info(txq);
134180a83cfcSMichal Kazior }
1342ba8c3d6fSFelix Fietkau
ieee80211_set_skb_enqueue_time(struct sk_buff * skb)13435caa328eSMichal Kazior static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
13445caa328eSMichal Kazior {
13457d360f60SFelix Fietkau struct sk_buff *next;
13467d360f60SFelix Fietkau codel_time_t now = codel_get_time();
13477d360f60SFelix Fietkau
13487d360f60SFelix Fietkau skb_list_walk_safe(skb, skb, next)
13497d360f60SFelix Fietkau IEEE80211_SKB_CB(skb)->control.enqueue_time = now;
13505caa328eSMichal Kazior }
13515caa328eSMichal Kazior
codel_skb_len_func(const struct sk_buff * skb)13525caa328eSMichal Kazior static u32 codel_skb_len_func(const struct sk_buff *skb)
13535caa328eSMichal Kazior {
13545caa328eSMichal Kazior return skb->len;
13555caa328eSMichal Kazior }
13565caa328eSMichal Kazior
codel_skb_time_func(const struct sk_buff * skb)13575caa328eSMichal Kazior static codel_time_t codel_skb_time_func(const struct sk_buff *skb)
13585caa328eSMichal Kazior {
13595caa328eSMichal Kazior const struct ieee80211_tx_info *info;
13605caa328eSMichal Kazior
13615caa328eSMichal Kazior info = (const struct ieee80211_tx_info *)skb->cb;
13625caa328eSMichal Kazior return info->control.enqueue_time;
13635caa328eSMichal Kazior }
13645caa328eSMichal Kazior
codel_dequeue_func(struct codel_vars * cvars,void * ctx)13655caa328eSMichal Kazior static struct sk_buff *codel_dequeue_func(struct codel_vars *cvars,
13665caa328eSMichal Kazior void *ctx)
13675caa328eSMichal Kazior {
13685caa328eSMichal Kazior struct ieee80211_local *local;
13695caa328eSMichal Kazior struct txq_info *txqi;
13705caa328eSMichal Kazior struct fq *fq;
13715caa328eSMichal Kazior struct fq_flow *flow;
13725caa328eSMichal Kazior
13735caa328eSMichal Kazior txqi = ctx;
13745caa328eSMichal Kazior local = vif_to_sdata(txqi->txq.vif)->local;
13755caa328eSMichal Kazior fq = &local->fq;
13765caa328eSMichal Kazior
13775caa328eSMichal Kazior if (cvars == &txqi->def_cvars)
1378bf9009bfSFelix Fietkau flow = &txqi->tin.default_flow;
13795caa328eSMichal Kazior else
13805caa328eSMichal Kazior flow = &fq->flows[cvars - local->cvars];
13815caa328eSMichal Kazior
13825caa328eSMichal Kazior return fq_flow_dequeue(fq, flow);
13835caa328eSMichal Kazior }
13845caa328eSMichal Kazior
codel_drop_func(struct sk_buff * skb,void * ctx)13855caa328eSMichal Kazior static void codel_drop_func(struct sk_buff *skb,
13865caa328eSMichal Kazior void *ctx)
13875caa328eSMichal Kazior {
13885caa328eSMichal Kazior struct ieee80211_local *local;
13895caa328eSMichal Kazior struct ieee80211_hw *hw;
13905caa328eSMichal Kazior struct txq_info *txqi;
13915caa328eSMichal Kazior
13925caa328eSMichal Kazior txqi = ctx;
13935caa328eSMichal Kazior local = vif_to_sdata(txqi->txq.vif)->local;
13945caa328eSMichal Kazior hw = &local->hw;
13955caa328eSMichal Kazior
13965caa328eSMichal Kazior ieee80211_free_txskb(hw, skb);
13975caa328eSMichal Kazior }
13985caa328eSMichal Kazior
fq_tin_dequeue_func(struct fq * fq,struct fq_tin * tin,struct fq_flow * flow)1399fa962b92SMichal Kazior static struct sk_buff *fq_tin_dequeue_func(struct fq *fq,
1400fa962b92SMichal Kazior struct fq_tin *tin,
1401fa962b92SMichal Kazior struct fq_flow *flow)
1402fa962b92SMichal Kazior {
14035caa328eSMichal Kazior struct ieee80211_local *local;
14045caa328eSMichal Kazior struct txq_info *txqi;
14055caa328eSMichal Kazior struct codel_vars *cvars;
14065caa328eSMichal Kazior struct codel_params *cparams;
14075caa328eSMichal Kazior struct codel_stats *cstats;
14085caa328eSMichal Kazior
14095caa328eSMichal Kazior local = container_of(fq, struct ieee80211_local, fq);
14105caa328eSMichal Kazior txqi = container_of(tin, struct txq_info, tin);
14118d51dbb8SToke Høiland-Jørgensen cstats = &txqi->cstats;
14125caa328eSMichal Kazior
1413484a54c2SToke Høiland-Jørgensen if (txqi->txq.sta) {
1414484a54c2SToke Høiland-Jørgensen struct sta_info *sta = container_of(txqi->txq.sta,
1415484a54c2SToke Høiland-Jørgensen struct sta_info, sta);
1416484a54c2SToke Høiland-Jørgensen cparams = &sta->cparams;
1417484a54c2SToke Høiland-Jørgensen } else {
1418484a54c2SToke Høiland-Jørgensen cparams = &local->cparams;
1419484a54c2SToke Høiland-Jørgensen }
1420484a54c2SToke Høiland-Jørgensen
1421bf9009bfSFelix Fietkau if (flow == &tin->default_flow)
14225caa328eSMichal Kazior cvars = &txqi->def_cvars;
14235caa328eSMichal Kazior else
14245caa328eSMichal Kazior cvars = &local->cvars[flow - fq->flows];
14255caa328eSMichal Kazior
14265caa328eSMichal Kazior return codel_dequeue(txqi,
14275caa328eSMichal Kazior &flow->backlog,
14285caa328eSMichal Kazior cparams,
14295caa328eSMichal Kazior cvars,
14305caa328eSMichal Kazior cstats,
14315caa328eSMichal Kazior codel_skb_len_func,
14325caa328eSMichal Kazior codel_skb_time_func,
14335caa328eSMichal Kazior codel_drop_func,
14345caa328eSMichal Kazior codel_dequeue_func);
1435fa962b92SMichal Kazior }
1436fa962b92SMichal Kazior
fq_skb_free_func(struct fq * fq,struct fq_tin * tin,struct fq_flow * flow,struct sk_buff * skb)1437fa962b92SMichal Kazior static void fq_skb_free_func(struct fq *fq,
1438fa962b92SMichal Kazior struct fq_tin *tin,
1439fa962b92SMichal Kazior struct fq_flow *flow,
1440fa962b92SMichal Kazior struct sk_buff *skb)
1441fa962b92SMichal Kazior {
1442fa962b92SMichal Kazior struct ieee80211_local *local;
1443fa962b92SMichal Kazior
1444fa962b92SMichal Kazior local = container_of(fq, struct ieee80211_local, fq);
1445fa962b92SMichal Kazior ieee80211_free_txskb(&local->hw, skb);
1446fa962b92SMichal Kazior }
1447fa962b92SMichal Kazior
ieee80211_txq_enqueue(struct ieee80211_local * local,struct txq_info * txqi,struct sk_buff * skb)144880a83cfcSMichal Kazior static void ieee80211_txq_enqueue(struct ieee80211_local *local,
144980a83cfcSMichal Kazior struct txq_info *txqi,
145080a83cfcSMichal Kazior struct sk_buff *skb)
145180a83cfcSMichal Kazior {
1452fa962b92SMichal Kazior struct fq *fq = &local->fq;
1453fa962b92SMichal Kazior struct fq_tin *tin = &txqi->tin;
1454f2af2df8SFelix Fietkau u32 flow_idx = fq_flow_idx(fq, skb);
145580a83cfcSMichal Kazior
14565caa328eSMichal Kazior ieee80211_set_skb_enqueue_time(skb);
1457f2af2df8SFelix Fietkau
1458f2af2df8SFelix Fietkau spin_lock_bh(&fq->lock);
145973bc9e0aSJohannes Berg /*
146073bc9e0aSJohannes Berg * For management frames, don't really apply codel etc.,
146173bc9e0aSJohannes Berg * we don't want to apply any shaping or anything we just
146273bc9e0aSJohannes Berg * want to simplify the driver API by having them on the
146373bc9e0aSJohannes Berg * txqi.
146473bc9e0aSJohannes Berg */
1465ca47b462SJohannes Berg if (unlikely(txqi->txq.tid == IEEE80211_NUM_TIDS)) {
1466ca47b462SJohannes Berg IEEE80211_SKB_CB(skb)->control.flags |=
1467ca47b462SJohannes Berg IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
146873bc9e0aSJohannes Berg __skb_queue_tail(&txqi->frags, skb);
1469ca47b462SJohannes Berg } else {
1470f2af2df8SFelix Fietkau fq_tin_enqueue(fq, tin, flow_idx, skb,
1471bf9009bfSFelix Fietkau fq_skb_free_func);
1472ca47b462SJohannes Berg }
1473f2af2df8SFelix Fietkau spin_unlock_bh(&fq->lock);
147480a83cfcSMichal Kazior }
147580a83cfcSMichal Kazior
fq_vlan_filter_func(struct fq * fq,struct fq_tin * tin,struct fq_flow * flow,struct sk_buff * skb,void * data)14762a9e2579SJohannes Berg static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin,
14772a9e2579SJohannes Berg struct fq_flow *flow, struct sk_buff *skb,
14782a9e2579SJohannes Berg void *data)
14792a9e2579SJohannes Berg {
14802a9e2579SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
14812a9e2579SJohannes Berg
14822a9e2579SJohannes Berg return info->control.vif == data;
14832a9e2579SJohannes Berg }
14842a9e2579SJohannes Berg
ieee80211_txq_remove_vlan(struct ieee80211_local * local,struct ieee80211_sub_if_data * sdata)14852a9e2579SJohannes Berg void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
14862a9e2579SJohannes Berg struct ieee80211_sub_if_data *sdata)
14872a9e2579SJohannes Berg {
14882a9e2579SJohannes Berg struct fq *fq = &local->fq;
14892a9e2579SJohannes Berg struct txq_info *txqi;
14902a9e2579SJohannes Berg struct fq_tin *tin;
14912a9e2579SJohannes Berg struct ieee80211_sub_if_data *ap;
14922a9e2579SJohannes Berg
14932a9e2579SJohannes Berg if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
14942a9e2579SJohannes Berg return;
14952a9e2579SJohannes Berg
14962a9e2579SJohannes Berg ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
14972a9e2579SJohannes Berg
14982a9e2579SJohannes Berg if (!ap->vif.txq)
14992a9e2579SJohannes Berg return;
15002a9e2579SJohannes Berg
15012a9e2579SJohannes Berg txqi = to_txq_info(ap->vif.txq);
15022a9e2579SJohannes Berg tin = &txqi->tin;
15032a9e2579SJohannes Berg
15042a9e2579SJohannes Berg spin_lock_bh(&fq->lock);
15052a9e2579SJohannes Berg fq_tin_filter(fq, tin, fq_vlan_filter_func, &sdata->vif,
15062a9e2579SJohannes Berg fq_skb_free_func);
15072a9e2579SJohannes Berg spin_unlock_bh(&fq->lock);
15082a9e2579SJohannes Berg }
15092a9e2579SJohannes Berg
ieee80211_txq_init(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct txq_info * txqi,int tid)1510fa962b92SMichal Kazior void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
1511fa962b92SMichal Kazior struct sta_info *sta,
1512fa962b92SMichal Kazior struct txq_info *txqi, int tid)
1513fa962b92SMichal Kazior {
1514fa962b92SMichal Kazior fq_tin_init(&txqi->tin);
15155caa328eSMichal Kazior codel_vars_init(&txqi->def_cvars);
15168d51dbb8SToke Høiland-Jørgensen codel_stats_init(&txqi->cstats);
1517bb42f2d1SToke Høiland-Jørgensen __skb_queue_head_init(&txqi->frags);
1518942741daSFelix Fietkau INIT_LIST_HEAD(&txqi->schedule_order);
1519fa962b92SMichal Kazior
1520fa962b92SMichal Kazior txqi->txq.vif = &sdata->vif;
1521fa962b92SMichal Kazior
1522adf8ed01SJohannes Berg if (!sta) {
1523fa962b92SMichal Kazior sdata->vif.txq = &txqi->txq;
1524fa962b92SMichal Kazior txqi->txq.tid = 0;
1525fa962b92SMichal Kazior txqi->txq.ac = IEEE80211_AC_BE;
1526adf8ed01SJohannes Berg
1527adf8ed01SJohannes Berg return;
1528fa962b92SMichal Kazior }
1529adf8ed01SJohannes Berg
1530adf8ed01SJohannes Berg if (tid == IEEE80211_NUM_TIDS) {
15310eeb2b67SSara Sharon if (sdata->vif.type == NL80211_IFTYPE_STATION) {
15320eeb2b67SSara Sharon /* Drivers need to opt in to the management MPDU TXQ */
15330eeb2b67SSara Sharon if (!ieee80211_hw_check(&sdata->local->hw,
15340eeb2b67SSara Sharon STA_MMPDU_TXQ))
1535adf8ed01SJohannes Berg return;
15360eeb2b67SSara Sharon } else if (!ieee80211_hw_check(&sdata->local->hw,
15370eeb2b67SSara Sharon BUFF_MMPDU_TXQ)) {
15380eeb2b67SSara Sharon /* Drivers need to opt in to the bufferable MMPDU TXQ */
15390eeb2b67SSara Sharon return;
15400eeb2b67SSara Sharon }
1541adf8ed01SJohannes Berg txqi->txq.ac = IEEE80211_AC_VO;
1542adf8ed01SJohannes Berg } else {
1543adf8ed01SJohannes Berg txqi->txq.ac = ieee80211_ac_from_tid(tid);
1544adf8ed01SJohannes Berg }
1545adf8ed01SJohannes Berg
1546adf8ed01SJohannes Berg txqi->txq.sta = &sta->sta;
1547adf8ed01SJohannes Berg txqi->txq.tid = tid;
1548adf8ed01SJohannes Berg sta->sta.txq[tid] = &txqi->txq;
1549fa962b92SMichal Kazior }
1550fa962b92SMichal Kazior
ieee80211_txq_purge(struct ieee80211_local * local,struct txq_info * txqi)1551fa962b92SMichal Kazior void ieee80211_txq_purge(struct ieee80211_local *local,
1552fa962b92SMichal Kazior struct txq_info *txqi)
1553fa962b92SMichal Kazior {
1554fa962b92SMichal Kazior struct fq *fq = &local->fq;
1555fa962b92SMichal Kazior struct fq_tin *tin = &txqi->tin;
1556fa962b92SMichal Kazior
1557b4809e94SToke Høiland-Jørgensen spin_lock_bh(&fq->lock);
1558fa962b92SMichal Kazior fq_tin_reset(fq, tin, fq_skb_free_func);
1559bb42f2d1SToke Høiland-Jørgensen ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
1560b4809e94SToke Høiland-Jørgensen spin_unlock_bh(&fq->lock);
1561b4809e94SToke Høiland-Jørgensen
1562942741daSFelix Fietkau spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
1563942741daSFelix Fietkau list_del_init(&txqi->schedule_order);
1564942741daSFelix Fietkau spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
1565fa962b92SMichal Kazior }
1566fa962b92SMichal Kazior
ieee80211_txq_set_params(struct ieee80211_local * local)15672fe4a29aSToke Høiland-Jørgensen void ieee80211_txq_set_params(struct ieee80211_local *local)
15682fe4a29aSToke Høiland-Jørgensen {
15692fe4a29aSToke Høiland-Jørgensen if (local->hw.wiphy->txq_limit)
15702fe4a29aSToke Høiland-Jørgensen local->fq.limit = local->hw.wiphy->txq_limit;
15712fe4a29aSToke Høiland-Jørgensen else
15722fe4a29aSToke Høiland-Jørgensen local->hw.wiphy->txq_limit = local->fq.limit;
15732fe4a29aSToke Høiland-Jørgensen
15742fe4a29aSToke Høiland-Jørgensen if (local->hw.wiphy->txq_memory_limit)
15752fe4a29aSToke Høiland-Jørgensen local->fq.memory_limit = local->hw.wiphy->txq_memory_limit;
15762fe4a29aSToke Høiland-Jørgensen else
15772fe4a29aSToke Høiland-Jørgensen local->hw.wiphy->txq_memory_limit = local->fq.memory_limit;
15782fe4a29aSToke Høiland-Jørgensen
15792fe4a29aSToke Høiland-Jørgensen if (local->hw.wiphy->txq_quantum)
15802fe4a29aSToke Høiland-Jørgensen local->fq.quantum = local->hw.wiphy->txq_quantum;
15812fe4a29aSToke Høiland-Jørgensen else
15822fe4a29aSToke Høiland-Jørgensen local->hw.wiphy->txq_quantum = local->fq.quantum;
15832fe4a29aSToke Høiland-Jørgensen }
15842fe4a29aSToke Høiland-Jørgensen
ieee80211_txq_setup_flows(struct ieee80211_local * local)1585fa962b92SMichal Kazior int ieee80211_txq_setup_flows(struct ieee80211_local *local)
1586fa962b92SMichal Kazior {
1587fa962b92SMichal Kazior struct fq *fq = &local->fq;
1588fa962b92SMichal Kazior int ret;
15895caa328eSMichal Kazior int i;
15903ff23cd5SToke Høiland-Jørgensen bool supp_vht = false;
15913ff23cd5SToke Høiland-Jørgensen enum nl80211_band band;
1592fa962b92SMichal Kazior
1593fa962b92SMichal Kazior ret = fq_init(fq, 4096);
1594fa962b92SMichal Kazior if (ret)
1595fa962b92SMichal Kazior return ret;
1596fa962b92SMichal Kazior
15973ff23cd5SToke Høiland-Jørgensen /*
15983ff23cd5SToke Høiland-Jørgensen * If the hardware doesn't support VHT, it is safe to limit the maximum
15993ff23cd5SToke Høiland-Jørgensen * queue size. 4 Mbytes is 64 max-size aggregates in 802.11n.
16003ff23cd5SToke Høiland-Jørgensen */
16013ff23cd5SToke Høiland-Jørgensen for (band = 0; band < NUM_NL80211_BANDS; band++) {
16023ff23cd5SToke Høiland-Jørgensen struct ieee80211_supported_band *sband;
16033ff23cd5SToke Høiland-Jørgensen
16043ff23cd5SToke Høiland-Jørgensen sband = local->hw.wiphy->bands[band];
16053ff23cd5SToke Høiland-Jørgensen if (!sband)
16063ff23cd5SToke Høiland-Jørgensen continue;
16073ff23cd5SToke Høiland-Jørgensen
16083ff23cd5SToke Høiland-Jørgensen supp_vht = supp_vht || sband->vht_cap.vht_supported;
16093ff23cd5SToke Høiland-Jørgensen }
16103ff23cd5SToke Høiland-Jørgensen
16113ff23cd5SToke Høiland-Jørgensen if (!supp_vht)
16123ff23cd5SToke Høiland-Jørgensen fq->memory_limit = 4 << 20; /* 4 Mbytes */
16133ff23cd5SToke Høiland-Jørgensen
16145caa328eSMichal Kazior codel_params_init(&local->cparams);
16155caa328eSMichal Kazior local->cparams.interval = MS2TIME(100);
16165caa328eSMichal Kazior local->cparams.target = MS2TIME(20);
16175caa328eSMichal Kazior local->cparams.ecn = true;
16185caa328eSMichal Kazior
16195caa328eSMichal Kazior local->cvars = kcalloc(fq->flows_cnt, sizeof(local->cvars[0]),
16205caa328eSMichal Kazior GFP_KERNEL);
16215caa328eSMichal Kazior if (!local->cvars) {
162259a7c828SMichal Kazior spin_lock_bh(&fq->lock);
16235caa328eSMichal Kazior fq_reset(fq, fq_skb_free_func);
162459a7c828SMichal Kazior spin_unlock_bh(&fq->lock);
16255caa328eSMichal Kazior return -ENOMEM;
16265caa328eSMichal Kazior }
16275caa328eSMichal Kazior
16285caa328eSMichal Kazior for (i = 0; i < fq->flows_cnt; i++)
16295caa328eSMichal Kazior codel_vars_init(&local->cvars[i]);
16305caa328eSMichal Kazior
16312fe4a29aSToke Høiland-Jørgensen ieee80211_txq_set_params(local);
16322fe4a29aSToke Høiland-Jørgensen
1633fa962b92SMichal Kazior return 0;
1634fa962b92SMichal Kazior }
1635fa962b92SMichal Kazior
ieee80211_txq_teardown_flows(struct ieee80211_local * local)1636fa962b92SMichal Kazior void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
1637fa962b92SMichal Kazior {
1638fa962b92SMichal Kazior struct fq *fq = &local->fq;
1639fa962b92SMichal Kazior
16405caa328eSMichal Kazior kfree(local->cvars);
16415caa328eSMichal Kazior local->cvars = NULL;
16425caa328eSMichal Kazior
164359a7c828SMichal Kazior spin_lock_bh(&fq->lock);
1644fa962b92SMichal Kazior fq_reset(fq, fq_skb_free_func);
164559a7c828SMichal Kazior spin_unlock_bh(&fq->lock);
1646ba8c3d6fSFelix Fietkau }
1647ba8c3d6fSFelix Fietkau
ieee80211_queue_skb(struct ieee80211_local * local,struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct sk_buff * skb)1648bb42f2d1SToke Høiland-Jørgensen static bool ieee80211_queue_skb(struct ieee80211_local *local,
1649bb42f2d1SToke Høiland-Jørgensen struct ieee80211_sub_if_data *sdata,
1650bb42f2d1SToke Høiland-Jørgensen struct sta_info *sta,
1651bb42f2d1SToke Høiland-Jørgensen struct sk_buff *skb)
1652bb42f2d1SToke Høiland-Jørgensen {
1653bb42f2d1SToke Høiland-Jørgensen struct ieee80211_vif *vif;
1654bb42f2d1SToke Høiland-Jørgensen struct txq_info *txqi;
1655bb42f2d1SToke Høiland-Jørgensen
1656107395f9SAlexander Wetzel if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
1657bb42f2d1SToke Høiland-Jørgensen return false;
1658bb42f2d1SToke Høiland-Jørgensen
1659bb42f2d1SToke Høiland-Jørgensen if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1660bb42f2d1SToke Høiland-Jørgensen sdata = container_of(sdata->bss,
1661bb42f2d1SToke Høiland-Jørgensen struct ieee80211_sub_if_data, u.ap);
1662bb42f2d1SToke Høiland-Jørgensen
1663bb42f2d1SToke Høiland-Jørgensen vif = &sdata->vif;
1664dbef5362SMichal Kazior txqi = ieee80211_get_txq(local, vif, sta, skb);
1665bb42f2d1SToke Høiland-Jørgensen
1666bb42f2d1SToke Høiland-Jørgensen if (!txqi)
1667bb42f2d1SToke Høiland-Jørgensen return false;
1668bb42f2d1SToke Høiland-Jørgensen
1669bb42f2d1SToke Høiland-Jørgensen ieee80211_txq_enqueue(local, txqi, skb);
1670bb42f2d1SToke Høiland-Jørgensen
167118667600SToke Høiland-Jørgensen schedule_and_wake_txq(local, txqi);
1672bb42f2d1SToke Høiland-Jørgensen
1673bb42f2d1SToke Høiland-Jørgensen return true;
1674bb42f2d1SToke Høiland-Jørgensen }
1675bb42f2d1SToke Høiland-Jørgensen
ieee80211_tx_frags(struct ieee80211_local * local,struct ieee80211_vif * vif,struct sta_info * sta,struct sk_buff_head * skbs,bool txpending)167611127e91SJohannes Berg static bool ieee80211_tx_frags(struct ieee80211_local *local,
167711127e91SJohannes Berg struct ieee80211_vif *vif,
16784fd0328dSJohannes Berg struct sta_info *sta,
167911127e91SJohannes Berg struct sk_buff_head *skbs,
168011127e91SJohannes Berg bool txpending)
1681e2ebc74dSJohannes Berg {
168280a83cfcSMichal Kazior struct ieee80211_tx_control control = {};
1683252b86c4SJohannes Berg struct sk_buff *skb, *tmp;
16843b8d81e0SJohannes Berg unsigned long flags;
1685e2ebc74dSJohannes Berg
1686252b86c4SJohannes Berg skb_queue_walk_safe(skbs, skb, tmp) {
16873a25a8c8SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
16883a25a8c8SJohannes Berg int q = info->hw_queue;
16893a25a8c8SJohannes Berg
16903a25a8c8SJohannes Berg #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
16913a25a8c8SJohannes Berg if (WARN_ON_ONCE(q >= local->hw.queues)) {
16923a25a8c8SJohannes Berg __skb_unlink(skb, skbs);
1693c3e7724bSFelix Fietkau ieee80211_free_txskb(&local->hw, skb);
16943a25a8c8SJohannes Berg continue;
16953a25a8c8SJohannes Berg }
16963a25a8c8SJohannes Berg #endif
16973b8d81e0SJohannes Berg
16983b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
16993b8d81e0SJohannes Berg if (local->queue_stop_reasons[q] ||
17007bb45683SJohannes Berg (!txpending && !skb_queue_empty(&local->pending[q]))) {
17016c17b77bSSeth Forshee if (unlikely(info->flags &
1702a7679ed5SSeth Forshee IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) {
1703a7679ed5SSeth Forshee if (local->queue_stop_reasons[q] &
1704a7679ed5SSeth Forshee ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL)) {
17056c17b77bSSeth Forshee /*
1706a7679ed5SSeth Forshee * Drop off-channel frames if queues
1707a7679ed5SSeth Forshee * are stopped for any reason other
1708a7679ed5SSeth Forshee * than off-channel operation. Never
1709a7679ed5SSeth Forshee * queue them.
17106c17b77bSSeth Forshee */
17116c17b77bSSeth Forshee spin_unlock_irqrestore(
1712a7679ed5SSeth Forshee &local->queue_stop_reason_lock,
1713a7679ed5SSeth Forshee flags);
1714a7679ed5SSeth Forshee ieee80211_purge_tx_queue(&local->hw,
1715a7679ed5SSeth Forshee skbs);
17166c17b77bSSeth Forshee return true;
17176c17b77bSSeth Forshee }
1718a7679ed5SSeth Forshee } else {
17196c17b77bSSeth Forshee
17207bb45683SJohannes Berg /*
1721a7679ed5SSeth Forshee * Since queue is stopped, queue up frames for
1722a7679ed5SSeth Forshee * later transmission from the tx-pending
1723a7679ed5SSeth Forshee * tasklet when the queue is woken again.
17247bb45683SJohannes Berg */
1725252b86c4SJohannes Berg if (txpending)
1726a7679ed5SSeth Forshee skb_queue_splice_init(skbs,
1727a7679ed5SSeth Forshee &local->pending[q]);
17287bb45683SJohannes Berg else
17294db4e0a1SJohannes Berg skb_queue_splice_tail_init(skbs,
17304db4e0a1SJohannes Berg &local->pending[q]);
17317bb45683SJohannes Berg
17327bb45683SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock,
17337bb45683SJohannes Berg flags);
17347bb45683SJohannes Berg return false;
17357bb45683SJohannes Berg }
1736a7679ed5SSeth Forshee }
17373b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
1738e2530083SJohannes Berg
173911127e91SJohannes Berg info->control.vif = vif;
17404fd0328dSJohannes Berg control.sta = sta ? &sta->sta : NULL;
1741ec25acc4SJohannes Berg
1742252b86c4SJohannes Berg __skb_unlink(skb, skbs);
174380a83cfcSMichal Kazior drv_tx(local, &control, skb);
1744e2ebc74dSJohannes Berg }
17452de8e0d9SJohannes Berg
174611127e91SJohannes Berg return true;
174711127e91SJohannes Berg }
174811127e91SJohannes Berg
174911127e91SJohannes Berg /*
175011127e91SJohannes Berg * Returns false if the frame couldn't be transmitted but was queued instead.
175111127e91SJohannes Berg */
__ieee80211_tx(struct ieee80211_local * local,struct sk_buff_head * skbs,struct sta_info * sta,bool txpending)175211127e91SJohannes Berg static bool __ieee80211_tx(struct ieee80211_local *local,
175330f6cf96SFelix Fietkau struct sk_buff_head *skbs, struct sta_info *sta,
175430f6cf96SFelix Fietkau bool txpending)
175511127e91SJohannes Berg {
175611127e91SJohannes Berg struct ieee80211_tx_info *info;
175711127e91SJohannes Berg struct ieee80211_sub_if_data *sdata;
175811127e91SJohannes Berg struct ieee80211_vif *vif;
175911127e91SJohannes Berg struct sk_buff *skb;
1760958574cbSColin Ian King bool result;
176111127e91SJohannes Berg
176211127e91SJohannes Berg if (WARN_ON(skb_queue_empty(skbs)))
176311127e91SJohannes Berg return true;
176411127e91SJohannes Berg
176511127e91SJohannes Berg skb = skb_peek(skbs);
176611127e91SJohannes Berg info = IEEE80211_SKB_CB(skb);
176711127e91SJohannes Berg sdata = vif_to_sdata(info->control.vif);
176811127e91SJohannes Berg if (sta && !sta->uploaded)
176911127e91SJohannes Berg sta = NULL;
177011127e91SJohannes Berg
177111127e91SJohannes Berg switch (sdata->vif.type) {
177211127e91SJohannes Berg case NL80211_IFTYPE_MONITOR:
1773d8212184SAviya Erenfeld if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
1774c82b5a74SJohannes Berg vif = &sdata->vif;
1775c82b5a74SJohannes Berg break;
1776c82b5a74SJohannes Berg }
17774b6f1dd6SJohannes Berg sdata = rcu_dereference(local->monitor_sdata);
17783a25a8c8SJohannes Berg if (sdata) {
17794b6f1dd6SJohannes Berg vif = &sdata->vif;
17803a25a8c8SJohannes Berg info->hw_queue =
17813a25a8c8SJohannes Berg vif->hw_queue[skb_get_queue_mapping(skb)];
178230686bf7SJohannes Berg } else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
178363b4d8b3SJohannes Berg ieee80211_purge_tx_queue(&local->hw, skbs);
17843a25a8c8SJohannes Berg return true;
17853a25a8c8SJohannes Berg } else
178611127e91SJohannes Berg vif = NULL;
178711127e91SJohannes Berg break;
178811127e91SJohannes Berg case NL80211_IFTYPE_AP_VLAN:
178911127e91SJohannes Berg sdata = container_of(sdata->bss,
179011127e91SJohannes Berg struct ieee80211_sub_if_data, u.ap);
1791fc0561dcSGustavo A. R. Silva fallthrough;
179211127e91SJohannes Berg default:
179311127e91SJohannes Berg vif = &sdata->vif;
179411127e91SJohannes Berg break;
179511127e91SJohannes Berg }
179611127e91SJohannes Berg
17974fd0328dSJohannes Berg result = ieee80211_tx_frags(local, vif, sta, skbs, txpending);
179811127e91SJohannes Berg
17994db4e0a1SJohannes Berg WARN_ON_ONCE(!skb_queue_empty(skbs));
1800252b86c4SJohannes Berg
180111127e91SJohannes Berg return result;
1802e2ebc74dSJohannes Berg }
1803e2ebc74dSJohannes Berg
180497b045d6SJohannes Berg /*
180597b045d6SJohannes Berg * Invoke TX handlers, return 0 on success and non-zero if the
180697b045d6SJohannes Berg * frame was dropped or queued.
1807bb42f2d1SToke Høiland-Jørgensen *
1808bb42f2d1SToke Høiland-Jørgensen * The handlers are split into an early and late part. The latter is everything
1809bb42f2d1SToke Høiland-Jørgensen * that can be sensitive to reordering, and will be deferred to after packets
1810bb42f2d1SToke Høiland-Jørgensen * are dequeued from the intermediate queues (when they are enabled).
181197b045d6SJohannes Berg */
invoke_tx_handlers_early(struct ieee80211_tx_data * tx)1812bb42f2d1SToke Høiland-Jørgensen static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
181397b045d6SJohannes Berg {
181497b045d6SJohannes Berg ieee80211_tx_result res = TX_DROP;
181597b045d6SJohannes Berg
1816d9e8a70fSJohannes Berg #define CALL_TXH(txh) \
18179aa4aee3SJohannes Berg do { \
1818d9e8a70fSJohannes Berg res = txh(tx); \
1819d9e8a70fSJohannes Berg if (res != TX_CONTINUE) \
18209aa4aee3SJohannes Berg goto txh_done; \
18219aa4aee3SJohannes Berg } while (0)
182297b045d6SJohannes Berg
18235c1b98a5SKalle Valo CALL_TXH(ieee80211_tx_h_dynamic_ps);
18249aa4aee3SJohannes Berg CALL_TXH(ieee80211_tx_h_check_assoc);
18259aa4aee3SJohannes Berg CALL_TXH(ieee80211_tx_h_ps_buf);
1826a621fa4dSJohannes Berg CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
18279aa4aee3SJohannes Berg CALL_TXH(ieee80211_tx_h_select_key);
1828c6fcf6bcSJohannes Berg
1829bb42f2d1SToke Høiland-Jørgensen txh_done:
1830bb42f2d1SToke Høiland-Jørgensen if (unlikely(res == TX_DROP)) {
1831bb42f2d1SToke Høiland-Jørgensen I802_DEBUG_INC(tx->local->tx_handlers_drop);
1832bb42f2d1SToke Høiland-Jørgensen if (tx->skb)
1833bb42f2d1SToke Høiland-Jørgensen ieee80211_free_txskb(&tx->local->hw, tx->skb);
1834bb42f2d1SToke Høiland-Jørgensen else
1835bb42f2d1SToke Høiland-Jørgensen ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
1836bb42f2d1SToke Høiland-Jørgensen return -1;
1837bb42f2d1SToke Høiland-Jørgensen } else if (unlikely(res == TX_QUEUED)) {
1838bb42f2d1SToke Høiland-Jørgensen I802_DEBUG_INC(tx->local->tx_handlers_queued);
1839bb42f2d1SToke Høiland-Jørgensen return -1;
1840bb42f2d1SToke Høiland-Jørgensen }
1841bb42f2d1SToke Høiland-Jørgensen
1842bb42f2d1SToke Høiland-Jørgensen return 0;
1843bb42f2d1SToke Høiland-Jørgensen }
1844bb42f2d1SToke Høiland-Jørgensen
1845bb42f2d1SToke Høiland-Jørgensen /*
1846bb42f2d1SToke Høiland-Jørgensen * Late handlers can be called while the sta lock is held. Handlers that can
1847bb42f2d1SToke Høiland-Jørgensen * cause packets to be generated will cause deadlock!
1848bb42f2d1SToke Høiland-Jørgensen */
invoke_tx_handlers_late(struct ieee80211_tx_data * tx)1849bb42f2d1SToke Høiland-Jørgensen static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
1850bb42f2d1SToke Høiland-Jørgensen {
1851bb42f2d1SToke Høiland-Jørgensen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
1852bb42f2d1SToke Høiland-Jørgensen ieee80211_tx_result res = TX_CONTINUE;
1853bb42f2d1SToke Høiland-Jørgensen
185418688c80SFelix Fietkau if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
185518688c80SFelix Fietkau CALL_TXH(ieee80211_tx_h_rate_ctrl);
185618688c80SFelix Fietkau
1857aa5b5492SJohannes Berg if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
1858aa5b5492SJohannes Berg __skb_queue_tail(&tx->skbs, tx->skb);
1859aa5b5492SJohannes Berg tx->skb = NULL;
1860c6fcf6bcSJohannes Berg goto txh_done;
1861aa5b5492SJohannes Berg }
1862c6fcf6bcSJohannes Berg
1863c6fcf6bcSJohannes Berg CALL_TXH(ieee80211_tx_h_michael_mic_add);
18649aa4aee3SJohannes Berg CALL_TXH(ieee80211_tx_h_sequence);
18659aa4aee3SJohannes Berg CALL_TXH(ieee80211_tx_h_fragment);
1866d9e8a70fSJohannes Berg /* handlers after fragment must be aware of tx info fragmentation! */
18679aa4aee3SJohannes Berg CALL_TXH(ieee80211_tx_h_stats);
18689aa4aee3SJohannes Berg CALL_TXH(ieee80211_tx_h_encrypt);
186930686bf7SJohannes Berg if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
18709aa4aee3SJohannes Berg CALL_TXH(ieee80211_tx_h_calculate_duration);
1871d9e8a70fSJohannes Berg #undef CALL_TXH
1872d9e8a70fSJohannes Berg
1873d9e8a70fSJohannes Berg txh_done:
187497b045d6SJohannes Berg if (unlikely(res == TX_DROP)) {
18755479d0e7STomas Winkler I802_DEBUG_INC(tx->local->tx_handlers_drop);
1876252b86c4SJohannes Berg if (tx->skb)
1877c3e7724bSFelix Fietkau ieee80211_free_txskb(&tx->local->hw, tx->skb);
1878252b86c4SJohannes Berg else
18791f98ab7fSFelix Fietkau ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
188097b045d6SJohannes Berg return -1;
188197b045d6SJohannes Berg } else if (unlikely(res == TX_QUEUED)) {
18825479d0e7STomas Winkler I802_DEBUG_INC(tx->local->tx_handlers_queued);
188397b045d6SJohannes Berg return -1;
188497b045d6SJohannes Berg }
188597b045d6SJohannes Berg
188697b045d6SJohannes Berg return 0;
188797b045d6SJohannes Berg }
188897b045d6SJohannes Berg
invoke_tx_handlers(struct ieee80211_tx_data * tx)1889bb42f2d1SToke Høiland-Jørgensen static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
1890bb42f2d1SToke Høiland-Jørgensen {
1891bb42f2d1SToke Høiland-Jørgensen int r = invoke_tx_handlers_early(tx);
1892bb42f2d1SToke Høiland-Jørgensen
1893bb42f2d1SToke Høiland-Jørgensen if (r)
1894bb42f2d1SToke Høiland-Jørgensen return r;
1895bb42f2d1SToke Høiland-Jørgensen return invoke_tx_handlers_late(tx);
1896bb42f2d1SToke Høiland-Jørgensen }
1897bb42f2d1SToke Høiland-Jørgensen
ieee80211_tx_prepare_skb(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct sk_buff * skb,int band,struct ieee80211_sta ** sta)189806be6b14SFelix Fietkau bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
189906be6b14SFelix Fietkau struct ieee80211_vif *vif, struct sk_buff *skb,
190006be6b14SFelix Fietkau int band, struct ieee80211_sta **sta)
190106be6b14SFelix Fietkau {
190206be6b14SFelix Fietkau struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
190306be6b14SFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
190406be6b14SFelix Fietkau struct ieee80211_tx_data tx;
190588724a81SJohannes Berg struct sk_buff *skb2;
190606be6b14SFelix Fietkau
19077c10770fSJohannes Berg if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
190806be6b14SFelix Fietkau return false;
190906be6b14SFelix Fietkau
191006be6b14SFelix Fietkau info->band = band;
191106be6b14SFelix Fietkau info->control.vif = vif;
191206be6b14SFelix Fietkau info->hw_queue = vif->hw_queue[skb_get_queue_mapping(skb)];
191306be6b14SFelix Fietkau
191406be6b14SFelix Fietkau if (invoke_tx_handlers(&tx))
191506be6b14SFelix Fietkau return false;
191606be6b14SFelix Fietkau
191706be6b14SFelix Fietkau if (sta) {
191806be6b14SFelix Fietkau if (tx.sta)
191906be6b14SFelix Fietkau *sta = &tx.sta->sta;
192006be6b14SFelix Fietkau else
192106be6b14SFelix Fietkau *sta = NULL;
192206be6b14SFelix Fietkau }
192306be6b14SFelix Fietkau
192488724a81SJohannes Berg /* this function isn't suitable for fragmented data frames */
192588724a81SJohannes Berg skb2 = __skb_dequeue(&tx.skbs);
192688724a81SJohannes Berg if (WARN_ON(skb2 != skb || !skb_queue_empty(&tx.skbs))) {
192788724a81SJohannes Berg ieee80211_free_txskb(hw, skb2);
192888724a81SJohannes Berg ieee80211_purge_tx_queue(hw, &tx.skbs);
192988724a81SJohannes Berg return false;
193088724a81SJohannes Berg }
193188724a81SJohannes Berg
193206be6b14SFelix Fietkau return true;
193306be6b14SFelix Fietkau }
193406be6b14SFelix Fietkau EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
193506be6b14SFelix Fietkau
19367bb45683SJohannes Berg /*
19377bb45683SJohannes Berg * Returns false if the frame couldn't be transmitted but was queued instead.
19387bb45683SJohannes Berg */
ieee80211_tx(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct sk_buff * skb,bool txpending)19397bb45683SJohannes Berg static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
19407c10770fSJohannes Berg struct sta_info *sta, struct sk_buff *skb,
194108aca29aSMathy Vanhoef bool txpending)
1942e2ebc74dSJohannes Berg {
19433b8d81e0SJohannes Berg struct ieee80211_local *local = sdata->local;
19445cf121c3SJohannes Berg struct ieee80211_tx_data tx;
194597b045d6SJohannes Berg ieee80211_tx_result res_prepare;
1946e039fa4aSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
19477bb45683SJohannes Berg bool result = true;
1948e2ebc74dSJohannes Berg
1949e2ebc74dSJohannes Berg if (unlikely(skb->len < 10)) {
1950e2ebc74dSJohannes Berg dev_kfree_skb(skb);
19517bb45683SJohannes Berg return true;
1952e2ebc74dSJohannes Berg }
1953e2ebc74dSJohannes Berg
195458d4185eSJohannes Berg /* initialises tx */
19557c10770fSJohannes Berg res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
1956e2ebc74dSJohannes Berg
1957cd8ffc80SJohannes Berg if (unlikely(res_prepare == TX_DROP)) {
1958c3e7724bSFelix Fietkau ieee80211_free_txskb(&local->hw, skb);
195955de908aSJohannes Berg return true;
1960cd8ffc80SJohannes Berg } else if (unlikely(res_prepare == TX_QUEUED)) {
196155de908aSJohannes Berg return true;
1962e2ebc74dSJohannes Berg }
1963e2ebc74dSJohannes Berg
19643a25a8c8SJohannes Berg /* set up hw_queue value early */
19653a25a8c8SJohannes Berg if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
196630686bf7SJohannes Berg !ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
19673a25a8c8SJohannes Berg info->hw_queue =
19683a25a8c8SJohannes Berg sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
19693a25a8c8SJohannes Berg
1970bb42f2d1SToke Høiland-Jørgensen if (invoke_tx_handlers_early(&tx))
19716eae4a6cSBob Copeland return true;
1972bb42f2d1SToke Høiland-Jørgensen
1973bb42f2d1SToke Høiland-Jørgensen if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb))
1974bb42f2d1SToke Høiland-Jørgensen return true;
1975bb42f2d1SToke Høiland-Jørgensen
1976bb42f2d1SToke Høiland-Jørgensen if (!invoke_tx_handlers_late(&tx))
197730f6cf96SFelix Fietkau result = __ieee80211_tx(local, &tx.skbs, tx.sta, txpending);
197855de908aSJohannes Berg
19797bb45683SJohannes Berg return result;
1980e2ebc74dSJohannes Berg }
1981e2ebc74dSJohannes Berg
1982e2ebc74dSJohannes Berg /* device xmit handlers */
1983e2ebc74dSJohannes Berg
198414f46c1eSJohannes Berg enum ieee80211_encrypt {
198514f46c1eSJohannes Berg ENCRYPT_NO,
198614f46c1eSJohannes Berg ENCRYPT_MGMT,
198714f46c1eSJohannes Berg ENCRYPT_DATA,
198814f46c1eSJohannes Berg };
198914f46c1eSJohannes Berg
ieee80211_skb_resize(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,int head_need,enum ieee80211_encrypt encrypt)19903bff1865SYogesh Ashok Powar static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
199123c0752aSJohannes Berg struct sk_buff *skb,
199214f46c1eSJohannes Berg int head_need,
199314f46c1eSJohannes Berg enum ieee80211_encrypt encrypt)
199423c0752aSJohannes Berg {
19953bff1865SYogesh Ashok Powar struct ieee80211_local *local = sdata->local;
19969d0f50b8SFelix Fietkau bool enc_tailroom;
199723c0752aSJohannes Berg int tail_need = 0;
199823c0752aSJohannes Berg
199914f46c1eSJohannes Berg enc_tailroom = encrypt == ENCRYPT_MGMT ||
200014f46c1eSJohannes Berg (encrypt == ENCRYPT_DATA &&
200114f46c1eSJohannes Berg sdata->crypto_tx_tailroom_needed_cnt);
20029d0f50b8SFelix Fietkau
20039d0f50b8SFelix Fietkau if (enc_tailroom) {
200423c0752aSJohannes Berg tail_need = IEEE80211_ENCRYPT_TAILROOM;
200523c0752aSJohannes Berg tail_need -= skb_tailroom(skb);
200623c0752aSJohannes Berg tail_need = max_t(int, tail_need, 0);
200723c0752aSJohannes Berg }
200823c0752aSJohannes Berg
2009c70f59a2SIdo Yariv if (skb_cloned(skb) &&
201030686bf7SJohannes Berg (!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) ||
20119d0f50b8SFelix Fietkau !skb_clone_writable(skb, ETH_HLEN) || enc_tailroom))
201223c0752aSJohannes Berg I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
20134cd06a34SFelix Fietkau else if (head_need || tail_need)
201423c0752aSJohannes Berg I802_DEBUG_INC(local->tx_expand_skb_head);
20154cd06a34SFelix Fietkau else
20164cd06a34SFelix Fietkau return 0;
201723c0752aSJohannes Berg
201823c0752aSJohannes Berg if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
20190fb9a9ecSJoe Perches wiphy_debug(local->hw.wiphy,
20200fb9a9ecSJoe Perches "failed to reallocate TX buffer\n");
202123c0752aSJohannes Berg return -ENOMEM;
202223c0752aSJohannes Berg }
202323c0752aSJohannes Berg
202423c0752aSJohannes Berg return 0;
202523c0752aSJohannes Berg }
202623c0752aSJohannes Berg
ieee80211_xmit(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct sk_buff * skb)20277c10770fSJohannes Berg void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
202808aca29aSMathy Vanhoef struct sta_info *sta, struct sk_buff *skb)
2029e2ebc74dSJohannes Berg {
20303b8d81e0SJohannes Berg struct ieee80211_local *local = sdata->local;
2031e039fa4aSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
203214f46c1eSJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
2033e2ebc74dSJohannes Berg int headroom;
203414f46c1eSJohannes Berg enum ieee80211_encrypt encrypt;
2035e2ebc74dSJohannes Berg
203614f46c1eSJohannes Berg if (info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)
203714f46c1eSJohannes Berg encrypt = ENCRYPT_NO;
203814f46c1eSJohannes Berg else if (ieee80211_is_mgmt(hdr->frame_control))
203914f46c1eSJohannes Berg encrypt = ENCRYPT_MGMT;
204014f46c1eSJohannes Berg else
204114f46c1eSJohannes Berg encrypt = ENCRYPT_DATA;
204223c0752aSJohannes Berg
20433b8d81e0SJohannes Berg headroom = local->tx_headroom;
204414f46c1eSJohannes Berg if (encrypt != ENCRYPT_NO)
204523a5f0afSJohannes Berg headroom += IEEE80211_ENCRYPT_HEADROOM;
204623c0752aSJohannes Berg headroom -= skb_headroom(skb);
204723c0752aSJohannes Berg headroom = max_t(int, 0, headroom);
204823c0752aSJohannes Berg
204914f46c1eSJohannes Berg if (ieee80211_skb_resize(sdata, skb, headroom, encrypt)) {
2050c3e7724bSFelix Fietkau ieee80211_free_txskb(&local->hw, skb);
20513b8d81e0SJohannes Berg return;
2052e2ebc74dSJohannes Berg }
2053e2ebc74dSJohannes Berg
205414f46c1eSJohannes Berg /* reload after potential resize */
2055740c1aa3SSteve deRosier hdr = (struct ieee80211_hdr *) skb->data;
20565061b0c2SJohannes Berg info->control.vif = &sdata->vif;
2057cd8ffc80SJohannes Berg
20583f52b7e3SMarco Porsch if (ieee80211_vif_is_mesh(&sdata->vif)) {
20593f52b7e3SMarco Porsch if (ieee80211_is_data(hdr->frame_control) &&
20603f52b7e3SMarco Porsch is_unicast_ether_addr(hdr->addr1)) {
2061bf7cd94dSJohannes Berg if (mesh_nexthop_resolve(sdata, skb))
20623f52b7e3SMarco Porsch return; /* skb queued: don't free */
20633f52b7e3SMarco Porsch } else {
20643f52b7e3SMarco Porsch ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
20653f52b7e3SMarco Porsch }
2066cca89496SJavier Cardona }
2067cca89496SJavier Cardona
20682154c81cSJavier Cardona ieee80211_set_qos_hdr(sdata, skb);
206908aca29aSMathy Vanhoef ieee80211_tx(sdata, sta, skb, false);
2070e2ebc74dSJohannes Berg }
2071e2ebc74dSJohannes Berg
ieee80211_validate_radiotap_len(struct sk_buff * skb)2072bddc0c41SMathy Vanhoef static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
207373b9f03aSJohannes Berg {
207473b9f03aSJohannes Berg struct ieee80211_radiotap_header *rthdr =
207573b9f03aSJohannes Berg (struct ieee80211_radiotap_header *)skb->data;
207673b9f03aSJohannes Berg
2077cb17ed29SMathy Vanhoef /* check for not even having the fixed radiotap header part */
2078cb17ed29SMathy Vanhoef if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
2079cb17ed29SMathy Vanhoef return false; /* too short to be possibly valid */
2080cb17ed29SMathy Vanhoef
2081cb17ed29SMathy Vanhoef /* is it a header version we can trust to find length from? */
2082cb17ed29SMathy Vanhoef if (unlikely(rthdr->it_version))
2083cb17ed29SMathy Vanhoef return false; /* only version 0 is supported */
2084cb17ed29SMathy Vanhoef
2085cb17ed29SMathy Vanhoef /* does the skb contain enough to deliver on the alleged length? */
2086cb17ed29SMathy Vanhoef if (unlikely(skb->len < ieee80211_get_radiotap_len(skb->data)))
2087cb17ed29SMathy Vanhoef return false; /* skb too short for claimed rt header extent */
2088cb17ed29SMathy Vanhoef
2089bddc0c41SMathy Vanhoef return true;
2090bddc0c41SMathy Vanhoef }
2091bddc0c41SMathy Vanhoef
ieee80211_parse_tx_radiotap(struct sk_buff * skb,struct net_device * dev)2092bddc0c41SMathy Vanhoef bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
2093bddc0c41SMathy Vanhoef struct net_device *dev)
2094bddc0c41SMathy Vanhoef {
2095bddc0c41SMathy Vanhoef struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
2096bddc0c41SMathy Vanhoef struct ieee80211_radiotap_iterator iterator;
2097bddc0c41SMathy Vanhoef struct ieee80211_radiotap_header *rthdr =
2098bddc0c41SMathy Vanhoef (struct ieee80211_radiotap_header *) skb->data;
2099bddc0c41SMathy Vanhoef struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2100bddc0c41SMathy Vanhoef int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
2101bddc0c41SMathy Vanhoef NULL);
2102bddc0c41SMathy Vanhoef u16 txflags;
2103bddc0c41SMathy Vanhoef u16 rate = 0;
2104bddc0c41SMathy Vanhoef bool rate_found = false;
2105bddc0c41SMathy Vanhoef u8 rate_retries = 0;
2106bddc0c41SMathy Vanhoef u16 rate_flags = 0;
2107bddc0c41SMathy Vanhoef u8 mcs_known, mcs_flags, mcs_bw;
2108bddc0c41SMathy Vanhoef u16 vht_known;
2109bddc0c41SMathy Vanhoef u8 vht_mcs = 0, vht_nss = 0;
2110bddc0c41SMathy Vanhoef int i;
2111bddc0c41SMathy Vanhoef
2112bddc0c41SMathy Vanhoef if (!ieee80211_validate_radiotap_len(skb))
2113bddc0c41SMathy Vanhoef return false;
2114bddc0c41SMathy Vanhoef
211573b9f03aSJohannes Berg info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
211673b9f03aSJohannes Berg IEEE80211_TX_CTL_DONTFRAG;
211773b9f03aSJohannes Berg
211873b9f03aSJohannes Berg /*
211973b9f03aSJohannes Berg * for every radiotap entry that is present
212073b9f03aSJohannes Berg * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
212173b9f03aSJohannes Berg * entries present, or -EINVAL on error)
212273b9f03aSJohannes Berg */
212373b9f03aSJohannes Berg
212473b9f03aSJohannes Berg while (!ret) {
212573b9f03aSJohannes Berg ret = ieee80211_radiotap_iterator_next(&iterator);
212673b9f03aSJohannes Berg
212773b9f03aSJohannes Berg if (ret)
212873b9f03aSJohannes Berg continue;
212973b9f03aSJohannes Berg
213073b9f03aSJohannes Berg /* see if this argument is something we can use */
213173b9f03aSJohannes Berg switch (iterator.this_arg_index) {
213273b9f03aSJohannes Berg /*
213373b9f03aSJohannes Berg * You must take care when dereferencing iterator.this_arg
213473b9f03aSJohannes Berg * for multibyte types... the pointer is not aligned. Use
213573b9f03aSJohannes Berg * get_unaligned((type *)iterator.this_arg) to dereference
213673b9f03aSJohannes Berg * iterator.this_arg for type "type" safely on all arches.
213773b9f03aSJohannes Berg */
213873b9f03aSJohannes Berg case IEEE80211_RADIOTAP_FLAGS:
213973b9f03aSJohannes Berg if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
214073b9f03aSJohannes Berg /*
214173b9f03aSJohannes Berg * this indicates that the skb we have been
214273b9f03aSJohannes Berg * handed has the 32-bit FCS CRC at the end...
214373b9f03aSJohannes Berg * we should react to that by snipping it off
214473b9f03aSJohannes Berg * because it will be recomputed and added
214573b9f03aSJohannes Berg * on transmission
214673b9f03aSJohannes Berg */
214773b9f03aSJohannes Berg if (skb->len < (iterator._max_length + FCS_LEN))
214873b9f03aSJohannes Berg return false;
214973b9f03aSJohannes Berg
215073b9f03aSJohannes Berg skb_trim(skb, skb->len - FCS_LEN);
215173b9f03aSJohannes Berg }
215273b9f03aSJohannes Berg if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
215373b9f03aSJohannes Berg info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
215473b9f03aSJohannes Berg if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
215573b9f03aSJohannes Berg info->flags &= ~IEEE80211_TX_CTL_DONTFRAG;
215673b9f03aSJohannes Berg break;
215773b9f03aSJohannes Berg
215873b9f03aSJohannes Berg case IEEE80211_RADIOTAP_TX_FLAGS:
215973b9f03aSJohannes Berg txflags = get_unaligned_le16(iterator.this_arg);
216073b9f03aSJohannes Berg if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK)
216173b9f03aSJohannes Berg info->flags |= IEEE80211_TX_CTL_NO_ACK;
2162e02281e7SMathy Vanhoef if (txflags & IEEE80211_RADIOTAP_F_TX_NOSEQNO)
2163e02281e7SMathy Vanhoef info->control.flags |= IEEE80211_TX_CTRL_NO_SEQNO;
216430df8130SMathy Vanhoef if (txflags & IEEE80211_RADIOTAP_F_TX_ORDER)
216530df8130SMathy Vanhoef info->control.flags |=
216630df8130SMathy Vanhoef IEEE80211_TX_CTRL_DONT_REORDER;
216773b9f03aSJohannes Berg break;
216873b9f03aSJohannes Berg
2169dfdfc2beSSven Eckelmann case IEEE80211_RADIOTAP_RATE:
2170dfdfc2beSSven Eckelmann rate = *iterator.this_arg;
2171dfdfc2beSSven Eckelmann rate_flags = 0;
2172dfdfc2beSSven Eckelmann rate_found = true;
2173dfdfc2beSSven Eckelmann break;
2174dfdfc2beSSven Eckelmann
2175dfdfc2beSSven Eckelmann case IEEE80211_RADIOTAP_DATA_RETRIES:
2176dfdfc2beSSven Eckelmann rate_retries = *iterator.this_arg;
2177dfdfc2beSSven Eckelmann break;
2178dfdfc2beSSven Eckelmann
2179dfdfc2beSSven Eckelmann case IEEE80211_RADIOTAP_MCS:
2180dfdfc2beSSven Eckelmann mcs_known = iterator.this_arg[0];
2181dfdfc2beSSven Eckelmann mcs_flags = iterator.this_arg[1];
2182dfdfc2beSSven Eckelmann if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS))
2183dfdfc2beSSven Eckelmann break;
2184dfdfc2beSSven Eckelmann
2185dfdfc2beSSven Eckelmann rate_found = true;
2186dfdfc2beSSven Eckelmann rate = iterator.this_arg[2];
2187dfdfc2beSSven Eckelmann rate_flags = IEEE80211_TX_RC_MCS;
2188dfdfc2beSSven Eckelmann
2189dfdfc2beSSven Eckelmann if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI &&
2190dfdfc2beSSven Eckelmann mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
2191dfdfc2beSSven Eckelmann rate_flags |= IEEE80211_TX_RC_SHORT_GI;
2192dfdfc2beSSven Eckelmann
2193f66b60f6SSven Eckelmann mcs_bw = mcs_flags & IEEE80211_RADIOTAP_MCS_BW_MASK;
2194dfdfc2beSSven Eckelmann if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
2195f66b60f6SSven Eckelmann mcs_bw == IEEE80211_RADIOTAP_MCS_BW_40)
2196dfdfc2beSSven Eckelmann rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
2197f1864e19SPhilipp Borgers
2198f1864e19SPhilipp Borgers if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_FEC &&
2199f1864e19SPhilipp Borgers mcs_flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC)
2200f1864e19SPhilipp Borgers info->flags |= IEEE80211_TX_CTL_LDPC;
2201549fdd34SPhilipp Borgers
2202549fdd34SPhilipp Borgers if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_STBC) {
2203549fdd34SPhilipp Borgers u8 stbc = u8_get_bits(mcs_flags,
2204549fdd34SPhilipp Borgers IEEE80211_RADIOTAP_MCS_STBC_MASK);
2205549fdd34SPhilipp Borgers
2206549fdd34SPhilipp Borgers info->flags |=
2207549fdd34SPhilipp Borgers u32_encode_bits(stbc,
2208549fdd34SPhilipp Borgers IEEE80211_TX_CTL_STBC);
2209549fdd34SPhilipp Borgers }
2210dfdfc2beSSven Eckelmann break;
2211dfdfc2beSSven Eckelmann
2212646e76bbSLorenzo Bianconi case IEEE80211_RADIOTAP_VHT:
2213646e76bbSLorenzo Bianconi vht_known = get_unaligned_le16(iterator.this_arg);
2214646e76bbSLorenzo Bianconi rate_found = true;
2215646e76bbSLorenzo Bianconi
2216646e76bbSLorenzo Bianconi rate_flags = IEEE80211_TX_RC_VHT_MCS;
2217646e76bbSLorenzo Bianconi if ((vht_known & IEEE80211_RADIOTAP_VHT_KNOWN_GI) &&
2218646e76bbSLorenzo Bianconi (iterator.this_arg[2] &
2219646e76bbSLorenzo Bianconi IEEE80211_RADIOTAP_VHT_FLAG_SGI))
2220646e76bbSLorenzo Bianconi rate_flags |= IEEE80211_TX_RC_SHORT_GI;
2221646e76bbSLorenzo Bianconi if (vht_known &
2222646e76bbSLorenzo Bianconi IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH) {
2223646e76bbSLorenzo Bianconi if (iterator.this_arg[3] == 1)
2224646e76bbSLorenzo Bianconi rate_flags |=
2225646e76bbSLorenzo Bianconi IEEE80211_TX_RC_40_MHZ_WIDTH;
2226646e76bbSLorenzo Bianconi else if (iterator.this_arg[3] == 4)
2227646e76bbSLorenzo Bianconi rate_flags |=
2228646e76bbSLorenzo Bianconi IEEE80211_TX_RC_80_MHZ_WIDTH;
2229646e76bbSLorenzo Bianconi else if (iterator.this_arg[3] == 11)
2230646e76bbSLorenzo Bianconi rate_flags |=
2231646e76bbSLorenzo Bianconi IEEE80211_TX_RC_160_MHZ_WIDTH;
2232646e76bbSLorenzo Bianconi }
2233646e76bbSLorenzo Bianconi
2234646e76bbSLorenzo Bianconi vht_mcs = iterator.this_arg[4] >> 4;
223513cb6d82SLorenzo Bianconi if (vht_mcs > 11)
223613cb6d82SLorenzo Bianconi vht_mcs = 0;
2237646e76bbSLorenzo Bianconi vht_nss = iterator.this_arg[4] & 0xF;
223813cb6d82SLorenzo Bianconi if (!vht_nss || vht_nss > 8)
223913cb6d82SLorenzo Bianconi vht_nss = 1;
2240646e76bbSLorenzo Bianconi break;
2241646e76bbSLorenzo Bianconi
224273b9f03aSJohannes Berg /*
224373b9f03aSJohannes Berg * Please update the file
2244429ff87bSMauro Carvalho Chehab * Documentation/networking/mac80211-injection.rst
224573b9f03aSJohannes Berg * when parsing new fields here.
224673b9f03aSJohannes Berg */
224773b9f03aSJohannes Berg
224873b9f03aSJohannes Berg default:
224973b9f03aSJohannes Berg break;
225073b9f03aSJohannes Berg }
225173b9f03aSJohannes Berg }
225273b9f03aSJohannes Berg
225373b9f03aSJohannes Berg if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
225473b9f03aSJohannes Berg return false;
225573b9f03aSJohannes Berg
2256dfdfc2beSSven Eckelmann if (rate_found) {
2257bddc0c41SMathy Vanhoef struct ieee80211_supported_band *sband =
2258bddc0c41SMathy Vanhoef local->hw.wiphy->bands[info->band];
2259bddc0c41SMathy Vanhoef
2260dfdfc2beSSven Eckelmann info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
2261dfdfc2beSSven Eckelmann
2262dfdfc2beSSven Eckelmann for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
2263dfdfc2beSSven Eckelmann info->control.rates[i].idx = -1;
2264dfdfc2beSSven Eckelmann info->control.rates[i].flags = 0;
2265dfdfc2beSSven Eckelmann info->control.rates[i].count = 0;
2266dfdfc2beSSven Eckelmann }
2267dfdfc2beSSven Eckelmann
2268dfdfc2beSSven Eckelmann if (rate_flags & IEEE80211_TX_RC_MCS) {
2269dfdfc2beSSven Eckelmann info->control.rates[0].idx = rate;
2270646e76bbSLorenzo Bianconi } else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) {
2271646e76bbSLorenzo Bianconi ieee80211_rate_set_vht(info->control.rates, vht_mcs,
2272646e76bbSLorenzo Bianconi vht_nss);
2273bddc0c41SMathy Vanhoef } else if (sband) {
2274dfdfc2beSSven Eckelmann for (i = 0; i < sband->n_bitrates; i++) {
2275dfdfc2beSSven Eckelmann if (rate * 5 != sband->bitrates[i].bitrate)
2276dfdfc2beSSven Eckelmann continue;
2277dfdfc2beSSven Eckelmann
2278dfdfc2beSSven Eckelmann info->control.rates[0].idx = i;
2279dfdfc2beSSven Eckelmann break;
2280dfdfc2beSSven Eckelmann }
2281dfdfc2beSSven Eckelmann }
2282dfdfc2beSSven Eckelmann
228307310a63SFelix Fietkau if (info->control.rates[0].idx < 0)
228407310a63SFelix Fietkau info->control.flags &= ~IEEE80211_TX_CTRL_RATE_INJECT;
228507310a63SFelix Fietkau
2286dfdfc2beSSven Eckelmann info->control.rates[0].flags = rate_flags;
2287dfdfc2beSSven Eckelmann info->control.rates[0].count = min_t(u8, rate_retries + 1,
2288dfdfc2beSSven Eckelmann local->hw.max_rate_tries);
2289dfdfc2beSSven Eckelmann }
2290dfdfc2beSSven Eckelmann
229173b9f03aSJohannes Berg return true;
229273b9f03aSJohannes Berg }
229373b9f03aSJohannes Berg
ieee80211_monitor_start_xmit(struct sk_buff * skb,struct net_device * dev)2294d0cf9c0dSStephen Hemminger netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
2295e2ebc74dSJohannes Berg struct net_device *dev)
2296e2ebc74dSJohannes Berg {
2297e2ebc74dSJohannes Berg struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
229855de908aSJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf;
22993b8d81e0SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2300f75f5c6fSHelmut Schaa struct ieee80211_hdr *hdr;
23015d9cf4a5SJohannes Berg struct ieee80211_sub_if_data *tmp_sdata, *sdata;
2302b4932836SJanusz Dziedzic struct cfg80211_chan_def *chandef;
23039b8a74e3SAndy Green u16 len_rthdr;
23045d9cf4a5SJohannes Berg int hdrlen;
2305e2ebc74dSJohannes Berg
2306c95014e1SAlexander Wetzel sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2307c95014e1SAlexander Wetzel if (unlikely(!ieee80211_sdata_running(sdata)))
2308c95014e1SAlexander Wetzel goto fail;
2309c95014e1SAlexander Wetzel
2310cb17ed29SMathy Vanhoef memset(info, 0, sizeof(*info));
2311cb17ed29SMathy Vanhoef info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
2312cb17ed29SMathy Vanhoef IEEE80211_TX_CTL_INJECTED;
23139b8a74e3SAndy Green
2314bddc0c41SMathy Vanhoef /* Sanity-check the length of the radiotap header */
2315bddc0c41SMathy Vanhoef if (!ieee80211_validate_radiotap_len(skb))
2316cb17ed29SMathy Vanhoef goto fail;
23179b8a74e3SAndy Green
2318cb17ed29SMathy Vanhoef /* we now know there is a radiotap header with a length we can use */
23199b8a74e3SAndy Green len_rthdr = ieee80211_get_radiotap_len(skb->data);
23209b8a74e3SAndy Green
2321e2ebc74dSJohannes Berg /*
2322e2ebc74dSJohannes Berg * fix up the pointers accounting for the radiotap
2323e2ebc74dSJohannes Berg * header still being in there. We are being given
2324e2ebc74dSJohannes Berg * a precooked IEEE80211 header so no need for
2325e2ebc74dSJohannes Berg * normal processing
2326e2ebc74dSJohannes Berg */
23279b8a74e3SAndy Green skb_set_mac_header(skb, len_rthdr);
2328e2ebc74dSJohannes Berg /*
23299b8a74e3SAndy Green * these are just fixed to the end of the rt area since we
23309b8a74e3SAndy Green * don't have any better information and at this point, nobody cares
2331e2ebc74dSJohannes Berg */
23329b8a74e3SAndy Green skb_set_network_header(skb, len_rthdr);
23339b8a74e3SAndy Green skb_set_transport_header(skb, len_rthdr);
2334e2ebc74dSJohannes Berg
23355d9cf4a5SJohannes Berg if (skb->len < len_rthdr + 2)
23365d9cf4a5SJohannes Berg goto fail;
23375d9cf4a5SJohannes Berg
23385d9cf4a5SJohannes Berg hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
23395d9cf4a5SJohannes Berg hdrlen = ieee80211_hdrlen(hdr->frame_control);
23405d9cf4a5SJohannes Berg
23415d9cf4a5SJohannes Berg if (skb->len < len_rthdr + hdrlen)
23425d9cf4a5SJohannes Berg goto fail;
23435d9cf4a5SJohannes Berg
2344f75f5c6fSHelmut Schaa /*
2345f75f5c6fSHelmut Schaa * Initialize skb->protocol if the injected frame is a data frame
2346f75f5c6fSHelmut Schaa * carrying a rfc1042 header
2347f75f5c6fSHelmut Schaa */
2348f75f5c6fSHelmut Schaa if (ieee80211_is_data(hdr->frame_control) &&
23495d9cf4a5SJohannes Berg skb->len >= len_rthdr + hdrlen + sizeof(rfc1042_header) + 2) {
23505d9cf4a5SJohannes Berg u8 *payload = (u8 *)hdr + hdrlen;
23515d9cf4a5SJohannes Berg
2352b203ca39SJoe Perches if (ether_addr_equal(payload, rfc1042_header))
2353f75f5c6fSHelmut Schaa skb->protocol = cpu_to_be16((payload[6] << 8) |
2354f75f5c6fSHelmut Schaa payload[7]);
2355f75f5c6fSHelmut Schaa }
2356f75f5c6fSHelmut Schaa
23575d9cf4a5SJohannes Berg rcu_read_lock();
23585d9cf4a5SJohannes Berg
23595d9cf4a5SJohannes Berg /*
23605d9cf4a5SJohannes Berg * We process outgoing injected frames that have a local address
23615d9cf4a5SJohannes Berg * we handle as though they are non-injected frames.
23625d9cf4a5SJohannes Berg * This code here isn't entirely correct, the local MAC address
23635d9cf4a5SJohannes Berg * isn't always enough to find the interface to use; for proper
236470d9c599SJohannes Berg * VLAN support we have an nl80211-based mechanism.
2365b226a826SJohannes Berg *
2366b226a826SJohannes Berg * This is necessary, for example, for old hostapd versions that
2367b226a826SJohannes Berg * don't use nl80211-based management TX/RX.
23685d9cf4a5SJohannes Berg */
23695d9cf4a5SJohannes Berg list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) {
23705d9cf4a5SJohannes Berg if (!ieee80211_sdata_running(tmp_sdata))
23715d9cf4a5SJohannes Berg continue;
23725d9cf4a5SJohannes Berg if (tmp_sdata->vif.type == NL80211_IFTYPE_MONITOR ||
237370d9c599SJohannes Berg tmp_sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
23745d9cf4a5SJohannes Berg continue;
2375b203ca39SJoe Perches if (ether_addr_equal(tmp_sdata->vif.addr, hdr->addr2)) {
23765d9cf4a5SJohannes Berg sdata = tmp_sdata;
23775d9cf4a5SJohannes Berg break;
23785d9cf4a5SJohannes Berg }
23795d9cf4a5SJohannes Berg }
23807351c6bdSJohannes Berg
2381d0a9123eSJohannes Berg chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
238255de908aSJohannes Berg if (!chanctx_conf) {
238355de908aSJohannes Berg tmp_sdata = rcu_dereference(local->monitor_sdata);
238455de908aSJohannes Berg if (tmp_sdata)
238555de908aSJohannes Berg chanctx_conf =
2386d0a9123eSJohannes Berg rcu_dereference(tmp_sdata->vif.bss_conf.chanctx_conf);
238755de908aSJohannes Berg }
238855de908aSJohannes Berg
2389b4a7ff75SFelix Fietkau if (chanctx_conf)
2390b4932836SJanusz Dziedzic chandef = &chanctx_conf->def;
2391b4a7ff75SFelix Fietkau else if (!local->use_chanctx)
2392b4932836SJanusz Dziedzic chandef = &local->_oper_chandef;
2393b4a7ff75SFelix Fietkau else
2394b4a7ff75SFelix Fietkau goto fail_rcu;
239555de908aSJohannes Berg
239655de908aSJohannes Berg /*
239755de908aSJohannes Berg * Frame injection is not allowed if beaconing is not allowed
239855de908aSJohannes Berg * or if we need radar detection. Beaconing is usually not allowed when
239955de908aSJohannes Berg * the mode or operation (Adhoc, AP, Mesh) does not support DFS.
240055de908aSJohannes Berg * Passive scan is also used in world regulatory domains where
240155de908aSJohannes Berg * your country is not known and as such it should be treated as
240255de908aSJohannes Berg * NO TX unless the channel is explicitly allowed in which case
240355de908aSJohannes Berg * your current regulatory domain would not have the passive scan
240455de908aSJohannes Berg * flag.
240555de908aSJohannes Berg *
240655de908aSJohannes Berg * Since AP mode uses monitor interfaces to inject/TX management
240755de908aSJohannes Berg * frames we can make AP mode the exception to this rule once it
240855de908aSJohannes Berg * supports radar detection as its implementation can deal with
240955de908aSJohannes Berg * radar detection by itself. We can do that later by adding a
241055de908aSJohannes Berg * monitor flag interfaces used for AP support.
241155de908aSJohannes Berg */
2412b4932836SJanusz Dziedzic if (!cfg80211_reg_can_beacon(local->hw.wiphy, chandef,
2413b4932836SJanusz Dziedzic sdata->vif.type))
241455de908aSJohannes Berg goto fail_rcu;
241555de908aSJohannes Berg
241673c4e195SJohannes Berg info->band = chandef->chan->band;
2417109843b0SLorenzo Bianconi
241896a7109aSJohan Almbladh /* Initialize skb->priority according to frame type and TID class,
241996a7109aSJohan Almbladh * with respect to the sub interface that the frame will actually
242096a7109aSJohan Almbladh * be transmitted on. If the DONT_REORDER flag is set, the original
242196a7109aSJohan Almbladh * skb-priority is preserved to assure frames injected with this
242296a7109aSJohan Almbladh * flag are not reordered relative to each other.
242396a7109aSJohan Almbladh */
242496a7109aSJohan Almbladh ieee80211_select_queue_80211(sdata, skb, hdr);
242596a7109aSJohan Almbladh skb_set_queue_mapping(skb, ieee80211_ac_from_tid(skb->priority));
242696a7109aSJohan Almbladh
2427bddc0c41SMathy Vanhoef /*
2428bddc0c41SMathy Vanhoef * Process the radiotap header. This will now take into account the
2429bddc0c41SMathy Vanhoef * selected chandef above to accurately set injection rates and
2430bddc0c41SMathy Vanhoef * retransmissions.
2431bddc0c41SMathy Vanhoef */
2432bddc0c41SMathy Vanhoef if (!ieee80211_parse_tx_radiotap(skb, dev))
2433bddc0c41SMathy Vanhoef goto fail_rcu;
2434bddc0c41SMathy Vanhoef
2435cb17ed29SMathy Vanhoef /* remove the injection radiotap header */
2436cb17ed29SMathy Vanhoef skb_pull(skb, len_rthdr);
2437109843b0SLorenzo Bianconi
243808aca29aSMathy Vanhoef ieee80211_xmit(sdata, NULL, skb);
24395d9cf4a5SJohannes Berg rcu_read_unlock();
24405d9cf4a5SJohannes Berg
2441e2ebc74dSJohannes Berg return NETDEV_TX_OK;
24429b8a74e3SAndy Green
244355de908aSJohannes Berg fail_rcu:
244455de908aSJohannes Berg rcu_read_unlock();
24459b8a74e3SAndy Green fail:
24469b8a74e3SAndy Green dev_kfree_skb(skb);
24479b8a74e3SAndy Green return NETDEV_TX_OK; /* meaning, we dealt with the skb */
2448e2ebc74dSJohannes Berg }
2449e2ebc74dSJohannes Berg
ieee80211_is_tdls_setup(struct sk_buff * skb)245097ffe757SJohannes Berg static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb)
2451ad38bfc9SMatti Gottlieb {
245297ffe757SJohannes Berg u16 ethertype = (skb->data[12] << 8) | skb->data[13];
2453ad38bfc9SMatti Gottlieb
245497ffe757SJohannes Berg return ethertype == ETH_P_TDLS &&
245597ffe757SJohannes Berg skb->len > 14 &&
245697ffe757SJohannes Berg skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
245797ffe757SJohannes Berg }
245897ffe757SJohannes Berg
ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,struct sta_info ** sta_out)245950ff477aSJohn Crispin int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
246097ffe757SJohannes Berg struct sk_buff *skb,
246197ffe757SJohannes Berg struct sta_info **sta_out)
246297ffe757SJohannes Berg {
246397ffe757SJohannes Berg struct sta_info *sta;
246497ffe757SJohannes Berg
246597ffe757SJohannes Berg switch (sdata->vif.type) {
246697ffe757SJohannes Berg case NL80211_IFTYPE_AP_VLAN:
246797ffe757SJohannes Berg sta = rcu_dereference(sdata->u.vlan.sta);
246897ffe757SJohannes Berg if (sta) {
246997ffe757SJohannes Berg *sta_out = sta;
247097ffe757SJohannes Berg return 0;
247197ffe757SJohannes Berg } else if (sdata->wdev.use_4addr) {
247297ffe757SJohannes Berg return -ENOLINK;
247397ffe757SJohannes Berg }
2474fc0561dcSGustavo A. R. Silva fallthrough;
247597ffe757SJohannes Berg case NL80211_IFTYPE_AP:
247697ffe757SJohannes Berg case NL80211_IFTYPE_OCB:
247797ffe757SJohannes Berg case NL80211_IFTYPE_ADHOC:
247897ffe757SJohannes Berg if (is_multicast_ether_addr(skb->data)) {
247997ffe757SJohannes Berg *sta_out = ERR_PTR(-ENOENT);
248097ffe757SJohannes Berg return 0;
248197ffe757SJohannes Berg }
248297ffe757SJohannes Berg sta = sta_info_get_bss(sdata, skb->data);
248397ffe757SJohannes Berg break;
248497ffe757SJohannes Berg #ifdef CONFIG_MAC80211_MESH
248597ffe757SJohannes Berg case NL80211_IFTYPE_MESH_POINT:
248697ffe757SJohannes Berg /* determined much later */
248797ffe757SJohannes Berg *sta_out = NULL;
248897ffe757SJohannes Berg return 0;
248997ffe757SJohannes Berg #endif
249097ffe757SJohannes Berg case NL80211_IFTYPE_STATION:
249197ffe757SJohannes Berg if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
249297ffe757SJohannes Berg sta = sta_info_get(sdata, skb->data);
249311d62cafSJohannes Berg if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
249411d62cafSJohannes Berg if (test_sta_flag(sta,
249511d62cafSJohannes Berg WLAN_STA_TDLS_PEER_AUTH)) {
249697ffe757SJohannes Berg *sta_out = sta;
249797ffe757SJohannes Berg return 0;
249897ffe757SJohannes Berg }
249997ffe757SJohannes Berg
250097ffe757SJohannes Berg /*
250197ffe757SJohannes Berg * TDLS link during setup - throw out frames to
250297ffe757SJohannes Berg * peer. Allow TDLS-setup frames to unauthorized
250397ffe757SJohannes Berg * peers for the special case of a link teardown
250497ffe757SJohannes Berg * after a TDLS sta is removed due to being
250597ffe757SJohannes Berg * unreachable.
250697ffe757SJohannes Berg */
250711d62cafSJohannes Berg if (!ieee80211_is_tdls_setup(skb))
250897ffe757SJohannes Berg return -EINVAL;
250997ffe757SJohannes Berg }
251097ffe757SJohannes Berg
251197ffe757SJohannes Berg }
251297ffe757SJohannes Berg
251381151ce4SJohannes Berg sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
251497ffe757SJohannes Berg if (!sta)
251597ffe757SJohannes Berg return -ENOLINK;
251697ffe757SJohannes Berg break;
251797ffe757SJohannes Berg default:
251897ffe757SJohannes Berg return -EINVAL;
251997ffe757SJohannes Berg }
252097ffe757SJohannes Berg
252197ffe757SJohannes Berg *sta_out = sta ?: ERR_PTR(-ENOENT);
252297ffe757SJohannes Berg return 0;
2523ad38bfc9SMatti Gottlieb }
2524ad38bfc9SMatti Gottlieb
ieee80211_store_ack_skb(struct ieee80211_local * local,struct sk_buff * skb,u32 * info_flags,u64 * cookie)2525a7528198SMarkus Theil static u16 ieee80211_store_ack_skb(struct ieee80211_local *local,
25265d8983c8SJohn Crispin struct sk_buff *skb,
2527a7528198SMarkus Theil u32 *info_flags,
2528a7528198SMarkus Theil u64 *cookie)
25295d8983c8SJohn Crispin {
2530a7528198SMarkus Theil struct sk_buff *ack_skb;
25315d8983c8SJohn Crispin u16 info_id = 0;
25325d8983c8SJohn Crispin
2533a7528198SMarkus Theil if (skb->sk)
2534a7528198SMarkus Theil ack_skb = skb_clone_sk(skb);
2535a7528198SMarkus Theil else
2536a7528198SMarkus Theil ack_skb = skb_clone(skb, GFP_ATOMIC);
2537a7528198SMarkus Theil
25385d8983c8SJohn Crispin if (ack_skb) {
25395d8983c8SJohn Crispin unsigned long flags;
25405d8983c8SJohn Crispin int id;
25415d8983c8SJohn Crispin
25425d8983c8SJohn Crispin spin_lock_irqsave(&local->ack_status_lock, flags);
25435d8983c8SJohn Crispin id = idr_alloc(&local->ack_status_frames, ack_skb,
2544f2b18bacSJohannes Berg 1, 0x2000, GFP_ATOMIC);
25455d8983c8SJohn Crispin spin_unlock_irqrestore(&local->ack_status_lock, flags);
25465d8983c8SJohn Crispin
25475d8983c8SJohn Crispin if (id >= 0) {
25485d8983c8SJohn Crispin info_id = id;
25495d8983c8SJohn Crispin *info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
2550a7528198SMarkus Theil if (cookie) {
2551a7528198SMarkus Theil *cookie = ieee80211_mgmt_tx_cookie(local);
2552a7528198SMarkus Theil IEEE80211_SKB_CB(ack_skb)->ack.cookie = *cookie;
2553a7528198SMarkus Theil }
25545d8983c8SJohn Crispin } else {
25555d8983c8SJohn Crispin kfree_skb(ack_skb);
25565d8983c8SJohn Crispin }
25575d8983c8SJohn Crispin }
25585d8983c8SJohn Crispin
25595d8983c8SJohn Crispin return info_id;
25605d8983c8SJohn Crispin }
25615d8983c8SJohn Crispin
2562e2ebc74dSJohannes Berg /**
25634c9451edSJohannes Berg * ieee80211_build_hdr - build 802.11 header in the given frame
25644c9451edSJohannes Berg * @sdata: virtual interface to build the header for
25654c9451edSJohannes Berg * @skb: the skb to build the header in
256624d342c5SLiad Kaufman * @info_flags: skb flags to set
2567f0daf54fSJohannes Berg * @sta: the station pointer
256806016772SRajkumar Manoharan * @ctrl_flags: info control flags to set
2569f0daf54fSJohannes Berg * @cookie: cookie pointer to fill (if not %NULL)
2570e2ebc74dSJohannes Berg *
25714c9451edSJohannes Berg * This function takes the skb with 802.3 header and reformats the header to
25724c9451edSJohannes Berg * the appropriate IEEE 802.11 header based on which interface the packet is
25734c9451edSJohannes Berg * being transmitted on.
2574e2ebc74dSJohannes Berg *
25754c9451edSJohannes Berg * Note that this function also takes care of the TX status request and
25764c9451edSJohannes Berg * potential unsharing of the SKB - this needs to be interleaved with the
25774c9451edSJohannes Berg * header building.
25784c9451edSJohannes Berg *
25794c9451edSJohannes Berg * The function requires the read-side RCU lock held
25804c9451edSJohannes Berg *
25814c9451edSJohannes Berg * Returns: the (possibly reallocated) skb or an ERR_PTR() code
2582e2ebc74dSJohannes Berg */
ieee80211_build_hdr(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,u32 info_flags,struct sta_info * sta,u32 ctrl_flags,u64 * cookie)25834c9451edSJohannes Berg static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
25847c10770fSJohannes Berg struct sk_buff *skb, u32 info_flags,
2585a7528198SMarkus Theil struct sta_info *sta, u32 ctrl_flags,
2586a7528198SMarkus Theil u64 *cookie)
2587e2ebc74dSJohannes Berg {
2588133b8226SJohannes Berg struct ieee80211_local *local = sdata->local;
2589489ee919SFelix Fietkau struct ieee80211_tx_info *info;
2590dcf33963SJohannes Berg int head_need;
2591065e9605SHarvey Harrison u16 ethertype, hdrlen, meshhdrlen = 0;
2592065e9605SHarvey Harrison __le16 fc;
2593e2ebc74dSJohannes Berg struct ieee80211_hdr hdr;
2594ff67bb86SWey-Yi Guy struct ieee80211s_hdr mesh_hdr __maybe_unused;
2595b8bacc18SChun-Yeow Yeoh struct mesh_path __maybe_unused *mppath = NULL, *mpath = NULL;
2596e2ebc74dSJohannes Berg const u8 *encaps_data;
2597e2ebc74dSJohannes Berg int encaps_len, skip_header_bytes;
259897ffe757SJohannes Berg bool wme_sta = false, authorized = false;
259997ffe757SJohannes Berg bool tdls_peer;
2600a729cff8SJohannes Berg bool multicast;
2601a729cff8SJohannes Berg u16 info_id = 0;
2602eef25a66SJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf = NULL;
260357fbcce3SJohannes Berg enum nl80211_band band;
26044c9451edSJohannes Berg int ret;
2605963d0e8dSJohannes Berg u8 link_id = u32_get_bits(ctrl_flags, IEEE80211_TX_CTRL_MLO_LINK);
2606e2ebc74dSJohannes Berg
260797ffe757SJohannes Berg if (IS_ERR(sta))
260897ffe757SJohannes Berg sta = NULL;
260997ffe757SJohannes Berg
2610276d9e82SJulius Niedworok #ifdef CONFIG_MAC80211_DEBUGFS
2611276d9e82SJulius Niedworok if (local->force_tx_status)
2612276d9e82SJulius Niedworok info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
2613276d9e82SJulius Niedworok #endif
2614276d9e82SJulius Niedworok
2615e2ebc74dSJohannes Berg /* convert Ethernet header to proper 802.11 header (based on
2616e2ebc74dSJohannes Berg * operation mode) */
2617e2ebc74dSJohannes Berg ethertype = (skb->data[12] << 8) | skb->data[13];
2618065e9605SHarvey Harrison fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
2619e2ebc74dSJohannes Berg
2620f1871abdSIlan Peer if (!ieee80211_vif_is_mld(&sdata->vif))
2621eef25a66SJohannes Berg chanctx_conf =
2622eef25a66SJohannes Berg rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
262327f852deSJohannes Berg
262451fb61e7SJohannes Berg switch (sdata->vif.type) {
262505c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN:
262697ffe757SJohannes Berg if (sdata->wdev.use_4addr) {
2627f14543eeSFelix Fietkau fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
2628f14543eeSFelix Fietkau /* RA TA DA SA */
2629f14543eeSFelix Fietkau memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
263047846c9bSJohannes Berg memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
2631f14543eeSFelix Fietkau memcpy(hdr.addr3, skb->data, ETH_ALEN);
2632f14543eeSFelix Fietkau memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
2633f14543eeSFelix Fietkau hdrlen = 30;
2634c2c98fdeSJohannes Berg authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
2635a74a8c84SJohannes Berg wme_sta = sta->sta.wme;
2636f14543eeSFelix Fietkau }
2637f1871abdSIlan Peer if (!ieee80211_vif_is_mld(&sdata->vif)) {
2638eef25a66SJohannes Berg struct ieee80211_sub_if_data *ap_sdata;
2639eef25a66SJohannes Berg
264027f852deSJohannes Berg /* override chanctx_conf from AP (we don't have one) */
2641eef25a66SJohannes Berg ap_sdata = container_of(sdata->bss,
2642eef25a66SJohannes Berg struct ieee80211_sub_if_data,
264355de908aSJohannes Berg u.ap);
2644eef25a66SJohannes Berg chanctx_conf =
2645eef25a66SJohannes Berg rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf);
2646eef25a66SJohannes Berg }
264797ffe757SJohannes Berg if (sdata->wdev.use_4addr)
2648f14543eeSFelix Fietkau break;
2649fc0561dcSGustavo A. R. Silva fallthrough;
2650f14543eeSFelix Fietkau case NL80211_IFTYPE_AP:
2651065e9605SHarvey Harrison fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
2652e2ebc74dSJohannes Berg /* DA BSSID SA */
2653e2ebc74dSJohannes Berg memcpy(hdr.addr1, skb->data, ETH_ALEN);
26543e0278b7SAndrei Otcheretianski
2655f1871abdSIlan Peer if (ieee80211_vif_is_mld(&sdata->vif) && sta && !sta->sta.mlo) {
26563e0278b7SAndrei Otcheretianski struct ieee80211_link_data *link;
26573e0278b7SAndrei Otcheretianski
26583e0278b7SAndrei Otcheretianski link_id = sta->deflink.link_id;
26593e0278b7SAndrei Otcheretianski link = rcu_dereference(sdata->link[link_id]);
26603e0278b7SAndrei Otcheretianski if (WARN_ON(!link)) {
26613e0278b7SAndrei Otcheretianski ret = -ENOLINK;
26623e0278b7SAndrei Otcheretianski goto free;
26633e0278b7SAndrei Otcheretianski }
26643e0278b7SAndrei Otcheretianski memcpy(hdr.addr2, link->conf->addr, ETH_ALEN);
2665a6ba64d0SJohannes Berg } else if (link_id == IEEE80211_LINK_UNSPECIFIED ||
2666a6ba64d0SJohannes Berg (sta && sta->sta.mlo)) {
266747846c9bSJohannes Berg memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
2668963d0e8dSJohannes Berg } else {
2669963d0e8dSJohannes Berg struct ieee80211_bss_conf *conf;
2670963d0e8dSJohannes Berg
2671963d0e8dSJohannes Berg conf = rcu_dereference(sdata->vif.link_conf[link_id]);
2672963d0e8dSJohannes Berg if (unlikely(!conf)) {
2673963d0e8dSJohannes Berg ret = -ENOLINK;
2674963d0e8dSJohannes Berg goto free;
2675963d0e8dSJohannes Berg }
2676963d0e8dSJohannes Berg
2677963d0e8dSJohannes Berg memcpy(hdr.addr2, conf->addr, ETH_ALEN);
26783e0278b7SAndrei Otcheretianski }
26793e0278b7SAndrei Otcheretianski
2680e2ebc74dSJohannes Berg memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
2681e2ebc74dSJohannes Berg hdrlen = 24;
2682cf966838SJohannes Berg break;
268333b64eb2SLuis Carlos Cobo #ifdef CONFIG_MAC80211_MESH
268405c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT:
2685b8bacc18SChun-Yeow Yeoh if (!is_multicast_ether_addr(skb->data)) {
2686163df6cfSChun-Yeow Yeoh struct sta_info *next_hop;
2687163df6cfSChun-Yeow Yeoh bool mpp_lookup = true;
2688163df6cfSChun-Yeow Yeoh
2689bf7cd94dSJohannes Berg mpath = mesh_path_lookup(sdata, skb->data);
2690163df6cfSChun-Yeow Yeoh if (mpath) {
2691163df6cfSChun-Yeow Yeoh mpp_lookup = false;
2692163df6cfSChun-Yeow Yeoh next_hop = rcu_dereference(mpath->next_hop);
2693163df6cfSChun-Yeow Yeoh if (!next_hop ||
2694163df6cfSChun-Yeow Yeoh !(mpath->flags & (MESH_PATH_ACTIVE |
2695163df6cfSChun-Yeow Yeoh MESH_PATH_RESOLVING)))
2696163df6cfSChun-Yeow Yeoh mpp_lookup = true;
2697163df6cfSChun-Yeow Yeoh }
2698163df6cfSChun-Yeow Yeoh
2699ab1c7906SHenning Rogge if (mpp_lookup) {
2700bf7cd94dSJohannes Berg mppath = mpp_path_lookup(sdata, skb->data);
2701ab1c7906SHenning Rogge if (mppath)
2702ab1c7906SHenning Rogge mppath->exp_time = jiffies;
2703ab1c7906SHenning Rogge }
2704163df6cfSChun-Yeow Yeoh
2705163df6cfSChun-Yeow Yeoh if (mppath && mpath)
27062bdaf386SBob Copeland mesh_path_del(sdata, mpath->dst);
2707b8bacc18SChun-Yeow Yeoh }
270879617deeSYanBo
2709f76b57b4SJoel A Fernandes /*
27109d52501bSJoel A Fernandes * Use address extension if it is a packet from
27119d52501bSJoel A Fernandes * another interface or if we know the destination
27129d52501bSJoel A Fernandes * is being proxied by a portal (i.e. portal address
27139d52501bSJoel A Fernandes * differs from proxied address)
2714f76b57b4SJoel A Fernandes */
2715b203ca39SJoe Perches if (ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN) &&
2716b203ca39SJoe Perches !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) {
27173c5772a5SJavier Cardona hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
27183c5772a5SJavier Cardona skb->data, skb->data + ETH_ALEN);
2719bf7cd94dSJohannes Berg meshhdrlen = ieee80211_new_mesh_header(sdata, &mesh_hdr,
2720bf7cd94dSJohannes Berg NULL, NULL);
272179617deeSYanBo } else {
272227f01124SThomas Pedersen /* DS -> MBSS (802.11-2012 13.11.3.3).
272327f01124SThomas Pedersen * For unicast with unknown forwarding information,
272427f01124SThomas Pedersen * destination might be in the MBSS or if that fails
272527f01124SThomas Pedersen * forwarded to another mesh gate. In either case
272627f01124SThomas Pedersen * resolution will be handled in ieee80211_xmit(), so
272727f01124SThomas Pedersen * leave the original DA. This also works for mcast */
272827f01124SThomas Pedersen const u8 *mesh_da = skb->data;
272979617deeSYanBo
273027f01124SThomas Pedersen if (mppath)
27313c5772a5SJavier Cardona mesh_da = mppath->mpp;
273227f01124SThomas Pedersen else if (mpath)
27337c41f315SChun-Yeow Yeoh mesh_da = mpath->dst;
273427f01124SThomas Pedersen
27353c5772a5SJavier Cardona hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
273647846c9bSJohannes Berg mesh_da, sdata->vif.addr);
273727f01124SThomas Pedersen if (is_multicast_ether_addr(mesh_da))
273827f01124SThomas Pedersen /* DA TA mSA AE:SA */
2739bf7cd94dSJohannes Berg meshhdrlen = ieee80211_new_mesh_header(
2740bf7cd94dSJohannes Berg sdata, &mesh_hdr,
2741bf7cd94dSJohannes Berg skb->data + ETH_ALEN, NULL);
27423c5772a5SJavier Cardona else
274327f01124SThomas Pedersen /* RA TA mDA mSA AE:DA SA */
2744bf7cd94dSJohannes Berg meshhdrlen = ieee80211_new_mesh_header(
2745bf7cd94dSJohannes Berg sdata, &mesh_hdr, skb->data,
27463c5772a5SJavier Cardona skb->data + ETH_ALEN);
274779617deeSYanBo
274879617deeSYanBo }
27498828f81aSRajkumar Manoharan
27508828f81aSRajkumar Manoharan /* For injected frames, fill RA right away as nexthop lookup
27518828f81aSRajkumar Manoharan * will be skipped.
27528828f81aSRajkumar Manoharan */
27538828f81aSRajkumar Manoharan if ((ctrl_flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) &&
27548828f81aSRajkumar Manoharan is_zero_ether_addr(hdr.addr1))
27558828f81aSRajkumar Manoharan memcpy(hdr.addr1, skb->data, ETH_ALEN);
275633b64eb2SLuis Carlos Cobo break;
275733b64eb2SLuis Carlos Cobo #endif
275805c914feSJohannes Berg case NL80211_IFTYPE_STATION:
275997ffe757SJohannes Berg /* we already did checks when looking up the RA STA */
276097ffe757SJohannes Berg tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER);
2761941c93cdSArik Nemtsov
276297ffe757SJohannes Berg if (tdls_peer) {
27638cc07265SAbhishek Naik /* For TDLS only one link can be valid with peer STA */
27648cc07265SAbhishek Naik int tdls_link_id = sta->sta.valid_links ?
27658cc07265SAbhishek Naik __ffs(sta->sta.valid_links) : 0;
27668cc07265SAbhishek Naik struct ieee80211_link_data *link;
27678cc07265SAbhishek Naik
2768941c93cdSArik Nemtsov /* DA SA BSSID */
2769941c93cdSArik Nemtsov memcpy(hdr.addr1, skb->data, ETH_ALEN);
2770941c93cdSArik Nemtsov memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
27718cc07265SAbhishek Naik link = rcu_dereference(sdata->link[tdls_link_id]);
27728cc07265SAbhishek Naik if (WARN_ON_ONCE(!link)) {
27738cc07265SAbhishek Naik ret = -EINVAL;
27748cc07265SAbhishek Naik goto free;
27758cc07265SAbhishek Naik }
27768cc07265SAbhishek Naik memcpy(hdr.addr3, link->u.mgd.bssid, ETH_ALEN);
2777941c93cdSArik Nemtsov hdrlen = 24;
2778941c93cdSArik Nemtsov } else if (sdata->u.mgd.use_4addr &&
2779a621fa4dSJohannes Berg cpu_to_be16(ethertype) != sdata->control_port_protocol) {
2780941c93cdSArik Nemtsov fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
2781941c93cdSArik Nemtsov IEEE80211_FCTL_TODS);
2782f14543eeSFelix Fietkau /* RA TA DA SA */
2783bfd8403aSJohannes Berg memcpy(hdr.addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN);
278447846c9bSJohannes Berg memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
2785f14543eeSFelix Fietkau memcpy(hdr.addr3, skb->data, ETH_ALEN);
2786f14543eeSFelix Fietkau memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
2787f14543eeSFelix Fietkau hdrlen = 30;
2788f14543eeSFelix Fietkau } else {
2789065e9605SHarvey Harrison fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
2790e2ebc74dSJohannes Berg /* BSSID SA DA */
27918a9be422SJohannes Berg memcpy(hdr.addr1, sdata->vif.cfg.ap_addr, ETH_ALEN);
2792e2ebc74dSJohannes Berg memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
2793e2ebc74dSJohannes Berg memcpy(hdr.addr3, skb->data, ETH_ALEN);
2794e2ebc74dSJohannes Berg hdrlen = 24;
2795f14543eeSFelix Fietkau }
2796cf966838SJohannes Berg break;
2797239281f8SRostislav Lisovy case NL80211_IFTYPE_OCB:
2798239281f8SRostislav Lisovy /* DA SA BSSID */
2799239281f8SRostislav Lisovy memcpy(hdr.addr1, skb->data, ETH_ALEN);
2800239281f8SRostislav Lisovy memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
2801239281f8SRostislav Lisovy eth_broadcast_addr(hdr.addr3);
2802239281f8SRostislav Lisovy hdrlen = 24;
2803239281f8SRostislav Lisovy break;
280405c914feSJohannes Berg case NL80211_IFTYPE_ADHOC:
2805e2ebc74dSJohannes Berg /* DA SA BSSID */
2806e2ebc74dSJohannes Berg memcpy(hdr.addr1, skb->data, ETH_ALEN);
2807e2ebc74dSJohannes Berg memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
280846900298SJohannes Berg memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);
2809e2ebc74dSJohannes Berg hdrlen = 24;
2810cf966838SJohannes Berg break;
2811cf966838SJohannes Berg default:
28124c9451edSJohannes Berg ret = -EINVAL;
28134c9451edSJohannes Berg goto free;
2814e2ebc74dSJohannes Berg }
2815e2ebc74dSJohannes Berg
281627f852deSJohannes Berg if (!chanctx_conf) {
2817f1871abdSIlan Peer if (!ieee80211_vif_is_mld(&sdata->vif)) {
281827f852deSJohannes Berg ret = -ENOTCONN;
281927f852deSJohannes Berg goto free;
282027f852deSJohannes Berg }
2821eef25a66SJohannes Berg /* MLD transmissions must not rely on the band */
2822eef25a66SJohannes Berg band = 0;
2823eef25a66SJohannes Berg } else {
282427f852deSJohannes Berg band = chanctx_conf->def.chan->band;
2825eef25a66SJohannes Berg }
282627f852deSJohannes Berg
2827a729cff8SJohannes Berg multicast = is_multicast_ether_addr(hdr.addr1);
282897ffe757SJohannes Berg
282997ffe757SJohannes Berg /* sta is always NULL for mesh */
2830c2c98fdeSJohannes Berg if (sta) {
2831c2c98fdeSJohannes Berg authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
2832a74a8c84SJohannes Berg wme_sta = sta->sta.wme;
283397ffe757SJohannes Berg } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
28344777be41SJavier Cardona /* For mesh, the use of the QoS header is mandatory */
2835c2c98fdeSJohannes Berg wme_sta = true;
283697ffe757SJohannes Berg }
28374777be41SJavier Cardona
2838527871d7SJohannes Berg /* receiver does QoS (which also means we do) use it */
2839527871d7SJohannes Berg if (wme_sta) {
2840065e9605SHarvey Harrison fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
2841e2ebc74dSJohannes Berg hdrlen += 2;
2842e2ebc74dSJohannes Berg }
2843ce3edf6dSJohannes Berg
2844ce3edf6dSJohannes Berg /*
2845238814fdSJohannes Berg * Drop unicast frames to unauthorised stations unless they are
2846238814fdSJohannes Berg * EAPOL frames from the local station.
2847ce3edf6dSJohannes Berg */
284855182e4aSJohannes Berg if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
2849239281f8SRostislav Lisovy (sdata->vif.type != NL80211_IFTYPE_OCB) &&
2850a6ececf4SSergey Ryazanov !multicast && !authorized &&
285155182e4aSJohannes Berg (cpu_to_be16(ethertype) != sdata->control_port_protocol ||
28520d5891e3SAndrei Otcheretianski !ieee80211_is_our_addr(sdata, skb->data + ETH_ALEN, NULL)))) {
2853ce3edf6dSJohannes Berg #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
2854bdcbd8e0SJohannes Berg net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n",
28554c9451edSJohannes Berg sdata->name, hdr.addr1);
2856ce3edf6dSJohannes Berg #endif
2857ce3edf6dSJohannes Berg
2858ce3edf6dSJohannes Berg I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
2859ce3edf6dSJohannes Berg
28604c9451edSJohannes Berg ret = -EPERM;
28614c9451edSJohannes Berg goto free;
2862e2ebc74dSJohannes Berg }
2863e2ebc74dSJohannes Berg
2864a7528198SMarkus Theil if (unlikely(!multicast && ((skb->sk &&
2865a7528198SMarkus Theil skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS) ||
2866a7528198SMarkus Theil ctrl_flags & IEEE80211_TX_CTL_REQ_TX_STATUS)))
2867a7528198SMarkus Theil info_id = ieee80211_store_ack_skb(local, skb, &info_flags,
2868a7528198SMarkus Theil cookie);
2869a729cff8SJohannes Berg
28707e244707SHelmut Schaa /*
28717e244707SHelmut Schaa * If the skb is shared we need to obtain our own copy.
28727e244707SHelmut Schaa */
2873a4926abbSRyder Lee skb = skb_share_check(skb, GFP_ATOMIC);
2874a4926abbSRyder Lee if (unlikely(!skb)) {
28754c9451edSJohannes Berg ret = -ENOMEM;
28764c9451edSJohannes Berg goto free;
28774c9451edSJohannes Berg }
28787e244707SHelmut Schaa
2879065e9605SHarvey Harrison hdr.frame_control = fc;
2880e2ebc74dSJohannes Berg hdr.duration_id = 0;
2881e2ebc74dSJohannes Berg hdr.seq_ctrl = 0;
2882e2ebc74dSJohannes Berg
2883e2ebc74dSJohannes Berg skip_header_bytes = ETH_HLEN;
2884e2ebc74dSJohannes Berg if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
2885e2ebc74dSJohannes Berg encaps_data = bridge_tunnel_header;
2886e2ebc74dSJohannes Berg encaps_len = sizeof(bridge_tunnel_header);
2887e2ebc74dSJohannes Berg skip_header_bytes -= 2;
2888e5c5d22eSSimon Horman } else if (ethertype >= ETH_P_802_3_MIN) {
2889e2ebc74dSJohannes Berg encaps_data = rfc1042_header;
2890e2ebc74dSJohannes Berg encaps_len = sizeof(rfc1042_header);
2891e2ebc74dSJohannes Berg skip_header_bytes -= 2;
2892e2ebc74dSJohannes Berg } else {
2893e2ebc74dSJohannes Berg encaps_data = NULL;
2894e2ebc74dSJohannes Berg encaps_len = 0;
2895e2ebc74dSJohannes Berg }
2896e2ebc74dSJohannes Berg
2897e2ebc74dSJohannes Berg skb_pull(skb, skip_header_bytes);
289823c0752aSJohannes Berg head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
2899e2ebc74dSJohannes Berg
290023c0752aSJohannes Berg /*
290123c0752aSJohannes Berg * So we need to modify the skb header and hence need a copy of
290223c0752aSJohannes Berg * that. The head_need variable above doesn't, so far, include
290323c0752aSJohannes Berg * the needed header space that we don't need right away. If we
290423c0752aSJohannes Berg * can, then we don't reallocate right now but only after the
290523c0752aSJohannes Berg * frame arrives at the master device (if it does...)
290623c0752aSJohannes Berg *
290723c0752aSJohannes Berg * If we cannot, however, then we will reallocate to include all
290823c0752aSJohannes Berg * the ever needed space. Also, if we need to reallocate it anyway,
290923c0752aSJohannes Berg * make it big enough for everything we may ever need.
291023c0752aSJohannes Berg */
2911e2ebc74dSJohannes Berg
29123a5be7d4SDavid S. Miller if (head_need > 0 || skb_cloned(skb)) {
291323a5f0afSJohannes Berg head_need += IEEE80211_ENCRYPT_HEADROOM;
291423c0752aSJohannes Berg head_need += local->tx_headroom;
291523c0752aSJohannes Berg head_need = max_t(int, 0, head_need);
291614f46c1eSJohannes Berg if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
2917c3e7724bSFelix Fietkau ieee80211_free_txskb(&local->hw, skb);
29181c963becSJohannes Berg skb = NULL;
29194c9451edSJohannes Berg return ERR_PTR(-ENOMEM);
2920c3e7724bSFelix Fietkau }
2921e2ebc74dSJohannes Berg }
2922e2ebc74dSJohannes Berg
2923eae4430eSFelix Fietkau if (encaps_data)
2924e2ebc74dSJohannes Berg memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
2925c29b9b9bSJohannes Berg
2926e4ab7eb0SYuri Ershov #ifdef CONFIG_MAC80211_MESH
2927eae4430eSFelix Fietkau if (meshhdrlen > 0)
292833b64eb2SLuis Carlos Cobo memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
2929e4ab7eb0SYuri Ershov #endif
293033b64eb2SLuis Carlos Cobo
2931065e9605SHarvey Harrison if (ieee80211_is_data_qos(fc)) {
2932c29b9b9bSJohannes Berg __le16 *qos_control;
2933c29b9b9bSJohannes Berg
2934d58ff351SJohannes Berg qos_control = skb_push(skb, 2);
2935c29b9b9bSJohannes Berg memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
2936c29b9b9bSJohannes Berg /*
2937c29b9b9bSJohannes Berg * Maybe we could actually set some fields here, for now just
2938c29b9b9bSJohannes Berg * initialise to zero to indicate no special operation.
2939c29b9b9bSJohannes Berg */
2940c29b9b9bSJohannes Berg *qos_control = 0;
2941c29b9b9bSJohannes Berg } else
2942e2ebc74dSJohannes Berg memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
2943c29b9b9bSJohannes Berg
2944d57a544dSZhang Shengju skb_reset_mac_header(skb);
2945e2ebc74dSJohannes Berg
2946489ee919SFelix Fietkau info = IEEE80211_SKB_CB(skb);
29473b8d81e0SJohannes Berg memset(info, 0, sizeof(*info));
29483b8d81e0SJohannes Berg
2949a729cff8SJohannes Berg info->flags = info_flags;
2950a729cff8SJohannes Berg info->ack_frame_id = info_id;
295173c4e195SJohannes Berg info->band = band;
29529dd19538SJohannes Berg
29539dd19538SJohannes Berg if (likely(!cookie)) {
29549dd19538SJohannes Berg ctrl_flags |= u32_encode_bits(link_id,
295569d41b5aSJohannes Berg IEEE80211_TX_CTRL_MLO_LINK);
29569dd19538SJohannes Berg } else {
29579dd19538SJohannes Berg unsigned int pre_conf_link_id;
29589dd19538SJohannes Berg
29599dd19538SJohannes Berg /*
29609dd19538SJohannes Berg * ctrl_flags already have been set by
29619dd19538SJohannes Berg * ieee80211_tx_control_port(), here
29629dd19538SJohannes Berg * we just sanity check that
29639dd19538SJohannes Berg */
29649dd19538SJohannes Berg
29659dd19538SJohannes Berg pre_conf_link_id = u32_get_bits(ctrl_flags,
29669dd19538SJohannes Berg IEEE80211_TX_CTRL_MLO_LINK);
29679dd19538SJohannes Berg
29689dd19538SJohannes Berg if (pre_conf_link_id != link_id &&
29699dd19538SJohannes Berg link_id != IEEE80211_LINK_UNSPECIFIED) {
29709d13aff9SJohannes Berg #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
29719dd19538SJohannes Berg net_info_ratelimited("%s: dropped frame to %pM with bad link ID request (%d vs. %d)\n",
29729dd19538SJohannes Berg sdata->name, hdr.addr1,
29739dd19538SJohannes Berg pre_conf_link_id, link_id);
29749dd19538SJohannes Berg #endif
29759dd19538SJohannes Berg ret = -EINVAL;
29769dd19538SJohannes Berg goto free;
29779dd19538SJohannes Berg }
29789dd19538SJohannes Berg }
29799dd19538SJohannes Berg
29809dd19538SJohannes Berg info->control.flags = ctrl_flags;
2981a729cff8SJohannes Berg
29824c9451edSJohannes Berg return skb;
29834c9451edSJohannes Berg free:
29844c9451edSJohannes Berg kfree_skb(skb);
29854c9451edSJohannes Berg return ERR_PTR(ret);
2986e2ebc74dSJohannes Berg }
2987e2ebc74dSJohannes Berg
298817c18bf8SJohannes Berg /*
298917c18bf8SJohannes Berg * fast-xmit overview
299017c18bf8SJohannes Berg *
299117c18bf8SJohannes Berg * The core idea of this fast-xmit is to remove per-packet checks by checking
299217c18bf8SJohannes Berg * them out of band. ieee80211_check_fast_xmit() implements the out-of-band
299317c18bf8SJohannes Berg * checks that are needed to get the sta->fast_tx pointer assigned, after which
299417c18bf8SJohannes Berg * much less work can be done per packet. For example, fragmentation must be
299517c18bf8SJohannes Berg * disabled or the fast_tx pointer will not be set. All the conditions are seen
299617c18bf8SJohannes Berg * in the code here.
299717c18bf8SJohannes Berg *
299817c18bf8SJohannes Berg * Once assigned, the fast_tx data structure also caches the per-packet 802.11
299917c18bf8SJohannes Berg * header and other data to aid packet processing in ieee80211_xmit_fast().
300017c18bf8SJohannes Berg *
300117c18bf8SJohannes Berg * The most difficult part of this is that when any of these assumptions
300217c18bf8SJohannes Berg * change, an external trigger (i.e. a call to ieee80211_clear_fast_xmit(),
300317c18bf8SJohannes Berg * ieee80211_check_fast_xmit() or friends) is required to reset the data,
300417c18bf8SJohannes Berg * since the per-packet code no longer checks the conditions. This is reflected
300517c18bf8SJohannes Berg * by the calls to these functions throughout the rest of the code, and must be
300617c18bf8SJohannes Berg * maintained if any of the TX path checks change.
300717c18bf8SJohannes Berg */
300817c18bf8SJohannes Berg
ieee80211_check_fast_xmit(struct sta_info * sta)300917c18bf8SJohannes Berg void ieee80211_check_fast_xmit(struct sta_info *sta)
301017c18bf8SJohannes Berg {
301117c18bf8SJohannes Berg struct ieee80211_fast_tx build = {}, *fast_tx = NULL, *old;
301217c18bf8SJohannes Berg struct ieee80211_local *local = sta->local;
301317c18bf8SJohannes Berg struct ieee80211_sub_if_data *sdata = sta->sdata;
301417c18bf8SJohannes Berg struct ieee80211_hdr *hdr = (void *)build.hdr;
301517c18bf8SJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf;
301617c18bf8SJohannes Berg __le16 fc;
301717c18bf8SJohannes Berg
301830686bf7SJohannes Berg if (!ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT))
301917c18bf8SJohannes Berg return;
302017c18bf8SJohannes Berg
3021d5edb9aeSFelix Fietkau if (ieee80211_vif_is_mesh(&sdata->vif))
3022d5edb9aeSFelix Fietkau mesh_fast_tx_flush_sta(sdata, sta);
3023d5edb9aeSFelix Fietkau
302417c18bf8SJohannes Berg /* Locking here protects both the pointer itself, and against concurrent
302517c18bf8SJohannes Berg * invocations winning data access races to, e.g., the key pointer that
302617c18bf8SJohannes Berg * is used.
302717c18bf8SJohannes Berg * Without it, the invocation of this function right after the key
302817c18bf8SJohannes Berg * pointer changes wouldn't be sufficient, as another CPU could access
302917c18bf8SJohannes Berg * the pointer, then stall, and then do the cache update after the CPU
303017c18bf8SJohannes Berg * that invalidated the key.
303117c18bf8SJohannes Berg * With the locking, such scenarios cannot happen as the check for the
303217c18bf8SJohannes Berg * key and the fast-tx assignment are done atomically, so the CPU that
303317c18bf8SJohannes Berg * modifies the key will either wait or other one will see the key
303417c18bf8SJohannes Berg * cleared/changed already.
303517c18bf8SJohannes Berg */
303617c18bf8SJohannes Berg spin_lock_bh(&sta->lock);
303730686bf7SJohannes Berg if (ieee80211_hw_check(&local->hw, SUPPORTS_PS) &&
303830686bf7SJohannes Berg !ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS) &&
303917c18bf8SJohannes Berg sdata->vif.type == NL80211_IFTYPE_STATION)
304017c18bf8SJohannes Berg goto out;
304117c18bf8SJohannes Berg
304254b79d87SFelix Fietkau if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED) || !sta->uploaded)
304317c18bf8SJohannes Berg goto out;
304417c18bf8SJohannes Berg
304517c18bf8SJohannes Berg if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
304617c18bf8SJohannes Berg test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
3047f7418bc1SFelix Fietkau test_sta_flag(sta, WLAN_STA_PS_DELIVER) ||
3048f7418bc1SFelix Fietkau test_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT))
304917c18bf8SJohannes Berg goto out;
305017c18bf8SJohannes Berg
305117c18bf8SJohannes Berg if (sdata->noack_map)
305217c18bf8SJohannes Berg goto out;
305317c18bf8SJohannes Berg
305417c18bf8SJohannes Berg /* fast-xmit doesn't handle fragmentation at all */
3055725b812cSJohannes Berg if (local->hw.wiphy->frag_threshold != (u32)-1 &&
3056f3fe4e93SSara Sharon !ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG))
305717c18bf8SJohannes Berg goto out;
305817c18bf8SJohannes Berg
3059f1871abdSIlan Peer if (!ieee80211_vif_is_mld(&sdata->vif)) {
306017c18bf8SJohannes Berg rcu_read_lock();
3061eef25a66SJohannes Berg chanctx_conf =
3062eef25a66SJohannes Berg rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
306317c18bf8SJohannes Berg if (!chanctx_conf) {
306417c18bf8SJohannes Berg rcu_read_unlock();
306517c18bf8SJohannes Berg goto out;
306617c18bf8SJohannes Berg }
306717c18bf8SJohannes Berg build.band = chanctx_conf->def.chan->band;
306817c18bf8SJohannes Berg rcu_read_unlock();
3069eef25a66SJohannes Berg } else {
3070eef25a66SJohannes Berg /* MLD transmissions must not rely on the band */
3071eef25a66SJohannes Berg build.band = 0;
3072eef25a66SJohannes Berg }
307317c18bf8SJohannes Berg
307417c18bf8SJohannes Berg fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
307517c18bf8SJohannes Berg
307617c18bf8SJohannes Berg switch (sdata->vif.type) {
30773ffd8840SJohannes Berg case NL80211_IFTYPE_ADHOC:
30783ffd8840SJohannes Berg /* DA SA BSSID */
30793ffd8840SJohannes Berg build.da_offs = offsetof(struct ieee80211_hdr, addr1);
30803ffd8840SJohannes Berg build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
30813ffd8840SJohannes Berg memcpy(hdr->addr3, sdata->u.ibss.bssid, ETH_ALEN);
30823ffd8840SJohannes Berg build.hdr_len = 24;
30833ffd8840SJohannes Berg break;
308417c18bf8SJohannes Berg case NL80211_IFTYPE_STATION:
308517c18bf8SJohannes Berg if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
30868cc07265SAbhishek Naik /* For TDLS only one link can be valid with peer STA */
30878cc07265SAbhishek Naik int tdls_link_id = sta->sta.valid_links ?
30888cc07265SAbhishek Naik __ffs(sta->sta.valid_links) : 0;
30898cc07265SAbhishek Naik struct ieee80211_link_data *link;
30908cc07265SAbhishek Naik
309117c18bf8SJohannes Berg /* DA SA BSSID */
309217c18bf8SJohannes Berg build.da_offs = offsetof(struct ieee80211_hdr, addr1);
309317c18bf8SJohannes Berg build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
3094fc3432aeSJohannes Berg rcu_read_lock();
30958cc07265SAbhishek Naik link = rcu_dereference(sdata->link[tdls_link_id]);
3096fc3432aeSJohannes Berg if (!WARN_ON_ONCE(!link))
30978cc07265SAbhishek Naik memcpy(hdr->addr3, link->u.mgd.bssid, ETH_ALEN);
3098fc3432aeSJohannes Berg rcu_read_unlock();
309917c18bf8SJohannes Berg build.hdr_len = 24;
310017c18bf8SJohannes Berg break;
310117c18bf8SJohannes Berg }
310217c18bf8SJohannes Berg
310317c18bf8SJohannes Berg if (sdata->u.mgd.use_4addr) {
310417c18bf8SJohannes Berg /* non-regular ethertype cannot use the fastpath */
310517c18bf8SJohannes Berg fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
310617c18bf8SJohannes Berg IEEE80211_FCTL_TODS);
310717c18bf8SJohannes Berg /* RA TA DA SA */
3108bfd8403aSJohannes Berg memcpy(hdr->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN);
310917c18bf8SJohannes Berg memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
311017c18bf8SJohannes Berg build.da_offs = offsetof(struct ieee80211_hdr, addr3);
311117c18bf8SJohannes Berg build.sa_offs = offsetof(struct ieee80211_hdr, addr4);
311217c18bf8SJohannes Berg build.hdr_len = 30;
311317c18bf8SJohannes Berg break;
311417c18bf8SJohannes Berg }
311517c18bf8SJohannes Berg fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
311617c18bf8SJohannes Berg /* BSSID SA DA */
31178a9be422SJohannes Berg memcpy(hdr->addr1, sdata->vif.cfg.ap_addr, ETH_ALEN);
311817c18bf8SJohannes Berg build.da_offs = offsetof(struct ieee80211_hdr, addr3);
311917c18bf8SJohannes Berg build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
312017c18bf8SJohannes Berg build.hdr_len = 24;
312117c18bf8SJohannes Berg break;
312217c18bf8SJohannes Berg case NL80211_IFTYPE_AP_VLAN:
312317c18bf8SJohannes Berg if (sdata->wdev.use_4addr) {
312417c18bf8SJohannes Berg fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
312517c18bf8SJohannes Berg IEEE80211_FCTL_TODS);
312617c18bf8SJohannes Berg /* RA TA DA SA */
312717c18bf8SJohannes Berg memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
312817c18bf8SJohannes Berg memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
312917c18bf8SJohannes Berg build.da_offs = offsetof(struct ieee80211_hdr, addr3);
313017c18bf8SJohannes Berg build.sa_offs = offsetof(struct ieee80211_hdr, addr4);
313117c18bf8SJohannes Berg build.hdr_len = 30;
313217c18bf8SJohannes Berg break;
313317c18bf8SJohannes Berg }
3134fc0561dcSGustavo A. R. Silva fallthrough;
313517c18bf8SJohannes Berg case NL80211_IFTYPE_AP:
313617c18bf8SJohannes Berg fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
313717c18bf8SJohannes Berg /* DA BSSID SA */
313817c18bf8SJohannes Berg build.da_offs = offsetof(struct ieee80211_hdr, addr1);
3139f1871abdSIlan Peer if (sta->sta.mlo || !ieee80211_vif_is_mld(&sdata->vif)) {
314017c18bf8SJohannes Berg memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
31410f13f3c3SJohannes Berg } else {
31420f13f3c3SJohannes Berg unsigned int link_id = sta->deflink.link_id;
31430f13f3c3SJohannes Berg struct ieee80211_link_data *link;
31440f13f3c3SJohannes Berg
31450f13f3c3SJohannes Berg rcu_read_lock();
31460f13f3c3SJohannes Berg link = rcu_dereference(sdata->link[link_id]);
31470f13f3c3SJohannes Berg if (WARN_ON(!link)) {
31480f13f3c3SJohannes Berg rcu_read_unlock();
31490f13f3c3SJohannes Berg goto out;
31500f13f3c3SJohannes Berg }
31510f13f3c3SJohannes Berg memcpy(hdr->addr2, link->conf->addr, ETH_ALEN);
31520f13f3c3SJohannes Berg rcu_read_unlock();
31530f13f3c3SJohannes Berg }
315417c18bf8SJohannes Berg build.sa_offs = offsetof(struct ieee80211_hdr, addr3);
315517c18bf8SJohannes Berg build.hdr_len = 24;
315617c18bf8SJohannes Berg break;
315717c18bf8SJohannes Berg default:
315817c18bf8SJohannes Berg /* not handled on fast-xmit */
315917c18bf8SJohannes Berg goto out;
316017c18bf8SJohannes Berg }
316117c18bf8SJohannes Berg
316217c18bf8SJohannes Berg if (sta->sta.wme) {
316317c18bf8SJohannes Berg build.hdr_len += 2;
316417c18bf8SJohannes Berg fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
316517c18bf8SJohannes Berg }
316617c18bf8SJohannes Berg
316717c18bf8SJohannes Berg /* We store the key here so there's no point in using rcu_dereference()
316817c18bf8SJohannes Berg * but that's fine because the code that changes the pointers will call
316917c18bf8SJohannes Berg * this function after doing so. For a single CPU that would be enough,
317017c18bf8SJohannes Berg * for multiple see the comment above.
317117c18bf8SJohannes Berg */
317217c18bf8SJohannes Berg build.key = rcu_access_pointer(sta->ptk[sta->ptk_idx]);
317317c18bf8SJohannes Berg if (!build.key)
317417c18bf8SJohannes Berg build.key = rcu_access_pointer(sdata->default_unicast_key);
317517c18bf8SJohannes Berg if (build.key) {
3176e495c247SJohannes Berg bool gen_iv, iv_spc, mmic;
317717c18bf8SJohannes Berg
317817c18bf8SJohannes Berg gen_iv = build.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV;
317917c18bf8SJohannes Berg iv_spc = build.key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE;
31809de18d81SDavid Spinadel mmic = build.key->conf.flags &
31819de18d81SDavid Spinadel (IEEE80211_KEY_FLAG_GENERATE_MMIC |
31829de18d81SDavid Spinadel IEEE80211_KEY_FLAG_PUT_MIC_SPACE);
318317c18bf8SJohannes Berg
318417c18bf8SJohannes Berg /* don't handle software crypto */
318517c18bf8SJohannes Berg if (!(build.key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
318617c18bf8SJohannes Berg goto out;
318717c18bf8SJohannes Berg
318862872a9bSAlexander Wetzel /* Key is being removed */
318962872a9bSAlexander Wetzel if (build.key->flags & KEY_FLAG_TAINTED)
319062872a9bSAlexander Wetzel goto out;
319162872a9bSAlexander Wetzel
319217c18bf8SJohannes Berg switch (build.key->conf.cipher) {
319317c18bf8SJohannes Berg case WLAN_CIPHER_SUITE_CCMP:
319417c18bf8SJohannes Berg case WLAN_CIPHER_SUITE_CCMP_256:
319596fc6efbSAlexander Wetzel if (gen_iv)
319617c18bf8SJohannes Berg build.pn_offs = build.hdr_len;
319717c18bf8SJohannes Berg if (gen_iv || iv_spc)
319817c18bf8SJohannes Berg build.hdr_len += IEEE80211_CCMP_HDR_LEN;
319917c18bf8SJohannes Berg break;
320017c18bf8SJohannes Berg case WLAN_CIPHER_SUITE_GCMP:
320117c18bf8SJohannes Berg case WLAN_CIPHER_SUITE_GCMP_256:
320296fc6efbSAlexander Wetzel if (gen_iv)
320317c18bf8SJohannes Berg build.pn_offs = build.hdr_len;
320417c18bf8SJohannes Berg if (gen_iv || iv_spc)
320517c18bf8SJohannes Berg build.hdr_len += IEEE80211_GCMP_HDR_LEN;
320617c18bf8SJohannes Berg break;
3207e495c247SJohannes Berg case WLAN_CIPHER_SUITE_TKIP:
3208e495c247SJohannes Berg /* cannot handle MMIC or IV generation in xmit-fast */
3209e495c247SJohannes Berg if (mmic || gen_iv)
321017c18bf8SJohannes Berg goto out;
3211e495c247SJohannes Berg if (iv_spc)
3212e495c247SJohannes Berg build.hdr_len += IEEE80211_TKIP_IV_LEN;
3213e495c247SJohannes Berg break;
3214e495c247SJohannes Berg case WLAN_CIPHER_SUITE_WEP40:
3215e495c247SJohannes Berg case WLAN_CIPHER_SUITE_WEP104:
3216e495c247SJohannes Berg /* cannot handle IV generation in fast-xmit */
3217e495c247SJohannes Berg if (gen_iv)
3218e495c247SJohannes Berg goto out;
3219e495c247SJohannes Berg if (iv_spc)
3220e495c247SJohannes Berg build.hdr_len += IEEE80211_WEP_IV_LEN;
3221e495c247SJohannes Berg break;
3222e495c247SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC:
3223e495c247SJohannes Berg case WLAN_CIPHER_SUITE_BIP_CMAC_256:
3224e495c247SJohannes Berg case WLAN_CIPHER_SUITE_BIP_GMAC_128:
3225e495c247SJohannes Berg case WLAN_CIPHER_SUITE_BIP_GMAC_256:
3226e495c247SJohannes Berg WARN(1,
3227e495c247SJohannes Berg "management cipher suite 0x%x enabled for data\n",
3228e495c247SJohannes Berg build.key->conf.cipher);
3229e495c247SJohannes Berg goto out;
3230e495c247SJohannes Berg default:
3231e495c247SJohannes Berg /* we don't know how to generate IVs for this at all */
3232e495c247SJohannes Berg if (WARN_ON(gen_iv))
3233e495c247SJohannes Berg goto out;
323417c18bf8SJohannes Berg }
323517c18bf8SJohannes Berg
323617c18bf8SJohannes Berg fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
323717c18bf8SJohannes Berg }
323817c18bf8SJohannes Berg
323917c18bf8SJohannes Berg hdr->frame_control = fc;
324017c18bf8SJohannes Berg
324117c18bf8SJohannes Berg memcpy(build.hdr + build.hdr_len,
324217c18bf8SJohannes Berg rfc1042_header, sizeof(rfc1042_header));
324317c18bf8SJohannes Berg build.hdr_len += sizeof(rfc1042_header);
324417c18bf8SJohannes Berg
324517c18bf8SJohannes Berg fast_tx = kmemdup(&build, sizeof(build), GFP_ATOMIC);
324617c18bf8SJohannes Berg /* if the kmemdup fails, continue w/o fast_tx */
324717c18bf8SJohannes Berg
324817c18bf8SJohannes Berg out:
324917c18bf8SJohannes Berg /* we might have raced against another call to this function */
325017c18bf8SJohannes Berg old = rcu_dereference_protected(sta->fast_tx,
325117c18bf8SJohannes Berg lockdep_is_held(&sta->lock));
325217c18bf8SJohannes Berg rcu_assign_pointer(sta->fast_tx, fast_tx);
325317c18bf8SJohannes Berg if (old)
325417c18bf8SJohannes Berg kfree_rcu(old, rcu_head);
325517c18bf8SJohannes Berg spin_unlock_bh(&sta->lock);
325617c18bf8SJohannes Berg }
325717c18bf8SJohannes Berg
ieee80211_check_fast_xmit_all(struct ieee80211_local * local)325817c18bf8SJohannes Berg void ieee80211_check_fast_xmit_all(struct ieee80211_local *local)
325917c18bf8SJohannes Berg {
326017c18bf8SJohannes Berg struct sta_info *sta;
326117c18bf8SJohannes Berg
326217c18bf8SJohannes Berg rcu_read_lock();
326317c18bf8SJohannes Berg list_for_each_entry_rcu(sta, &local->sta_list, list)
326417c18bf8SJohannes Berg ieee80211_check_fast_xmit(sta);
326517c18bf8SJohannes Berg rcu_read_unlock();
326617c18bf8SJohannes Berg }
326717c18bf8SJohannes Berg
ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data * sdata)326817c18bf8SJohannes Berg void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata)
326917c18bf8SJohannes Berg {
327017c18bf8SJohannes Berg struct ieee80211_local *local = sdata->local;
327117c18bf8SJohannes Berg struct sta_info *sta;
327217c18bf8SJohannes Berg
327317c18bf8SJohannes Berg rcu_read_lock();
327417c18bf8SJohannes Berg
327517c18bf8SJohannes Berg list_for_each_entry_rcu(sta, &local->sta_list, list) {
327617c18bf8SJohannes Berg if (sdata != sta->sdata &&
327717c18bf8SJohannes Berg (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
327817c18bf8SJohannes Berg continue;
327917c18bf8SJohannes Berg ieee80211_check_fast_xmit(sta);
328017c18bf8SJohannes Berg }
328117c18bf8SJohannes Berg
328217c18bf8SJohannes Berg rcu_read_unlock();
328317c18bf8SJohannes Berg }
328417c18bf8SJohannes Berg
ieee80211_clear_fast_xmit(struct sta_info * sta)328517c18bf8SJohannes Berg void ieee80211_clear_fast_xmit(struct sta_info *sta)
328617c18bf8SJohannes Berg {
328717c18bf8SJohannes Berg struct ieee80211_fast_tx *fast_tx;
328817c18bf8SJohannes Berg
328917c18bf8SJohannes Berg spin_lock_bh(&sta->lock);
329017c18bf8SJohannes Berg fast_tx = rcu_dereference_protected(sta->fast_tx,
329117c18bf8SJohannes Berg lockdep_is_held(&sta->lock));
329217c18bf8SJohannes Berg RCU_INIT_POINTER(sta->fast_tx, NULL);
329317c18bf8SJohannes Berg spin_unlock_bh(&sta->lock);
329417c18bf8SJohannes Berg
329517c18bf8SJohannes Berg if (fast_tx)
329617c18bf8SJohannes Berg kfree_rcu(fast_tx, rcu_head);
329717c18bf8SJohannes Berg }
329817c18bf8SJohannes Berg
ieee80211_amsdu_realloc_pad(struct ieee80211_local * local,struct sk_buff * skb,int headroom)32996e0456b5SFelix Fietkau static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local,
3300166ac9d5SSara Sharon struct sk_buff *skb, int headroom)
33016e0456b5SFelix Fietkau {
3302166ac9d5SSara Sharon if (skb_headroom(skb) < headroom) {
33036e0456b5SFelix Fietkau I802_DEBUG_INC(local->tx_expand_skb_head);
33046e0456b5SFelix Fietkau
3305166ac9d5SSara Sharon if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
33066e0456b5SFelix Fietkau wiphy_debug(local->hw.wiphy,
33076e0456b5SFelix Fietkau "failed to reallocate TX buffer\n");
33086e0456b5SFelix Fietkau return false;
33096e0456b5SFelix Fietkau }
33106e0456b5SFelix Fietkau }
33116e0456b5SFelix Fietkau
33126e0456b5SFelix Fietkau return true;
33136e0456b5SFelix Fietkau }
33146e0456b5SFelix Fietkau
ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data * sdata,struct ieee80211_fast_tx * fast_tx,struct sk_buff * skb)33156e0456b5SFelix Fietkau static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata,
33166e0456b5SFelix Fietkau struct ieee80211_fast_tx *fast_tx,
33176e0456b5SFelix Fietkau struct sk_buff *skb)
33186e0456b5SFelix Fietkau {
33196e0456b5SFelix Fietkau struct ieee80211_local *local = sdata->local;
33206e0456b5SFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
33216e0456b5SFelix Fietkau struct ieee80211_hdr *hdr;
332206f2bb1eSMichael Braun struct ethhdr *amsdu_hdr;
33236e0456b5SFelix Fietkau int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header);
33246e0456b5SFelix Fietkau int subframe_len = skb->len - hdr_len;
33256e0456b5SFelix Fietkau void *data;
332606f2bb1eSMichael Braun u8 *qc, *h_80211_src, *h_80211_dst;
3327a3e2f4b6SMichael Braun const u8 *bssid;
33286e0456b5SFelix Fietkau
33296e0456b5SFelix Fietkau if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
33306e0456b5SFelix Fietkau return false;
33316e0456b5SFelix Fietkau
33326e0456b5SFelix Fietkau if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
33336e0456b5SFelix Fietkau return true;
33346e0456b5SFelix Fietkau
3335f50d2ff8SChih-Kang Chang if (!ieee80211_amsdu_realloc_pad(local, skb,
3336f50d2ff8SChih-Kang Chang sizeof(*amsdu_hdr) +
3337f50d2ff8SChih-Kang Chang local->hw.extra_tx_headroom))
33386e0456b5SFelix Fietkau return false;
33396e0456b5SFelix Fietkau
334006f2bb1eSMichael Braun data = skb_push(skb, sizeof(*amsdu_hdr));
334106f2bb1eSMichael Braun memmove(data, data + sizeof(*amsdu_hdr), hdr_len);
33426e0456b5SFelix Fietkau hdr = data;
334306f2bb1eSMichael Braun amsdu_hdr = data + hdr_len;
334406f2bb1eSMichael Braun /* h_80211_src/dst is addr* field within hdr */
334506f2bb1eSMichael Braun h_80211_src = data + fast_tx->sa_offs;
334606f2bb1eSMichael Braun h_80211_dst = data + fast_tx->da_offs;
334706f2bb1eSMichael Braun
334806f2bb1eSMichael Braun amsdu_hdr->h_proto = cpu_to_be16(subframe_len);
334906f2bb1eSMichael Braun ether_addr_copy(amsdu_hdr->h_source, h_80211_src);
335006f2bb1eSMichael Braun ether_addr_copy(amsdu_hdr->h_dest, h_80211_dst);
335106f2bb1eSMichael Braun
3352a3e2f4b6SMichael Braun /* according to IEEE 802.11-2012 8.3.2 table 8-19, the outer SA/DA
3353a3e2f4b6SMichael Braun * fields needs to be changed to BSSID for A-MSDU frames depending
3354a3e2f4b6SMichael Braun * on FromDS/ToDS values.
3355a3e2f4b6SMichael Braun */
3356a3e2f4b6SMichael Braun switch (sdata->vif.type) {
3357a3e2f4b6SMichael Braun case NL80211_IFTYPE_STATION:
33588a9be422SJohannes Berg bssid = sdata->vif.cfg.ap_addr;
3359a3e2f4b6SMichael Braun break;
3360a3e2f4b6SMichael Braun case NL80211_IFTYPE_AP:
3361a3e2f4b6SMichael Braun case NL80211_IFTYPE_AP_VLAN:
3362a3e2f4b6SMichael Braun bssid = sdata->vif.addr;
3363a3e2f4b6SMichael Braun break;
3364a3e2f4b6SMichael Braun default:
3365a3e2f4b6SMichael Braun bssid = NULL;
3366a3e2f4b6SMichael Braun }
3367a3e2f4b6SMichael Braun
3368a3e2f4b6SMichael Braun if (bssid && ieee80211_has_fromds(hdr->frame_control))
3369a3e2f4b6SMichael Braun ether_addr_copy(h_80211_src, bssid);
3370a3e2f4b6SMichael Braun
3371a3e2f4b6SMichael Braun if (bssid && ieee80211_has_tods(hdr->frame_control))
3372a3e2f4b6SMichael Braun ether_addr_copy(h_80211_dst, bssid);
3373a3e2f4b6SMichael Braun
33746e0456b5SFelix Fietkau qc = ieee80211_get_qos_ctl(hdr);
33756e0456b5SFelix Fietkau *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
33766e0456b5SFelix Fietkau
33776e0456b5SFelix Fietkau info->control.flags |= IEEE80211_TX_CTRL_AMSDU;
33786e0456b5SFelix Fietkau
33796e0456b5SFelix Fietkau return true;
33806e0456b5SFelix Fietkau }
33816e0456b5SFelix Fietkau
ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct ieee80211_fast_tx * fast_tx,struct sk_buff * skb,const u8 * da,const u8 * sa)33826e0456b5SFelix Fietkau static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
33836e0456b5SFelix Fietkau struct sta_info *sta,
33846e0456b5SFelix Fietkau struct ieee80211_fast_tx *fast_tx,
3385d5edb9aeSFelix Fietkau struct sk_buff *skb,
3386d5edb9aeSFelix Fietkau const u8 *da, const u8 *sa)
33876e0456b5SFelix Fietkau {
33886e0456b5SFelix Fietkau struct ieee80211_local *local = sdata->local;
3389fa962b92SMichal Kazior struct fq *fq = &local->fq;
3390fa962b92SMichal Kazior struct fq_tin *tin;
3391fa962b92SMichal Kazior struct fq_flow *flow;
33926e0456b5SFelix Fietkau u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
33936e0456b5SFelix Fietkau struct ieee80211_txq *txq = sta->sta.txq[tid];
33946e0456b5SFelix Fietkau struct txq_info *txqi;
33956e0456b5SFelix Fietkau struct sk_buff **frag_tail, *head;
33966e0456b5SFelix Fietkau int subframe_len = skb->len - ETH_ALEN;
33976e0456b5SFelix Fietkau u8 max_subframes = sta->sta.max_amsdu_subframes;
33986e0456b5SFelix Fietkau int max_frags = local->hw.max_tx_fragments;
33994c51541dSBenjamin Berg int max_amsdu_len = sta->sta.cur->max_amsdu_len;
3400eb9b64e3SFelix Fietkau int orig_truesize;
3401f2af2df8SFelix Fietkau u32 flow_idx;
34026e0456b5SFelix Fietkau __be16 len;
34036e0456b5SFelix Fietkau void *data;
34046e0456b5SFelix Fietkau bool ret = false;
3405fa962b92SMichal Kazior unsigned int orig_len;
340666eb02d8SLorenzo Bianconi int n = 2, nfrags, pad = 0;
3407166ac9d5SSara Sharon u16 hdrlen;
34086e0456b5SFelix Fietkau
34096e0456b5SFelix Fietkau if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
34106e0456b5SFelix Fietkau return false;
34116e0456b5SFelix Fietkau
34124f2e3eb6SRyder Lee if (sdata->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
34134f2e3eb6SRyder Lee return false;
34144f2e3eb6SRyder Lee
3415d5edb9aeSFelix Fietkau if (ieee80211_vif_is_mesh(&sdata->vif))
3416d5edb9aeSFelix Fietkau return false;
3417d5edb9aeSFelix Fietkau
3418344f8e00SSara Sharon if (skb_is_gso(skb))
3419344f8e00SSara Sharon return false;
3420344f8e00SSara Sharon
34216e0456b5SFelix Fietkau if (!txq)
34226e0456b5SFelix Fietkau return false;
34236e0456b5SFelix Fietkau
34246e0456b5SFelix Fietkau txqi = to_txq_info(txq);
34256e0456b5SFelix Fietkau if (test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags))
34266e0456b5SFelix Fietkau return false;
34276e0456b5SFelix Fietkau
34284c51541dSBenjamin Berg if (sta->sta.cur->max_rc_amsdu_len)
34296e0456b5SFelix Fietkau max_amsdu_len = min_t(int, max_amsdu_len,
34304c51541dSBenjamin Berg sta->sta.cur->max_rc_amsdu_len);
34316e0456b5SFelix Fietkau
34324c51541dSBenjamin Berg if (sta->sta.cur->max_tid_amsdu_len[tid])
3433edba6bdaSSara Sharon max_amsdu_len = min_t(int, max_amsdu_len,
34344c51541dSBenjamin Berg sta->sta.cur->max_tid_amsdu_len[tid]);
3435edba6bdaSSara Sharon
3436f2af2df8SFelix Fietkau flow_idx = fq_flow_idx(fq, skb);
3437f2af2df8SFelix Fietkau
3438fa962b92SMichal Kazior spin_lock_bh(&fq->lock);
34396e0456b5SFelix Fietkau
3440fa962b92SMichal Kazior /* TODO: Ideally aggregation should be done on dequeue to remain
3441fa962b92SMichal Kazior * responsive to environment changes.
3442fa962b92SMichal Kazior */
3443fa962b92SMichal Kazior
3444fa962b92SMichal Kazior tin = &txqi->tin;
3445bf9009bfSFelix Fietkau flow = fq_flow_classify(fq, tin, flow_idx, skb);
3446fa962b92SMichal Kazior head = skb_peek_tail(&flow->queue);
3447344f8e00SSara Sharon if (!head || skb_is_gso(head))
34486e0456b5SFelix Fietkau goto out;
34496e0456b5SFelix Fietkau
3450eb9b64e3SFelix Fietkau orig_truesize = head->truesize;
3451fa962b92SMichal Kazior orig_len = head->len;
3452fa962b92SMichal Kazior
34536e0456b5SFelix Fietkau if (skb->len + head->len > max_amsdu_len)
34546e0456b5SFelix Fietkau goto out;
34556e0456b5SFelix Fietkau
34566e0456b5SFelix Fietkau nfrags = 1 + skb_shinfo(skb)->nr_frags;
34576e0456b5SFelix Fietkau nfrags += 1 + skb_shinfo(head)->nr_frags;
34586e0456b5SFelix Fietkau frag_tail = &skb_shinfo(head)->frag_list;
34596e0456b5SFelix Fietkau while (*frag_tail) {
34606e0456b5SFelix Fietkau nfrags += 1 + skb_shinfo(*frag_tail)->nr_frags;
34616e0456b5SFelix Fietkau frag_tail = &(*frag_tail)->next;
34626e0456b5SFelix Fietkau n++;
34636e0456b5SFelix Fietkau }
34646e0456b5SFelix Fietkau
34656e0456b5SFelix Fietkau if (max_subframes && n > max_subframes)
34666e0456b5SFelix Fietkau goto out;
34676e0456b5SFelix Fietkau
34686e0456b5SFelix Fietkau if (max_frags && nfrags > max_frags)
34696e0456b5SFelix Fietkau goto out;
34706e0456b5SFelix Fietkau
34719739fe29SSara Sharon if (!drv_can_aggregate_in_amsdu(local, head, skb))
34729739fe29SSara Sharon goto out;
34739739fe29SSara Sharon
34741eb50790SLorenzo Bianconi if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head))
34756e0456b5SFelix Fietkau goto out;
34766e0456b5SFelix Fietkau
3477fe94bac6SChih-Kang Chang /* If n == 2, the "while (*frag_tail)" loop above didn't execute
3478fe94bac6SChih-Kang Chang * and frag_tail should be &skb_shinfo(head)->frag_list.
3479fe94bac6SChih-Kang Chang * However, ieee80211_amsdu_prepare_head() can reallocate it.
3480fe94bac6SChih-Kang Chang * Reload frag_tail to have it pointing to the correct place.
3481fe94bac6SChih-Kang Chang */
3482fe94bac6SChih-Kang Chang if (n == 2)
3483fe94bac6SChih-Kang Chang frag_tail = &skb_shinfo(head)->frag_list;
3484fe94bac6SChih-Kang Chang
3485166ac9d5SSara Sharon /*
3486166ac9d5SSara Sharon * Pad out the previous subframe to a multiple of 4 by adding the
3487166ac9d5SSara Sharon * padding to the next one, that's being added. Note that head->len
3488166ac9d5SSara Sharon * is the length of the full A-MSDU, but that works since each time
3489166ac9d5SSara Sharon * we add a new subframe we pad out the previous one to a multiple
3490166ac9d5SSara Sharon * of 4 and thus it no longer matters in the next round.
3491166ac9d5SSara Sharon */
3492166ac9d5SSara Sharon hdrlen = fast_tx->hdr_len - sizeof(rfc1042_header);
3493166ac9d5SSara Sharon if ((head->len - hdrlen) & 3)
3494166ac9d5SSara Sharon pad = 4 - ((head->len - hdrlen) & 3);
3495166ac9d5SSara Sharon
3496166ac9d5SSara Sharon if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) +
3497166ac9d5SSara Sharon 2 + pad))
3498aa58acf3SJohannes Berg goto out_recalc;
34996e0456b5SFelix Fietkau
35006e0456b5SFelix Fietkau ret = true;
35016e0456b5SFelix Fietkau data = skb_push(skb, ETH_ALEN + 2);
3502d5edb9aeSFelix Fietkau ether_addr_copy(data, da);
3503d5edb9aeSFelix Fietkau ether_addr_copy(data + ETH_ALEN, sa);
35046e0456b5SFelix Fietkau
35056e0456b5SFelix Fietkau data += 2 * ETH_ALEN;
35066e0456b5SFelix Fietkau len = cpu_to_be16(subframe_len);
35076e0456b5SFelix Fietkau memcpy(data, &len, 2);
35086e0456b5SFelix Fietkau memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header));
35096e0456b5SFelix Fietkau
3510166ac9d5SSara Sharon memset(skb_push(skb, pad), 0, pad);
3511166ac9d5SSara Sharon
35126e0456b5SFelix Fietkau head->len += skb->len;
35136e0456b5SFelix Fietkau head->data_len += skb->len;
35146e0456b5SFelix Fietkau *frag_tail = skb;
35156e0456b5SFelix Fietkau
3516aa58acf3SJohannes Berg out_recalc:
3517eb9b64e3SFelix Fietkau fq->memory_usage += head->truesize - orig_truesize;
3518aa58acf3SJohannes Berg if (head->len != orig_len) {
3519fa962b92SMichal Kazior flow->backlog += head->len - orig_len;
3520fa962b92SMichal Kazior tin->backlog_bytes += head->len - orig_len;
3521aa58acf3SJohannes Berg }
35226e0456b5SFelix Fietkau out:
3523fa962b92SMichal Kazior spin_unlock_bh(&fq->lock);
35246e0456b5SFelix Fietkau
35256e0456b5SFelix Fietkau return ret;
35266e0456b5SFelix Fietkau }
35276e0456b5SFelix Fietkau
3528bb42f2d1SToke Høiland-Jørgensen /*
3529bb42f2d1SToke Høiland-Jørgensen * Can be called while the sta lock is held. Anything that can cause packets to
3530bb42f2d1SToke Høiland-Jørgensen * be generated will cause deadlock!
3531bb42f2d1SToke Høiland-Jørgensen */
353203c3911dSRyder Lee static ieee80211_tx_result
ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,u8 pn_offs,struct ieee80211_key * key,struct ieee80211_tx_data * tx)353303c3911dSRyder Lee ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
3534bb42f2d1SToke Høiland-Jørgensen struct sta_info *sta, u8 pn_offs,
3535bb42f2d1SToke Høiland-Jørgensen struct ieee80211_key *key,
353603c3911dSRyder Lee struct ieee80211_tx_data *tx)
3537bb42f2d1SToke Høiland-Jørgensen {
353803c3911dSRyder Lee struct sk_buff *skb = tx->skb;
3539bb42f2d1SToke Høiland-Jørgensen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3540bb42f2d1SToke Høiland-Jørgensen struct ieee80211_hdr *hdr = (void *)skb->data;
3541bb42f2d1SToke Høiland-Jørgensen u8 tid = IEEE80211_NUM_TIDS;
3542bb42f2d1SToke Høiland-Jørgensen
354303c3911dSRyder Lee if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL) &&
354403c3911dSRyder Lee ieee80211_tx_h_rate_ctrl(tx) != TX_CONTINUE)
354503c3911dSRyder Lee return TX_DROP;
354603c3911dSRyder Lee
3547bb42f2d1SToke Høiland-Jørgensen if (key)
3548bb42f2d1SToke Høiland-Jørgensen info->control.hw_key = &key->conf;
3549bb42f2d1SToke Høiland-Jørgensen
355036ec144fSLev Stipakov dev_sw_netstats_tx_add(skb->dev, 1, skb->len);
3551bb42f2d1SToke Høiland-Jørgensen
3552bb42f2d1SToke Høiland-Jørgensen if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
3553bb42f2d1SToke Høiland-Jørgensen tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
3554bb42f2d1SToke Høiland-Jørgensen hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
3555bb42f2d1SToke Høiland-Jørgensen } else {
3556bb42f2d1SToke Høiland-Jørgensen info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
3557bb42f2d1SToke Høiland-Jørgensen hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
3558bb42f2d1SToke Høiland-Jørgensen sdata->sequence_number += 0x10;
3559bb42f2d1SToke Høiland-Jørgensen }
3560bb42f2d1SToke Høiland-Jørgensen
3561bb42f2d1SToke Høiland-Jørgensen if (skb_shinfo(skb)->gso_size)
3562046d2e7cSSriram R sta->deflink.tx_stats.msdu[tid] +=
3563bb42f2d1SToke Høiland-Jørgensen DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size);
3564bb42f2d1SToke Høiland-Jørgensen else
3565046d2e7cSSriram R sta->deflink.tx_stats.msdu[tid]++;
3566bb42f2d1SToke Høiland-Jørgensen
3567bb42f2d1SToke Høiland-Jørgensen info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
3568bb42f2d1SToke Høiland-Jørgensen
3569bb42f2d1SToke Høiland-Jørgensen /* statistics normally done by ieee80211_tx_h_stats (but that
3570bb42f2d1SToke Høiland-Jørgensen * has to consider fragmentation, so is more complex)
3571bb42f2d1SToke Høiland-Jørgensen */
3572046d2e7cSSriram R sta->deflink.tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
3573046d2e7cSSriram R sta->deflink.tx_stats.packets[skb_get_queue_mapping(skb)]++;
3574bb42f2d1SToke Høiland-Jørgensen
3575bb42f2d1SToke Høiland-Jørgensen if (pn_offs) {
3576bb42f2d1SToke Høiland-Jørgensen u64 pn;
3577bb42f2d1SToke Høiland-Jørgensen u8 *crypto_hdr = skb->data + pn_offs;
3578bb42f2d1SToke Høiland-Jørgensen
3579bb42f2d1SToke Høiland-Jørgensen switch (key->conf.cipher) {
3580bb42f2d1SToke Høiland-Jørgensen case WLAN_CIPHER_SUITE_CCMP:
3581bb42f2d1SToke Høiland-Jørgensen case WLAN_CIPHER_SUITE_CCMP_256:
3582bb42f2d1SToke Høiland-Jørgensen case WLAN_CIPHER_SUITE_GCMP:
3583bb42f2d1SToke Høiland-Jørgensen case WLAN_CIPHER_SUITE_GCMP_256:
3584bb42f2d1SToke Høiland-Jørgensen pn = atomic64_inc_return(&key->conf.tx_pn);
3585bb42f2d1SToke Høiland-Jørgensen crypto_hdr[0] = pn;
3586bb42f2d1SToke Høiland-Jørgensen crypto_hdr[1] = pn >> 8;
358796fc6efbSAlexander Wetzel crypto_hdr[3] = 0x20 | (key->conf.keyidx << 6);
3588bb42f2d1SToke Høiland-Jørgensen crypto_hdr[4] = pn >> 16;
3589bb42f2d1SToke Høiland-Jørgensen crypto_hdr[5] = pn >> 24;
3590bb42f2d1SToke Høiland-Jørgensen crypto_hdr[6] = pn >> 32;
3591bb42f2d1SToke Høiland-Jørgensen crypto_hdr[7] = pn >> 40;
3592bb42f2d1SToke Høiland-Jørgensen break;
3593bb42f2d1SToke Høiland-Jørgensen }
3594bb42f2d1SToke Høiland-Jørgensen }
359503c3911dSRyder Lee
359603c3911dSRyder Lee return TX_CONTINUE;
3597bb42f2d1SToke Høiland-Jørgensen }
3598bb42f2d1SToke Høiland-Jørgensen
35997d360f60SFelix Fietkau static netdev_features_t
ieee80211_sdata_netdev_features(struct ieee80211_sub_if_data * sdata)36007d360f60SFelix Fietkau ieee80211_sdata_netdev_features(struct ieee80211_sub_if_data *sdata)
36017d360f60SFelix Fietkau {
36027d360f60SFelix Fietkau if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
36037d360f60SFelix Fietkau return sdata->vif.netdev_features;
36047d360f60SFelix Fietkau
36057d360f60SFelix Fietkau if (!sdata->bss)
36067d360f60SFelix Fietkau return 0;
36077d360f60SFelix Fietkau
36087d360f60SFelix Fietkau sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
36097d360f60SFelix Fietkau return sdata->vif.netdev_features;
36107d360f60SFelix Fietkau }
36117d360f60SFelix Fietkau
36127d360f60SFelix Fietkau static struct sk_buff *
ieee80211_tx_skb_fixup(struct sk_buff * skb,netdev_features_t features)36137d360f60SFelix Fietkau ieee80211_tx_skb_fixup(struct sk_buff *skb, netdev_features_t features)
36147d360f60SFelix Fietkau {
36157d360f60SFelix Fietkau if (skb_is_gso(skb)) {
36167d360f60SFelix Fietkau struct sk_buff *segs;
36177d360f60SFelix Fietkau
36187d360f60SFelix Fietkau segs = skb_gso_segment(skb, features);
36197d360f60SFelix Fietkau if (!segs)
36207d360f60SFelix Fietkau return skb;
36217d360f60SFelix Fietkau if (IS_ERR(segs))
36227d360f60SFelix Fietkau goto free;
36237d360f60SFelix Fietkau
36247d360f60SFelix Fietkau consume_skb(skb);
36257d360f60SFelix Fietkau return segs;
36267d360f60SFelix Fietkau }
36277d360f60SFelix Fietkau
36287d360f60SFelix Fietkau if (skb_needs_linearize(skb, features) && __skb_linearize(skb))
36297d360f60SFelix Fietkau goto free;
36307d360f60SFelix Fietkau
36317d360f60SFelix Fietkau if (skb->ip_summed == CHECKSUM_PARTIAL) {
36327d360f60SFelix Fietkau int ofs = skb_checksum_start_offset(skb);
36337d360f60SFelix Fietkau
36347d360f60SFelix Fietkau if (skb->encapsulation)
36357d360f60SFelix Fietkau skb_set_inner_transport_header(skb, ofs);
36367d360f60SFelix Fietkau else
36377d360f60SFelix Fietkau skb_set_transport_header(skb, ofs);
36387d360f60SFelix Fietkau
36397d360f60SFelix Fietkau if (skb_csum_hwoffload_help(skb, features))
36407d360f60SFelix Fietkau goto free;
36417d360f60SFelix Fietkau }
36427d360f60SFelix Fietkau
36437d360f60SFelix Fietkau skb_mark_not_on_list(skb);
36447d360f60SFelix Fietkau return skb;
36457d360f60SFelix Fietkau
36467d360f60SFelix Fietkau free:
36477d360f60SFelix Fietkau kfree_skb(skb);
36487d360f60SFelix Fietkau return NULL;
36497d360f60SFelix Fietkau }
36507d360f60SFelix Fietkau
__ieee80211_xmit_fast(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct ieee80211_fast_tx * fast_tx,struct sk_buff * skb,bool ampdu,const u8 * da,const u8 * sa)3651d5edb9aeSFelix Fietkau void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
36527d360f60SFelix Fietkau struct sta_info *sta,
36537d360f60SFelix Fietkau struct ieee80211_fast_tx *fast_tx,
3654d5edb9aeSFelix Fietkau struct sk_buff *skb, bool ampdu,
3655d5edb9aeSFelix Fietkau const u8 *da, const u8 *sa)
36567d360f60SFelix Fietkau {
36577d360f60SFelix Fietkau struct ieee80211_local *local = sdata->local;
36587d360f60SFelix Fietkau struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
36597d360f60SFelix Fietkau struct ieee80211_tx_info *info;
36607d360f60SFelix Fietkau struct ieee80211_tx_data tx;
36617d360f60SFelix Fietkau ieee80211_tx_result r;
36627d360f60SFelix Fietkau int hw_headroom = sdata->local->hw.extra_tx_headroom;
36637d360f60SFelix Fietkau int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
36647d360f60SFelix Fietkau
36657d360f60SFelix Fietkau skb = skb_share_check(skb, GFP_ATOMIC);
36667d360f60SFelix Fietkau if (unlikely(!skb))
36677d360f60SFelix Fietkau return;
36687d360f60SFelix Fietkau
36697d360f60SFelix Fietkau if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
3670d5edb9aeSFelix Fietkau ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb, da, sa))
36717d360f60SFelix Fietkau return;
36727d360f60SFelix Fietkau
36737d360f60SFelix Fietkau /* will not be crypto-handled beyond what we do here, so use false
36747d360f60SFelix Fietkau * as the may-encrypt argument for the resize to not account for
36757d360f60SFelix Fietkau * more room than we already have in 'extra_head'
36767d360f60SFelix Fietkau */
36777d360f60SFelix Fietkau if (unlikely(ieee80211_skb_resize(sdata, skb,
36787d360f60SFelix Fietkau max_t(int, extra_head + hw_headroom -
36797d360f60SFelix Fietkau skb_headroom(skb), 0),
36807d360f60SFelix Fietkau ENCRYPT_NO)))
36817d360f60SFelix Fietkau goto free;
36827d360f60SFelix Fietkau
36837d360f60SFelix Fietkau hdr = skb_push(skb, extra_head);
36847d360f60SFelix Fietkau memcpy(skb->data, fast_tx->hdr, fast_tx->hdr_len);
3685d5edb9aeSFelix Fietkau memcpy(skb->data + fast_tx->da_offs, da, ETH_ALEN);
3686d5edb9aeSFelix Fietkau memcpy(skb->data + fast_tx->sa_offs, sa, ETH_ALEN);
36877d360f60SFelix Fietkau
36887d360f60SFelix Fietkau info = IEEE80211_SKB_CB(skb);
36897d360f60SFelix Fietkau memset(info, 0, sizeof(*info));
36907d360f60SFelix Fietkau info->band = fast_tx->band;
36917d360f60SFelix Fietkau info->control.vif = &sdata->vif;
36927d360f60SFelix Fietkau info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
3693592234e9SAlexander Wetzel IEEE80211_TX_CTL_DONTFRAG;
36947d360f60SFelix Fietkau info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT |
36957d360f60SFelix Fietkau u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
36967d360f60SFelix Fietkau IEEE80211_TX_CTRL_MLO_LINK);
36977d360f60SFelix Fietkau
36987d360f60SFelix Fietkau #ifdef CONFIG_MAC80211_DEBUGFS
36997d360f60SFelix Fietkau if (local->force_tx_status)
37007d360f60SFelix Fietkau info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
37017d360f60SFelix Fietkau #endif
37027d360f60SFelix Fietkau
37037d360f60SFelix Fietkau if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
3704d5edb9aeSFelix Fietkau u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
3705d5edb9aeSFelix Fietkau
37067d360f60SFelix Fietkau *ieee80211_get_qos_ctl(hdr) = tid;
37077d360f60SFelix Fietkau }
37087d360f60SFelix Fietkau
37097d360f60SFelix Fietkau __skb_queue_head_init(&tx.skbs);
37107d360f60SFelix Fietkau
37117d360f60SFelix Fietkau tx.flags = IEEE80211_TX_UNICAST;
37127d360f60SFelix Fietkau tx.local = local;
37137d360f60SFelix Fietkau tx.sdata = sdata;
37147d360f60SFelix Fietkau tx.sta = sta;
37157d360f60SFelix Fietkau tx.key = fast_tx->key;
37167d360f60SFelix Fietkau
37177d360f60SFelix Fietkau if (ieee80211_queue_skb(local, sdata, sta, skb))
37187d360f60SFelix Fietkau return;
37197d360f60SFelix Fietkau
37207d360f60SFelix Fietkau tx.skb = skb;
37217d360f60SFelix Fietkau r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
37227d360f60SFelix Fietkau fast_tx->key, &tx);
37237d360f60SFelix Fietkau tx.skb = NULL;
37247d360f60SFelix Fietkau if (r == TX_DROP)
37257d360f60SFelix Fietkau goto free;
37267d360f60SFelix Fietkau
37277d360f60SFelix Fietkau if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
37287d360f60SFelix Fietkau sdata = container_of(sdata->bss,
37297d360f60SFelix Fietkau struct ieee80211_sub_if_data, u.ap);
37307d360f60SFelix Fietkau
37317d360f60SFelix Fietkau __skb_queue_tail(&tx.skbs, skb);
37327d360f60SFelix Fietkau ieee80211_tx_frags(local, &sdata->vif, sta, &tx.skbs, false);
37337d360f60SFelix Fietkau return;
37347d360f60SFelix Fietkau
37357d360f60SFelix Fietkau free:
37367d360f60SFelix Fietkau kfree_skb(skb);
37377d360f60SFelix Fietkau }
37387d360f60SFelix Fietkau
ieee80211_xmit_fast(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct ieee80211_fast_tx * fast_tx,struct sk_buff * skb)373917c18bf8SJohannes Berg static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
3740bb42f2d1SToke Høiland-Jørgensen struct sta_info *sta,
374117c18bf8SJohannes Berg struct ieee80211_fast_tx *fast_tx,
374217c18bf8SJohannes Berg struct sk_buff *skb)
374317c18bf8SJohannes Berg {
374417c18bf8SJohannes Berg u16 ethertype = (skb->data[12] << 8) | skb->data[13];
374517c18bf8SJohannes Berg struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
374617c18bf8SJohannes Berg struct tid_ampdu_tx *tid_tx = NULL;
37477d360f60SFelix Fietkau struct sk_buff *next;
3748d5edb9aeSFelix Fietkau struct ethhdr eth;
374917c18bf8SJohannes Berg u8 tid = IEEE80211_NUM_TIDS;
375017c18bf8SJohannes Berg
375117c18bf8SJohannes Berg /* control port protocol needs a lot of special handling */
375217c18bf8SJohannes Berg if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
375317c18bf8SJohannes Berg return false;
375417c18bf8SJohannes Berg
375517c18bf8SJohannes Berg /* only RFC 1042 SNAP */
375617c18bf8SJohannes Berg if (ethertype < ETH_P_802_3_MIN)
375717c18bf8SJohannes Berg return false;
375817c18bf8SJohannes Berg
375917c18bf8SJohannes Berg /* don't handle TX status request here either */
376017c18bf8SJohannes Berg if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
376117c18bf8SJohannes Berg return false;
376217c18bf8SJohannes Berg
376317c18bf8SJohannes Berg if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
376417c18bf8SJohannes Berg tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
376517c18bf8SJohannes Berg tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
3766472be00dSJohannes Berg if (tid_tx) {
3767472be00dSJohannes Berg if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
376817c18bf8SJohannes Berg return false;
3769472be00dSJohannes Berg if (tid_tx->timeout)
3770472be00dSJohannes Berg tid_tx->last_tx = jiffies;
3771472be00dSJohannes Berg }
377217c18bf8SJohannes Berg }
377317c18bf8SJohannes Berg
3774d5edb9aeSFelix Fietkau memcpy(ð, skb->data, ETH_HLEN - 2);
3775d5edb9aeSFelix Fietkau
377617c18bf8SJohannes Berg /* after this point (skb is modified) we cannot return false */
37777d360f60SFelix Fietkau skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
37787d360f60SFelix Fietkau if (!skb)
377917c18bf8SJohannes Berg return true;
378017c18bf8SJohannes Berg
37817d360f60SFelix Fietkau skb_list_walk_safe(skb, skb, next) {
37827d360f60SFelix Fietkau skb_mark_not_on_list(skb);
3783d5edb9aeSFelix Fietkau __ieee80211_xmit_fast(sdata, sta, fast_tx, skb, tid_tx,
3784d5edb9aeSFelix Fietkau eth.h_dest, eth.h_source);
378517c18bf8SJohannes Berg }
378617c18bf8SJohannes Berg
378717c18bf8SJohannes Berg return true;
378817c18bf8SJohannes Berg }
378917c18bf8SJohannes Berg
ieee80211_tx_dequeue(struct ieee80211_hw * hw,struct ieee80211_txq * txq)3790e0e2efffSToke Høiland-Jørgensen struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
3791e0e2efffSToke Høiland-Jørgensen struct ieee80211_txq *txq)
3792e0e2efffSToke Høiland-Jørgensen {
3793e0e2efffSToke Høiland-Jørgensen struct ieee80211_local *local = hw_to_local(hw);
3794e0e2efffSToke Høiland-Jørgensen struct txq_info *txqi = container_of(txq, struct txq_info, txq);
3795e0e2efffSToke Høiland-Jørgensen struct ieee80211_hdr *hdr;
3796e0e2efffSToke Høiland-Jørgensen struct sk_buff *skb = NULL;
3797e0e2efffSToke Høiland-Jørgensen struct fq *fq = &local->fq;
3798e0e2efffSToke Høiland-Jørgensen struct fq_tin *tin = &txqi->tin;
3799bb42f2d1SToke Høiland-Jørgensen struct ieee80211_tx_info *info;
3800bb42f2d1SToke Høiland-Jørgensen struct ieee80211_tx_data tx;
3801bb42f2d1SToke Høiland-Jørgensen ieee80211_tx_result r;
380221a5d4c3SManikanta Pubbisetty struct ieee80211_vif *vif = txq->vif;
38034444bc21SAlexander Wetzel int q = vif->hw_queue[txq->ac];
3804ef6e1997SMirsad Goran Todorovac unsigned long flags;
38054444bc21SAlexander Wetzel bool q_stopped;
3806e0e2efffSToke Høiland-Jørgensen
3807fb0e76abSErik Stromdahl WARN_ON_ONCE(softirq_count() == 0);
3808fb0e76abSErik Stromdahl
38097a89233aSToke Høiland-Jørgensen if (!ieee80211_txq_airtime_check(hw, txq))
38107a89233aSToke Høiland-Jørgensen return NULL;
38117a89233aSToke Høiland-Jørgensen
3812ded4698bSFelix Fietkau begin:
3813ef6e1997SMirsad Goran Todorovac spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
38144444bc21SAlexander Wetzel q_stopped = local->queue_stop_reasons[q];
3815ef6e1997SMirsad Goran Todorovac spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
38164444bc21SAlexander Wetzel
38174444bc21SAlexander Wetzel if (unlikely(q_stopped)) {
38184444bc21SAlexander Wetzel /* mark for waking later */
38194444bc21SAlexander Wetzel set_bit(IEEE80211_TXQ_DIRTY, &txqi->flags);
38204444bc21SAlexander Wetzel return NULL;
38214444bc21SAlexander Wetzel }
38224444bc21SAlexander Wetzel
3823e0e2efffSToke Høiland-Jørgensen spin_lock_bh(&fq->lock);
3824e0e2efffSToke Høiland-Jørgensen
3825bb42f2d1SToke Høiland-Jørgensen /* Make sure fragments stay together. */
3826bb42f2d1SToke Høiland-Jørgensen skb = __skb_dequeue(&txqi->frags);
3827ca47b462SJohannes Berg if (unlikely(skb)) {
3828ca47b462SJohannes Berg if (!(IEEE80211_SKB_CB(skb)->control.flags &
3829ca47b462SJohannes Berg IEEE80211_TX_INTCFL_NEED_TXPROCESSING))
3830bb42f2d1SToke Høiland-Jørgensen goto out;
3831ca47b462SJohannes Berg IEEE80211_SKB_CB(skb)->control.flags &=
3832ca47b462SJohannes Berg ~IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
3833ca47b462SJohannes Berg } else {
3834592234e9SAlexander Wetzel if (unlikely(test_bit(IEEE80211_TXQ_STOP, &txqi->flags)))
3835592234e9SAlexander Wetzel goto out;
3836592234e9SAlexander Wetzel
3837e0e2efffSToke Høiland-Jørgensen skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
3838ca47b462SJohannes Berg }
3839ca47b462SJohannes Berg
3840e0e2efffSToke Høiland-Jørgensen if (!skb)
3841e0e2efffSToke Høiland-Jørgensen goto out;
3842e0e2efffSToke Høiland-Jørgensen
3843ded4698bSFelix Fietkau spin_unlock_bh(&fq->lock);
3844ded4698bSFelix Fietkau
3845e0e2efffSToke Høiland-Jørgensen hdr = (struct ieee80211_hdr *)skb->data;
3846bb42f2d1SToke Høiland-Jørgensen info = IEEE80211_SKB_CB(skb);
3847bb42f2d1SToke Høiland-Jørgensen
3848bb42f2d1SToke Høiland-Jørgensen memset(&tx, 0, sizeof(tx));
3849bb42f2d1SToke Høiland-Jørgensen __skb_queue_head_init(&tx.skbs);
3850bb42f2d1SToke Høiland-Jørgensen tx.local = local;
3851bb42f2d1SToke Høiland-Jørgensen tx.skb = skb;
3852bb42f2d1SToke Høiland-Jørgensen tx.sdata = vif_to_sdata(info->control.vif);
3853bb42f2d1SToke Høiland-Jørgensen
3854804fc6a2SMathy Vanhoef if (txq->sta) {
3855bb42f2d1SToke Høiland-Jørgensen tx.sta = container_of(txq->sta, struct sta_info, sta);
3856ce2e1ca7SJouni Malinen /*
3857ce2e1ca7SJouni Malinen * Drop unicast frames to unauthorised stations unless they are
3858804fc6a2SMathy Vanhoef * injected frames or EAPOL frames from the local station.
3859ce2e1ca7SJouni Malinen */
3860804fc6a2SMathy Vanhoef if (unlikely(!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
3861804fc6a2SMathy Vanhoef ieee80211_is_data(hdr->frame_control) &&
3862be8c827fSJohannes Berg !ieee80211_vif_is_mesh(&tx.sdata->vif) &&
3863ce2e1ca7SJouni Malinen tx.sdata->vif.type != NL80211_IFTYPE_OCB &&
3864ce2e1ca7SJouni Malinen !is_multicast_ether_addr(hdr->addr1) &&
3865ce2e1ca7SJouni Malinen !test_sta_flag(tx.sta, WLAN_STA_AUTHORIZED) &&
3866ce2e1ca7SJouni Malinen (!(info->control.flags &
3867ce2e1ca7SJouni Malinen IEEE80211_TX_CTRL_PORT_CTRL_PROTO) ||
38683579f4c2SJohannes Berg !ieee80211_is_our_addr(tx.sdata, hdr->addr2,
38693579f4c2SJohannes Berg NULL)))) {
3870ce2e1ca7SJouni Malinen I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
3871ce2e1ca7SJouni Malinen ieee80211_free_txskb(&local->hw, skb);
3872ce2e1ca7SJouni Malinen goto begin;
3873ce2e1ca7SJouni Malinen }
3874ce2e1ca7SJouni Malinen }
3875bb42f2d1SToke Høiland-Jørgensen
3876bb42f2d1SToke Høiland-Jørgensen /*
3877bb42f2d1SToke Høiland-Jørgensen * The key can be removed while the packet was queued, so need to call
3878bb42f2d1SToke Høiland-Jørgensen * this here to get the current key.
3879bb42f2d1SToke Høiland-Jørgensen */
3880bb42f2d1SToke Høiland-Jørgensen r = ieee80211_tx_h_select_key(&tx);
3881bb42f2d1SToke Høiland-Jørgensen if (r != TX_CONTINUE) {
3882bb42f2d1SToke Høiland-Jørgensen ieee80211_free_txskb(&local->hw, skb);
3883bb42f2d1SToke Høiland-Jørgensen goto begin;
3884bb42f2d1SToke Høiland-Jørgensen }
3885bb42f2d1SToke Høiland-Jørgensen
3886c1f4c9edSFelix Fietkau if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
3887592234e9SAlexander Wetzel info->flags |= (IEEE80211_TX_CTL_AMPDU |
3888592234e9SAlexander Wetzel IEEE80211_TX_CTL_DONTFRAG);
3889c1f4c9edSFelix Fietkau
38903187ba0cSRyder Lee if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
38913187ba0cSRyder Lee if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
38923187ba0cSRyder Lee r = ieee80211_tx_h_rate_ctrl(&tx);
38933187ba0cSRyder Lee if (r != TX_CONTINUE) {
38943187ba0cSRyder Lee ieee80211_free_txskb(&local->hw, skb);
38953187ba0cSRyder Lee goto begin;
38963187ba0cSRyder Lee }
38973187ba0cSRyder Lee }
389850ff477aSJohn Crispin goto encap_out;
38993187ba0cSRyder Lee }
390050ff477aSJohn Crispin
3901bb42f2d1SToke Høiland-Jørgensen if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
3902e0e2efffSToke Høiland-Jørgensen struct sta_info *sta = container_of(txq->sta, struct sta_info,
3903e0e2efffSToke Høiland-Jørgensen sta);
3904bb42f2d1SToke Høiland-Jørgensen u8 pn_offs = 0;
3905e0e2efffSToke Høiland-Jørgensen
3906bb42f2d1SToke Høiland-Jørgensen if (tx.key &&
3907bb42f2d1SToke Høiland-Jørgensen (tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
3908bb42f2d1SToke Høiland-Jørgensen pn_offs = ieee80211_hdrlen(hdr->frame_control);
3909bb42f2d1SToke Høiland-Jørgensen
391003c3911dSRyder Lee r = ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
391103c3911dSRyder Lee tx.key, &tx);
391203c3911dSRyder Lee if (r != TX_CONTINUE) {
391303c3911dSRyder Lee ieee80211_free_txskb(&local->hw, skb);
391403c3911dSRyder Lee goto begin;
391503c3911dSRyder Lee }
3916bb42f2d1SToke Høiland-Jørgensen } else {
3917bb42f2d1SToke Høiland-Jørgensen if (invoke_tx_handlers_late(&tx))
3918bb42f2d1SToke Høiland-Jørgensen goto begin;
3919bb42f2d1SToke Høiland-Jørgensen
3920bb42f2d1SToke Høiland-Jørgensen skb = __skb_dequeue(&tx.skbs);
3921e700e44fSJohannes Berg info = IEEE80211_SKB_CB(skb);
3922bb42f2d1SToke Høiland-Jørgensen
3923ded4698bSFelix Fietkau if (!skb_queue_empty(&tx.skbs)) {
3924ded4698bSFelix Fietkau spin_lock_bh(&fq->lock);
3925bb42f2d1SToke Høiland-Jørgensen skb_queue_splice_tail(&tx.skbs, &txqi->frags);
3926ded4698bSFelix Fietkau spin_unlock_bh(&fq->lock);
3927ded4698bSFelix Fietkau }
3928e0e2efffSToke Høiland-Jørgensen }
3929e0e2efffSToke Høiland-Jørgensen
3930233e98dcSJohannes Berg if (skb_has_frag_list(skb) &&
39311e1430d5SJohannes Berg !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) {
39321e1430d5SJohannes Berg if (skb_linearize(skb)) {
39331e1430d5SJohannes Berg ieee80211_free_txskb(&local->hw, skb);
39341e1430d5SJohannes Berg goto begin;
39351e1430d5SJohannes Berg }
39361e1430d5SJohannes Berg }
39371e1430d5SJohannes Berg
393853168215SJohannes Berg switch (tx.sdata->vif.type) {
393953168215SJohannes Berg case NL80211_IFTYPE_MONITOR:
394053168215SJohannes Berg if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
394153168215SJohannes Berg vif = &tx.sdata->vif;
394253168215SJohannes Berg break;
394353168215SJohannes Berg }
394453168215SJohannes Berg tx.sdata = rcu_dereference(local->monitor_sdata);
394553168215SJohannes Berg if (tx.sdata) {
394653168215SJohannes Berg vif = &tx.sdata->vif;
394753168215SJohannes Berg info->hw_queue =
394853168215SJohannes Berg vif->hw_queue[skb_get_queue_mapping(skb)];
394953168215SJohannes Berg } else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
395053168215SJohannes Berg ieee80211_free_txskb(&local->hw, skb);
395153168215SJohannes Berg goto begin;
395253168215SJohannes Berg } else {
395353168215SJohannes Berg vif = NULL;
395453168215SJohannes Berg }
395553168215SJohannes Berg break;
395653168215SJohannes Berg case NL80211_IFTYPE_AP_VLAN:
395753168215SJohannes Berg tx.sdata = container_of(tx.sdata->bss,
395853168215SJohannes Berg struct ieee80211_sub_if_data, u.ap);
3959fc0561dcSGustavo A. R. Silva fallthrough;
396053168215SJohannes Berg default:
396153168215SJohannes Berg vif = &tx.sdata->vif;
396253168215SJohannes Berg break;
396353168215SJohannes Berg }
396453168215SJohannes Berg
396550ff477aSJohn Crispin encap_out:
3966e700e44fSJohannes Berg info->control.vif = vif;
39677a89233aSToke Høiland-Jørgensen
396851d3cfafSFelix Fietkau if (tx.sta &&
3969ca98c47dSJohannes Berg wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
39703ff901cbSFelix Fietkau bool ampdu = txq->ac != IEEE80211_AC_VO;
39717a89233aSToke Høiland-Jørgensen u32 airtime;
39727a89233aSToke Høiland-Jørgensen
39737a89233aSToke Høiland-Jørgensen airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
39743ff901cbSFelix Fietkau skb->len, ampdu);
39757a89233aSToke Høiland-Jørgensen if (airtime) {
39767a89233aSToke Høiland-Jørgensen airtime = ieee80211_info_set_tx_time_est(info, airtime);
39777a89233aSToke Høiland-Jørgensen ieee80211_sta_update_pending_airtime(local, tx.sta,
39787a89233aSToke Høiland-Jørgensen txq->ac,
39797a89233aSToke Høiland-Jørgensen airtime,
39807a89233aSToke Høiland-Jørgensen false);
39817a89233aSToke Høiland-Jørgensen }
39827a89233aSToke Høiland-Jørgensen }
39837a89233aSToke Høiland-Jørgensen
3984ded4698bSFelix Fietkau return skb;
398521a5d4c3SManikanta Pubbisetty
3986e0e2efffSToke Høiland-Jørgensen out:
3987e0e2efffSToke Høiland-Jørgensen spin_unlock_bh(&fq->lock);
3988e0e2efffSToke Høiland-Jørgensen
3989e0e2efffSToke Høiland-Jørgensen return skb;
3990e0e2efffSToke Høiland-Jørgensen }
3991e0e2efffSToke Høiland-Jørgensen EXPORT_SYMBOL(ieee80211_tx_dequeue);
3992e0e2efffSToke Høiland-Jørgensen
ieee80211_sta_deficit(struct sta_info * sta,u8 ac)39939c1be3cdSFelix Fietkau static inline s32 ieee80211_sta_deficit(struct sta_info *sta, u8 ac)
39949c1be3cdSFelix Fietkau {
39959c1be3cdSFelix Fietkau struct airtime_info *air_info = &sta->airtime[ac];
39969c1be3cdSFelix Fietkau
39979c1be3cdSFelix Fietkau return air_info->deficit - atomic_read(&air_info->aql_tx_pending);
39989c1be3cdSFelix Fietkau }
39999c1be3cdSFelix Fietkau
40008ccc0702SFelix Fietkau static void
ieee80211_txq_set_active(struct txq_info * txqi)40018ccc0702SFelix Fietkau ieee80211_txq_set_active(struct txq_info *txqi)
40028ccc0702SFelix Fietkau {
40038ccc0702SFelix Fietkau struct sta_info *sta;
40048ccc0702SFelix Fietkau
40058ccc0702SFelix Fietkau if (!txqi->txq.sta)
40068ccc0702SFelix Fietkau return;
40078ccc0702SFelix Fietkau
40088ccc0702SFelix Fietkau sta = container_of(txqi->txq.sta, struct sta_info, sta);
40098ccc0702SFelix Fietkau sta->airtime[txqi->txq.ac].last_active = (u32)jiffies;
40108ccc0702SFelix Fietkau }
40118ccc0702SFelix Fietkau
40128ccc0702SFelix Fietkau static bool
ieee80211_txq_keep_active(struct txq_info * txqi)40138ccc0702SFelix Fietkau ieee80211_txq_keep_active(struct txq_info *txqi)
40148ccc0702SFelix Fietkau {
40158ccc0702SFelix Fietkau struct sta_info *sta;
40168ccc0702SFelix Fietkau u32 diff;
40178ccc0702SFelix Fietkau
40188ccc0702SFelix Fietkau if (!txqi->txq.sta)
40198ccc0702SFelix Fietkau return false;
40208ccc0702SFelix Fietkau
40218ccc0702SFelix Fietkau sta = container_of(txqi->txq.sta, struct sta_info, sta);
40228ccc0702SFelix Fietkau if (ieee80211_sta_deficit(sta, txqi->txq.ac) >= 0)
40238ccc0702SFelix Fietkau return false;
40248ccc0702SFelix Fietkau
40258ccc0702SFelix Fietkau diff = (u32)jiffies - sta->airtime[txqi->txq.ac].last_active;
40268ccc0702SFelix Fietkau
40278ccc0702SFelix Fietkau return diff <= AIRTIME_ACTIVE_DURATION;
40288ccc0702SFelix Fietkau }
40298ccc0702SFelix Fietkau
ieee80211_next_txq(struct ieee80211_hw * hw,u8 ac)403018667600SToke Høiland-Jørgensen struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
403118667600SToke Høiland-Jørgensen {
403218667600SToke Høiland-Jørgensen struct ieee80211_local *local = hw_to_local(hw);
40335b989c18SFelix Fietkau struct ieee80211_txq *ret = NULL;
4034942741daSFelix Fietkau struct txq_info *txqi = NULL, *head = NULL;
4035942741daSFelix Fietkau bool found_eligible_txq = false;
403618667600SToke Høiland-Jørgensen
4037942741daSFelix Fietkau spin_lock_bh(&local->active_txq_lock[ac]);
403818667600SToke Høiland-Jørgensen
40398e4bac06SFelix Fietkau if (!local->schedule_round[ac])
40408e4bac06SFelix Fietkau goto out;
40418e4bac06SFelix Fietkau
4042b4809e94SToke Høiland-Jørgensen begin:
4043942741daSFelix Fietkau txqi = list_first_entry_or_null(&local->active_txqs[ac],
4044942741daSFelix Fietkau struct txq_info,
4045942741daSFelix Fietkau schedule_order);
4046942741daSFelix Fietkau if (!txqi)
4047942741daSFelix Fietkau goto out;
4048942741daSFelix Fietkau
4049942741daSFelix Fietkau if (txqi == head) {
4050942741daSFelix Fietkau if (!found_eligible_txq)
4051942741daSFelix Fietkau goto out;
4052942741daSFelix Fietkau else
4053942741daSFelix Fietkau found_eligible_txq = false;
40543ace10f5SKan Yan }
40553ace10f5SKan Yan
4056942741daSFelix Fietkau if (!head)
4057942741daSFelix Fietkau head = txqi;
40583ace10f5SKan Yan
4059942741daSFelix Fietkau if (txqi->txq.sta) {
4060942741daSFelix Fietkau struct sta_info *sta = container_of(txqi->txq.sta,
4061942741daSFelix Fietkau struct sta_info, sta);
4062942741daSFelix Fietkau bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
40639c1be3cdSFelix Fietkau s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac);
4064b4809e94SToke Høiland-Jørgensen
4065942741daSFelix Fietkau if (aql_check)
4066942741daSFelix Fietkau found_eligible_txq = true;
40673ace10f5SKan Yan
4068942741daSFelix Fietkau if (deficit < 0)
4069942741daSFelix Fietkau sta->airtime[txqi->txq.ac].deficit +=
4070942741daSFelix Fietkau sta->airtime_weight;
4071942741daSFelix Fietkau
4072942741daSFelix Fietkau if (deficit < 0 || !aql_check) {
4073942741daSFelix Fietkau list_move_tail(&txqi->schedule_order,
4074942741daSFelix Fietkau &local->active_txqs[txqi->txq.ac]);
4075b4809e94SToke Høiland-Jørgensen goto begin;
4076b4809e94SToke Høiland-Jørgensen }
4077942741daSFelix Fietkau }
4078b4809e94SToke Høiland-Jørgensen
4079942741daSFelix Fietkau if (txqi->schedule_round == local->schedule_round[ac])
4080942741daSFelix Fietkau goto out;
4081942741daSFelix Fietkau
4082942741daSFelix Fietkau list_del_init(&txqi->schedule_order);
4083942741daSFelix Fietkau txqi->schedule_round = local->schedule_round[ac];
40845b989c18SFelix Fietkau ret = &txqi->txq;
4085942741daSFelix Fietkau
40865b989c18SFelix Fietkau out:
4087942741daSFelix Fietkau spin_unlock_bh(&local->active_txq_lock[ac]);
40885b989c18SFelix Fietkau return ret;
408918667600SToke Høiland-Jørgensen }
409018667600SToke Høiland-Jørgensen EXPORT_SYMBOL(ieee80211_next_txq);
409118667600SToke Høiland-Jørgensen
__ieee80211_schedule_txq(struct ieee80211_hw * hw,struct ieee80211_txq * txq,bool force)4092942741daSFelix Fietkau void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
4093942741daSFelix Fietkau struct ieee80211_txq *txq,
4094942741daSFelix Fietkau bool force)
40952433647bSToke Høiland-Jørgensen {
40962433647bSToke Høiland-Jørgensen struct ieee80211_local *local = hw_to_local(hw);
40972433647bSToke Høiland-Jørgensen struct txq_info *txqi = to_txq_info(txq);
40988ccc0702SFelix Fietkau bool has_queue;
40992433647bSToke Høiland-Jørgensen
4100942741daSFelix Fietkau spin_lock_bh(&local->active_txq_lock[txq->ac]);
41012433647bSToke Høiland-Jørgensen
41028ccc0702SFelix Fietkau has_queue = force || txq_has_queue(txq);
4103942741daSFelix Fietkau if (list_empty(&txqi->schedule_order) &&
41048ccc0702SFelix Fietkau (has_queue || ieee80211_txq_keep_active(txqi))) {
4105942741daSFelix Fietkau /* If airtime accounting is active, always enqueue STAs at the
4106942741daSFelix Fietkau * head of the list to ensure that they only get moved to the
4107942741daSFelix Fietkau * back by the airtime DRR scheduler once they have a negative
4108942741daSFelix Fietkau * deficit. A station that already has a negative deficit will
4109942741daSFelix Fietkau * get immediately moved to the back of the list on the next
4110942741daSFelix Fietkau * call to ieee80211_next_txq().
41112433647bSToke Høiland-Jørgensen */
41128ccc0702SFelix Fietkau if (txqi->txq.sta && local->airtime_flags && has_queue &&
4113942741daSFelix Fietkau wiphy_ext_feature_isset(local->hw.wiphy,
4114942741daSFelix Fietkau NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
4115942741daSFelix Fietkau list_add(&txqi->schedule_order,
4116942741daSFelix Fietkau &local->active_txqs[txq->ac]);
41172433647bSToke Høiland-Jørgensen else
4118942741daSFelix Fietkau list_add_tail(&txqi->schedule_order,
4119942741daSFelix Fietkau &local->active_txqs[txq->ac]);
41208ccc0702SFelix Fietkau if (has_queue)
41218ccc0702SFelix Fietkau ieee80211_txq_set_active(txqi);
41222433647bSToke Høiland-Jørgensen }
41232433647bSToke Høiland-Jørgensen
4124942741daSFelix Fietkau spin_unlock_bh(&local->active_txq_lock[txq->ac]);
41252433647bSToke Høiland-Jørgensen }
4126942741daSFelix Fietkau EXPORT_SYMBOL(__ieee80211_schedule_txq);
4127390298e8SToke Høiland-Jørgensen
4128e908435eSLorenzo Bianconi DEFINE_STATIC_KEY_FALSE(aql_disable);
4129e908435eSLorenzo Bianconi
ieee80211_txq_airtime_check(struct ieee80211_hw * hw,struct ieee80211_txq * txq)41303ace10f5SKan Yan bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
41313ace10f5SKan Yan struct ieee80211_txq *txq)
41323ace10f5SKan Yan {
4133942741daSFelix Fietkau struct sta_info *sta;
41343ace10f5SKan Yan struct ieee80211_local *local = hw_to_local(hw);
41353ace10f5SKan Yan
4136911bde0fSToke Høiland-Jørgensen if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
41373ace10f5SKan Yan return true;
41383ace10f5SKan Yan
4139e908435eSLorenzo Bianconi if (static_branch_unlikely(&aql_disable))
4140e908435eSLorenzo Bianconi return true;
4141e908435eSLorenzo Bianconi
41423ace10f5SKan Yan if (!txq->sta)
41433ace10f5SKan Yan return true;
41443ace10f5SKan Yan
414573bc9e0aSJohannes Berg if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
414673bc9e0aSJohannes Berg return true;
414773bc9e0aSJohannes Berg
4148942741daSFelix Fietkau sta = container_of(txq->sta, struct sta_info, sta);
4149942741daSFelix Fietkau if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
4150942741daSFelix Fietkau sta->airtime[txq->ac].aql_limit_low)
41513ace10f5SKan Yan return true;
41523ace10f5SKan Yan
41533ace10f5SKan Yan if (atomic_read(&local->aql_total_pending_airtime) <
41543ace10f5SKan Yan local->aql_threshold &&
4155942741daSFelix Fietkau atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
4156942741daSFelix Fietkau sta->airtime[txq->ac].aql_limit_high)
41573ace10f5SKan Yan return true;
41583ace10f5SKan Yan
41593ace10f5SKan Yan return false;
41603ace10f5SKan Yan }
41613ace10f5SKan Yan EXPORT_SYMBOL(ieee80211_txq_airtime_check);
41623ace10f5SKan Yan
41638e4bac06SFelix Fietkau static bool
ieee80211_txq_schedule_airtime_check(struct ieee80211_local * local,u8 ac)41648e4bac06SFelix Fietkau ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac)
41658e4bac06SFelix Fietkau {
41668e4bac06SFelix Fietkau unsigned int num_txq = 0;
41678e4bac06SFelix Fietkau struct txq_info *txq;
41688e4bac06SFelix Fietkau u32 aql_limit;
41698e4bac06SFelix Fietkau
41708e4bac06SFelix Fietkau if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
41718e4bac06SFelix Fietkau return true;
41728e4bac06SFelix Fietkau
41738e4bac06SFelix Fietkau list_for_each_entry(txq, &local->active_txqs[ac], schedule_order)
41748e4bac06SFelix Fietkau num_txq++;
41758e4bac06SFelix Fietkau
41768e4bac06SFelix Fietkau aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 +
41778e4bac06SFelix Fietkau local->aql_txq_limit_high[ac];
41788e4bac06SFelix Fietkau
41798e4bac06SFelix Fietkau return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit;
41808e4bac06SFelix Fietkau }
41818e4bac06SFelix Fietkau
ieee80211_txq_may_transmit(struct ieee80211_hw * hw,struct ieee80211_txq * txq)4182b4809e94SToke Høiland-Jørgensen bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
4183b4809e94SToke Høiland-Jørgensen struct ieee80211_txq *txq)
4184b4809e94SToke Høiland-Jørgensen {
4185b4809e94SToke Høiland-Jørgensen struct ieee80211_local *local = hw_to_local(hw);
4186942741daSFelix Fietkau struct txq_info *iter, *tmp, *txqi = to_txq_info(txq);
4187942741daSFelix Fietkau struct sta_info *sta;
4188942741daSFelix Fietkau u8 ac = txq->ac;
4189b4809e94SToke Høiland-Jørgensen
4190942741daSFelix Fietkau spin_lock_bh(&local->active_txq_lock[ac]);
4191b4809e94SToke Høiland-Jørgensen
4192942741daSFelix Fietkau if (!txqi->txq.sta)
41932433647bSToke Høiland-Jørgensen goto out;
41942433647bSToke Høiland-Jørgensen
4195942741daSFelix Fietkau if (list_empty(&txqi->schedule_order))
4196942741daSFelix Fietkau goto out;
41972433647bSToke Høiland-Jørgensen
41988e4bac06SFelix Fietkau if (!ieee80211_txq_schedule_airtime_check(local, ac))
41998e4bac06SFelix Fietkau goto out;
42008e4bac06SFelix Fietkau
4201942741daSFelix Fietkau list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
4202942741daSFelix Fietkau schedule_order) {
4203942741daSFelix Fietkau if (iter == txqi)
4204942741daSFelix Fietkau break;
42052433647bSToke Høiland-Jørgensen
4206942741daSFelix Fietkau if (!iter->txq.sta) {
4207942741daSFelix Fietkau list_move_tail(&iter->schedule_order,
4208942741daSFelix Fietkau &local->active_txqs[ac]);
4209942741daSFelix Fietkau continue;
4210942741daSFelix Fietkau }
4211942741daSFelix Fietkau sta = container_of(iter->txq.sta, struct sta_info, sta);
42129c1be3cdSFelix Fietkau if (ieee80211_sta_deficit(sta, ac) < 0)
4213942741daSFelix Fietkau sta->airtime[ac].deficit += sta->airtime_weight;
4214942741daSFelix Fietkau list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
42152433647bSToke Høiland-Jørgensen }
42162433647bSToke Høiland-Jørgensen
4217942741daSFelix Fietkau sta = container_of(txqi->txq.sta, struct sta_info, sta);
4218942741daSFelix Fietkau if (sta->airtime[ac].deficit >= 0)
4219942741daSFelix Fietkau goto out;
42202433647bSToke Høiland-Jørgensen
4221942741daSFelix Fietkau sta->airtime[ac].deficit += sta->airtime_weight;
4222942741daSFelix Fietkau list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
4223942741daSFelix Fietkau spin_unlock_bh(&local->active_txq_lock[ac]);
4224942741daSFelix Fietkau
4225942741daSFelix Fietkau return false;
42262433647bSToke Høiland-Jørgensen out:
4227942741daSFelix Fietkau if (!list_empty(&txqi->schedule_order))
4228942741daSFelix Fietkau list_del_init(&txqi->schedule_order);
4229942741daSFelix Fietkau spin_unlock_bh(&local->active_txq_lock[ac]);
4230942741daSFelix Fietkau
4231942741daSFelix Fietkau return true;
4232b4809e94SToke Høiland-Jørgensen }
4233b4809e94SToke Høiland-Jørgensen EXPORT_SYMBOL(ieee80211_txq_may_transmit);
4234b4809e94SToke Høiland-Jørgensen
ieee80211_txq_schedule_start(struct ieee80211_hw * hw,u8 ac)423518667600SToke Høiland-Jørgensen void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
423618667600SToke Høiland-Jørgensen {
423718667600SToke Høiland-Jørgensen struct ieee80211_local *local = hw_to_local(hw);
423818667600SToke Høiland-Jørgensen
4239942741daSFelix Fietkau spin_lock_bh(&local->active_txq_lock[ac]);
42408e4bac06SFelix Fietkau
42418e4bac06SFelix Fietkau if (ieee80211_txq_schedule_airtime_check(local, ac)) {
4242942741daSFelix Fietkau local->schedule_round[ac]++;
42438e4bac06SFelix Fietkau if (!local->schedule_round[ac])
42448e4bac06SFelix Fietkau local->schedule_round[ac]++;
42458e4bac06SFelix Fietkau } else {
42468e4bac06SFelix Fietkau local->schedule_round[ac] = 0;
42478e4bac06SFelix Fietkau }
42488e4bac06SFelix Fietkau
4249942741daSFelix Fietkau spin_unlock_bh(&local->active_txq_lock[ac]);
425018667600SToke Høiland-Jørgensen }
42515b989c18SFelix Fietkau EXPORT_SYMBOL(ieee80211_txq_schedule_start);
425218667600SToke Høiland-Jørgensen
__ieee80211_subif_start_xmit(struct sk_buff * skb,struct net_device * dev,u32 info_flags,u32 ctrl_flags,u64 * cookie)42534c9451edSJohannes Berg void __ieee80211_subif_start_xmit(struct sk_buff *skb,
42544c9451edSJohannes Berg struct net_device *dev,
425506016772SRajkumar Manoharan u32 info_flags,
4256a7528198SMarkus Theil u32 ctrl_flags,
4257a7528198SMarkus Theil u64 *cookie)
42584c9451edSJohannes Berg {
42594c9451edSJohannes Berg struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
42601974da8bSFelix Fietkau struct ieee80211_local *local = sdata->local;
426197ffe757SJohannes Berg struct sta_info *sta;
426280616c0dSJohannes Berg struct sk_buff *next;
426330f6cf96SFelix Fietkau int len = skb->len;
42644c9451edSJohannes Berg
4265c95014e1SAlexander Wetzel if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
42664c9451edSJohannes Berg kfree_skb(skb);
42674c9451edSJohannes Berg return;
42684c9451edSJohannes Berg }
42694c9451edSJohannes Berg
4270d5edb9aeSFelix Fietkau sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
4271d5edb9aeSFelix Fietkau
42724c9451edSJohannes Berg rcu_read_lock();
42734c9451edSJohannes Berg
4274d5edb9aeSFelix Fietkau if (ieee80211_vif_is_mesh(&sdata->vif) &&
4275d5edb9aeSFelix Fietkau ieee80211_hw_check(&local->hw, SUPPORT_FAST_XMIT) &&
4276d5edb9aeSFelix Fietkau ieee80211_mesh_xmit_fast(sdata, skb, ctrl_flags))
4277d5edb9aeSFelix Fietkau goto out;
4278d5edb9aeSFelix Fietkau
42792d981fddSJohannes Berg if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
42802d981fddSJohannes Berg goto out_free;
42814c9451edSJohannes Berg
42821974da8bSFelix Fietkau if (IS_ERR(sta))
42831974da8bSFelix Fietkau sta = NULL;
42841974da8bSFelix Fietkau
4285107395f9SAlexander Wetzel skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
428608a46c64SFelix Fietkau ieee80211_aggr_check(sdata, sta, skb);
428708a46c64SFelix Fietkau
42881974da8bSFelix Fietkau if (sta) {
428917c18bf8SJohannes Berg struct ieee80211_fast_tx *fast_tx;
429017c18bf8SJohannes Berg
429117c18bf8SJohannes Berg fast_tx = rcu_dereference(sta->fast_tx);
429217c18bf8SJohannes Berg
429317c18bf8SJohannes Berg if (fast_tx &&
4294bb42f2d1SToke Høiland-Jørgensen ieee80211_xmit_fast(sdata, sta, fast_tx, skb))
429517c18bf8SJohannes Berg goto out;
429617c18bf8SJohannes Berg }
429717c18bf8SJohannes Berg
429880616c0dSJohannes Berg /* the frame could be fragmented, software-encrypted, and other
42997d360f60SFelix Fietkau * things so we cannot really handle checksum or GSO offload.
430080616c0dSJohannes Berg * fix it up in software before we handle anything else.
43012d981fddSJohannes Berg */
43027d360f60SFelix Fietkau skb = ieee80211_tx_skb_fixup(skb, 0);
43037d360f60SFelix Fietkau if (!skb) {
43047d360f60SFelix Fietkau len = 0;
43057d360f60SFelix Fietkau goto out;
430680616c0dSJohannes Berg }
430780616c0dSJohannes Berg
43089f3ef3d7SJason A. Donenfeld skb_list_walk_safe(skb, skb, next) {
43099f3ef3d7SJason A. Donenfeld skb_mark_not_on_list(skb);
43102d981fddSJohannes Berg
43115af7fef3SMarkus Theil if (skb->protocol == sdata->control_port_protocol)
43125af7fef3SMarkus Theil ctrl_flags |= IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP;
43135af7fef3SMarkus Theil
431406016772SRajkumar Manoharan skb = ieee80211_build_hdr(sdata, skb, info_flags,
4315a7528198SMarkus Theil sta, ctrl_flags, cookie);
43169f3ef3d7SJason A. Donenfeld if (IS_ERR(skb)) {
43179f3ef3d7SJason A. Donenfeld kfree_skb_list(next);
43184c9451edSJohannes Berg goto out;
43199f3ef3d7SJason A. Donenfeld }
43204c9451edSJohannes Berg
432136ec144fSLev Stipakov dev_sw_netstats_tx_add(dev, 1, skb->len);
43224c9451edSJohannes Berg
432308aca29aSMathy Vanhoef ieee80211_xmit(sdata, sta, skb);
432480616c0dSJohannes Berg }
43252d981fddSJohannes Berg goto out;
43262d981fddSJohannes Berg out_free:
43272d981fddSJohannes Berg kfree_skb(skb);
432830f6cf96SFelix Fietkau len = 0;
43294c9451edSJohannes Berg out:
433030f6cf96SFelix Fietkau if (len)
433130f6cf96SFelix Fietkau ieee80211_tpt_led_trig_tx(local, len);
43324c9451edSJohannes Berg rcu_read_unlock();
43334c9451edSJohannes Berg }
43344c9451edSJohannes Berg
ieee80211_change_da(struct sk_buff * skb,struct sta_info * sta)4335ebceec86SMichael Braun static int ieee80211_change_da(struct sk_buff *skb, struct sta_info *sta)
4336ebceec86SMichael Braun {
4337ebceec86SMichael Braun struct ethhdr *eth;
4338ebceec86SMichael Braun int err;
4339ebceec86SMichael Braun
4340ebceec86SMichael Braun err = skb_ensure_writable(skb, ETH_HLEN);
4341ebceec86SMichael Braun if (unlikely(err))
4342ebceec86SMichael Braun return err;
4343ebceec86SMichael Braun
4344ebceec86SMichael Braun eth = (void *)skb->data;
4345ebceec86SMichael Braun ether_addr_copy(eth->h_dest, sta->sta.addr);
4346ebceec86SMichael Braun
4347ebceec86SMichael Braun return 0;
4348ebceec86SMichael Braun }
4349ebceec86SMichael Braun
ieee80211_multicast_to_unicast(struct sk_buff * skb,struct net_device * dev)4350ebceec86SMichael Braun static bool ieee80211_multicast_to_unicast(struct sk_buff *skb,
4351ebceec86SMichael Braun struct net_device *dev)
4352ebceec86SMichael Braun {
4353ebceec86SMichael Braun struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
4354ebceec86SMichael Braun const struct ethhdr *eth = (void *)skb->data;
4355ebceec86SMichael Braun const struct vlan_ethhdr *ethvlan = (void *)skb->data;
4356ebceec86SMichael Braun __be16 ethertype;
4357ebceec86SMichael Braun
4358ebceec86SMichael Braun switch (sdata->vif.type) {
4359ebceec86SMichael Braun case NL80211_IFTYPE_AP_VLAN:
4360ebceec86SMichael Braun if (sdata->u.vlan.sta)
4361ebceec86SMichael Braun return false;
4362ebceec86SMichael Braun if (sdata->wdev.use_4addr)
4363ebceec86SMichael Braun return false;
4364fc0561dcSGustavo A. R. Silva fallthrough;
4365ebceec86SMichael Braun case NL80211_IFTYPE_AP:
4366ebceec86SMichael Braun /* check runtime toggle for this bss */
4367ebceec86SMichael Braun if (!sdata->bss->multicast_to_unicast)
4368ebceec86SMichael Braun return false;
4369ebceec86SMichael Braun break;
4370ebceec86SMichael Braun default:
4371ebceec86SMichael Braun return false;
4372ebceec86SMichael Braun }
4373ebceec86SMichael Braun
4374ebceec86SMichael Braun /* multicast to unicast conversion only for some payload */
4375ebceec86SMichael Braun ethertype = eth->h_proto;
4376ebceec86SMichael Braun if (ethertype == htons(ETH_P_8021Q) && skb->len >= VLAN_ETH_HLEN)
4377ebceec86SMichael Braun ethertype = ethvlan->h_vlan_encapsulated_proto;
4378ebceec86SMichael Braun switch (ethertype) {
4379ebceec86SMichael Braun case htons(ETH_P_ARP):
4380ebceec86SMichael Braun case htons(ETH_P_IP):
4381ebceec86SMichael Braun case htons(ETH_P_IPV6):
4382ebceec86SMichael Braun break;
4383ebceec86SMichael Braun default:
4384ebceec86SMichael Braun return false;
4385ebceec86SMichael Braun }
4386ebceec86SMichael Braun
4387ebceec86SMichael Braun return true;
4388ebceec86SMichael Braun }
4389ebceec86SMichael Braun
4390ebceec86SMichael Braun static void
ieee80211_convert_to_unicast(struct sk_buff * skb,struct net_device * dev,struct sk_buff_head * queue)4391ebceec86SMichael Braun ieee80211_convert_to_unicast(struct sk_buff *skb, struct net_device *dev,
4392ebceec86SMichael Braun struct sk_buff_head *queue)
4393ebceec86SMichael Braun {
4394ebceec86SMichael Braun struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
4395ebceec86SMichael Braun struct ieee80211_local *local = sdata->local;
4396ebceec86SMichael Braun const struct ethhdr *eth = (struct ethhdr *)skb->data;
4397ebceec86SMichael Braun struct sta_info *sta, *first = NULL;
4398ebceec86SMichael Braun struct sk_buff *cloned_skb;
4399ebceec86SMichael Braun
4400ebceec86SMichael Braun rcu_read_lock();
4401ebceec86SMichael Braun
4402ebceec86SMichael Braun list_for_each_entry_rcu(sta, &local->sta_list, list) {
4403ebceec86SMichael Braun if (sdata != sta->sdata)
4404ebceec86SMichael Braun /* AP-VLAN mismatch */
4405ebceec86SMichael Braun continue;
4406ebceec86SMichael Braun if (unlikely(ether_addr_equal(eth->h_source, sta->sta.addr)))
4407ebceec86SMichael Braun /* do not send back to source */
4408ebceec86SMichael Braun continue;
4409ebceec86SMichael Braun if (!first) {
4410ebceec86SMichael Braun first = sta;
4411ebceec86SMichael Braun continue;
4412ebceec86SMichael Braun }
4413ebceec86SMichael Braun cloned_skb = skb_clone(skb, GFP_ATOMIC);
4414ebceec86SMichael Braun if (!cloned_skb)
4415ebceec86SMichael Braun goto multicast;
4416ebceec86SMichael Braun if (unlikely(ieee80211_change_da(cloned_skb, sta))) {
4417ebceec86SMichael Braun dev_kfree_skb(cloned_skb);
4418ebceec86SMichael Braun goto multicast;
4419ebceec86SMichael Braun }
4420ebceec86SMichael Braun __skb_queue_tail(queue, cloned_skb);
4421ebceec86SMichael Braun }
4422ebceec86SMichael Braun
4423ebceec86SMichael Braun if (likely(first)) {
4424ebceec86SMichael Braun if (unlikely(ieee80211_change_da(skb, first)))
4425ebceec86SMichael Braun goto multicast;
4426ebceec86SMichael Braun __skb_queue_tail(queue, skb);
4427ebceec86SMichael Braun } else {
4428ebceec86SMichael Braun /* no STA connected, drop */
4429ebceec86SMichael Braun kfree_skb(skb);
4430ebceec86SMichael Braun skb = NULL;
4431ebceec86SMichael Braun }
4432ebceec86SMichael Braun
4433ebceec86SMichael Braun goto out;
4434ebceec86SMichael Braun multicast:
4435ebceec86SMichael Braun __skb_queue_purge(queue);
4436ebceec86SMichael Braun __skb_queue_tail(queue, skb);
4437ebceec86SMichael Braun out:
4438ebceec86SMichael Braun rcu_read_unlock();
4439ebceec86SMichael Braun }
4440ebceec86SMichael Braun
ieee80211_mlo_multicast_tx_one(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,u32 ctrl_flags,unsigned int link_id)4441963d0e8dSJohannes Berg static void ieee80211_mlo_multicast_tx_one(struct ieee80211_sub_if_data *sdata,
4442963d0e8dSJohannes Berg struct sk_buff *skb, u32 ctrl_flags,
4443963d0e8dSJohannes Berg unsigned int link_id)
4444963d0e8dSJohannes Berg {
4445963d0e8dSJohannes Berg struct sk_buff *out;
4446963d0e8dSJohannes Berg
4447963d0e8dSJohannes Berg out = skb_copy(skb, GFP_ATOMIC);
4448963d0e8dSJohannes Berg if (!out)
4449963d0e8dSJohannes Berg return;
4450963d0e8dSJohannes Berg
4451963d0e8dSJohannes Berg ctrl_flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK);
4452963d0e8dSJohannes Berg __ieee80211_subif_start_xmit(out, sdata->dev, 0, ctrl_flags, NULL);
4453963d0e8dSJohannes Berg }
4454963d0e8dSJohannes Berg
ieee80211_mlo_multicast_tx(struct net_device * dev,struct sk_buff * skb)4455963d0e8dSJohannes Berg static void ieee80211_mlo_multicast_tx(struct net_device *dev,
4456963d0e8dSJohannes Berg struct sk_buff *skb)
4457963d0e8dSJohannes Berg {
4458963d0e8dSJohannes Berg struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
44597b3b9ac8SIlan Peer unsigned long links = sdata->vif.active_links;
4460963d0e8dSJohannes Berg unsigned int link;
4461963d0e8dSJohannes Berg u32 ctrl_flags = IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX;
4462963d0e8dSJohannes Berg
4463963d0e8dSJohannes Berg if (hweight16(links) == 1) {
4464cf08e29dSJohannes Berg ctrl_flags |= u32_encode_bits(__ffs(links),
4465963d0e8dSJohannes Berg IEEE80211_TX_CTRL_MLO_LINK);
4466963d0e8dSJohannes Berg
4467963d0e8dSJohannes Berg __ieee80211_subif_start_xmit(skb, sdata->dev, 0, ctrl_flags,
4468963d0e8dSJohannes Berg NULL);
4469963d0e8dSJohannes Berg return;
4470963d0e8dSJohannes Berg }
4471963d0e8dSJohannes Berg
4472963d0e8dSJohannes Berg for_each_set_bit(link, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
4473963d0e8dSJohannes Berg ieee80211_mlo_multicast_tx_one(sdata, skb, ctrl_flags, link);
4474963d0e8dSJohannes Berg ctrl_flags = 0;
4475963d0e8dSJohannes Berg }
4476963d0e8dSJohannes Berg kfree_skb(skb);
4477963d0e8dSJohannes Berg }
4478963d0e8dSJohannes Berg
44794c9451edSJohannes Berg /**
44804c9451edSJohannes Berg * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs
44814c9451edSJohannes Berg * @skb: packet to be sent
44824c9451edSJohannes Berg * @dev: incoming interface
44834c9451edSJohannes Berg *
44844c9451edSJohannes Berg * On failure skb will be freed.
44854c9451edSJohannes Berg */
ieee80211_subif_start_xmit(struct sk_buff * skb,struct net_device * dev)448624d342c5SLiad Kaufman netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
448724d342c5SLiad Kaufman struct net_device *dev)
448824d342c5SLiad Kaufman {
4489963d0e8dSJohannes Berg struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
4490963d0e8dSJohannes Berg const struct ethhdr *eth = (void *)skb->data;
4491963d0e8dSJohannes Berg
4492963d0e8dSJohannes Berg if (likely(!is_multicast_ether_addr(eth->h_dest)))
4493963d0e8dSJohannes Berg goto normal;
4494963d0e8dSJohannes Berg
449578085418SZhengchao Shao if (unlikely(!ieee80211_sdata_running(sdata))) {
449678085418SZhengchao Shao kfree_skb(skb);
449778085418SZhengchao Shao return NETDEV_TX_OK;
449878085418SZhengchao Shao }
449978085418SZhengchao Shao
4500ebceec86SMichael Braun if (unlikely(ieee80211_multicast_to_unicast(skb, dev))) {
4501ebceec86SMichael Braun struct sk_buff_head queue;
4502ebceec86SMichael Braun
4503ebceec86SMichael Braun __skb_queue_head_init(&queue);
4504ebceec86SMichael Braun ieee80211_convert_to_unicast(skb, dev, &queue);
4505ebceec86SMichael Braun while ((skb = __skb_dequeue(&queue)))
4506963d0e8dSJohannes Berg __ieee80211_subif_start_xmit(skb, dev, 0,
4507963d0e8dSJohannes Berg IEEE80211_TX_CTRL_MLO_LINK_UNSPEC,
4508963d0e8dSJohannes Berg NULL);
4509f1871abdSIlan Peer } else if (ieee80211_vif_is_mld(&sdata->vif) &&
4510963d0e8dSJohannes Berg sdata->vif.type == NL80211_IFTYPE_AP &&
4511963d0e8dSJohannes Berg !ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX)) {
4512963d0e8dSJohannes Berg ieee80211_mlo_multicast_tx(dev, skb);
4513ebceec86SMichael Braun } else {
4514963d0e8dSJohannes Berg normal:
4515963d0e8dSJohannes Berg __ieee80211_subif_start_xmit(skb, dev, 0,
4516963d0e8dSJohannes Berg IEEE80211_TX_CTRL_MLO_LINK_UNSPEC,
4517963d0e8dSJohannes Berg NULL);
4518ebceec86SMichael Braun }
4519ebceec86SMichael Braun
452024d342c5SLiad Kaufman return NETDEV_TX_OK;
452124d342c5SLiad Kaufman }
4522e2ebc74dSJohannes Berg
45237d360f60SFelix Fietkau
45247d360f60SFelix Fietkau
__ieee80211_tx_8023(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,struct sta_info * sta,bool txpending)45257d360f60SFelix Fietkau static bool __ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
452630f6cf96SFelix Fietkau struct sk_buff *skb, struct sta_info *sta,
452750ff477aSJohn Crispin bool txpending)
452850ff477aSJohn Crispin {
452950ff477aSJohn Crispin struct ieee80211_local *local = sdata->local;
453050ff477aSJohn Crispin struct ieee80211_tx_control control = {};
453150ff477aSJohn Crispin struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
453250ff477aSJohn Crispin struct ieee80211_sta *pubsta = NULL;
453350ff477aSJohn Crispin unsigned long flags;
453450ff477aSJohn Crispin int q = info->hw_queue;
453550ff477aSJohn Crispin
453650ff477aSJohn Crispin spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
453750ff477aSJohn Crispin
453850ff477aSJohn Crispin if (local->queue_stop_reasons[q] ||
453950ff477aSJohn Crispin (!txpending && !skb_queue_empty(&local->pending[q]))) {
454050ff477aSJohn Crispin if (txpending)
454150ff477aSJohn Crispin skb_queue_head(&local->pending[q], skb);
454250ff477aSJohn Crispin else
454350ff477aSJohn Crispin skb_queue_tail(&local->pending[q], skb);
454450ff477aSJohn Crispin
454550ff477aSJohn Crispin spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
454650ff477aSJohn Crispin
454750ff477aSJohn Crispin return false;
454850ff477aSJohn Crispin }
454950ff477aSJohn Crispin
455050ff477aSJohn Crispin spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
455150ff477aSJohn Crispin
455250ff477aSJohn Crispin if (sta && sta->uploaded)
455350ff477aSJohn Crispin pubsta = &sta->sta;
455450ff477aSJohn Crispin
455550ff477aSJohn Crispin control.sta = pubsta;
455650ff477aSJohn Crispin
455750ff477aSJohn Crispin drv_tx(local, &control, skb);
455850ff477aSJohn Crispin
455950ff477aSJohn Crispin return true;
456050ff477aSJohn Crispin }
456150ff477aSJohn Crispin
ieee80211_tx_8023(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,struct sta_info * sta,bool txpending)45627d360f60SFelix Fietkau static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
45637d360f60SFelix Fietkau struct sk_buff *skb, struct sta_info *sta,
45647d360f60SFelix Fietkau bool txpending)
45657d360f60SFelix Fietkau {
45667d360f60SFelix Fietkau struct ieee80211_local *local = sdata->local;
45677d360f60SFelix Fietkau struct sk_buff *next;
45687d360f60SFelix Fietkau bool ret = true;
45697d360f60SFelix Fietkau
45707d360f60SFelix Fietkau if (ieee80211_queue_skb(local, sdata, sta, skb))
45717d360f60SFelix Fietkau return true;
45727d360f60SFelix Fietkau
45737d360f60SFelix Fietkau skb_list_walk_safe(skb, skb, next) {
45747d360f60SFelix Fietkau skb_mark_not_on_list(skb);
45757d360f60SFelix Fietkau if (!__ieee80211_tx_8023(sdata, skb, sta, txpending))
45767d360f60SFelix Fietkau ret = false;
45777d360f60SFelix Fietkau }
45787d360f60SFelix Fietkau
45797d360f60SFelix Fietkau return ret;
45807d360f60SFelix Fietkau }
45817d360f60SFelix Fietkau
ieee80211_8023_xmit(struct ieee80211_sub_if_data * sdata,struct net_device * dev,struct sta_info * sta,struct ieee80211_key * key,struct sk_buff * skb)458250ff477aSJohn Crispin static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
458350ff477aSJohn Crispin struct net_device *dev, struct sta_info *sta,
45846aea26ceSFelix Fietkau struct ieee80211_key *key, struct sk_buff *skb)
458550ff477aSJohn Crispin {
4586a4926abbSRyder Lee struct ieee80211_tx_info *info;
458750ff477aSJohn Crispin struct ieee80211_local *local = sdata->local;
458896ae9cd0SFelix Fietkau struct tid_ampdu_tx *tid_tx;
45897d360f60SFelix Fietkau struct sk_buff *seg, *next;
45907d360f60SFelix Fietkau unsigned int skbs = 0, len = 0;
45917d360f60SFelix Fietkau u16 queue;
459296ae9cd0SFelix Fietkau u8 tid;
459350ff477aSJohn Crispin
45947d360f60SFelix Fietkau queue = ieee80211_select_queue(sdata, sta, skb);
45957d360f60SFelix Fietkau skb_set_queue_mapping(skb, queue);
45965f8d69eaSFelix Fietkau
459750ff477aSJohn Crispin if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
459850ff477aSJohn Crispin test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
459950ff477aSJohn Crispin goto out_free;
460050ff477aSJohn Crispin
4601a4926abbSRyder Lee skb = skb_share_check(skb, GFP_ATOMIC);
4602a4926abbSRyder Lee if (unlikely(!skb))
4603a4926abbSRyder Lee return;
4604a4926abbSRyder Lee
460508a46c64SFelix Fietkau ieee80211_aggr_check(sdata, sta, skb);
460608a46c64SFelix Fietkau
460796ae9cd0SFelix Fietkau tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
460896ae9cd0SFelix Fietkau tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
460996ae9cd0SFelix Fietkau if (tid_tx) {
461096ae9cd0SFelix Fietkau if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
461196ae9cd0SFelix Fietkau /* fall back to non-offload slow path */
4612963d0e8dSJohannes Berg __ieee80211_subif_start_xmit(skb, dev, 0,
4613963d0e8dSJohannes Berg IEEE80211_TX_CTRL_MLO_LINK_UNSPEC,
4614963d0e8dSJohannes Berg NULL);
461596ae9cd0SFelix Fietkau return;
461696ae9cd0SFelix Fietkau }
461796ae9cd0SFelix Fietkau
461896ae9cd0SFelix Fietkau if (tid_tx->timeout)
461996ae9cd0SFelix Fietkau tid_tx->last_tx = jiffies;
462096ae9cd0SFelix Fietkau }
462196ae9cd0SFelix Fietkau
46227d360f60SFelix Fietkau skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
46237d360f60SFelix Fietkau if (!skb)
46247d360f60SFelix Fietkau return;
462550ff477aSJohn Crispin
46267d360f60SFelix Fietkau info = IEEE80211_SKB_CB(skb);
46277d360f60SFelix Fietkau memset(info, 0, sizeof(*info));
462850ff477aSJohn Crispin
46297d360f60SFelix Fietkau info->hw_queue = sdata->vif.hw_queue[queue];
463050ff477aSJohn Crispin
463150ff477aSJohn Crispin if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
463250ff477aSJohn Crispin sdata = container_of(sdata->bss,
463350ff477aSJohn Crispin struct ieee80211_sub_if_data, u.ap);
463450ff477aSJohn Crispin
4635cc20ff2cSFelix Fietkau info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP;
463650ff477aSJohn Crispin info->control.vif = &sdata->vif;
463750ff477aSJohn Crispin
4638ae045152SFelix Fietkau if (key)
4639ae045152SFelix Fietkau info->control.hw_key = &key->conf;
4640ae045152SFelix Fietkau
46417d360f60SFelix Fietkau skb_list_walk_safe(skb, seg, next) {
46427d360f60SFelix Fietkau skbs++;
46437d360f60SFelix Fietkau len += seg->len;
46447d360f60SFelix Fietkau if (seg != skb)
46457d360f60SFelix Fietkau memcpy(IEEE80211_SKB_CB(seg), info, sizeof(*info));
46467d360f60SFelix Fietkau }
46477d360f60SFelix Fietkau
46487d360f60SFelix Fietkau if (unlikely(skb->sk &&
46497d360f60SFelix Fietkau skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
46507d360f60SFelix Fietkau info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
46517d360f60SFelix Fietkau &info->flags, NULL);
46527d360f60SFelix Fietkau
46537d360f60SFelix Fietkau dev_sw_netstats_tx_add(dev, skbs, len);
46547d360f60SFelix Fietkau sta->deflink.tx_stats.packets[queue] += skbs;
46557d360f60SFelix Fietkau sta->deflink.tx_stats.bytes[queue] += len;
46567d360f60SFelix Fietkau
46577d360f60SFelix Fietkau ieee80211_tpt_led_trig_tx(local, len);
46587d360f60SFelix Fietkau
465930f6cf96SFelix Fietkau ieee80211_tx_8023(sdata, skb, sta, false);
466050ff477aSJohn Crispin
466150ff477aSJohn Crispin return;
466250ff477aSJohn Crispin
466350ff477aSJohn Crispin out_free:
466450ff477aSJohn Crispin kfree_skb(skb);
466550ff477aSJohn Crispin }
466650ff477aSJohn Crispin
ieee80211_subif_start_xmit_8023(struct sk_buff * skb,struct net_device * dev)466750ff477aSJohn Crispin netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
466850ff477aSJohn Crispin struct net_device *dev)
466950ff477aSJohn Crispin {
467050ff477aSJohn Crispin struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
4671aea6a3f0SFelix Fietkau struct ethhdr *ehdr = (struct ethhdr *)skb->data;
46726aea26ceSFelix Fietkau struct ieee80211_key *key;
467350ff477aSJohn Crispin struct sta_info *sta;
467450ff477aSJohn Crispin
4675c95014e1SAlexander Wetzel if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
467650ff477aSJohn Crispin kfree_skb(skb);
467750ff477aSJohn Crispin return NETDEV_TX_OK;
467850ff477aSJohn Crispin }
467950ff477aSJohn Crispin
468050ff477aSJohn Crispin rcu_read_lock();
468150ff477aSJohn Crispin
46826aea26ceSFelix Fietkau if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
468350ff477aSJohn Crispin kfree_skb(skb);
46846aea26ceSFelix Fietkau goto out;
46856aea26ceSFelix Fietkau }
46866aea26ceSFelix Fietkau
46876aea26ceSFelix Fietkau if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
4688aea6a3f0SFelix Fietkau !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
4689aea6a3f0SFelix Fietkau sdata->control_port_protocol == ehdr->h_proto))
4690b101dd2dSFelix Fietkau goto skip_offload;
4691b101dd2dSFelix Fietkau
4692b101dd2dSFelix Fietkau key = rcu_dereference(sta->ptk[sta->ptk_idx]);
4693b101dd2dSFelix Fietkau if (!key)
4694b101dd2dSFelix Fietkau key = rcu_dereference(sdata->default_unicast_key);
4695b101dd2dSFelix Fietkau
4696b101dd2dSFelix Fietkau if (key && (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) ||
46976aea26ceSFelix Fietkau key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
4698b101dd2dSFelix Fietkau goto skip_offload;
469950ff477aSJohn Crispin
47007d360f60SFelix Fietkau sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
47016aea26ceSFelix Fietkau ieee80211_8023_xmit(sdata, dev, sta, key, skb);
4702b101dd2dSFelix Fietkau goto out;
47036aea26ceSFelix Fietkau
4704b101dd2dSFelix Fietkau skip_offload:
4705b101dd2dSFelix Fietkau ieee80211_subif_start_xmit(skb, dev);
47066aea26ceSFelix Fietkau out:
470750ff477aSJohn Crispin rcu_read_unlock();
470850ff477aSJohn Crispin
470950ff477aSJohn Crispin return NETDEV_TX_OK;
471050ff477aSJohn Crispin }
471150ff477aSJohn Crispin
47127528ec57SJohannes Berg struct sk_buff *
ieee80211_build_data_template(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,u32 info_flags)47137528ec57SJohannes Berg ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
47147528ec57SJohannes Berg struct sk_buff *skb, u32 info_flags)
47157528ec57SJohannes Berg {
47167528ec57SJohannes Berg struct ieee80211_hdr *hdr;
47177528ec57SJohannes Berg struct ieee80211_tx_data tx = {
47187528ec57SJohannes Berg .local = sdata->local,
47197528ec57SJohannes Berg .sdata = sdata,
47207528ec57SJohannes Berg };
472197ffe757SJohannes Berg struct sta_info *sta;
47227528ec57SJohannes Berg
47237528ec57SJohannes Berg rcu_read_lock();
47247528ec57SJohannes Berg
472597ffe757SJohannes Berg if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
472697ffe757SJohannes Berg kfree_skb(skb);
472797ffe757SJohannes Berg skb = ERR_PTR(-EINVAL);
472897ffe757SJohannes Berg goto out;
472997ffe757SJohannes Berg }
473097ffe757SJohannes Berg
4731963d0e8dSJohannes Berg skb = ieee80211_build_hdr(sdata, skb, info_flags, sta,
4732963d0e8dSJohannes Berg IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, NULL);
47337528ec57SJohannes Berg if (IS_ERR(skb))
47347528ec57SJohannes Berg goto out;
47357528ec57SJohannes Berg
47367528ec57SJohannes Berg hdr = (void *)skb->data;
47377528ec57SJohannes Berg tx.sta = sta_info_get(sdata, hdr->addr1);
47387528ec57SJohannes Berg tx.skb = skb;
47397528ec57SJohannes Berg
47407528ec57SJohannes Berg if (ieee80211_tx_h_select_key(&tx) != TX_CONTINUE) {
47417528ec57SJohannes Berg rcu_read_unlock();
47427528ec57SJohannes Berg kfree_skb(skb);
47437528ec57SJohannes Berg return ERR_PTR(-EINVAL);
47447528ec57SJohannes Berg }
47457528ec57SJohannes Berg
47467528ec57SJohannes Berg out:
47477528ec57SJohannes Berg rcu_read_unlock();
47487528ec57SJohannes Berg return skb;
47497528ec57SJohannes Berg }
47507528ec57SJohannes Berg
4751e2530083SJohannes Berg /*
4752e2530083SJohannes Berg * ieee80211_clear_tx_pending may not be called in a context where
4753e2530083SJohannes Berg * it is possible that it packets could come in again.
4754e2530083SJohannes Berg */
ieee80211_clear_tx_pending(struct ieee80211_local * local)4755e2ebc74dSJohannes Berg void ieee80211_clear_tx_pending(struct ieee80211_local *local)
4756e2ebc74dSJohannes Berg {
47571f98ab7fSFelix Fietkau struct sk_buff *skb;
47582de8e0d9SJohannes Berg int i;
4759e2ebc74dSJohannes Berg
47601f98ab7fSFelix Fietkau for (i = 0; i < local->hw.queues; i++) {
47611f98ab7fSFelix Fietkau while ((skb = skb_dequeue(&local->pending[i])) != NULL)
47621f98ab7fSFelix Fietkau ieee80211_free_txskb(&local->hw, skb);
47631f98ab7fSFelix Fietkau }
4764e2ebc74dSJohannes Berg }
4765e2ebc74dSJohannes Berg
47667bb45683SJohannes Berg /*
47677bb45683SJohannes Berg * Returns false if the frame couldn't be transmitted but was queued instead,
47687bb45683SJohannes Berg * which in this case means re-queued -- take as an indication to stop sending
47697bb45683SJohannes Berg * more pending frames.
47707bb45683SJohannes Berg */
ieee80211_tx_pending_skb(struct ieee80211_local * local,struct sk_buff * skb)4771cd8ffc80SJohannes Berg static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
4772cd8ffc80SJohannes Berg struct sk_buff *skb)
4773cd8ffc80SJohannes Berg {
4774cd8ffc80SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
4775cd8ffc80SJohannes Berg struct ieee80211_sub_if_data *sdata;
4776cd8ffc80SJohannes Berg struct sta_info *sta;
4777cd8ffc80SJohannes Berg struct ieee80211_hdr *hdr;
47787bb45683SJohannes Berg bool result;
477955de908aSJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf;
4780cd8ffc80SJohannes Berg
47815061b0c2SJohannes Berg sdata = vif_to_sdata(info->control.vif);
4782cd8ffc80SJohannes Berg
4783cc20ff2cSFelix Fietkau if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) {
4784eef25a66SJohannes Berg /* update band only for non-MLD */
4785f1871abdSIlan Peer if (!ieee80211_vif_is_mld(&sdata->vif)) {
4786eef25a66SJohannes Berg chanctx_conf =
4787eef25a66SJohannes Berg rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
478855de908aSJohannes Berg if (unlikely(!chanctx_conf)) {
478955de908aSJohannes Berg dev_kfree_skb(skb);
479055de908aSJohannes Berg return true;
479155de908aSJohannes Berg }
479273c4e195SJohannes Berg info->band = chanctx_conf->def.chan->band;
4793eef25a66SJohannes Berg }
479408aca29aSMathy Vanhoef result = ieee80211_tx(sdata, NULL, skb, true);
4795cc20ff2cSFelix Fietkau } else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
479650ff477aSJohn Crispin if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
479750ff477aSJohn Crispin dev_kfree_skb(skb);
479850ff477aSJohn Crispin return true;
479950ff477aSJohn Crispin }
480050ff477aSJohn Crispin
480150ff477aSJohn Crispin if (IS_ERR(sta) || (sta && !sta->uploaded))
480250ff477aSJohn Crispin sta = NULL;
480350ff477aSJohn Crispin
480430f6cf96SFelix Fietkau result = ieee80211_tx_8023(sdata, skb, sta, true);
4805cd8ffc80SJohannes Berg } else {
4806252b86c4SJohannes Berg struct sk_buff_head skbs;
4807252b86c4SJohannes Berg
4808252b86c4SJohannes Berg __skb_queue_head_init(&skbs);
4809252b86c4SJohannes Berg __skb_queue_tail(&skbs, skb);
4810252b86c4SJohannes Berg
4811cd8ffc80SJohannes Berg hdr = (struct ieee80211_hdr *)skb->data;
4812abe60632SJohannes Berg sta = sta_info_get(sdata, hdr->addr1);
4813cd8ffc80SJohannes Berg
481430f6cf96SFelix Fietkau result = __ieee80211_tx(local, &skbs, sta, true);
4815cd8ffc80SJohannes Berg }
4816cd8ffc80SJohannes Berg
4817cd8ffc80SJohannes Berg return result;
4818cd8ffc80SJohannes Berg }
4819cd8ffc80SJohannes Berg
4820e2530083SJohannes Berg /*
48213b8d81e0SJohannes Berg * Transmit all pending packets. Called from tasklet.
4822e2530083SJohannes Berg */
ieee80211_tx_pending(struct tasklet_struct * t)4823da1cad73SAllen Pais void ieee80211_tx_pending(struct tasklet_struct *t)
4824e2ebc74dSJohannes Berg {
4825da1cad73SAllen Pais struct ieee80211_local *local = from_tasklet(local, t,
4826da1cad73SAllen Pais tx_pending_tasklet);
48272a577d98SJohannes Berg unsigned long flags;
4828cd8ffc80SJohannes Berg int i;
48293b8d81e0SJohannes Berg bool txok;
4830e2ebc74dSJohannes Berg
4831f0e72851SJohannes Berg rcu_read_lock();
48322a577d98SJohannes Berg
48333b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
4834176be728SJohannes Berg for (i = 0; i < local->hw.queues; i++) {
48352a577d98SJohannes Berg /*
48362a577d98SJohannes Berg * If queue is stopped by something other than due to pending
48372a577d98SJohannes Berg * frames, or we have no pending frames, proceed to next queue.
48382a577d98SJohannes Berg */
48393b8d81e0SJohannes Berg if (local->queue_stop_reasons[i] ||
48402a577d98SJohannes Berg skb_queue_empty(&local->pending[i]))
4841e2ebc74dSJohannes Berg continue;
4842e2530083SJohannes Berg
48432a577d98SJohannes Berg while (!skb_queue_empty(&local->pending[i])) {
48443b8d81e0SJohannes Berg struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
48455061b0c2SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
48465061b0c2SJohannes Berg
4847a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) {
4848c3e7724bSFelix Fietkau ieee80211_free_txskb(&local->hw, skb);
4849a7bc376cSJohannes Berg continue;
4850a7bc376cSJohannes Berg }
4851a7bc376cSJohannes Berg
48523b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock,
48533b8d81e0SJohannes Berg flags);
48542a577d98SJohannes Berg
48553b8d81e0SJohannes Berg txok = ieee80211_tx_pending_skb(local, skb);
48563b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock,
48573b8d81e0SJohannes Berg flags);
48583b8d81e0SJohannes Berg if (!txok)
48592a577d98SJohannes Berg break;
4860e2ebc74dSJohannes Berg }
4861e2ebc74dSJohannes Berg }
48623b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
48632a577d98SJohannes Berg
4864f0e72851SJohannes Berg rcu_read_unlock();
4865e2ebc74dSJohannes Berg }
4866e2ebc74dSJohannes Berg
4867e2ebc74dSJohannes Berg /* functions for drivers to get certain frames */
4868e2ebc74dSJohannes Berg
__ieee80211_beacon_add_tim(struct ieee80211_sub_if_data * sdata,struct ieee80211_link_data * link,struct ps_data * ps,struct sk_buff * skb,bool is_template)4869eac70c13SMarco Porsch static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
4870d8675a63SJohannes Berg struct ieee80211_link_data *link,
48716ec8c332SAndrei Otcheretianski struct ps_data *ps, struct sk_buff *skb,
4872d8675a63SJohannes Berg bool is_template)
4873e2ebc74dSJohannes Berg {
4874e2ebc74dSJohannes Berg u8 *pos, *tim;
4875e2ebc74dSJohannes Berg int aid0 = 0;
4876e2ebc74dSJohannes Berg int i, have_bits = 0, n1, n2;
4877d8675a63SJohannes Berg struct ieee80211_bss_conf *link_conf = link->conf;
4878e2ebc74dSJohannes Berg
4879e2ebc74dSJohannes Berg /* Generate bitmap for TIM only if there are any STAs in power save
4880e2ebc74dSJohannes Berg * mode. */
4881d012a605SMarco Porsch if (atomic_read(&ps->num_sta_ps) > 0)
4882e2ebc74dSJohannes Berg /* in the hope that this is faster than
4883e2ebc74dSJohannes Berg * checking byte-for-byte */
4884d012a605SMarco Porsch have_bits = !bitmap_empty((unsigned long *)ps->tim,
4885e2ebc74dSJohannes Berg IEEE80211_MAX_AID+1);
48866ec8c332SAndrei Otcheretianski if (!is_template) {
4887d012a605SMarco Porsch if (ps->dtim_count == 0)
48886e8912a5SShaul Triebitz ps->dtim_count = link_conf->dtim_period - 1;
4889e2ebc74dSJohannes Berg else
4890d012a605SMarco Porsch ps->dtim_count--;
48916ec8c332SAndrei Otcheretianski }
4892e2ebc74dSJohannes Berg
4893209d70d3SKieran Frewen tim = pos = skb_put(skb, 5);
4894e2ebc74dSJohannes Berg *pos++ = WLAN_EID_TIM;
4895209d70d3SKieran Frewen *pos++ = 3;
4896d012a605SMarco Porsch *pos++ = ps->dtim_count;
48976e8912a5SShaul Triebitz *pos++ = link_conf->dtim_period;
4898e2ebc74dSJohannes Berg
4899d012a605SMarco Porsch if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf))
4900e2ebc74dSJohannes Berg aid0 = 1;
4901e2ebc74dSJohannes Berg
4902d012a605SMarco Porsch ps->dtim_bc_mc = aid0 == 1;
4903512119b3SChristian Lamparter
4904e2ebc74dSJohannes Berg if (have_bits) {
4905e2ebc74dSJohannes Berg /* Find largest even number N1 so that bits numbered 1 through
4906e2ebc74dSJohannes Berg * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits
4907e2ebc74dSJohannes Berg * (N2 + 1) x 8 through 2007 are 0. */
4908e2ebc74dSJohannes Berg n1 = 0;
4909e2ebc74dSJohannes Berg for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
4910d012a605SMarco Porsch if (ps->tim[i]) {
4911e2ebc74dSJohannes Berg n1 = i & 0xfe;
4912e2ebc74dSJohannes Berg break;
4913e2ebc74dSJohannes Berg }
4914e2ebc74dSJohannes Berg }
4915e2ebc74dSJohannes Berg n2 = n1;
4916e2ebc74dSJohannes Berg for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
4917d012a605SMarco Porsch if (ps->tim[i]) {
4918e2ebc74dSJohannes Berg n2 = i;
4919e2ebc74dSJohannes Berg break;
4920e2ebc74dSJohannes Berg }
4921e2ebc74dSJohannes Berg }
4922e2ebc74dSJohannes Berg
4923e2ebc74dSJohannes Berg /* Bitmap control */
4924e2ebc74dSJohannes Berg *pos++ = n1 | aid0;
4925e2ebc74dSJohannes Berg /* Part Virt Bitmap */
4926209d70d3SKieran Frewen skb_put_data(skb, ps->tim + n1, n2 - n1 + 1);
4927e2ebc74dSJohannes Berg
4928e2ebc74dSJohannes Berg tim[1] = n2 - n1 + 4;
4929e2ebc74dSJohannes Berg } else {
4930e2ebc74dSJohannes Berg *pos++ = aid0; /* Bitmap control */
4931209d70d3SKieran Frewen
4932209d70d3SKieran Frewen if (ieee80211_get_link_sband(link)->band != NL80211_BAND_S1GHZ) {
4933209d70d3SKieran Frewen tim[1] = 4;
4934209d70d3SKieran Frewen /* Part Virt Bitmap */
4935209d70d3SKieran Frewen skb_put_u8(skb, 0);
4936209d70d3SKieran Frewen }
4937e2ebc74dSJohannes Berg }
4938e2ebc74dSJohannes Berg }
4939e2ebc74dSJohannes Berg
ieee80211_beacon_add_tim(struct ieee80211_sub_if_data * sdata,struct ieee80211_link_data * link,struct ps_data * ps,struct sk_buff * skb,bool is_template)4940eac70c13SMarco Porsch static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
4941d8675a63SJohannes Berg struct ieee80211_link_data *link,
49426ec8c332SAndrei Otcheretianski struct ps_data *ps, struct sk_buff *skb,
4943d8675a63SJohannes Berg bool is_template)
4944eac70c13SMarco Porsch {
4945eac70c13SMarco Porsch struct ieee80211_local *local = sdata->local;
4946eac70c13SMarco Porsch
4947eac70c13SMarco Porsch /*
4948eac70c13SMarco Porsch * Not very nice, but we want to allow the driver to call
4949eac70c13SMarco Porsch * ieee80211_beacon_get() as a response to the set_tim()
4950eac70c13SMarco Porsch * callback. That, however, is already invoked under the
4951eac70c13SMarco Porsch * sta_lock to guarantee consistent and race-free update
4952eac70c13SMarco Porsch * of the tim bitmap in mac80211 and the driver.
4953eac70c13SMarco Porsch */
4954eac70c13SMarco Porsch if (local->tim_in_locked_section) {
4955d8675a63SJohannes Berg __ieee80211_beacon_add_tim(sdata, link, ps, skb, is_template);
4956eac70c13SMarco Porsch } else {
49571b91731dSJohannes Berg spin_lock_bh(&local->tim_lock);
4958d8675a63SJohannes Berg __ieee80211_beacon_add_tim(sdata, link, ps, skb, is_template);
49591b91731dSJohannes Berg spin_unlock_bh(&local->tim_lock);
4960eac70c13SMarco Porsch }
4961eac70c13SMarco Porsch
4962eac70c13SMarco Porsch return 0;
4963eac70c13SMarco Porsch }
4964eac70c13SMarco Porsch
ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data * sdata,struct beacon_data * beacon,struct ieee80211_link_data * link)49658552a434SJohn Crispin static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,
49666e8912a5SShaul Triebitz struct beacon_data *beacon,
4967d8675a63SJohannes Berg struct ieee80211_link_data *link)
496873da7d5bSSimon Wunderlich {
49695f9404abSJohn Crispin u8 *beacon_data, count, max_count = 1;
497073da7d5bSSimon Wunderlich struct probe_resp *resp;
4971cd7760e6SSimon Wunderlich size_t beacon_data_len;
49725f9404abSJohn Crispin u16 *bcn_offsets;
49730d06d9baSAndrei Otcheretianski int i;
497473da7d5bSSimon Wunderlich
4975cd7760e6SSimon Wunderlich switch (sdata->vif.type) {
4976cd7760e6SSimon Wunderlich case NL80211_IFTYPE_AP:
4977cd7760e6SSimon Wunderlich beacon_data = beacon->tail;
4978cd7760e6SSimon Wunderlich beacon_data_len = beacon->tail_len;
4979cd7760e6SSimon Wunderlich break;
4980cd7760e6SSimon Wunderlich case NL80211_IFTYPE_ADHOC:
4981cd7760e6SSimon Wunderlich beacon_data = beacon->head;
4982cd7760e6SSimon Wunderlich beacon_data_len = beacon->head_len;
4983cd7760e6SSimon Wunderlich break;
4984b8456a14SChun-Yeow Yeoh case NL80211_IFTYPE_MESH_POINT:
4985b8456a14SChun-Yeow Yeoh beacon_data = beacon->head;
4986b8456a14SChun-Yeow Yeoh beacon_data_len = beacon->head_len;
4987b8456a14SChun-Yeow Yeoh break;
4988cd7760e6SSimon Wunderlich default:
4989cd7760e6SSimon Wunderlich return;
4990cd7760e6SSimon Wunderlich }
49910d06d9baSAndrei Otcheretianski
4992d8675a63SJohannes Berg resp = rcu_dereference(link->u.ap.probe_resp);
499373da7d5bSSimon Wunderlich
49945f9404abSJohn Crispin bcn_offsets = beacon->cntdwn_counter_offsets;
49955f9404abSJohn Crispin count = beacon->cntdwn_current_counter;
4996d8675a63SJohannes Berg if (link->conf->csa_active)
49975f9404abSJohn Crispin max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM;
49985f9404abSJohn Crispin
49995f9404abSJohn Crispin for (i = 0; i < max_count; ++i) {
50005f9404abSJohn Crispin if (bcn_offsets[i]) {
5001d8675a63SJohannes Berg if (WARN_ON_ONCE(bcn_offsets[i] >= beacon_data_len))
500273da7d5bSSimon Wunderlich return;
50035f9404abSJohn Crispin beacon_data[bcn_offsets[i]] = count;
5004af296bdbSMichal Kazior }
5005af296bdbSMichal Kazior
50065f9404abSJohn Crispin if (sdata->vif.type == NL80211_IFTYPE_AP && resp) {
50075f9404abSJohn Crispin u16 *resp_offsets = resp->cntdwn_counter_offsets;
50085f9404abSJohn Crispin
50095f9404abSJohn Crispin resp->data[resp_offsets[i]] = count;
50105f9404abSJohn Crispin }
5011af296bdbSMichal Kazior }
501273da7d5bSSimon Wunderlich }
50131af586c9SAndrei Otcheretianski
__ieee80211_beacon_update_cntdwn(struct beacon_data * beacon)50148552a434SJohn Crispin static u8 __ieee80211_beacon_update_cntdwn(struct beacon_data *beacon)
5015e996ec2aSWojciech Dubowik {
50168552a434SJohn Crispin beacon->cntdwn_current_counter--;
5017e996ec2aSWojciech Dubowik
5018e996ec2aSWojciech Dubowik /* the counter should never reach 0 */
50198552a434SJohn Crispin WARN_ON_ONCE(!beacon->cntdwn_current_counter);
5020e996ec2aSWojciech Dubowik
50218552a434SJohn Crispin return beacon->cntdwn_current_counter;
5022e996ec2aSWojciech Dubowik }
5023e996ec2aSWojciech Dubowik
ieee80211_beacon_update_cntdwn(struct ieee80211_vif * vif)50248552a434SJohn Crispin u8 ieee80211_beacon_update_cntdwn(struct ieee80211_vif *vif)
50251af586c9SAndrei Otcheretianski {
50261af586c9SAndrei Otcheretianski struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
5027af296bdbSMichal Kazior struct beacon_data *beacon = NULL;
5028af296bdbSMichal Kazior u8 count = 0;
502973da7d5bSSimon Wunderlich
5030af296bdbSMichal Kazior rcu_read_lock();
5031af296bdbSMichal Kazior
5032af296bdbSMichal Kazior if (sdata->vif.type == NL80211_IFTYPE_AP)
5033bfd8403aSJohannes Berg beacon = rcu_dereference(sdata->deflink.u.ap.beacon);
5034af296bdbSMichal Kazior else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
5035af296bdbSMichal Kazior beacon = rcu_dereference(sdata->u.ibss.presp);
5036af296bdbSMichal Kazior else if (ieee80211_vif_is_mesh(&sdata->vif))
5037af296bdbSMichal Kazior beacon = rcu_dereference(sdata->u.mesh.beacon);
5038af296bdbSMichal Kazior
5039af296bdbSMichal Kazior if (!beacon)
5040af296bdbSMichal Kazior goto unlock;
5041af296bdbSMichal Kazior
50428552a434SJohn Crispin count = __ieee80211_beacon_update_cntdwn(beacon);
50431af586c9SAndrei Otcheretianski
5044af296bdbSMichal Kazior unlock:
5045af296bdbSMichal Kazior rcu_read_unlock();
5046af296bdbSMichal Kazior return count;
50470d06d9baSAndrei Otcheretianski }
50488552a434SJohn Crispin EXPORT_SYMBOL(ieee80211_beacon_update_cntdwn);
50490d06d9baSAndrei Otcheretianski
ieee80211_beacon_set_cntdwn(struct ieee80211_vif * vif,u8 counter)50508552a434SJohn Crispin void ieee80211_beacon_set_cntdwn(struct ieee80211_vif *vif, u8 counter)
505103737001SGregory Greenman {
505203737001SGregory Greenman struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
505303737001SGregory Greenman struct beacon_data *beacon = NULL;
505403737001SGregory Greenman
505503737001SGregory Greenman rcu_read_lock();
505603737001SGregory Greenman
505703737001SGregory Greenman if (sdata->vif.type == NL80211_IFTYPE_AP)
5058bfd8403aSJohannes Berg beacon = rcu_dereference(sdata->deflink.u.ap.beacon);
505903737001SGregory Greenman else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
506003737001SGregory Greenman beacon = rcu_dereference(sdata->u.ibss.presp);
506103737001SGregory Greenman else if (ieee80211_vif_is_mesh(&sdata->vif))
506203737001SGregory Greenman beacon = rcu_dereference(sdata->u.mesh.beacon);
506303737001SGregory Greenman
506403737001SGregory Greenman if (!beacon)
506503737001SGregory Greenman goto unlock;
506603737001SGregory Greenman
50678552a434SJohn Crispin if (counter < beacon->cntdwn_current_counter)
50688552a434SJohn Crispin beacon->cntdwn_current_counter = counter;
506903737001SGregory Greenman
507003737001SGregory Greenman unlock:
507103737001SGregory Greenman rcu_read_unlock();
507203737001SGregory Greenman }
50738552a434SJohn Crispin EXPORT_SYMBOL(ieee80211_beacon_set_cntdwn);
507403737001SGregory Greenman
ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif * vif)50758552a434SJohn Crispin bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif)
507673da7d5bSSimon Wunderlich {
507773da7d5bSSimon Wunderlich struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
507873da7d5bSSimon Wunderlich struct beacon_data *beacon = NULL;
507973da7d5bSSimon Wunderlich u8 *beacon_data;
508073da7d5bSSimon Wunderlich size_t beacon_data_len;
508173da7d5bSSimon Wunderlich int ret = false;
508273da7d5bSSimon Wunderlich
508373da7d5bSSimon Wunderlich if (!ieee80211_sdata_running(sdata))
508473da7d5bSSimon Wunderlich return false;
508573da7d5bSSimon Wunderlich
508673da7d5bSSimon Wunderlich rcu_read_lock();
508773da7d5bSSimon Wunderlich if (vif->type == NL80211_IFTYPE_AP) {
5088bfd8403aSJohannes Berg beacon = rcu_dereference(sdata->deflink.u.ap.beacon);
508973da7d5bSSimon Wunderlich if (WARN_ON(!beacon || !beacon->tail))
509073da7d5bSSimon Wunderlich goto out;
509173da7d5bSSimon Wunderlich beacon_data = beacon->tail;
509273da7d5bSSimon Wunderlich beacon_data_len = beacon->tail_len;
5093cd7760e6SSimon Wunderlich } else if (vif->type == NL80211_IFTYPE_ADHOC) {
5094cd7760e6SSimon Wunderlich struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
5095cd7760e6SSimon Wunderlich
5096cd7760e6SSimon Wunderlich beacon = rcu_dereference(ifibss->presp);
5097cd7760e6SSimon Wunderlich if (!beacon)
5098cd7760e6SSimon Wunderlich goto out;
5099cd7760e6SSimon Wunderlich
5100cd7760e6SSimon Wunderlich beacon_data = beacon->head;
5101cd7760e6SSimon Wunderlich beacon_data_len = beacon->head_len;
5102b8456a14SChun-Yeow Yeoh } else if (vif->type == NL80211_IFTYPE_MESH_POINT) {
5103b8456a14SChun-Yeow Yeoh struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
5104b8456a14SChun-Yeow Yeoh
5105b8456a14SChun-Yeow Yeoh beacon = rcu_dereference(ifmsh->beacon);
5106b8456a14SChun-Yeow Yeoh if (!beacon)
5107b8456a14SChun-Yeow Yeoh goto out;
5108b8456a14SChun-Yeow Yeoh
5109b8456a14SChun-Yeow Yeoh beacon_data = beacon->head;
5110b8456a14SChun-Yeow Yeoh beacon_data_len = beacon->head_len;
511173da7d5bSSimon Wunderlich } else {
511273da7d5bSSimon Wunderlich WARN_ON(1);
511373da7d5bSSimon Wunderlich goto out;
511473da7d5bSSimon Wunderlich }
511573da7d5bSSimon Wunderlich
51168552a434SJohn Crispin if (!beacon->cntdwn_counter_offsets[0])
511710d78f27SMichal Kazior goto out;
511810d78f27SMichal Kazior
51198552a434SJohn Crispin if (WARN_ON_ONCE(beacon->cntdwn_counter_offsets[0] > beacon_data_len))
512073da7d5bSSimon Wunderlich goto out;
512173da7d5bSSimon Wunderlich
51228552a434SJohn Crispin if (beacon_data[beacon->cntdwn_counter_offsets[0]] == 1)
512373da7d5bSSimon Wunderlich ret = true;
51248552a434SJohn Crispin
512573da7d5bSSimon Wunderlich out:
512673da7d5bSSimon Wunderlich rcu_read_unlock();
512773da7d5bSSimon Wunderlich
512873da7d5bSSimon Wunderlich return ret;
512973da7d5bSSimon Wunderlich }
51308552a434SJohn Crispin EXPORT_SYMBOL(ieee80211_beacon_cntdwn_is_complete);
513173da7d5bSSimon Wunderlich
ieee80211_beacon_protect(struct sk_buff * skb,struct ieee80211_local * local,struct ieee80211_sub_if_data * sdata,struct ieee80211_link_data * link)51320a3a8436SJouni Malinen static int ieee80211_beacon_protect(struct sk_buff *skb,
51330a3a8436SJouni Malinen struct ieee80211_local *local,
51346e8912a5SShaul Triebitz struct ieee80211_sub_if_data *sdata,
5135d8675a63SJohannes Berg struct ieee80211_link_data *link)
51360a3a8436SJouni Malinen {
51370a3a8436SJouni Malinen ieee80211_tx_result res;
51380a3a8436SJouni Malinen struct ieee80211_tx_data tx;
513995247705SJohannes Berg struct sk_buff *check_skb;
51400a3a8436SJouni Malinen
51410a3a8436SJouni Malinen memset(&tx, 0, sizeof(tx));
5142d8675a63SJohannes Berg tx.key = rcu_dereference(link->default_beacon_key);
51430a3a8436SJouni Malinen if (!tx.key)
51440a3a8436SJouni Malinen return 0;
51453ffcc659SJohannes Berg
51463ffcc659SJohannes Berg if (unlikely(tx.key->flags & KEY_FLAG_TAINTED)) {
51473ffcc659SJohannes Berg tx.key = NULL;
51483ffcc659SJohannes Berg return -EINVAL;
51493ffcc659SJohannes Berg }
51503ffcc659SJohannes Berg
5151d1b9bb65SJohannes Berg if (!(tx.key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT_TX) &&
5152d1b9bb65SJohannes Berg tx.key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
5153d1b9bb65SJohannes Berg IEEE80211_SKB_CB(skb)->control.hw_key = &tx.key->conf;
5154d1b9bb65SJohannes Berg
51550a3a8436SJouni Malinen tx.local = local;
51560a3a8436SJouni Malinen tx.sdata = sdata;
51570a3a8436SJouni Malinen __skb_queue_head_init(&tx.skbs);
51580a3a8436SJouni Malinen __skb_queue_tail(&tx.skbs, skb);
51590a3a8436SJouni Malinen res = ieee80211_tx_h_encrypt(&tx);
516095247705SJohannes Berg check_skb = __skb_dequeue(&tx.skbs);
516195247705SJohannes Berg /* we may crash after this, but it'd be a bug in crypto */
516295247705SJohannes Berg WARN_ON(check_skb != skb);
51630a3a8436SJouni Malinen if (WARN_ON_ONCE(res != TX_CONTINUE))
516495247705SJohannes Berg return -EINVAL;
51650a3a8436SJouni Malinen
51660a3a8436SJouni Malinen return 0;
51670a3a8436SJouni Malinen }
51680a3a8436SJouni Malinen
5169a6e34fdeSAloka Dixit static void
ieee80211_beacon_get_finish(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_link_data * link,struct ieee80211_mutable_offsets * offs,struct beacon_data * beacon,struct sk_buff * skb,struct ieee80211_chanctx_conf * chanctx_conf,u16 csa_off_base)5170a6e34fdeSAloka Dixit ieee80211_beacon_get_finish(struct ieee80211_hw *hw,
5171a6e34fdeSAloka Dixit struct ieee80211_vif *vif,
5172d8675a63SJohannes Berg struct ieee80211_link_data *link,
5173a6e34fdeSAloka Dixit struct ieee80211_mutable_offsets *offs,
5174a6e34fdeSAloka Dixit struct beacon_data *beacon,
5175a6e34fdeSAloka Dixit struct sk_buff *skb,
5176a6e34fdeSAloka Dixit struct ieee80211_chanctx_conf *chanctx_conf,
5177d8675a63SJohannes Berg u16 csa_off_base)
5178a6e34fdeSAloka Dixit {
5179a6e34fdeSAloka Dixit struct ieee80211_local *local = hw_to_local(hw);
5180a6e34fdeSAloka Dixit struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
5181a6e34fdeSAloka Dixit struct ieee80211_tx_info *info;
5182a6e34fdeSAloka Dixit enum nl80211_band band;
5183a6e34fdeSAloka Dixit struct ieee80211_tx_rate_control txrc;
5184a6e34fdeSAloka Dixit
5185a6e34fdeSAloka Dixit /* CSA offsets */
5186a6e34fdeSAloka Dixit if (offs && beacon) {
5187a6e34fdeSAloka Dixit u16 i;
5188a6e34fdeSAloka Dixit
5189a6e34fdeSAloka Dixit for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) {
5190a6e34fdeSAloka Dixit u16 csa_off = beacon->cntdwn_counter_offsets[i];
5191a6e34fdeSAloka Dixit
5192a6e34fdeSAloka Dixit if (!csa_off)
5193a6e34fdeSAloka Dixit continue;
5194a6e34fdeSAloka Dixit
5195a6e34fdeSAloka Dixit offs->cntdwn_counter_offs[i] = csa_off_base + csa_off;
5196a6e34fdeSAloka Dixit }
5197a6e34fdeSAloka Dixit }
5198a6e34fdeSAloka Dixit
5199a6e34fdeSAloka Dixit band = chanctx_conf->def.chan->band;
5200a6e34fdeSAloka Dixit info = IEEE80211_SKB_CB(skb);
5201a6e34fdeSAloka Dixit info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
5202a6e34fdeSAloka Dixit info->flags |= IEEE80211_TX_CTL_NO_ACK;
5203a6e34fdeSAloka Dixit info->band = band;
5204a6e34fdeSAloka Dixit
5205a6e34fdeSAloka Dixit memset(&txrc, 0, sizeof(txrc));
5206a6e34fdeSAloka Dixit txrc.hw = hw;
5207a6e34fdeSAloka Dixit txrc.sband = local->hw.wiphy->bands[band];
5208d8675a63SJohannes Berg txrc.bss_conf = link->conf;
5209a6e34fdeSAloka Dixit txrc.skb = skb;
5210a6e34fdeSAloka Dixit txrc.reported_rate.idx = -1;
5211a6e34fdeSAloka Dixit if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band])
5212a6e34fdeSAloka Dixit txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band];
5213a6e34fdeSAloka Dixit else
5214a6e34fdeSAloka Dixit txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
5215a6e34fdeSAloka Dixit txrc.bss = true;
5216a6e34fdeSAloka Dixit rate_control_get_rate(sdata, NULL, &txrc);
5217a6e34fdeSAloka Dixit
5218a6e34fdeSAloka Dixit info->control.vif = vif;
52198b06d13eSJohannes Berg info->control.flags |= u32_encode_bits(link->link_id,
52208b06d13eSJohannes Berg IEEE80211_TX_CTRL_MLO_LINK);
5221a6e34fdeSAloka Dixit info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
5222a6e34fdeSAloka Dixit IEEE80211_TX_CTL_ASSIGN_SEQ |
5223a6e34fdeSAloka Dixit IEEE80211_TX_CTL_FIRST_FRAGMENT;
5224a6e34fdeSAloka Dixit }
5225a6e34fdeSAloka Dixit
52262b3171c6SLorenzo Bianconi static void
ieee80211_beacon_add_mbssid(struct sk_buff * skb,struct beacon_data * beacon,u8 i)5227bd54f3c2SAloka Dixit ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon,
5228bd54f3c2SAloka Dixit u8 i)
52292b3171c6SLorenzo Bianconi {
5230bd54f3c2SAloka Dixit if (!beacon->mbssid_ies || !beacon->mbssid_ies->cnt ||
5231bd54f3c2SAloka Dixit i > beacon->mbssid_ies->cnt)
52322b3171c6SLorenzo Bianconi return;
52332b3171c6SLorenzo Bianconi
5234bd54f3c2SAloka Dixit if (i < beacon->mbssid_ies->cnt) {
5235bd54f3c2SAloka Dixit skb_put_data(skb, beacon->mbssid_ies->elem[i].data,
5236bd54f3c2SAloka Dixit beacon->mbssid_ies->elem[i].len);
523768b9bea2SAloka Dixit
523868b9bea2SAloka Dixit if (beacon->rnr_ies && beacon->rnr_ies->cnt) {
523968b9bea2SAloka Dixit skb_put_data(skb, beacon->rnr_ies->elem[i].data,
524068b9bea2SAloka Dixit beacon->rnr_ies->elem[i].len);
524168b9bea2SAloka Dixit
524268b9bea2SAloka Dixit for (i = beacon->mbssid_ies->cnt; i < beacon->rnr_ies->cnt; i++)
524368b9bea2SAloka Dixit skb_put_data(skb, beacon->rnr_ies->elem[i].data,
524468b9bea2SAloka Dixit beacon->rnr_ies->elem[i].len);
524568b9bea2SAloka Dixit }
5246bd54f3c2SAloka Dixit return;
5247bd54f3c2SAloka Dixit }
5248bd54f3c2SAloka Dixit
5249bd54f3c2SAloka Dixit /* i == beacon->mbssid_ies->cnt, include all MBSSID elements */
52502b3171c6SLorenzo Bianconi for (i = 0; i < beacon->mbssid_ies->cnt; i++)
52512b3171c6SLorenzo Bianconi skb_put_data(skb, beacon->mbssid_ies->elem[i].data,
52522b3171c6SLorenzo Bianconi beacon->mbssid_ies->elem[i].len);
52532b3171c6SLorenzo Bianconi }
52542b3171c6SLorenzo Bianconi
5255a6e34fdeSAloka Dixit static struct sk_buff *
ieee80211_beacon_get_ap(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_link_data * link,struct ieee80211_mutable_offsets * offs,bool is_template,struct beacon_data * beacon,struct ieee80211_chanctx_conf * chanctx_conf,u8 ema_index)5256a6e34fdeSAloka Dixit ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
5257a6e34fdeSAloka Dixit struct ieee80211_vif *vif,
5258d8675a63SJohannes Berg struct ieee80211_link_data *link,
5259a6e34fdeSAloka Dixit struct ieee80211_mutable_offsets *offs,
5260a6e34fdeSAloka Dixit bool is_template,
5261a6e34fdeSAloka Dixit struct beacon_data *beacon,
5262bd54f3c2SAloka Dixit struct ieee80211_chanctx_conf *chanctx_conf,
5263bd54f3c2SAloka Dixit u8 ema_index)
5264a6e34fdeSAloka Dixit {
5265a6e34fdeSAloka Dixit struct ieee80211_local *local = hw_to_local(hw);
5266a6e34fdeSAloka Dixit struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
5267a6e34fdeSAloka Dixit struct ieee80211_if_ap *ap = &sdata->u.ap;
5268a6e34fdeSAloka Dixit struct sk_buff *skb = NULL;
5269a6e34fdeSAloka Dixit u16 csa_off_base = 0;
52702b3171c6SLorenzo Bianconi int mbssid_len;
5271a6e34fdeSAloka Dixit
5272a6e34fdeSAloka Dixit if (beacon->cntdwn_counter_offsets[0]) {
5273a6e34fdeSAloka Dixit if (!is_template)
5274a6e34fdeSAloka Dixit ieee80211_beacon_update_cntdwn(vif);
5275a6e34fdeSAloka Dixit
5276d8675a63SJohannes Berg ieee80211_set_beacon_cntdwn(sdata, beacon, link);
5277a6e34fdeSAloka Dixit }
5278a6e34fdeSAloka Dixit
5279a6e34fdeSAloka Dixit /* headroom, head length,
52802b3171c6SLorenzo Bianconi * tail length, maximum TIM length and multiple BSSID length
5281a6e34fdeSAloka Dixit */
5282bd54f3c2SAloka Dixit mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies,
528368b9bea2SAloka Dixit beacon->rnr_ies,
5284bd54f3c2SAloka Dixit ema_index);
5285bd54f3c2SAloka Dixit
5286a6e34fdeSAloka Dixit skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
5287a6e34fdeSAloka Dixit beacon->tail_len + 256 +
52882b3171c6SLorenzo Bianconi local->hw.extra_beacon_tailroom + mbssid_len);
5289a6e34fdeSAloka Dixit if (!skb)
5290a6e34fdeSAloka Dixit return NULL;
5291a6e34fdeSAloka Dixit
5292a6e34fdeSAloka Dixit skb_reserve(skb, local->tx_headroom);
5293a6e34fdeSAloka Dixit skb_put_data(skb, beacon->head, beacon->head_len);
5294a6e34fdeSAloka Dixit
5295d8675a63SJohannes Berg ieee80211_beacon_add_tim(sdata, link, &ap->ps, skb, is_template);
5296a6e34fdeSAloka Dixit
5297a6e34fdeSAloka Dixit if (offs) {
5298a6e34fdeSAloka Dixit offs->tim_offset = beacon->head_len;
5299a6e34fdeSAloka Dixit offs->tim_length = skb->len - beacon->head_len;
5300a6e34fdeSAloka Dixit offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0];
5301a6e34fdeSAloka Dixit
53022b3171c6SLorenzo Bianconi if (mbssid_len) {
5303bd54f3c2SAloka Dixit ieee80211_beacon_add_mbssid(skb, beacon, ema_index);
53042b3171c6SLorenzo Bianconi offs->mbssid_off = skb->len - mbssid_len;
53052b3171c6SLorenzo Bianconi }
53062b3171c6SLorenzo Bianconi
5307a6e34fdeSAloka Dixit /* for AP the csa offsets are from tail */
5308a6e34fdeSAloka Dixit csa_off_base = skb->len;
5309a6e34fdeSAloka Dixit }
5310a6e34fdeSAloka Dixit
5311a6e34fdeSAloka Dixit if (beacon->tail)
5312a6e34fdeSAloka Dixit skb_put_data(skb, beacon->tail, beacon->tail_len);
5313a6e34fdeSAloka Dixit
53149902dacdSDmitry Antipov if (ieee80211_beacon_protect(skb, local, sdata, link) < 0) {
53159902dacdSDmitry Antipov dev_kfree_skb(skb);
5316a6e34fdeSAloka Dixit return NULL;
53179902dacdSDmitry Antipov }
5318a6e34fdeSAloka Dixit
5319d8675a63SJohannes Berg ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb,
5320d8675a63SJohannes Berg chanctx_conf, csa_off_base);
5321a6e34fdeSAloka Dixit return skb;
5322a6e34fdeSAloka Dixit }
5323a6e34fdeSAloka Dixit
5324bd54f3c2SAloka Dixit static struct ieee80211_ema_beacons *
ieee80211_beacon_get_ap_ema_list(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_link_data * link,struct ieee80211_mutable_offsets * offs,bool is_template,struct beacon_data * beacon,struct ieee80211_chanctx_conf * chanctx_conf)5325bd54f3c2SAloka Dixit ieee80211_beacon_get_ap_ema_list(struct ieee80211_hw *hw,
5326bd54f3c2SAloka Dixit struct ieee80211_vif *vif,
5327bd54f3c2SAloka Dixit struct ieee80211_link_data *link,
5328bd54f3c2SAloka Dixit struct ieee80211_mutable_offsets *offs,
5329bd54f3c2SAloka Dixit bool is_template, struct beacon_data *beacon,
5330bd54f3c2SAloka Dixit struct ieee80211_chanctx_conf *chanctx_conf)
5331bd54f3c2SAloka Dixit {
5332bd54f3c2SAloka Dixit struct ieee80211_ema_beacons *ema = NULL;
5333bd54f3c2SAloka Dixit
5334bd54f3c2SAloka Dixit if (!beacon->mbssid_ies || !beacon->mbssid_ies->cnt)
5335bd54f3c2SAloka Dixit return NULL;
5336bd54f3c2SAloka Dixit
5337bd54f3c2SAloka Dixit ema = kzalloc(struct_size(ema, bcn, beacon->mbssid_ies->cnt),
5338bd54f3c2SAloka Dixit GFP_ATOMIC);
5339bd54f3c2SAloka Dixit if (!ema)
5340bd54f3c2SAloka Dixit return NULL;
5341bd54f3c2SAloka Dixit
5342bd54f3c2SAloka Dixit for (ema->cnt = 0; ema->cnt < beacon->mbssid_ies->cnt; ema->cnt++) {
5343bd54f3c2SAloka Dixit ema->bcn[ema->cnt].skb =
5344bd54f3c2SAloka Dixit ieee80211_beacon_get_ap(hw, vif, link,
5345bd54f3c2SAloka Dixit &ema->bcn[ema->cnt].offs,
5346bd54f3c2SAloka Dixit is_template, beacon,
5347bd54f3c2SAloka Dixit chanctx_conf, ema->cnt);
5348bd54f3c2SAloka Dixit if (!ema->bcn[ema->cnt].skb)
5349bd54f3c2SAloka Dixit break;
5350bd54f3c2SAloka Dixit }
5351bd54f3c2SAloka Dixit
5352bd54f3c2SAloka Dixit if (ema->cnt == beacon->mbssid_ies->cnt)
5353bd54f3c2SAloka Dixit return ema;
5354bd54f3c2SAloka Dixit
5355bd54f3c2SAloka Dixit ieee80211_beacon_free_ema_list(ema);
5356bd54f3c2SAloka Dixit return NULL;
5357bd54f3c2SAloka Dixit }
5358bd54f3c2SAloka Dixit
5359bd54f3c2SAloka Dixit #define IEEE80211_INCLUDE_ALL_MBSSID_ELEMS -1
5360bd54f3c2SAloka Dixit
53616ec8c332SAndrei Otcheretianski static struct sk_buff *
__ieee80211_beacon_get(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_mutable_offsets * offs,bool is_template,unsigned int link_id,int ema_index,struct ieee80211_ema_beacons ** ema_beacons)53626ec8c332SAndrei Otcheretianski __ieee80211_beacon_get(struct ieee80211_hw *hw,
5363eddcbb94SJohannes Berg struct ieee80211_vif *vif,
53646ec8c332SAndrei Otcheretianski struct ieee80211_mutable_offsets *offs,
53656e8912a5SShaul Triebitz bool is_template,
5366bd54f3c2SAloka Dixit unsigned int link_id,
5367bd54f3c2SAloka Dixit int ema_index,
5368bd54f3c2SAloka Dixit struct ieee80211_ema_beacons **ema_beacons)
5369e2ebc74dSJohannes Berg {
5370e2ebc74dSJohannes Berg struct ieee80211_local *local = hw_to_local(hw);
5371af296bdbSMichal Kazior struct beacon_data *beacon = NULL;
53729d139c81SJohannes Berg struct sk_buff *skb = NULL;
5373e2ebc74dSJohannes Berg struct ieee80211_sub_if_data *sdata = NULL;
537455de908aSJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf;
5375d8675a63SJohannes Berg struct ieee80211_link_data *link;
53768318d78aSJohannes Berg
53775dfdaf58SJohannes Berg rcu_read_lock();
5378e2ebc74dSJohannes Berg
537932bfd35dSJohannes Berg sdata = vif_to_sdata(vif);
5380d8675a63SJohannes Berg link = rcu_dereference(sdata->link[link_id]);
5381d8675a63SJohannes Berg if (!link)
5382d8675a63SJohannes Berg goto out;
53836e8912a5SShaul Triebitz chanctx_conf =
5384d8675a63SJohannes Berg rcu_dereference(link->conf->chanctx_conf);
538533b64eb2SLuis Carlos Cobo
538655de908aSJohannes Berg if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
5387eb3e554bSFelix Fietkau goto out;
5388eb3e554bSFelix Fietkau
53896ec8c332SAndrei Otcheretianski if (offs)
53906ec8c332SAndrei Otcheretianski memset(offs, 0, sizeof(*offs));
5391eddcbb94SJohannes Berg
539205c914feSJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_AP) {
5393d8675a63SJohannes Berg beacon = rcu_dereference(link->u.ap.beacon);
5394a6e34fdeSAloka Dixit if (!beacon)
53955dfdaf58SJohannes Berg goto out;
5396e2ebc74dSJohannes Berg
5397bd54f3c2SAloka Dixit if (ema_beacons) {
5398bd54f3c2SAloka Dixit *ema_beacons =
5399bd54f3c2SAloka Dixit ieee80211_beacon_get_ap_ema_list(hw, vif, link,
5400bd54f3c2SAloka Dixit offs,
5401bd54f3c2SAloka Dixit is_template,
5402bd54f3c2SAloka Dixit beacon,
5403bd54f3c2SAloka Dixit chanctx_conf);
5404bd54f3c2SAloka Dixit } else {
5405bd54f3c2SAloka Dixit if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) {
5406bd54f3c2SAloka Dixit if (ema_index >= beacon->mbssid_ies->cnt)
5407bd54f3c2SAloka Dixit goto out; /* End of MBSSID elements */
5408bd54f3c2SAloka Dixit
5409bd54f3c2SAloka Dixit if (ema_index <= IEEE80211_INCLUDE_ALL_MBSSID_ELEMS)
5410bd54f3c2SAloka Dixit ema_index = beacon->mbssid_ies->cnt;
5411bd54f3c2SAloka Dixit } else {
5412bd54f3c2SAloka Dixit ema_index = 0;
5413bd54f3c2SAloka Dixit }
5414bd54f3c2SAloka Dixit
5415bd54f3c2SAloka Dixit skb = ieee80211_beacon_get_ap(hw, vif, link, offs,
5416bd54f3c2SAloka Dixit is_template, beacon,
5417bd54f3c2SAloka Dixit chanctx_conf,
5418bd54f3c2SAloka Dixit ema_index);
5419bd54f3c2SAloka Dixit }
542005c914feSJohannes Berg } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
542146900298SJohannes Berg struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
54229d139c81SJohannes Berg struct ieee80211_hdr *hdr;
542333b64eb2SLuis Carlos Cobo
5424af296bdbSMichal Kazior beacon = rcu_dereference(ifibss->presp);
5425af296bdbSMichal Kazior if (!beacon)
54269d139c81SJohannes Berg goto out;
54279d139c81SJohannes Berg
54288552a434SJohn Crispin if (beacon->cntdwn_counter_offsets[0]) {
54291af586c9SAndrei Otcheretianski if (!is_template)
54308552a434SJohn Crispin __ieee80211_beacon_update_cntdwn(beacon);
5431cd7760e6SSimon Wunderlich
5432d8675a63SJohannes Berg ieee80211_set_beacon_cntdwn(sdata, beacon, link);
54331af586c9SAndrei Otcheretianski }
5434cd7760e6SSimon Wunderlich
5435af296bdbSMichal Kazior skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
543670dabeb7SFelix Fietkau local->hw.extra_beacon_tailroom);
54379d139c81SJohannes Berg if (!skb)
54389d139c81SJohannes Berg goto out;
5439c3ffeab4SJohannes Berg skb_reserve(skb, local->tx_headroom);
544059ae1d12SJohannes Berg skb_put_data(skb, beacon->head, beacon->head_len);
54419d139c81SJohannes Berg
54429d139c81SJohannes Berg hdr = (struct ieee80211_hdr *) skb->data;
5443e7827a70SHarvey Harrison hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
54449d139c81SJohannes Berg IEEE80211_STYPE_BEACON);
5445a6e34fdeSAloka Dixit
5446d8675a63SJohannes Berg ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb,
5447d8675a63SJohannes Berg chanctx_conf, 0);
5448902acc78SJohannes Berg } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
5449dbf498fbSJavier Cardona struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
5450472dbc45SJohannes Berg
5451af296bdbSMichal Kazior beacon = rcu_dereference(ifmsh->beacon);
5452af296bdbSMichal Kazior if (!beacon)
5453ac1bd846SJohannes Berg goto out;
5454ac1bd846SJohannes Berg
54558552a434SJohn Crispin if (beacon->cntdwn_counter_offsets[0]) {
54561af586c9SAndrei Otcheretianski if (!is_template)
54571af586c9SAndrei Otcheretianski /* TODO: For mesh csa_counter is in TU, so
54581af586c9SAndrei Otcheretianski * decrementing it by one isn't correct, but
54591af586c9SAndrei Otcheretianski * for now we leave it consistent with overall
54601af586c9SAndrei Otcheretianski * mac80211's behavior.
54611af586c9SAndrei Otcheretianski */
54628552a434SJohn Crispin __ieee80211_beacon_update_cntdwn(beacon);
54631af586c9SAndrei Otcheretianski
5464d8675a63SJohannes Berg ieee80211_set_beacon_cntdwn(sdata, beacon, link);
54651af586c9SAndrei Otcheretianski }
5466b8456a14SChun-Yeow Yeoh
5467dbf498fbSJavier Cardona if (ifmsh->sync_ops)
5468445cd452SMasashi Honma ifmsh->sync_ops->adjust_tsf(sdata, beacon);
5469dbf498fbSJavier Cardona
54703b69a9c5SThomas Pedersen skb = dev_alloc_skb(local->tx_headroom +
5471af296bdbSMichal Kazior beacon->head_len +
54723f52b7e3SMarco Porsch 256 + /* TIM IE */
5473af296bdbSMichal Kazior beacon->tail_len +
547470dabeb7SFelix Fietkau local->hw.extra_beacon_tailroom);
5475902acc78SJohannes Berg if (!skb)
5476902acc78SJohannes Berg goto out;
54772b5e1967SThomas Pedersen skb_reserve(skb, local->tx_headroom);
547859ae1d12SJohannes Berg skb_put_data(skb, beacon->head, beacon->head_len);
5479d8675a63SJohannes Berg ieee80211_beacon_add_tim(sdata, link, &ifmsh->ps, skb,
5480d8675a63SJohannes Berg is_template);
54816ec8c332SAndrei Otcheretianski
54826ec8c332SAndrei Otcheretianski if (offs) {
5483af296bdbSMichal Kazior offs->tim_offset = beacon->head_len;
5484af296bdbSMichal Kazior offs->tim_length = skb->len - beacon->head_len;
54856ec8c332SAndrei Otcheretianski }
54866ec8c332SAndrei Otcheretianski
548759ae1d12SJohannes Berg skb_put_data(skb, beacon->tail, beacon->tail_len);
5488d8675a63SJohannes Berg ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb,
5489d8675a63SJohannes Berg chanctx_conf, 0);
54909d139c81SJohannes Berg } else {
54919d139c81SJohannes Berg WARN_ON(1);
549233b64eb2SLuis Carlos Cobo goto out;
549333b64eb2SLuis Carlos Cobo }
549433b64eb2SLuis Carlos Cobo
54955dfdaf58SJohannes Berg out:
54965dfdaf58SJohannes Berg rcu_read_unlock();
5497e2ebc74dSJohannes Berg return skb;
54986ec8c332SAndrei Otcheretianski
54996ec8c332SAndrei Otcheretianski }
55006ec8c332SAndrei Otcheretianski
55016ec8c332SAndrei Otcheretianski struct sk_buff *
ieee80211_beacon_get_template(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_mutable_offsets * offs,unsigned int link_id)55026ec8c332SAndrei Otcheretianski ieee80211_beacon_get_template(struct ieee80211_hw *hw,
55036ec8c332SAndrei Otcheretianski struct ieee80211_vif *vif,
55046e8912a5SShaul Triebitz struct ieee80211_mutable_offsets *offs,
55056e8912a5SShaul Triebitz unsigned int link_id)
55066ec8c332SAndrei Otcheretianski {
5507bd54f3c2SAloka Dixit return __ieee80211_beacon_get(hw, vif, offs, true, link_id,
5508bd54f3c2SAloka Dixit IEEE80211_INCLUDE_ALL_MBSSID_ELEMS, NULL);
55096ec8c332SAndrei Otcheretianski }
55106ec8c332SAndrei Otcheretianski EXPORT_SYMBOL(ieee80211_beacon_get_template);
55116ec8c332SAndrei Otcheretianski
5512bd54f3c2SAloka Dixit struct sk_buff *
ieee80211_beacon_get_template_ema_index(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_mutable_offsets * offs,unsigned int link_id,u8 ema_index)5513bd54f3c2SAloka Dixit ieee80211_beacon_get_template_ema_index(struct ieee80211_hw *hw,
5514bd54f3c2SAloka Dixit struct ieee80211_vif *vif,
5515bd54f3c2SAloka Dixit struct ieee80211_mutable_offsets *offs,
5516bd54f3c2SAloka Dixit unsigned int link_id, u8 ema_index)
5517bd54f3c2SAloka Dixit {
5518bd54f3c2SAloka Dixit return __ieee80211_beacon_get(hw, vif, offs, true, link_id, ema_index,
5519bd54f3c2SAloka Dixit NULL);
5520bd54f3c2SAloka Dixit }
5521bd54f3c2SAloka Dixit EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_index);
5522bd54f3c2SAloka Dixit
ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons * ema_beacons)5523bd54f3c2SAloka Dixit void ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons *ema_beacons)
5524bd54f3c2SAloka Dixit {
5525bd54f3c2SAloka Dixit u8 i;
5526bd54f3c2SAloka Dixit
5527bd54f3c2SAloka Dixit if (!ema_beacons)
5528bd54f3c2SAloka Dixit return;
5529bd54f3c2SAloka Dixit
5530bd54f3c2SAloka Dixit for (i = 0; i < ema_beacons->cnt; i++)
5531bd54f3c2SAloka Dixit kfree_skb(ema_beacons->bcn[i].skb);
5532bd54f3c2SAloka Dixit
5533bd54f3c2SAloka Dixit kfree(ema_beacons);
5534bd54f3c2SAloka Dixit }
5535bd54f3c2SAloka Dixit EXPORT_SYMBOL(ieee80211_beacon_free_ema_list);
5536bd54f3c2SAloka Dixit
5537bd54f3c2SAloka Dixit struct ieee80211_ema_beacons *
ieee80211_beacon_get_template_ema_list(struct ieee80211_hw * hw,struct ieee80211_vif * vif,unsigned int link_id)5538bd54f3c2SAloka Dixit ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
5539bd54f3c2SAloka Dixit struct ieee80211_vif *vif,
5540bd54f3c2SAloka Dixit unsigned int link_id)
5541bd54f3c2SAloka Dixit {
5542bd54f3c2SAloka Dixit struct ieee80211_ema_beacons *ema_beacons = NULL;
5543bd54f3c2SAloka Dixit
55441afa18e9SAditya Kumar Singh WARN_ON(__ieee80211_beacon_get(hw, vif, NULL, true, link_id, 0,
5545bd54f3c2SAloka Dixit &ema_beacons));
5546bd54f3c2SAloka Dixit
5547bd54f3c2SAloka Dixit return ema_beacons;
5548bd54f3c2SAloka Dixit }
5549bd54f3c2SAloka Dixit EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_list);
5550bd54f3c2SAloka Dixit
ieee80211_beacon_get_tim(struct ieee80211_hw * hw,struct ieee80211_vif * vif,u16 * tim_offset,u16 * tim_length,unsigned int link_id)55516ec8c332SAndrei Otcheretianski struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
55526ec8c332SAndrei Otcheretianski struct ieee80211_vif *vif,
55536e8912a5SShaul Triebitz u16 *tim_offset, u16 *tim_length,
55546e8912a5SShaul Triebitz unsigned int link_id)
55556ec8c332SAndrei Otcheretianski {
55566ec8c332SAndrei Otcheretianski struct ieee80211_mutable_offsets offs = {};
55576e8912a5SShaul Triebitz struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false,
5558bd54f3c2SAloka Dixit link_id,
5559bd54f3c2SAloka Dixit IEEE80211_INCLUDE_ALL_MBSSID_ELEMS,
5560bd54f3c2SAloka Dixit NULL);
556135afa588SHelmut Schaa struct sk_buff *copy;
556235afa588SHelmut Schaa int shift;
556335afa588SHelmut Schaa
556435afa588SHelmut Schaa if (!bcn)
556535afa588SHelmut Schaa return bcn;
55666ec8c332SAndrei Otcheretianski
55676ec8c332SAndrei Otcheretianski if (tim_offset)
55686ec8c332SAndrei Otcheretianski *tim_offset = offs.tim_offset;
55696ec8c332SAndrei Otcheretianski
55706ec8c332SAndrei Otcheretianski if (tim_length)
55716ec8c332SAndrei Otcheretianski *tim_length = offs.tim_length;
55726ec8c332SAndrei Otcheretianski
557335afa588SHelmut Schaa if (ieee80211_hw_check(hw, BEACON_TX_STATUS) ||
557435afa588SHelmut Schaa !hw_to_local(hw)->monitors)
557535afa588SHelmut Schaa return bcn;
557635afa588SHelmut Schaa
557735afa588SHelmut Schaa /* send a copy to monitor interfaces */
557835afa588SHelmut Schaa copy = skb_copy(bcn, GFP_ATOMIC);
557935afa588SHelmut Schaa if (!copy)
558035afa588SHelmut Schaa return bcn;
558135afa588SHelmut Schaa
558235afa588SHelmut Schaa shift = ieee80211_vif_get_shift(vif);
5583e5c0ee01SJohannes Berg ieee80211_tx_monitor(hw_to_local(hw), copy, 1, shift, false, NULL);
558435afa588SHelmut Schaa
55856ec8c332SAndrei Otcheretianski return bcn;
5586e2ebc74dSJohannes Berg }
5587eddcbb94SJohannes Berg EXPORT_SYMBOL(ieee80211_beacon_get_tim);
5588e2ebc74dSJohannes Berg
ieee80211_proberesp_get(struct ieee80211_hw * hw,struct ieee80211_vif * vif)558902945821SArik Nemtsov struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
559002945821SArik Nemtsov struct ieee80211_vif *vif)
559102945821SArik Nemtsov {
5592aa7a0080SEyal Shapira struct sk_buff *skb = NULL;
5593aa7a0080SEyal Shapira struct probe_resp *presp = NULL;
559402945821SArik Nemtsov struct ieee80211_hdr *hdr;
559502945821SArik Nemtsov struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
559602945821SArik Nemtsov
559702945821SArik Nemtsov if (sdata->vif.type != NL80211_IFTYPE_AP)
559802945821SArik Nemtsov return NULL;
559902945821SArik Nemtsov
560002945821SArik Nemtsov rcu_read_lock();
5601bfd8403aSJohannes Berg presp = rcu_dereference(sdata->deflink.u.ap.probe_resp);
560202945821SArik Nemtsov if (!presp)
560302945821SArik Nemtsov goto out;
560402945821SArik Nemtsov
5605aa7a0080SEyal Shapira skb = dev_alloc_skb(presp->len);
560602945821SArik Nemtsov if (!skb)
560702945821SArik Nemtsov goto out;
560802945821SArik Nemtsov
560959ae1d12SJohannes Berg skb_put_data(skb, presp->data, presp->len);
5610aa7a0080SEyal Shapira
561102945821SArik Nemtsov hdr = (struct ieee80211_hdr *) skb->data;
561202945821SArik Nemtsov memset(hdr->addr1, 0, sizeof(hdr->addr1));
561302945821SArik Nemtsov
561402945821SArik Nemtsov out:
561502945821SArik Nemtsov rcu_read_unlock();
561602945821SArik Nemtsov return skb;
561702945821SArik Nemtsov }
561802945821SArik Nemtsov EXPORT_SYMBOL(ieee80211_proberesp_get);
561902945821SArik Nemtsov
ieee80211_get_fils_discovery_tmpl(struct ieee80211_hw * hw,struct ieee80211_vif * vif)5620295b02c4SAloka Dixit struct sk_buff *ieee80211_get_fils_discovery_tmpl(struct ieee80211_hw *hw,
5621295b02c4SAloka Dixit struct ieee80211_vif *vif)
5622295b02c4SAloka Dixit {
5623295b02c4SAloka Dixit struct sk_buff *skb = NULL;
5624295b02c4SAloka Dixit struct fils_discovery_data *tmpl = NULL;
5625295b02c4SAloka Dixit struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
5626295b02c4SAloka Dixit
5627295b02c4SAloka Dixit if (sdata->vif.type != NL80211_IFTYPE_AP)
5628295b02c4SAloka Dixit return NULL;
5629295b02c4SAloka Dixit
5630295b02c4SAloka Dixit rcu_read_lock();
5631bfd8403aSJohannes Berg tmpl = rcu_dereference(sdata->deflink.u.ap.fils_discovery);
5632295b02c4SAloka Dixit if (!tmpl) {
5633295b02c4SAloka Dixit rcu_read_unlock();
5634295b02c4SAloka Dixit return NULL;
5635295b02c4SAloka Dixit }
5636295b02c4SAloka Dixit
5637295b02c4SAloka Dixit skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + tmpl->len);
5638295b02c4SAloka Dixit if (skb) {
5639295b02c4SAloka Dixit skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
5640295b02c4SAloka Dixit skb_put_data(skb, tmpl->data, tmpl->len);
5641295b02c4SAloka Dixit }
5642295b02c4SAloka Dixit
5643295b02c4SAloka Dixit rcu_read_unlock();
5644295b02c4SAloka Dixit return skb;
5645295b02c4SAloka Dixit }
5646295b02c4SAloka Dixit EXPORT_SYMBOL(ieee80211_get_fils_discovery_tmpl);
5647295b02c4SAloka Dixit
5648632189a0SAloka Dixit struct sk_buff *
ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw * hw,struct ieee80211_vif * vif)5649632189a0SAloka Dixit ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
5650632189a0SAloka Dixit struct ieee80211_vif *vif)
5651632189a0SAloka Dixit {
5652632189a0SAloka Dixit struct sk_buff *skb = NULL;
5653632189a0SAloka Dixit struct unsol_bcast_probe_resp_data *tmpl = NULL;
5654632189a0SAloka Dixit struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
5655632189a0SAloka Dixit
5656632189a0SAloka Dixit if (sdata->vif.type != NL80211_IFTYPE_AP)
5657632189a0SAloka Dixit return NULL;
5658632189a0SAloka Dixit
5659632189a0SAloka Dixit rcu_read_lock();
5660bfd8403aSJohannes Berg tmpl = rcu_dereference(sdata->deflink.u.ap.unsol_bcast_probe_resp);
5661632189a0SAloka Dixit if (!tmpl) {
5662632189a0SAloka Dixit rcu_read_unlock();
5663632189a0SAloka Dixit return NULL;
5664632189a0SAloka Dixit }
5665632189a0SAloka Dixit
5666632189a0SAloka Dixit skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + tmpl->len);
5667632189a0SAloka Dixit if (skb) {
5668632189a0SAloka Dixit skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
5669632189a0SAloka Dixit skb_put_data(skb, tmpl->data, tmpl->len);
5670632189a0SAloka Dixit }
5671632189a0SAloka Dixit
5672632189a0SAloka Dixit rcu_read_unlock();
5673632189a0SAloka Dixit return skb;
5674632189a0SAloka Dixit }
5675632189a0SAloka Dixit EXPORT_SYMBOL(ieee80211_get_unsol_bcast_probe_resp_tmpl);
5676632189a0SAloka Dixit
ieee80211_pspoll_get(struct ieee80211_hw * hw,struct ieee80211_vif * vif)56777044cc56SKalle Valo struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
56787044cc56SKalle Valo struct ieee80211_vif *vif)
56797044cc56SKalle Valo {
56807044cc56SKalle Valo struct ieee80211_sub_if_data *sdata;
56817044cc56SKalle Valo struct ieee80211_pspoll *pspoll;
56827044cc56SKalle Valo struct ieee80211_local *local;
56837044cc56SKalle Valo struct sk_buff *skb;
56847044cc56SKalle Valo
56857044cc56SKalle Valo if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
56867044cc56SKalle Valo return NULL;
56877044cc56SKalle Valo
56887044cc56SKalle Valo sdata = vif_to_sdata(vif);
56897044cc56SKalle Valo local = sdata->local;
56907044cc56SKalle Valo
56917044cc56SKalle Valo skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
5692d15b8459SJoe Perches if (!skb)
56937044cc56SKalle Valo return NULL;
5694d15b8459SJoe Perches
56957044cc56SKalle Valo skb_reserve(skb, local->hw.extra_tx_headroom);
56967044cc56SKalle Valo
5697b080db58SJohannes Berg pspoll = skb_put_zero(skb, sizeof(*pspoll));
56987044cc56SKalle Valo pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
56997044cc56SKalle Valo IEEE80211_STYPE_PSPOLL);
5700f276e20bSJohannes Berg pspoll->aid = cpu_to_le16(sdata->vif.cfg.aid);
57017044cc56SKalle Valo
57027044cc56SKalle Valo /* aid in PS-Poll has its two MSBs each set to 1 */
57037044cc56SKalle Valo pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
57047044cc56SKalle Valo
5705bfd8403aSJohannes Berg memcpy(pspoll->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN);
57067044cc56SKalle Valo memcpy(pspoll->ta, vif->addr, ETH_ALEN);
57077044cc56SKalle Valo
57087044cc56SKalle Valo return skb;
57097044cc56SKalle Valo }
57107044cc56SKalle Valo EXPORT_SYMBOL(ieee80211_pspoll_get);
57117044cc56SKalle Valo
ieee80211_nullfunc_get(struct ieee80211_hw * hw,struct ieee80211_vif * vif,int link_id,bool qos_ok)57127044cc56SKalle Valo struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
57137b6ddeafSJohannes Berg struct ieee80211_vif *vif,
57140ab26380SJohannes Berg int link_id, bool qos_ok)
57157044cc56SKalle Valo {
57160ab26380SJohannes Berg struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
57170ab26380SJohannes Berg struct ieee80211_local *local = sdata->local;
57180ab26380SJohannes Berg struct ieee80211_link_data *link = NULL;
57197044cc56SKalle Valo struct ieee80211_hdr_3addr *nullfunc;
57207044cc56SKalle Valo struct sk_buff *skb;
57217b6ddeafSJohannes Berg bool qos = false;
57227044cc56SKalle Valo
57237044cc56SKalle Valo if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
57247044cc56SKalle Valo return NULL;
57257044cc56SKalle Valo
57267b6ddeafSJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom +
57277b6ddeafSJohannes Berg sizeof(*nullfunc) + 2);
5728d15b8459SJoe Perches if (!skb)
57297044cc56SKalle Valo return NULL;
5730d15b8459SJoe Perches
57310ab26380SJohannes Berg rcu_read_lock();
57320ab26380SJohannes Berg if (qos_ok) {
57330ab26380SJohannes Berg struct sta_info *sta;
57340ab26380SJohannes Berg
57350ab26380SJohannes Berg sta = sta_info_get(sdata, vif->cfg.ap_addr);
57360ab26380SJohannes Berg qos = sta && sta->sta.wme;
57370ab26380SJohannes Berg }
57380ab26380SJohannes Berg
57390ab26380SJohannes Berg if (link_id >= 0) {
57400ab26380SJohannes Berg link = rcu_dereference(sdata->link[link_id]);
57410ab26380SJohannes Berg if (WARN_ON_ONCE(!link)) {
57420ab26380SJohannes Berg rcu_read_unlock();
57430ab26380SJohannes Berg kfree_skb(skb);
57440ab26380SJohannes Berg return NULL;
57450ab26380SJohannes Berg }
57460ab26380SJohannes Berg }
57470ab26380SJohannes Berg
57487044cc56SKalle Valo skb_reserve(skb, local->hw.extra_tx_headroom);
57497044cc56SKalle Valo
5750b080db58SJohannes Berg nullfunc = skb_put_zero(skb, sizeof(*nullfunc));
57517044cc56SKalle Valo nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
57527044cc56SKalle Valo IEEE80211_STYPE_NULLFUNC |
57537044cc56SKalle Valo IEEE80211_FCTL_TODS);
57547b6ddeafSJohannes Berg if (qos) {
5755e0ba7095SJohannes Berg __le16 qoshdr = cpu_to_le16(7);
57567b6ddeafSJohannes Berg
57577b6ddeafSJohannes Berg BUILD_BUG_ON((IEEE80211_STYPE_QOS_NULLFUNC |
57587b6ddeafSJohannes Berg IEEE80211_STYPE_NULLFUNC) !=
57597b6ddeafSJohannes Berg IEEE80211_STYPE_QOS_NULLFUNC);
57607b6ddeafSJohannes Berg nullfunc->frame_control |=
57617b6ddeafSJohannes Berg cpu_to_le16(IEEE80211_STYPE_QOS_NULLFUNC);
57627b6ddeafSJohannes Berg skb->priority = 7;
57637b6ddeafSJohannes Berg skb_set_queue_mapping(skb, IEEE80211_AC_VO);
5764e0ba7095SJohannes Berg skb_put_data(skb, &qoshdr, sizeof(qoshdr));
57657b6ddeafSJohannes Berg }
57667b6ddeafSJohannes Berg
57670ab26380SJohannes Berg if (link) {
57680ab26380SJohannes Berg memcpy(nullfunc->addr1, link->conf->bssid, ETH_ALEN);
57690ab26380SJohannes Berg memcpy(nullfunc->addr2, link->conf->addr, ETH_ALEN);
57700ab26380SJohannes Berg memcpy(nullfunc->addr3, link->conf->bssid, ETH_ALEN);
57710ab26380SJohannes Berg } else {
57720ab26380SJohannes Berg memcpy(nullfunc->addr1, vif->cfg.ap_addr, ETH_ALEN);
57737044cc56SKalle Valo memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
57740ab26380SJohannes Berg memcpy(nullfunc->addr3, vif->cfg.ap_addr, ETH_ALEN);
57750ab26380SJohannes Berg }
57760ab26380SJohannes Berg rcu_read_unlock();
57777044cc56SKalle Valo
57787044cc56SKalle Valo return skb;
57797044cc56SKalle Valo }
57807044cc56SKalle Valo EXPORT_SYMBOL(ieee80211_nullfunc_get);
57817044cc56SKalle Valo
ieee80211_probereq_get(struct ieee80211_hw * hw,const u8 * src_addr,const u8 * ssid,size_t ssid_len,size_t tailroom)578205e54ea6SKalle Valo struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
5783a344d677SJohannes Berg const u8 *src_addr,
578405e54ea6SKalle Valo const u8 *ssid, size_t ssid_len,
5785b9a9ada1SJohannes Berg size_t tailroom)
578605e54ea6SKalle Valo {
5787a344d677SJohannes Berg struct ieee80211_local *local = hw_to_local(hw);
578805e54ea6SKalle Valo struct ieee80211_hdr_3addr *hdr;
578905e54ea6SKalle Valo struct sk_buff *skb;
579005e54ea6SKalle Valo size_t ie_ssid_len;
579105e54ea6SKalle Valo u8 *pos;
579205e54ea6SKalle Valo
579305e54ea6SKalle Valo ie_ssid_len = 2 + ssid_len;
579405e54ea6SKalle Valo
579505e54ea6SKalle Valo skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) +
5796b9a9ada1SJohannes Berg ie_ssid_len + tailroom);
5797d15b8459SJoe Perches if (!skb)
579805e54ea6SKalle Valo return NULL;
579905e54ea6SKalle Valo
580005e54ea6SKalle Valo skb_reserve(skb, local->hw.extra_tx_headroom);
580105e54ea6SKalle Valo
5802b080db58SJohannes Berg hdr = skb_put_zero(skb, sizeof(*hdr));
580305e54ea6SKalle Valo hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
580405e54ea6SKalle Valo IEEE80211_STYPE_PROBE_REQ);
5805e83e6541SJohannes Berg eth_broadcast_addr(hdr->addr1);
5806a344d677SJohannes Berg memcpy(hdr->addr2, src_addr, ETH_ALEN);
5807e83e6541SJohannes Berg eth_broadcast_addr(hdr->addr3);
580805e54ea6SKalle Valo
580905e54ea6SKalle Valo pos = skb_put(skb, ie_ssid_len);
581005e54ea6SKalle Valo *pos++ = WLAN_EID_SSID;
581105e54ea6SKalle Valo *pos++ = ssid_len;
581288c868c4SStanislaw Gruszka if (ssid_len)
581305e54ea6SKalle Valo memcpy(pos, ssid, ssid_len);
581405e54ea6SKalle Valo pos += ssid_len;
581505e54ea6SKalle Valo
581605e54ea6SKalle Valo return skb;
581705e54ea6SKalle Valo }
581805e54ea6SKalle Valo EXPORT_SYMBOL(ieee80211_probereq_get);
581905e54ea6SKalle Valo
ieee80211_rts_get(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const void * frame,size_t frame_len,const struct ieee80211_tx_info * frame_txctl,struct ieee80211_rts * rts)582032bfd35dSJohannes Berg void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
5821e2ebc74dSJohannes Berg const void *frame, size_t frame_len,
5822e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl,
5823e2ebc74dSJohannes Berg struct ieee80211_rts *rts)
5824e2ebc74dSJohannes Berg {
5825e2ebc74dSJohannes Berg const struct ieee80211_hdr *hdr = frame;
5826e2ebc74dSJohannes Berg
5827065e9605SHarvey Harrison rts->frame_control =
5828065e9605SHarvey Harrison cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
582932bfd35dSJohannes Berg rts->duration = ieee80211_rts_duration(hw, vif, frame_len,
583032bfd35dSJohannes Berg frame_txctl);
5831e2ebc74dSJohannes Berg memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
5832e2ebc74dSJohannes Berg memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
5833e2ebc74dSJohannes Berg }
5834e2ebc74dSJohannes Berg EXPORT_SYMBOL(ieee80211_rts_get);
5835e2ebc74dSJohannes Berg
ieee80211_ctstoself_get(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const void * frame,size_t frame_len,const struct ieee80211_tx_info * frame_txctl,struct ieee80211_cts * cts)583632bfd35dSJohannes Berg void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
5837e2ebc74dSJohannes Berg const void *frame, size_t frame_len,
5838e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl,
5839e2ebc74dSJohannes Berg struct ieee80211_cts *cts)
5840e2ebc74dSJohannes Berg {
5841e2ebc74dSJohannes Berg const struct ieee80211_hdr *hdr = frame;
5842e2ebc74dSJohannes Berg
5843065e9605SHarvey Harrison cts->frame_control =
5844065e9605SHarvey Harrison cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
584532bfd35dSJohannes Berg cts->duration = ieee80211_ctstoself_duration(hw, vif,
584632bfd35dSJohannes Berg frame_len, frame_txctl);
5847e2ebc74dSJohannes Berg memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
5848e2ebc74dSJohannes Berg }
5849e2ebc74dSJohannes Berg EXPORT_SYMBOL(ieee80211_ctstoself_get);
5850e2ebc74dSJohannes Berg
5851e2ebc74dSJohannes Berg struct sk_buff *
ieee80211_get_buffered_bc(struct ieee80211_hw * hw,struct ieee80211_vif * vif)585232bfd35dSJohannes Berg ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
5853e039fa4aSJohannes Berg struct ieee80211_vif *vif)
5854e2ebc74dSJohannes Berg {
5855e2ebc74dSJohannes Berg struct ieee80211_local *local = hw_to_local(hw);
5856747cf5e9STomas Winkler struct sk_buff *skb = NULL;
58575cf121c3SJohannes Berg struct ieee80211_tx_data tx;
5858e2ebc74dSJohannes Berg struct ieee80211_sub_if_data *sdata;
5859d012a605SMarco Porsch struct ps_data *ps;
5860e039fa4aSJohannes Berg struct ieee80211_tx_info *info;
586155de908aSJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf;
5862e2ebc74dSJohannes Berg
586332bfd35dSJohannes Berg sdata = vif_to_sdata(vif);
58645dfdaf58SJohannes Berg
58655dfdaf58SJohannes Berg rcu_read_lock();
5866d0a9123eSJohannes Berg chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
58675dfdaf58SJohannes Berg
5868d012a605SMarco Porsch if (!chanctx_conf)
5869747cf5e9STomas Winkler goto out;
58705dfdaf58SJohannes Berg
5871d012a605SMarco Porsch if (sdata->vif.type == NL80211_IFTYPE_AP) {
5872d012a605SMarco Porsch struct beacon_data *beacon =
5873bfd8403aSJohannes Berg rcu_dereference(sdata->deflink.u.ap.beacon);
5874d012a605SMarco Porsch
5875d012a605SMarco Porsch if (!beacon || !beacon->head)
5876d012a605SMarco Porsch goto out;
5877d012a605SMarco Porsch
5878d012a605SMarco Porsch ps = &sdata->u.ap.ps;
58793f52b7e3SMarco Porsch } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
58803f52b7e3SMarco Porsch ps = &sdata->u.mesh.ps;
5881d012a605SMarco Porsch } else {
5882d012a605SMarco Porsch goto out;
5883d012a605SMarco Porsch }
5884d012a605SMarco Porsch
5885d012a605SMarco Porsch if (ps->dtim_count != 0 || !ps->dtim_bc_mc)
5886747cf5e9STomas Winkler goto out; /* send buffered bc/mc only after DTIM beacon */
5887e039fa4aSJohannes Berg
5888e2ebc74dSJohannes Berg while (1) {
5889d012a605SMarco Porsch skb = skb_dequeue(&ps->bc_buf);
5890e2ebc74dSJohannes Berg if (!skb)
5891747cf5e9STomas Winkler goto out;
5892e2ebc74dSJohannes Berg local->total_ps_buffered--;
5893e2ebc74dSJohannes Berg
5894d012a605SMarco Porsch if (!skb_queue_empty(&ps->bc_buf) && skb->len >= 2) {
5895e2ebc74dSJohannes Berg struct ieee80211_hdr *hdr =
5896e2ebc74dSJohannes Berg (struct ieee80211_hdr *) skb->data;
5897e2ebc74dSJohannes Berg /* more buffered multicast/broadcast frames ==> set
5898e2ebc74dSJohannes Berg * MoreData flag in IEEE 802.11 header to inform PS
5899e2ebc74dSJohannes Berg * STAs */
5900e2ebc74dSJohannes Berg hdr->frame_control |=
5901e2ebc74dSJohannes Berg cpu_to_le16(IEEE80211_FCTL_MOREDATA);
5902e2ebc74dSJohannes Berg }
5903e2ebc74dSJohannes Berg
5904112c44b2SMichael Braun if (sdata->vif.type == NL80211_IFTYPE_AP)
5905de74a1d9SMichael Braun sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
59067c10770fSJohannes Berg if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb))
5907e2ebc74dSJohannes Berg break;
59086b07d9caSFelix Fietkau ieee80211_free_txskb(hw, skb);
5909e2ebc74dSJohannes Berg }
5910e039fa4aSJohannes Berg
5911e039fa4aSJohannes Berg info = IEEE80211_SKB_CB(skb);
5912e039fa4aSJohannes Berg
59135cf121c3SJohannes Berg tx.flags |= IEEE80211_TX_PS_BUFFERED;
59144bf88530SJohannes Berg info->band = chanctx_conf->def.chan->band;
5915e2ebc74dSJohannes Berg
591697b045d6SJohannes Berg if (invoke_tx_handlers(&tx))
5917e2ebc74dSJohannes Berg skb = NULL;
5918747cf5e9STomas Winkler out:
5919d0709a65SJohannes Berg rcu_read_unlock();
5920e2ebc74dSJohannes Berg
5921e2ebc74dSJohannes Berg return skb;
5922e2ebc74dSJohannes Berg }
5923e2ebc74dSJohannes Berg EXPORT_SYMBOL(ieee80211_get_buffered_bc);
59243b8d81e0SJohannes Berg
ieee80211_reserve_tid(struct ieee80211_sta * pubsta,u8 tid)5925b6da911bSLiad Kaufman int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid)
5926b6da911bSLiad Kaufman {
5927b6da911bSLiad Kaufman struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
5928b6da911bSLiad Kaufman struct ieee80211_sub_if_data *sdata = sta->sdata;
5929b6da911bSLiad Kaufman struct ieee80211_local *local = sdata->local;
5930b6da911bSLiad Kaufman int ret;
5931b6da911bSLiad Kaufman u32 queues;
5932b6da911bSLiad Kaufman
5933b6da911bSLiad Kaufman lockdep_assert_held(&local->sta_mtx);
5934b6da911bSLiad Kaufman
5935b6da911bSLiad Kaufman /* only some cases are supported right now */
5936b6da911bSLiad Kaufman switch (sdata->vif.type) {
5937b6da911bSLiad Kaufman case NL80211_IFTYPE_STATION:
5938b6da911bSLiad Kaufman case NL80211_IFTYPE_AP:
5939b6da911bSLiad Kaufman case NL80211_IFTYPE_AP_VLAN:
5940b6da911bSLiad Kaufman break;
5941b6da911bSLiad Kaufman default:
5942b6da911bSLiad Kaufman WARN_ON(1);
5943b6da911bSLiad Kaufman return -EINVAL;
5944b6da911bSLiad Kaufman }
5945b6da911bSLiad Kaufman
5946b6da911bSLiad Kaufman if (WARN_ON(tid >= IEEE80211_NUM_UPS))
5947b6da911bSLiad Kaufman return -EINVAL;
5948b6da911bSLiad Kaufman
5949b6da911bSLiad Kaufman if (sta->reserved_tid == tid) {
5950b6da911bSLiad Kaufman ret = 0;
5951b6da911bSLiad Kaufman goto out;
5952b6da911bSLiad Kaufman }
5953b6da911bSLiad Kaufman
5954b6da911bSLiad Kaufman if (sta->reserved_tid != IEEE80211_TID_UNRESERVED) {
5955b6da911bSLiad Kaufman sdata_err(sdata, "TID reservation already active\n");
5956b6da911bSLiad Kaufman ret = -EALREADY;
5957b6da911bSLiad Kaufman goto out;
5958b6da911bSLiad Kaufman }
5959b6da911bSLiad Kaufman
5960b6da911bSLiad Kaufman ieee80211_stop_vif_queues(sdata->local, sdata,
5961b6da911bSLiad Kaufman IEEE80211_QUEUE_STOP_REASON_RESERVE_TID);
5962b6da911bSLiad Kaufman
5963b6da911bSLiad Kaufman synchronize_net();
5964b6da911bSLiad Kaufman
5965b6da911bSLiad Kaufman /* Tear down BA sessions so we stop aggregating on this TID */
596630686bf7SJohannes Berg if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION)) {
5967b6da911bSLiad Kaufman set_sta_flag(sta, WLAN_STA_BLOCK_BA);
5968b6da911bSLiad Kaufman __ieee80211_stop_tx_ba_session(sta, tid,
5969b6da911bSLiad Kaufman AGG_STOP_LOCAL_REQUEST);
5970b6da911bSLiad Kaufman }
5971b6da911bSLiad Kaufman
5972b6da911bSLiad Kaufman queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]);
59733b24f4c6SEmmanuel Grumbach __ieee80211_flush_queues(local, sdata, queues, false);
5974b6da911bSLiad Kaufman
5975b6da911bSLiad Kaufman sta->reserved_tid = tid;
5976b6da911bSLiad Kaufman
5977b6da911bSLiad Kaufman ieee80211_wake_vif_queues(local, sdata,
5978b6da911bSLiad Kaufman IEEE80211_QUEUE_STOP_REASON_RESERVE_TID);
5979b6da911bSLiad Kaufman
598030686bf7SJohannes Berg if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION))
5981b6da911bSLiad Kaufman clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
5982b6da911bSLiad Kaufman
5983b6da911bSLiad Kaufman ret = 0;
5984b6da911bSLiad Kaufman out:
5985b6da911bSLiad Kaufman return ret;
5986b6da911bSLiad Kaufman }
5987b6da911bSLiad Kaufman EXPORT_SYMBOL(ieee80211_reserve_tid);
5988b6da911bSLiad Kaufman
ieee80211_unreserve_tid(struct ieee80211_sta * pubsta,u8 tid)5989b6da911bSLiad Kaufman void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid)
5990b6da911bSLiad Kaufman {
5991b6da911bSLiad Kaufman struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
5992b6da911bSLiad Kaufman struct ieee80211_sub_if_data *sdata = sta->sdata;
5993b6da911bSLiad Kaufman
5994b6da911bSLiad Kaufman lockdep_assert_held(&sdata->local->sta_mtx);
5995b6da911bSLiad Kaufman
5996b6da911bSLiad Kaufman /* only some cases are supported right now */
5997b6da911bSLiad Kaufman switch (sdata->vif.type) {
5998b6da911bSLiad Kaufman case NL80211_IFTYPE_STATION:
5999b6da911bSLiad Kaufman case NL80211_IFTYPE_AP:
6000b6da911bSLiad Kaufman case NL80211_IFTYPE_AP_VLAN:
6001b6da911bSLiad Kaufman break;
6002b6da911bSLiad Kaufman default:
6003b6da911bSLiad Kaufman WARN_ON(1);
6004b6da911bSLiad Kaufman return;
6005b6da911bSLiad Kaufman }
6006b6da911bSLiad Kaufman
6007b6da911bSLiad Kaufman if (tid != sta->reserved_tid) {
6008b6da911bSLiad Kaufman sdata_err(sdata, "TID to unreserve (%d) isn't reserved\n", tid);
6009b6da911bSLiad Kaufman return;
6010b6da911bSLiad Kaufman }
6011b6da911bSLiad Kaufman
6012b6da911bSLiad Kaufman sta->reserved_tid = IEEE80211_TID_UNRESERVED;
6013b6da911bSLiad Kaufman }
6014b6da911bSLiad Kaufman EXPORT_SYMBOL(ieee80211_unreserve_tid);
6015b6da911bSLiad Kaufman
__ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,int tid,int link_id,enum nl80211_band band)601655de908aSJohannes Berg void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
6017e1e68b14SJohannes Berg struct sk_buff *skb, int tid, int link_id,
601808aca29aSMathy Vanhoef enum nl80211_band band)
60193b8d81e0SJohannes Berg {
602069d41b5aSJohannes Berg const struct ieee80211_hdr *hdr = (void *)skb->data;
6021731977e9SAmadeusz Sławiński int ac = ieee80211_ac_from_tid(tid);
602269d41b5aSJohannes Berg unsigned int link;
60233a25a8c8SJohannes Berg
6024d57a544dSZhang Shengju skb_reset_mac_header(skb);
60253a25a8c8SJohannes Berg skb_set_queue_mapping(skb, ac);
6026cf6bb79aSHelmut Schaa skb->priority = tid;
6027cf0277e7SJohannes Berg
602889afe614SJohannes Berg skb->dev = sdata->dev;
602989afe614SJohannes Berg
603069d41b5aSJohannes Berg BUILD_BUG_ON(IEEE80211_LINK_UNSPECIFIED < IEEE80211_MLD_MAX_NUM_LINKS);
603169d41b5aSJohannes Berg BUILD_BUG_ON(!FIELD_FIT(IEEE80211_TX_CTRL_MLO_LINK,
603269d41b5aSJohannes Berg IEEE80211_LINK_UNSPECIFIED));
603369d41b5aSJohannes Berg
6034f1871abdSIlan Peer if (!ieee80211_vif_is_mld(&sdata->vif)) {
603569d41b5aSJohannes Berg link = 0;
6036e1e68b14SJohannes Berg } else if (link_id >= 0) {
6037e1e68b14SJohannes Berg link = link_id;
603869d41b5aSJohannes Berg } else if (memcmp(sdata->vif.addr, hdr->addr2, ETH_ALEN) == 0) {
603969d41b5aSJohannes Berg /* address from the MLD */
604069d41b5aSJohannes Berg link = IEEE80211_LINK_UNSPECIFIED;
604169d41b5aSJohannes Berg } else {
604269d41b5aSJohannes Berg /* otherwise must be addressed from a link */
6043d8675a63SJohannes Berg rcu_read_lock();
604469d41b5aSJohannes Berg for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) {
6045d8675a63SJohannes Berg struct ieee80211_bss_conf *link_conf;
6046d8675a63SJohannes Berg
6047d8675a63SJohannes Berg link_conf = rcu_dereference(sdata->vif.link_conf[link]);
6048d8675a63SJohannes Berg if (!link_conf)
6049d8675a63SJohannes Berg continue;
6050d8675a63SJohannes Berg if (memcmp(link_conf->addr, hdr->addr2, ETH_ALEN) == 0)
605169d41b5aSJohannes Berg break;
605269d41b5aSJohannes Berg }
6053d8675a63SJohannes Berg rcu_read_unlock();
605469d41b5aSJohannes Berg
605569d41b5aSJohannes Berg if (WARN_ON_ONCE(link == ARRAY_SIZE(sdata->vif.link_conf)))
60567b3b9ac8SIlan Peer link = ffs(sdata->vif.active_links) - 1;
605769d41b5aSJohannes Berg }
605869d41b5aSJohannes Berg
605969d41b5aSJohannes Berg IEEE80211_SKB_CB(skb)->control.flags |=
606069d41b5aSJohannes Berg u32_encode_bits(link, IEEE80211_TX_CTRL_MLO_LINK);
606169d41b5aSJohannes Berg
60623d34deb6SJohannes Berg /*
60633d34deb6SJohannes Berg * The other path calling ieee80211_xmit is from the tasklet,
60643d34deb6SJohannes Berg * and while we can handle concurrent transmissions locking
60653d34deb6SJohannes Berg * requirements are that we do not come into tx with bhs on.
60663d34deb6SJohannes Berg */
60673d34deb6SJohannes Berg local_bh_disable();
606873c4e195SJohannes Berg IEEE80211_SKB_CB(skb)->band = band;
606908aca29aSMathy Vanhoef ieee80211_xmit(sdata, NULL, skb);
60703d34deb6SJohannes Berg local_bh_enable();
60713b8d81e0SJohannes Berg }
607291180649SDenis Kenzior
ieee80211_tx_skb_tid(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,int tid,int link_id)6073eef25a66SJohannes Berg void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
6074e1e68b14SJohannes Berg struct sk_buff *skb, int tid, int link_id)
6075eef25a66SJohannes Berg {
6076eef25a66SJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf;
6077eef25a66SJohannes Berg enum nl80211_band band;
6078eef25a66SJohannes Berg
6079eef25a66SJohannes Berg rcu_read_lock();
6080f1871abdSIlan Peer if (!ieee80211_vif_is_mld(&sdata->vif)) {
6081e1e68b14SJohannes Berg WARN_ON(link_id >= 0);
6082eef25a66SJohannes Berg chanctx_conf =
6083eef25a66SJohannes Berg rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
6084eef25a66SJohannes Berg if (WARN_ON(!chanctx_conf)) {
6085eef25a66SJohannes Berg rcu_read_unlock();
6086eef25a66SJohannes Berg kfree_skb(skb);
6087eef25a66SJohannes Berg return;
6088eef25a66SJohannes Berg }
6089eef25a66SJohannes Berg band = chanctx_conf->def.chan->band;
6090eef25a66SJohannes Berg } else {
6091e1e68b14SJohannes Berg WARN_ON(link_id >= 0 &&
60927b3b9ac8SIlan Peer !(sdata->vif.active_links & BIT(link_id)));
6093eef25a66SJohannes Berg /* MLD transmissions must not rely on the band */
6094eef25a66SJohannes Berg band = 0;
6095eef25a66SJohannes Berg }
6096eef25a66SJohannes Berg
6097e1e68b14SJohannes Berg __ieee80211_tx_skb_tid_band(sdata, skb, tid, link_id, band);
6098eef25a66SJohannes Berg rcu_read_unlock();
6099eef25a66SJohannes Berg }
6100eef25a66SJohannes Berg
ieee80211_tx_control_port(struct wiphy * wiphy,struct net_device * dev,const u8 * buf,size_t len,const u8 * dest,__be16 proto,bool unencrypted,int link_id,u64 * cookie)610191180649SDenis Kenzior int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
610291180649SDenis Kenzior const u8 *buf, size_t len,
6103dca9ca2dSMarkus Theil const u8 *dest, __be16 proto, bool unencrypted,
610467207babSAndrei Otcheretianski int link_id, u64 *cookie)
610591180649SDenis Kenzior {
610691180649SDenis Kenzior struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
610791180649SDenis Kenzior struct ieee80211_local *local = sdata->local;
610810cb8e61SMarkus Theil struct sta_info *sta;
610991180649SDenis Kenzior struct sk_buff *skb;
611091180649SDenis Kenzior struct ethhdr *ehdr;
6111b95d2ccdSJohannes Berg u32 ctrl_flags = 0;
6112a7528198SMarkus Theil u32 flags = 0;
6113dd820ed6SJohannes Berg int err;
611491180649SDenis Kenzior
611591180649SDenis Kenzior /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE
611691180649SDenis Kenzior * or Pre-Authentication
611791180649SDenis Kenzior */
611891180649SDenis Kenzior if (proto != sdata->control_port_protocol &&
611991180649SDenis Kenzior proto != cpu_to_be16(ETH_P_PREAUTH))
612091180649SDenis Kenzior return -EINVAL;
612191180649SDenis Kenzior
6122b95d2ccdSJohannes Berg if (proto == sdata->control_port_protocol)
61235af7fef3SMarkus Theil ctrl_flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO |
61245af7fef3SMarkus Theil IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP;
6125b95d2ccdSJohannes Berg
612691180649SDenis Kenzior if (unencrypted)
6127a7528198SMarkus Theil flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
6128a7528198SMarkus Theil
6129a7528198SMarkus Theil if (cookie)
6130a7528198SMarkus Theil ctrl_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
6131a7528198SMarkus Theil
613210cb8e61SMarkus Theil flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX;
613391180649SDenis Kenzior
613491180649SDenis Kenzior skb = dev_alloc_skb(local->hw.extra_tx_headroom +
613591180649SDenis Kenzior sizeof(struct ethhdr) + len);
613691180649SDenis Kenzior if (!skb)
613791180649SDenis Kenzior return -ENOMEM;
613891180649SDenis Kenzior
613991180649SDenis Kenzior skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr));
614091180649SDenis Kenzior
614191180649SDenis Kenzior skb_put_data(skb, buf, len);
614291180649SDenis Kenzior
614391180649SDenis Kenzior ehdr = skb_push(skb, sizeof(struct ethhdr));
614491180649SDenis Kenzior memcpy(ehdr->h_dest, dest, ETH_ALEN);
614567207babSAndrei Otcheretianski
61469dd19538SJohannes Berg /* we may override the SA for MLO STA later */
614767207babSAndrei Otcheretianski if (link_id < 0) {
61489dd19538SJohannes Berg ctrl_flags |= u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
61499dd19538SJohannes Berg IEEE80211_TX_CTRL_MLO_LINK);
61508079e4feSJohannes Berg memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
615167207babSAndrei Otcheretianski } else {
615267207babSAndrei Otcheretianski struct ieee80211_bss_conf *link_conf;
615367207babSAndrei Otcheretianski
61549dd19538SJohannes Berg ctrl_flags |= u32_encode_bits(link_id,
61559dd19538SJohannes Berg IEEE80211_TX_CTRL_MLO_LINK);
61569dd19538SJohannes Berg
615767207babSAndrei Otcheretianski rcu_read_lock();
615867207babSAndrei Otcheretianski link_conf = rcu_dereference(sdata->vif.link_conf[link_id]);
615967207babSAndrei Otcheretianski if (!link_conf) {
616067207babSAndrei Otcheretianski dev_kfree_skb(skb);
616167207babSAndrei Otcheretianski rcu_read_unlock();
616267207babSAndrei Otcheretianski return -ENOLINK;
616367207babSAndrei Otcheretianski }
616467207babSAndrei Otcheretianski memcpy(ehdr->h_source, link_conf->addr, ETH_ALEN);
616567207babSAndrei Otcheretianski rcu_read_unlock();
616667207babSAndrei Otcheretianski }
616767207babSAndrei Otcheretianski
616891180649SDenis Kenzior ehdr->h_proto = proto;
616991180649SDenis Kenzior
617091180649SDenis Kenzior skb->dev = dev;
617110cb8e61SMarkus Theil skb->protocol = proto;
617291180649SDenis Kenzior skb_reset_network_header(skb);
617391180649SDenis Kenzior skb_reset_mac_header(skb);
617491180649SDenis Kenzior
6175d873697eSHans de Goede if (local->hw.queues < IEEE80211_NUM_ACS)
6176d873697eSHans de Goede goto start_xmit;
6177d873697eSHans de Goede
617810cb8e61SMarkus Theil /* update QoS header to prioritize control port frames if possible,
617910cb8e61SMarkus Theil * priorization also happens for control port frames send over
618010cb8e61SMarkus Theil * AF_PACKET
618110cb8e61SMarkus Theil */
618210cb8e61SMarkus Theil rcu_read_lock();
6183dd820ed6SJohannes Berg err = ieee80211_lookup_ra_sta(sdata, skb, &sta);
6184dd820ed6SJohannes Berg if (err) {
618562b03f45SYang Yingliang dev_kfree_skb(skb);
6186dd820ed6SJohannes Berg rcu_read_unlock();
6187dd820ed6SJohannes Berg return err;
6188dd820ed6SJohannes Berg }
618910cb8e61SMarkus Theil
6190dd820ed6SJohannes Berg if (!IS_ERR(sta)) {
6191107395f9SAlexander Wetzel u16 queue = ieee80211_select_queue(sdata, sta, skb);
619210cb8e61SMarkus Theil
619310cb8e61SMarkus Theil skb_set_queue_mapping(skb, queue);
61949dd19538SJohannes Berg
61959dd19538SJohannes Berg /*
61969dd19538SJohannes Berg * for MLO STA, the SA should be the AP MLD address, but
61979dd19538SJohannes Berg * the link ID has been selected already
61989dd19538SJohannes Berg */
619955f0a489SDan Carpenter if (sta && sta->sta.mlo)
62009dd19538SJohannes Berg memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
620110cb8e61SMarkus Theil }
620210cb8e61SMarkus Theil rcu_read_unlock();
620310cb8e61SMarkus Theil
6204d873697eSHans de Goede start_xmit:
6205a7528198SMarkus Theil /* mutex lock is only needed for incrementing the cookie counter */
6206a7528198SMarkus Theil mutex_lock(&local->mtx);
6207a7528198SMarkus Theil
6208e7441c92SDenis Kenzior local_bh_disable();
6209a7528198SMarkus Theil __ieee80211_subif_start_xmit(skb, skb->dev, flags, ctrl_flags, cookie);
6210e7441c92SDenis Kenzior local_bh_enable();
621191180649SDenis Kenzior
6212a7528198SMarkus Theil mutex_unlock(&local->mtx);
6213a7528198SMarkus Theil
621491180649SDenis Kenzior return 0;
621591180649SDenis Kenzior }
62168828f81aSRajkumar Manoharan
ieee80211_probe_mesh_link(struct wiphy * wiphy,struct net_device * dev,const u8 * buf,size_t len)62178828f81aSRajkumar Manoharan int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
62188828f81aSRajkumar Manoharan const u8 *buf, size_t len)
62198828f81aSRajkumar Manoharan {
62208828f81aSRajkumar Manoharan struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
62218828f81aSRajkumar Manoharan struct ieee80211_local *local = sdata->local;
62228828f81aSRajkumar Manoharan struct sk_buff *skb;
62238828f81aSRajkumar Manoharan
62248828f81aSRajkumar Manoharan skb = dev_alloc_skb(local->hw.extra_tx_headroom + len +
62258828f81aSRajkumar Manoharan 30 + /* header size */
62268828f81aSRajkumar Manoharan 18); /* 11s header size */
62278828f81aSRajkumar Manoharan if (!skb)
62288828f81aSRajkumar Manoharan return -ENOMEM;
62298828f81aSRajkumar Manoharan
62308828f81aSRajkumar Manoharan skb_reserve(skb, local->hw.extra_tx_headroom);
62318828f81aSRajkumar Manoharan skb_put_data(skb, buf, len);
62328828f81aSRajkumar Manoharan
62338828f81aSRajkumar Manoharan skb->dev = dev;
62348828f81aSRajkumar Manoharan skb->protocol = htons(ETH_P_802_3);
62358828f81aSRajkumar Manoharan skb_reset_network_header(skb);
62368828f81aSRajkumar Manoharan skb_reset_mac_header(skb);
62378828f81aSRajkumar Manoharan
62388828f81aSRajkumar Manoharan local_bh_disable();
62398828f81aSRajkumar Manoharan __ieee80211_subif_start_xmit(skb, skb->dev, 0,
6240a7528198SMarkus Theil IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP,
6241a7528198SMarkus Theil NULL);
6242e2ebc74dSJohannes Berg local_bh_enable();
6243e2ebc74dSJohannes Berg
6244e2ebc74dSJohannes Berg return 0;
6245e2ebc74dSJohannes Berg }
6246