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