]>
Commit | Line | Data |
---|---|---|
780e87c2 JB |
1 | /****************************************************************************** |
2 | * | |
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | * redistributing this file, you may do so under either license. | |
5 | * | |
6 | * GPL LICENSE SUMMARY | |
7 | * | |
8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | |
9 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH | |
9c36fd71 | 10 | * Copyright(c) 2015 - 2017 Intel Deutschland GmbH |
780e87c2 JB |
11 | * |
12 | * This program is free software; you can redistribute it and/or modify | |
13 | * it under the terms of version 2 of the GNU General Public License as | |
14 | * published by the Free Software Foundation. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, but | |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * General Public License for more details. | |
20 | * | |
21 | * The full GNU General Public License is included in this distribution | |
22 | * in the file called COPYING. | |
23 | * | |
24 | * Contact Information: | |
25 | * Intel Linux Wireless <ilw@linux.intel.com> | |
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
27 | * | |
28 | * BSD LICENSE | |
29 | * | |
30 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | |
31 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH | |
9c36fd71 | 32 | * Copyright(c) 2015 - 2017 Intel Deutschland GmbH |
780e87c2 JB |
33 | * All rights reserved. |
34 | * | |
35 | * Redistribution and use in source and binary forms, with or without | |
36 | * modification, are permitted provided that the following conditions | |
37 | * are met: | |
38 | * | |
39 | * * Redistributions of source code must retain the above copyright | |
40 | * notice, this list of conditions and the following disclaimer. | |
41 | * * Redistributions in binary form must reproduce the above copyright | |
42 | * notice, this list of conditions and the following disclaimer in | |
43 | * the documentation and/or other materials provided with the | |
44 | * distribution. | |
45 | * * Neither the name Intel Corporation nor the names of its | |
46 | * contributors may be used to endorse or promote products derived | |
47 | * from this software without specific prior written permission. | |
48 | * | |
49 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
50 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
51 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
52 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
53 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
54 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
55 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
56 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
57 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
58 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
59 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
60 | *****************************************************************************/ | |
61 | #include <linux/etherdevice.h> | |
62 | #include <linux/skbuff.h> | |
63 | #include "iwl-trans.h" | |
64 | #include "mvm.h" | |
65 | #include "fw-api.h" | |
780e87c2 | 66 | |
f5e28eac JB |
67 | static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, |
68 | int queue, struct ieee80211_sta *sta) | |
69 | { | |
70 | struct iwl_mvm_sta *mvmsta; | |
71 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | |
72 | struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb); | |
73 | struct iwl_mvm_key_pn *ptk_pn; | |
74 | u8 tid, keyidx; | |
75 | u8 pn[IEEE80211_CCMP_PN_LEN]; | |
76 | u8 *extiv; | |
77 | ||
78 | /* do PN checking */ | |
79 | ||
80 | /* multicast and non-data only arrives on default queue */ | |
81 | if (!ieee80211_is_data(hdr->frame_control) || | |
82 | is_multicast_ether_addr(hdr->addr1)) | |
83 | return 0; | |
84 | ||
85 | /* do not check PN for open AP */ | |
86 | if (!(stats->flag & RX_FLAG_DECRYPTED)) | |
87 | return 0; | |
88 | ||
89 | /* | |
90 | * avoid checking for default queue - we don't want to replicate | |
91 | * all the logic that's necessary for checking the PN on fragmented | |
92 | * frames, leave that to mac80211 | |
93 | */ | |
94 | if (queue == 0) | |
95 | return 0; | |
96 | ||
97 | /* if we are here - this for sure is either CCMP or GCMP */ | |
98 | if (IS_ERR_OR_NULL(sta)) { | |
99 | IWL_ERR(mvm, | |
100 | "expected hw-decrypted unicast frame for station\n"); | |
101 | return -1; | |
102 | } | |
103 | ||
104 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | |
105 | ||
106 | extiv = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); | |
107 | keyidx = extiv[3] >> 6; | |
108 | ||
109 | ptk_pn = rcu_dereference(mvmsta->ptk_pn[keyidx]); | |
110 | if (!ptk_pn) | |
111 | return -1; | |
112 | ||
113 | if (ieee80211_is_data_qos(hdr->frame_control)) | |
114 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | |
115 | else | |
116 | tid = 0; | |
117 | ||
118 | /* we don't use HCCA/802.11 QoS TSPECs, so drop such frames */ | |
119 | if (tid >= IWL_MAX_TID_COUNT) | |
120 | return -1; | |
121 | ||
122 | /* load pn */ | |
123 | pn[0] = extiv[7]; | |
124 | pn[1] = extiv[6]; | |
125 | pn[2] = extiv[5]; | |
126 | pn[3] = extiv[4]; | |
127 | pn[4] = extiv[1]; | |
128 | pn[5] = extiv[0]; | |
129 | ||
130 | if (memcmp(pn, ptk_pn->q[queue].pn[tid], | |
131 | IEEE80211_CCMP_PN_LEN) <= 0) | |
132 | return -1; | |
133 | ||
f1ae02b1 SS |
134 | if (!(stats->flag & RX_FLAG_AMSDU_MORE)) |
135 | memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); | |
f5e28eac JB |
136 | stats->flag |= RX_FLAG_PN_VALIDATED; |
137 | ||
138 | return 0; | |
139 | } | |
140 | ||
141 | /* iwl_mvm_create_skb Adds the rxb to a new skb */ | |
142 | static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, | |
143 | u16 len, u8 crypt_len, | |
144 | struct iwl_rx_cmd_buffer *rxb) | |
780e87c2 | 145 | { |
e29cc6b9 SS |
146 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
147 | struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; | |
148 | unsigned int headlen, fraglen, pad_len = 0; | |
149 | unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); | |
150 | ||
4b40571e | 151 | if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) { |
e29cc6b9 | 152 | pad_len = 2; |
4b40571e JB |
153 | |
154 | /* | |
155 | * If the device inserted padding it means that (it thought) | |
156 | * the 802.11 header wasn't a multiple of 4 bytes long. In | |
157 | * this case, reserve two bytes at the start of the SKB to | |
158 | * align the payload properly in case we end up copying it. | |
159 | */ | |
160 | skb_reserve(skb, pad_len); | |
161 | } | |
e29cc6b9 | 162 | len -= pad_len; |
780e87c2 JB |
163 | |
164 | /* If frame is small enough to fit in skb->head, pull it completely. | |
165 | * If not, only pull ieee80211_hdr (including crypto if present, and | |
166 | * an additional 8 bytes for SNAP/ethertype, see below) so that | |
167 | * splice() or TCP coalesce are more efficient. | |
168 | * | |
169 | * Since, in addition, ieee80211_data_to_8023() always pull in at | |
170 | * least 8 bytes (possibly more for mesh) we can do the same here | |
171 | * to save the cost of doing it later. That still doesn't pull in | |
172 | * the actual IP header since the typical case has a SNAP header. | |
173 | * If the latter changes (there are efforts in the standards group | |
174 | * to do so) we should revisit this and ieee80211_data_to_8023(). | |
175 | */ | |
e29cc6b9 SS |
176 | headlen = (len <= skb_tailroom(skb)) ? len : |
177 | hdrlen + crypt_len + 8; | |
780e87c2 | 178 | |
e29cc6b9 SS |
179 | /* The firmware may align the packet to DWORD. |
180 | * The padding is inserted after the IV. | |
181 | * After copying the header + IV skip the padding if | |
182 | * present before copying packet data. | |
183 | */ | |
184 | hdrlen += crypt_len; | |
59ae1d12 JB |
185 | skb_put_data(skb, hdr, hdrlen); |
186 | skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen); | |
e29cc6b9 SS |
187 | |
188 | fraglen = len - headlen; | |
780e87c2 JB |
189 | |
190 | if (fraglen) { | |
e29cc6b9 | 191 | int offset = (void *)hdr + headlen + pad_len - |
780e87c2 JB |
192 | rxb_addr(rxb) + rxb_offset(rxb); |
193 | ||
194 | skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, | |
195 | fraglen, rxb->truesize); | |
196 | } | |
f5e28eac | 197 | } |
780e87c2 | 198 | |
f5e28eac JB |
199 | /* iwl_mvm_pass_packet_to_mac80211 - passes the packet for mac80211 */ |
200 | static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |
201 | struct napi_struct *napi, | |
202 | struct sk_buff *skb, int queue, | |
203 | struct ieee80211_sta *sta) | |
204 | { | |
205 | if (iwl_mvm_check_pn(mvm, skb, queue, sta)) | |
206 | kfree_skb(skb); | |
207 | else | |
43ec72b7 | 208 | ieee80211_rx_napi(mvm->hw, sta, skb, napi); |
780e87c2 JB |
209 | } |
210 | ||
211 | static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, | |
212 | struct iwl_rx_mpdu_desc *desc, | |
213 | struct ieee80211_rx_status *rx_status) | |
214 | { | |
d56a7801 | 215 | int energy_a, energy_b, max_energy; |
c4e45c84 | 216 | u32 rate_flags = le32_to_cpu(desc->rate_n_flags); |
780e87c2 JB |
217 | |
218 | energy_a = desc->energy_a; | |
219 | energy_a = energy_a ? -energy_a : S8_MIN; | |
220 | energy_b = desc->energy_b; | |
221 | energy_b = energy_b ? -energy_b : S8_MIN; | |
780e87c2 | 222 | max_energy = max(energy_a, energy_b); |
780e87c2 | 223 | |
d56a7801 SS |
224 | IWL_DEBUG_STATS(mvm, "energy In A %d B %d, and max %d\n", |
225 | energy_a, energy_b, max_energy); | |
780e87c2 JB |
226 | |
227 | rx_status->signal = max_energy; | |
c4e45c84 ST |
228 | rx_status->chains = |
229 | (rate_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS; | |
780e87c2 JB |
230 | rx_status->chain_signal[0] = energy_a; |
231 | rx_status->chain_signal[1] = energy_b; | |
d56a7801 | 232 | rx_status->chain_signal[2] = S8_MIN; |
780e87c2 JB |
233 | } |
234 | ||
f5e28eac | 235 | static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, |
780e87c2 | 236 | struct ieee80211_rx_status *stats, |
9d0fc5a5 DS |
237 | struct iwl_rx_mpdu_desc *desc, u32 pkt_flags, |
238 | int queue, u8 *crypt_len) | |
780e87c2 JB |
239 | { |
240 | u16 status = le16_to_cpu(desc->status); | |
241 | ||
242 | if (!ieee80211_has_protected(hdr->frame_control) || | |
243 | (status & IWL_RX_MPDU_STATUS_SEC_MASK) == | |
244 | IWL_RX_MPDU_STATUS_SEC_NONE) | |
245 | return 0; | |
246 | ||
247 | /* TODO: handle packets encrypted with unknown alg */ | |
248 | ||
249 | switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) { | |
250 | case IWL_RX_MPDU_STATUS_SEC_CCM: | |
251 | case IWL_RX_MPDU_STATUS_SEC_GCM: | |
f5e28eac | 252 | BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != IEEE80211_GCMP_PN_LEN); |
780e87c2 JB |
253 | /* alg is CCM: check MIC only */ |
254 | if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) | |
255 | return -1; | |
256 | ||
257 | stats->flag |= RX_FLAG_DECRYPTED; | |
bf190370 SS |
258 | if (pkt_flags & FH_RSCSR_RADA_EN) |
259 | stats->flag |= RX_FLAG_MIC_STRIPPED; | |
780e87c2 JB |
260 | *crypt_len = IEEE80211_CCMP_HDR_LEN; |
261 | return 0; | |
262 | case IWL_RX_MPDU_STATUS_SEC_TKIP: | |
263 | /* Don't drop the frame and decrypt it in SW */ | |
264 | if (!(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK)) | |
265 | return 0; | |
266 | ||
267 | *crypt_len = IEEE80211_TKIP_IV_LEN; | |
268 | /* fall through if TTAK OK */ | |
269 | case IWL_RX_MPDU_STATUS_SEC_WEP: | |
270 | if (!(status & IWL_RX_MPDU_STATUS_ICV_OK)) | |
271 | return -1; | |
272 | ||
273 | stats->flag |= RX_FLAG_DECRYPTED; | |
274 | if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) == | |
275 | IWL_RX_MPDU_STATUS_SEC_WEP) | |
276 | *crypt_len = IEEE80211_WEP_IV_LEN; | |
9d0fc5a5 DS |
277 | |
278 | if (pkt_flags & FH_RSCSR_RADA_EN) | |
279 | stats->flag |= RX_FLAG_ICV_STRIPPED; | |
280 | ||
780e87c2 JB |
281 | return 0; |
282 | case IWL_RX_MPDU_STATUS_SEC_EXT_ENC: | |
283 | if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) | |
284 | return -1; | |
285 | stats->flag |= RX_FLAG_DECRYPTED; | |
286 | return 0; | |
287 | default: | |
baf41bc3 ST |
288 | /* Expected in monitor (not having the keys) */ |
289 | if (!mvm->monitor_on) | |
290 | IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status); | |
780e87c2 JB |
291 | } |
292 | ||
293 | return 0; | |
294 | } | |
295 | ||
296 | static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, | |
297 | struct sk_buff *skb, | |
298 | struct iwl_rx_mpdu_desc *desc) | |
299 | { | |
300 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | |
301 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); | |
b238be07 SS |
302 | u16 flags = le16_to_cpu(desc->l3l4_flags); |
303 | u8 l3_prot = (u8)((flags & IWL_RX_L3L4_L3_PROTO_MASK) >> | |
304 | IWL_RX_L3_PROTO_POS); | |
780e87c2 JB |
305 | |
306 | if (mvmvif->features & NETIF_F_RXCSUM && | |
b238be07 SS |
307 | flags & IWL_RX_L3L4_TCP_UDP_CSUM_OK && |
308 | (flags & IWL_RX_L3L4_IP_HDR_CSUM_OK || | |
309 | l3_prot == IWL_RX_L3_TYPE_IPV6 || | |
310 | l3_prot == IWL_RX_L3_TYPE_IPV6_FRAG)) | |
780e87c2 JB |
311 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
312 | } | |
313 | ||
a571f5f6 SS |
314 | /* |
315 | * returns true if a packet outside BA session is a duplicate and | |
316 | * should be dropped | |
317 | */ | |
318 | static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, | |
319 | struct ieee80211_rx_status *rx_status, | |
320 | struct ieee80211_hdr *hdr, | |
321 | struct iwl_rx_mpdu_desc *desc) | |
322 | { | |
323 | struct iwl_mvm_sta *mvm_sta; | |
324 | struct iwl_mvm_rxq_dup_data *dup_data; | |
325 | u8 baid, tid, sub_frame_idx; | |
326 | ||
327 | if (WARN_ON(IS_ERR_OR_NULL(sta))) | |
328 | return false; | |
329 | ||
330 | baid = (le32_to_cpu(desc->reorder_data) & | |
331 | IWL_RX_MPDU_REORDER_BAID_MASK) >> | |
332 | IWL_RX_MPDU_REORDER_BAID_SHIFT; | |
333 | ||
334 | if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) | |
335 | return false; | |
336 | ||
337 | mvm_sta = iwl_mvm_sta_from_mac80211(sta); | |
338 | dup_data = &mvm_sta->dup_data[queue]; | |
339 | ||
340 | /* | |
341 | * Drop duplicate 802.11 retransmissions | |
342 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") | |
343 | */ | |
344 | if (ieee80211_is_ctl(hdr->frame_control) || | |
345 | ieee80211_is_qos_nullfunc(hdr->frame_control) || | |
346 | is_multicast_ether_addr(hdr->addr1)) { | |
347 | rx_status->flag |= RX_FLAG_DUP_VALIDATED; | |
348 | return false; | |
349 | } | |
350 | ||
351 | if (ieee80211_is_data_qos(hdr->frame_control)) | |
352 | /* frame has qos control */ | |
353 | tid = *ieee80211_get_qos_ctl(hdr) & | |
354 | IEEE80211_QOS_CTL_TID_MASK; | |
355 | else | |
356 | tid = IWL_MAX_TID_COUNT; | |
357 | ||
358 | /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */ | |
359 | sub_frame_idx = desc->amsdu_info & IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; | |
360 | ||
361 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && | |
362 | dup_data->last_seq[tid] == hdr->seq_ctrl && | |
363 | dup_data->last_sub_frame[tid] >= sub_frame_idx)) | |
364 | return true; | |
365 | ||
366 | dup_data->last_seq[tid] = hdr->seq_ctrl; | |
367 | dup_data->last_sub_frame[tid] = sub_frame_idx; | |
368 | ||
369 | rx_status->flag |= RX_FLAG_DUP_VALIDATED; | |
370 | ||
371 | return false; | |
372 | } | |
373 | ||
94bb4481 SS |
374 | int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, |
375 | const u8 *data, u32 count) | |
376 | { | |
377 | struct iwl_rxq_sync_cmd *cmd; | |
378 | u32 data_size = sizeof(*cmd) + count; | |
379 | int ret; | |
380 | ||
381 | /* should be DWORD aligned */ | |
382 | if (WARN_ON(count & 3 || count > IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE)) | |
383 | return -EINVAL; | |
384 | ||
385 | cmd = kzalloc(data_size, GFP_KERNEL); | |
386 | if (!cmd) | |
387 | return -ENOMEM; | |
388 | ||
389 | cmd->rxq_mask = cpu_to_le32(rxq_mask); | |
390 | cmd->count = cpu_to_le32(count); | |
391 | cmd->flags = 0; | |
392 | memcpy(cmd->payload, data, count); | |
393 | ||
394 | ret = iwl_mvm_send_cmd_pdu(mvm, | |
395 | WIDE_ID(DATA_PATH_GROUP, | |
396 | TRIGGER_RX_QUEUES_NOTIF_CMD), | |
397 | 0, data_size, cmd); | |
398 | ||
399 | kfree(cmd); | |
400 | return ret; | |
401 | } | |
402 | ||
74dd1764 SS |
403 | /* |
404 | * Returns true if sn2 - buffer_size < sn1 < sn2. | |
405 | * To be used only in order to compare reorder buffer head with NSSN. | |
406 | * We fully trust NSSN unless it is behind us due to reorder timeout. | |
407 | * Reorder timeout can only bring us up to buffer_size SNs ahead of NSSN. | |
408 | */ | |
409 | static bool iwl_mvm_is_sn_less(u16 sn1, u16 sn2, u16 buffer_size) | |
410 | { | |
411 | return ieee80211_sn_less(sn1, sn2) && | |
412 | !ieee80211_sn_less(sn1, sn2 - buffer_size); | |
413 | } | |
414 | ||
0690405f SS |
415 | #define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10) |
416 | ||
b915c101 SS |
417 | static void iwl_mvm_release_frames(struct iwl_mvm *mvm, |
418 | struct ieee80211_sta *sta, | |
419 | struct napi_struct *napi, | |
76f4a85e | 420 | struct iwl_mvm_baid_data *baid_data, |
b915c101 SS |
421 | struct iwl_mvm_reorder_buffer *reorder_buf, |
422 | u16 nssn) | |
423 | { | |
dfdddd92 JB |
424 | struct iwl_mvm_reorder_buf_entry *entries = |
425 | &baid_data->entries[reorder_buf->queue * | |
426 | baid_data->entries_per_queue]; | |
b915c101 SS |
427 | u16 ssn = reorder_buf->head_sn; |
428 | ||
0690405f SS |
429 | lockdep_assert_held(&reorder_buf->lock); |
430 | ||
431 | /* ignore nssn smaller than head sn - this can happen due to timeout */ | |
74dd1764 | 432 | if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size)) |
5351f9ab | 433 | goto set_timer; |
0690405f | 434 | |
74dd1764 | 435 | while (iwl_mvm_is_sn_less(ssn, nssn, reorder_buf->buf_size)) { |
b915c101 | 436 | int index = ssn % reorder_buf->buf_size; |
dfdddd92 | 437 | struct sk_buff_head *skb_list = &entries[index].e.frames; |
b915c101 SS |
438 | struct sk_buff *skb; |
439 | ||
440 | ssn = ieee80211_sn_inc(ssn); | |
441 | ||
5a710b86 SS |
442 | /* |
443 | * Empty the list. Will have more than one frame for A-MSDU. | |
444 | * Empty list is valid as well since nssn indicates frames were | |
445 | * received. | |
446 | */ | |
b915c101 SS |
447 | while ((skb = __skb_dequeue(skb_list))) { |
448 | iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, | |
449 | reorder_buf->queue, | |
450 | sta); | |
451 | reorder_buf->num_stored--; | |
452 | } | |
453 | } | |
454 | reorder_buf->head_sn = nssn; | |
0690405f | 455 | |
5351f9ab | 456 | set_timer: |
0690405f SS |
457 | if (reorder_buf->num_stored && !reorder_buf->removed) { |
458 | u16 index = reorder_buf->head_sn % reorder_buf->buf_size; | |
459 | ||
dfdddd92 | 460 | while (skb_queue_empty(&entries[index].e.frames)) |
0690405f SS |
461 | index = (index + 1) % reorder_buf->buf_size; |
462 | /* modify timer to match next frame's expiration time */ | |
463 | mod_timer(&reorder_buf->reorder_timer, | |
dfdddd92 | 464 | entries[index].e.reorder_time + 1 + |
0690405f SS |
465 | RX_REORDER_BUF_TIMEOUT_MQ); |
466 | } else { | |
467 | del_timer(&reorder_buf->reorder_timer); | |
468 | } | |
469 | } | |
470 | ||
8cef5344 | 471 | void iwl_mvm_reorder_timer_expired(struct timer_list *t) |
0690405f | 472 | { |
8cef5344 | 473 | struct iwl_mvm_reorder_buffer *buf = from_timer(buf, t, reorder_timer); |
dfdddd92 JB |
474 | struct iwl_mvm_baid_data *baid_data = |
475 | iwl_mvm_baid_data_from_reorder_buf(buf); | |
476 | struct iwl_mvm_reorder_buf_entry *entries = | |
477 | &baid_data->entries[buf->queue * baid_data->entries_per_queue]; | |
0690405f SS |
478 | int i; |
479 | u16 sn = 0, index = 0; | |
480 | bool expired = false; | |
9c36fd71 | 481 | bool cont = false; |
0690405f | 482 | |
9b856836 | 483 | spin_lock(&buf->lock); |
0690405f SS |
484 | |
485 | if (!buf->num_stored || buf->removed) { | |
9b856836 | 486 | spin_unlock(&buf->lock); |
0690405f SS |
487 | return; |
488 | } | |
489 | ||
490 | for (i = 0; i < buf->buf_size ; i++) { | |
491 | index = (buf->head_sn + i) % buf->buf_size; | |
492 | ||
dfdddd92 | 493 | if (skb_queue_empty(&entries[index].e.frames)) { |
9c36fd71 SS |
494 | /* |
495 | * If there is a hole and the next frame didn't expire | |
496 | * we want to break and not advance SN | |
497 | */ | |
498 | cont = false; | |
0690405f | 499 | continue; |
9c36fd71 | 500 | } |
dfdddd92 JB |
501 | if (!cont && |
502 | !time_after(jiffies, entries[index].e.reorder_time + | |
9c36fd71 | 503 | RX_REORDER_BUF_TIMEOUT_MQ)) |
0690405f | 504 | break; |
9c36fd71 | 505 | |
0690405f | 506 | expired = true; |
9c36fd71 SS |
507 | /* continue until next hole after this expired frames */ |
508 | cont = true; | |
0690405f SS |
509 | sn = ieee80211_sn_add(buf->head_sn, i + 1); |
510 | } | |
511 | ||
512 | if (expired) { | |
513 | struct ieee80211_sta *sta; | |
528a542a | 514 | struct iwl_mvm_sta *mvmsta; |
3f1c4c58 | 515 | u8 sta_id = baid_data->sta_id; |
0690405f SS |
516 | |
517 | rcu_read_lock(); | |
3f1c4c58 | 518 | sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[sta_id]); |
528a542a EG |
519 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
520 | ||
0690405f | 521 | /* SN is set to the last expired frame + 1 */ |
35263a03 SS |
522 | IWL_DEBUG_HT(buf->mvm, |
523 | "Releasing expired frames for sta %u, sn %d\n", | |
3f1c4c58 | 524 | sta_id, sn); |
528a542a | 525 | iwl_mvm_event_frame_timeout_callback(buf->mvm, mvmsta->vif, |
3f1c4c58 | 526 | sta, baid_data->tid); |
76f4a85e | 527 | iwl_mvm_release_frames(buf->mvm, sta, NULL, baid_data, buf, sn); |
0690405f | 528 | rcu_read_unlock(); |
aeb8012c | 529 | } else { |
0690405f SS |
530 | /* |
531 | * If no frame expired and there are stored frames, index is now | |
532 | * pointing to the first unexpired frame - modify timer | |
533 | * accordingly to this frame. | |
534 | */ | |
535 | mod_timer(&buf->reorder_timer, | |
dfdddd92 | 536 | entries[index].e.reorder_time + |
0690405f SS |
537 | 1 + RX_REORDER_BUF_TIMEOUT_MQ); |
538 | } | |
9b856836 | 539 | spin_unlock(&buf->lock); |
b915c101 SS |
540 | } |
541 | ||
542 | static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue, | |
543 | struct iwl_mvm_delba_data *data) | |
544 | { | |
545 | struct iwl_mvm_baid_data *ba_data; | |
546 | struct ieee80211_sta *sta; | |
547 | struct iwl_mvm_reorder_buffer *reorder_buf; | |
548 | u8 baid = data->baid; | |
549 | ||
fd659f8e | 550 | if (WARN_ONCE(baid >= IWL_MAX_BAID, "invalid BAID: %x\n", baid)) |
b915c101 SS |
551 | return; |
552 | ||
553 | rcu_read_lock(); | |
554 | ||
555 | ba_data = rcu_dereference(mvm->baid_map[baid]); | |
556 | if (WARN_ON_ONCE(!ba_data)) | |
557 | goto out; | |
558 | ||
559 | sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]); | |
560 | if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) | |
561 | goto out; | |
562 | ||
563 | reorder_buf = &ba_data->reorder_buf[queue]; | |
564 | ||
565 | /* release all frames that are in the reorder buffer to the stack */ | |
0690405f | 566 | spin_lock_bh(&reorder_buf->lock); |
76f4a85e | 567 | iwl_mvm_release_frames(mvm, sta, NULL, ba_data, reorder_buf, |
b915c101 SS |
568 | ieee80211_sn_add(reorder_buf->head_sn, |
569 | reorder_buf->buf_size)); | |
0690405f SS |
570 | spin_unlock_bh(&reorder_buf->lock); |
571 | del_timer_sync(&reorder_buf->reorder_timer); | |
b915c101 SS |
572 | |
573 | out: | |
574 | rcu_read_unlock(); | |
575 | } | |
576 | ||
94bb4481 SS |
577 | void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, |
578 | int queue) | |
579 | { | |
580 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | |
581 | struct iwl_rxq_sync_notification *notif; | |
582 | struct iwl_mvm_internal_rxq_notif *internal_notif; | |
583 | ||
584 | notif = (void *)pkt->data; | |
585 | internal_notif = (void *)notif->payload; | |
586 | ||
d0ff5d22 SS |
587 | if (internal_notif->sync) { |
588 | if (mvm->queue_sync_cookie != internal_notif->cookie) { | |
0636b938 SS |
589 | WARN_ONCE(1, |
590 | "Received expired RX queue sync message\n"); | |
d0ff5d22 SS |
591 | return; |
592 | } | |
3a732c65 SS |
593 | if (!atomic_dec_return(&mvm->queue_sync_counter)) |
594 | wake_up(&mvm->rx_sync_waitq); | |
d0ff5d22 SS |
595 | } |
596 | ||
597 | switch (internal_notif->type) { | |
598 | case IWL_MVM_RXQ_EMPTY: | |
0636b938 | 599 | break; |
94bb4481 | 600 | case IWL_MVM_RXQ_NOTIF_DEL_BA: |
b915c101 | 601 | iwl_mvm_del_ba(mvm, queue, (void *)internal_notif->data); |
94bb4481 SS |
602 | break; |
603 | default: | |
604 | WARN_ONCE(1, "Invalid identifier %d", internal_notif->type); | |
605 | } | |
606 | } | |
607 | ||
b915c101 SS |
608 | /* |
609 | * Returns true if the MPDU was buffered\dropped, false if it should be passed | |
610 | * to upper layer. | |
611 | */ | |
612 | static bool iwl_mvm_reorder(struct iwl_mvm *mvm, | |
613 | struct napi_struct *napi, | |
614 | int queue, | |
615 | struct ieee80211_sta *sta, | |
616 | struct sk_buff *skb, | |
617 | struct iwl_rx_mpdu_desc *desc) | |
618 | { | |
619 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | |
1f9788f3 | 620 | struct iwl_mvm_sta *mvm_sta; |
b915c101 SS |
621 | struct iwl_mvm_baid_data *baid_data; |
622 | struct iwl_mvm_reorder_buffer *buffer; | |
623 | struct sk_buff *tail; | |
624 | u32 reorder = le32_to_cpu(desc->reorder_data); | |
625 | bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU; | |
e7e14089 SS |
626 | bool last_subframe = |
627 | desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME; | |
b915c101 SS |
628 | u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; |
629 | u8 sub_frame_idx = desc->amsdu_info & | |
630 | IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; | |
dfdddd92 | 631 | struct iwl_mvm_reorder_buf_entry *entries; |
b915c101 SS |
632 | int index; |
633 | u16 nssn, sn; | |
634 | u8 baid; | |
635 | ||
636 | baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK) >> | |
637 | IWL_RX_MPDU_REORDER_BAID_SHIFT; | |
638 | ||
8ec8ed43 JB |
639 | /* |
640 | * This also covers the case of receiving a Block Ack Request | |
641 | * outside a BA session; we'll pass it to mac80211 and that | |
642 | * then sends a delBA action frame. | |
643 | */ | |
b915c101 SS |
644 | if (baid == IWL_RX_REORDER_DATA_INVALID_BAID) |
645 | return false; | |
646 | ||
647 | /* no sta yet */ | |
417795a3 SS |
648 | if (WARN_ONCE(IS_ERR_OR_NULL(sta), |
649 | "Got valid BAID without a valid station assigned\n")) | |
b915c101 SS |
650 | return false; |
651 | ||
1f9788f3 LC |
652 | mvm_sta = iwl_mvm_sta_from_mac80211(sta); |
653 | ||
9a73a7d2 SS |
654 | /* not a data packet or a bar */ |
655 | if (!ieee80211_is_back_req(hdr->frame_control) && | |
656 | (!ieee80211_is_data_qos(hdr->frame_control) || | |
657 | is_multicast_ether_addr(hdr->addr1))) | |
b915c101 SS |
658 | return false; |
659 | ||
660 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | |
661 | return false; | |
662 | ||
663 | baid_data = rcu_dereference(mvm->baid_map[baid]); | |
5d43eab6 | 664 | if (!baid_data) { |
a600852a EG |
665 | IWL_DEBUG_RX(mvm, |
666 | "Got valid BAID but no baid allocated, bypass the re-ordering buffer. Baid %d reorder 0x%x\n", | |
667 | baid, reorder); | |
b915c101 | 668 | return false; |
5d43eab6 SS |
669 | } |
670 | ||
b915c101 SS |
671 | if (WARN(tid != baid_data->tid || mvm_sta->sta_id != baid_data->sta_id, |
672 | "baid 0x%x is mapped to sta:%d tid:%d, but was received for sta:%d tid:%d\n", | |
673 | baid, baid_data->sta_id, baid_data->tid, mvm_sta->sta_id, | |
674 | tid)) | |
675 | return false; | |
676 | ||
677 | nssn = reorder & IWL_RX_MPDU_REORDER_NSSN_MASK; | |
678 | sn = (reorder & IWL_RX_MPDU_REORDER_SN_MASK) >> | |
679 | IWL_RX_MPDU_REORDER_SN_SHIFT; | |
680 | ||
681 | buffer = &baid_data->reorder_buf[queue]; | |
dfdddd92 | 682 | entries = &baid_data->entries[queue * baid_data->entries_per_queue]; |
b915c101 | 683 | |
0690405f SS |
684 | spin_lock_bh(&buffer->lock); |
685 | ||
5d43eab6 SS |
686 | if (!buffer->valid) { |
687 | if (reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN) { | |
688 | spin_unlock_bh(&buffer->lock); | |
689 | return false; | |
690 | } | |
691 | buffer->valid = true; | |
692 | } | |
693 | ||
9a73a7d2 | 694 | if (ieee80211_is_back_req(hdr->frame_control)) { |
76f4a85e | 695 | iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, nssn); |
9a73a7d2 SS |
696 | goto drop; |
697 | } | |
698 | ||
b915c101 SS |
699 | /* |
700 | * If there was a significant jump in the nssn - adjust. | |
701 | * If the SN is smaller than the NSSN it might need to first go into | |
702 | * the reorder buffer, in which case we just release up to it and the | |
5f90472c SS |
703 | * rest of the function will take care of storing it and releasing up to |
704 | * the nssn | |
b915c101 | 705 | */ |
74dd1764 | 706 | if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size, |
5f90472c SS |
707 | buffer->buf_size) || |
708 | !ieee80211_sn_less(sn, buffer->head_sn + buffer->buf_size)) { | |
b915c101 SS |
709 | u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn; |
710 | ||
76f4a85e JB |
711 | iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, |
712 | min_sn); | |
b915c101 SS |
713 | } |
714 | ||
715 | /* drop any oudated packets */ | |
716 | if (ieee80211_sn_less(sn, buffer->head_sn)) | |
717 | goto drop; | |
718 | ||
719 | /* release immediately if allowed by nssn and no stored frames */ | |
720 | if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { | |
74dd1764 | 721 | if (iwl_mvm_is_sn_less(buffer->head_sn, nssn, |
e7e14089 SS |
722 | buffer->buf_size) && |
723 | (!amsdu || last_subframe)) | |
0690405f | 724 | buffer->head_sn = nssn; |
b915c101 | 725 | /* No need to update AMSDU last SN - we are moving the head */ |
0690405f | 726 | spin_unlock_bh(&buffer->lock); |
b915c101 SS |
727 | return false; |
728 | } | |
729 | ||
14a1f85b SS |
730 | /* |
731 | * release immediately if there are no stored frames, and the sn is | |
732 | * equal to the head. | |
733 | * This can happen due to reorder timer, where NSSN is behind head_sn. | |
734 | * When we released everything, and we got the next frame in the | |
735 | * sequence, according to the NSSN we can't release immediately, | |
736 | * while technically there is no hole and we can move forward. | |
737 | */ | |
738 | if (!buffer->num_stored && sn == buffer->head_sn) { | |
739 | if (!amsdu || last_subframe) | |
740 | buffer->head_sn = ieee80211_sn_inc(buffer->head_sn); | |
741 | /* No need to update AMSDU last SN - we are moving the head */ | |
742 | spin_unlock_bh(&buffer->lock); | |
743 | return false; | |
744 | } | |
745 | ||
b915c101 SS |
746 | index = sn % buffer->buf_size; |
747 | ||
748 | /* | |
749 | * Check if we already stored this frame | |
750 | * As AMSDU is either received or not as whole, logic is simple: | |
751 | * If we have frames in that position in the buffer and the last frame | |
752 | * originated from AMSDU had a different SN then it is a retransmission. | |
753 | * If it is the same SN then if the subframe index is incrementing it | |
754 | * is the same AMSDU - otherwise it is a retransmission. | |
755 | */ | |
dfdddd92 | 756 | tail = skb_peek_tail(&entries[index].e.frames); |
b915c101 SS |
757 | if (tail && !amsdu) |
758 | goto drop; | |
759 | else if (tail && (sn != buffer->last_amsdu || | |
760 | buffer->last_sub_index >= sub_frame_idx)) | |
761 | goto drop; | |
762 | ||
763 | /* put in reorder buffer */ | |
dfdddd92 | 764 | __skb_queue_tail(&entries[index].e.frames, skb); |
b915c101 | 765 | buffer->num_stored++; |
dfdddd92 | 766 | entries[index].e.reorder_time = jiffies; |
0690405f | 767 | |
b915c101 SS |
768 | if (amsdu) { |
769 | buffer->last_amsdu = sn; | |
770 | buffer->last_sub_index = sub_frame_idx; | |
771 | } | |
772 | ||
e7e14089 SS |
773 | /* |
774 | * We cannot trust NSSN for AMSDU sub-frames that are not the last. | |
775 | * The reason is that NSSN advances on the first sub-frame, and may | |
776 | * cause the reorder buffer to advance before all the sub-frames arrive. | |
777 | * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with | |
778 | * SN 1. NSSN for first sub frame will be 3 with the result of driver | |
779 | * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is | |
780 | * already ahead and it will be dropped. | |
781 | * If the last sub-frame is not on this queue - we will get frame | |
782 | * release notification with up to date NSSN. | |
783 | */ | |
784 | if (!amsdu || last_subframe) | |
76f4a85e | 785 | iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, nssn); |
e7e14089 | 786 | |
0690405f | 787 | spin_unlock_bh(&buffer->lock); |
b915c101 SS |
788 | return true; |
789 | ||
790 | drop: | |
791 | kfree_skb(skb); | |
0690405f | 792 | spin_unlock_bh(&buffer->lock); |
b915c101 SS |
793 | return true; |
794 | } | |
795 | ||
5d43eab6 SS |
796 | static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, |
797 | u32 reorder_data, u8 baid) | |
10b2b201 SS |
798 | { |
799 | unsigned long now = jiffies; | |
800 | unsigned long timeout; | |
801 | struct iwl_mvm_baid_data *data; | |
802 | ||
803 | rcu_read_lock(); | |
804 | ||
805 | data = rcu_dereference(mvm->baid_map[baid]); | |
5d43eab6 | 806 | if (!data) { |
a600852a EG |
807 | IWL_DEBUG_RX(mvm, |
808 | "Got valid BAID but no baid allocated, bypass the re-ordering buffer. Baid %d reorder 0x%x\n", | |
809 | baid, reorder_data); | |
10b2b201 | 810 | goto out; |
5d43eab6 | 811 | } |
10b2b201 SS |
812 | |
813 | if (!data->timeout) | |
814 | goto out; | |
815 | ||
816 | timeout = data->timeout; | |
817 | /* | |
818 | * Do not update last rx all the time to avoid cache bouncing | |
819 | * between the rx queues. | |
820 | * Update it every timeout. Worst case is the session will | |
821 | * expire after ~ 2 * timeout, which doesn't matter that much. | |
822 | */ | |
823 | if (time_before(data->last_rx + TU_TO_JIFFIES(timeout), now)) | |
824 | /* Update is atomic */ | |
825 | data->last_rx = now; | |
826 | ||
827 | out: | |
828 | rcu_read_unlock(); | |
829 | } | |
830 | ||
780e87c2 JB |
831 | void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, |
832 | struct iwl_rx_cmd_buffer *rxb, int queue) | |
833 | { | |
834 | struct ieee80211_rx_status *rx_status; | |
835 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | |
836 | struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; | |
0c1c6e37 | 837 | struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc)); |
780e87c2 JB |
838 | u32 len = le16_to_cpu(desc->mpdu_len); |
839 | u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags); | |
fbe41127 | 840 | u16 phy_info = le16_to_cpu(desc->phy_info); |
780e87c2 JB |
841 | struct ieee80211_sta *sta = NULL; |
842 | struct sk_buff *skb; | |
780e87c2 JB |
843 | u8 crypt_len = 0; |
844 | ||
364a1ab9 SM |
845 | if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) |
846 | return; | |
847 | ||
780e87c2 JB |
848 | /* Dont use dev_alloc_skb(), we'll have enough headroom once |
849 | * ieee80211_hdr pulled. | |
850 | */ | |
851 | skb = alloc_skb(128, GFP_ATOMIC); | |
852 | if (!skb) { | |
853 | IWL_ERR(mvm, "alloc_skb failed\n"); | |
854 | return; | |
855 | } | |
856 | ||
857 | rx_status = IEEE80211_SKB_RXCB(skb); | |
858 | ||
9d0fc5a5 DS |
859 | if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, |
860 | le32_to_cpu(pkt->len_n_flags), queue, | |
861 | &crypt_len)) { | |
780e87c2 JB |
862 | kfree_skb(skb); |
863 | return; | |
864 | } | |
865 | ||
866 | /* | |
867 | * Keep packets with CRC errors (and with overrun) for monitor mode | |
868 | * (otherwise the firmware discards them) but mark them as bad. | |
869 | */ | |
870 | if (!(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_CRC_OK)) || | |
871 | !(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_OVERRUN_OK))) { | |
872 | IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", | |
873 | le16_to_cpu(desc->status)); | |
874 | rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; | |
875 | } | |
fbe41127 SS |
876 | /* set the preamble flag if appropriate */ |
877 | if (phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) | |
7fdd69c5 | 878 | rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE; |
fbe41127 SS |
879 | |
880 | if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) { | |
881 | rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise); | |
882 | /* TSF as indicated by the firmware is at INA time */ | |
883 | rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; | |
884 | } | |
780e87c2 | 885 | rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise); |
57fbcce3 JB |
886 | rx_status->band = desc->channel > 14 ? NL80211_BAND_5GHZ : |
887 | NL80211_BAND_2GHZ; | |
780e87c2 JB |
888 | rx_status->freq = ieee80211_channel_to_frequency(desc->channel, |
889 | rx_status->band); | |
890 | iwl_mvm_get_signal_strength(mvm, desc, rx_status); | |
fbe41127 SS |
891 | |
892 | /* update aggregation data for monitor sake on default queue */ | |
893 | if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { | |
894 | bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; | |
895 | ||
896 | rx_status->flag |= RX_FLAG_AMPDU_DETAILS; | |
897 | rx_status->ampdu_reference = mvm->ampdu_ref; | |
898 | /* toggle is switched whenever new aggregation starts */ | |
899 | if (toggle_bit != mvm->ampdu_toggle) { | |
900 | mvm->ampdu_ref++; | |
901 | mvm->ampdu_toggle = toggle_bit; | |
902 | } | |
903 | } | |
780e87c2 JB |
904 | |
905 | rcu_read_lock(); | |
906 | ||
c67a3d05 | 907 | if (desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) { |
780e87c2 JB |
908 | u8 id = desc->sta_id_flags & IWL_RX_MPDU_SIF_STA_ID_MASK; |
909 | ||
0ae98812 | 910 | if (!WARN_ON_ONCE(id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) { |
780e87c2 JB |
911 | sta = rcu_dereference(mvm->fw_id_to_mac_id[id]); |
912 | if (IS_ERR(sta)) | |
913 | sta = NULL; | |
914 | } | |
915 | } else if (!is_multicast_ether_addr(hdr->addr2)) { | |
916 | /* | |
917 | * This is fine since we prevent two stations with the same | |
918 | * address from being added. | |
919 | */ | |
920 | sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL); | |
921 | } | |
922 | ||
923 | if (sta) { | |
924 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | |
d3a108a4 AO |
925 | struct ieee80211_vif *tx_blocked_vif = |
926 | rcu_dereference(mvm->csa_tx_blocked_vif); | |
10b2b201 SS |
927 | u8 baid = (u8)((le32_to_cpu(desc->reorder_data) & |
928 | IWL_RX_MPDU_REORDER_BAID_MASK) >> | |
929 | IWL_RX_MPDU_REORDER_BAID_SHIFT); | |
780e87c2 JB |
930 | |
931 | /* | |
932 | * We have tx blocked stations (with CS bit). If we heard | |
933 | * frames from a blocked station on a new channel we can | |
934 | * TX to it again. | |
935 | */ | |
d3a108a4 AO |
936 | if (unlikely(tx_blocked_vif) && |
937 | tx_blocked_vif == mvmsta->vif) { | |
938 | struct iwl_mvm_vif *mvmvif = | |
939 | iwl_mvm_vif_from_mac80211(tx_blocked_vif); | |
940 | ||
941 | if (mvmvif->csa_target_freq == rx_status->freq) | |
942 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, | |
943 | false); | |
944 | } | |
780e87c2 JB |
945 | |
946 | rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); | |
947 | ||
948 | if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) && | |
949 | ieee80211_is_beacon(hdr->frame_control)) { | |
950 | struct iwl_fw_dbg_trigger_tlv *trig; | |
951 | struct iwl_fw_dbg_trigger_low_rssi *rssi_trig; | |
952 | bool trig_check; | |
953 | s32 rssi; | |
954 | ||
955 | trig = iwl_fw_dbg_get_trigger(mvm->fw, | |
956 | FW_DBG_TRIGGER_RSSI); | |
957 | rssi_trig = (void *)trig->data; | |
958 | rssi = le32_to_cpu(rssi_trig->rssi); | |
959 | ||
960 | trig_check = | |
7174beb6 JB |
961 | iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, |
962 | ieee80211_vif_to_wdev(mvmsta->vif), | |
780e87c2 JB |
963 | trig); |
964 | if (trig_check && rx_status->signal < rssi) | |
7174beb6 JB |
965 | iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, |
966 | NULL); | |
780e87c2 JB |
967 | } |
968 | ||
780e87c2 JB |
969 | if (ieee80211_is_data(hdr->frame_control)) |
970 | iwl_mvm_rx_csum(sta, skb, desc); | |
a571f5f6 SS |
971 | |
972 | if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { | |
973 | kfree_skb(skb); | |
cb2de6bb | 974 | goto out; |
a571f5f6 | 975 | } |
62d23403 SS |
976 | |
977 | /* | |
978 | * Our hardware de-aggregates AMSDUs but copies the mac header | |
979 | * as it to the de-aggregated MPDUs. We need to turn off the | |
980 | * AMSDU bit in the QoS control ourselves. | |
9dfa2151 | 981 | * In addition, HW reverses addr3 and addr4 - reverse it back. |
62d23403 SS |
982 | */ |
983 | if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) && | |
984 | !WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) { | |
a56cb4f0 | 985 | int i; |
62d23403 | 986 | u8 *qc = ieee80211_get_qos_ctl(hdr); |
a56cb4f0 | 987 | u8 mac_addr[ETH_ALEN]; |
62d23403 SS |
988 | |
989 | *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; | |
a56cb4f0 SS |
990 | |
991 | for (i = 0; i < ETH_ALEN; i++) | |
992 | mac_addr[i] = hdr->addr3[ETH_ALEN - i - 1]; | |
993 | ether_addr_copy(hdr->addr3, mac_addr); | |
9dfa2151 SS |
994 | |
995 | if (ieee80211_has_a4(hdr->frame_control)) { | |
996 | for (i = 0; i < ETH_ALEN; i++) | |
997 | mac_addr[i] = | |
998 | hdr->addr4[ETH_ALEN - i - 1]; | |
999 | ether_addr_copy(hdr->addr4, mac_addr); | |
1000 | } | |
62d23403 | 1001 | } |
5d43eab6 SS |
1002 | if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) { |
1003 | u32 reorder_data = le32_to_cpu(desc->reorder_data); | |
1004 | ||
1005 | iwl_mvm_agg_rx_received(mvm, reorder_data, baid); | |
1006 | } | |
780e87c2 JB |
1007 | } |
1008 | ||
780e87c2 JB |
1009 | /* Set up the HT phy flags */ |
1010 | switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { | |
1011 | case RATE_MCS_CHAN_WIDTH_20: | |
1012 | break; | |
1013 | case RATE_MCS_CHAN_WIDTH_40: | |
da6a4352 | 1014 | rx_status->bw = RATE_INFO_BW_40; |
780e87c2 JB |
1015 | break; |
1016 | case RATE_MCS_CHAN_WIDTH_80: | |
da6a4352 | 1017 | rx_status->bw = RATE_INFO_BW_80; |
780e87c2 JB |
1018 | break; |
1019 | case RATE_MCS_CHAN_WIDTH_160: | |
da6a4352 | 1020 | rx_status->bw = RATE_INFO_BW_160; |
780e87c2 JB |
1021 | break; |
1022 | } | |
1023 | if (rate_n_flags & RATE_MCS_SGI_MSK) | |
7fdd69c5 | 1024 | rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; |
780e87c2 | 1025 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) |
7fdd69c5 | 1026 | rx_status->enc_flags |= RX_ENC_FLAG_HT_GF; |
780e87c2 | 1027 | if (rate_n_flags & RATE_MCS_LDPC_MSK) |
7fdd69c5 | 1028 | rx_status->enc_flags |= RX_ENC_FLAG_LDPC; |
780e87c2 | 1029 | if (rate_n_flags & RATE_MCS_HT_MSK) { |
77e40945 | 1030 | u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> |
780e87c2 | 1031 | RATE_MCS_STBC_POS; |
da6a4352 | 1032 | rx_status->encoding = RX_ENC_HT; |
780e87c2 | 1033 | rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; |
7fdd69c5 | 1034 | rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; |
780e87c2 | 1035 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { |
77e40945 | 1036 | u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> |
780e87c2 | 1037 | RATE_MCS_STBC_POS; |
8613c948 | 1038 | rx_status->nss = |
780e87c2 JB |
1039 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> |
1040 | RATE_VHT_MCS_NSS_POS) + 1; | |
1041 | rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; | |
da6a4352 | 1042 | rx_status->encoding = RX_ENC_VHT; |
7fdd69c5 | 1043 | rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; |
780e87c2 | 1044 | if (rate_n_flags & RATE_MCS_BF_MSK) |
7fdd69c5 | 1045 | rx_status->enc_flags |= RX_ENC_FLAG_BF; |
780e87c2 | 1046 | } else { |
cb2de6bb SS |
1047 | int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, |
1048 | rx_status->band); | |
1049 | ||
1050 | if (WARN(rate < 0 || rate > 0xFF, | |
1051 | "Invalid rate flags 0x%x, band %d,\n", | |
1052 | rate_n_flags, rx_status->band)) { | |
1053 | kfree_skb(skb); | |
1054 | goto out; | |
1055 | } | |
1056 | rx_status->rate_idx = rate; | |
1057 | ||
780e87c2 JB |
1058 | } |
1059 | ||
fbe41127 SS |
1060 | /* management stuff on default queue */ |
1061 | if (!queue) { | |
1062 | if (unlikely((ieee80211_is_beacon(hdr->frame_control) || | |
1063 | ieee80211_is_probe_resp(hdr->frame_control)) && | |
1064 | mvm->sched_scan_pass_all == | |
1065 | SCHED_SCAN_PASS_ALL_ENABLED)) | |
1066 | mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND; | |
1067 | ||
1068 | if (unlikely(ieee80211_is_beacon(hdr->frame_control) || | |
1069 | ieee80211_is_probe_resp(hdr->frame_control))) | |
1070 | rx_status->boottime_ns = ktime_get_boot_ns(); | |
1071 | } | |
780e87c2 | 1072 | |
f5e28eac | 1073 | iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb); |
b915c101 SS |
1074 | if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc)) |
1075 | iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta); | |
cb2de6bb | 1076 | out: |
f5e28eac | 1077 | rcu_read_unlock(); |
780e87c2 | 1078 | } |
585a6fcc | 1079 | |
a338384b | 1080 | void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, |
585a6fcc SS |
1081 | struct iwl_rx_cmd_buffer *rxb, int queue) |
1082 | { | |
a338384b SS |
1083 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
1084 | struct iwl_frame_release *release = (void *)pkt->data; | |
1085 | struct ieee80211_sta *sta; | |
1086 | struct iwl_mvm_reorder_buffer *reorder_buf; | |
1087 | struct iwl_mvm_baid_data *ba_data; | |
1088 | ||
1089 | int baid = release->baid; | |
1090 | ||
35263a03 SS |
1091 | IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n", |
1092 | release->baid, le16_to_cpu(release->nssn)); | |
1093 | ||
a338384b SS |
1094 | if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID)) |
1095 | return; | |
1096 | ||
1097 | rcu_read_lock(); | |
1098 | ||
1099 | ba_data = rcu_dereference(mvm->baid_map[baid]); | |
1100 | if (WARN_ON_ONCE(!ba_data)) | |
1101 | goto out; | |
1102 | ||
1103 | sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]); | |
1104 | if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) | |
1105 | goto out; | |
1106 | ||
1107 | reorder_buf = &ba_data->reorder_buf[queue]; | |
1108 | ||
1109 | spin_lock_bh(&reorder_buf->lock); | |
76f4a85e | 1110 | iwl_mvm_release_frames(mvm, sta, napi, ba_data, reorder_buf, |
a338384b SS |
1111 | le16_to_cpu(release->nssn)); |
1112 | spin_unlock_bh(&reorder_buf->lock); | |
1113 | ||
1114 | out: | |
1115 | rcu_read_unlock(); | |
585a6fcc | 1116 | } |