Commit | Line | Data |
---|---|---|
a84fab3c CL |
1 | /* |
2 | * Atheros CARL9170 driver | |
3 | * | |
4 | * 802.11 & command trap routines | |
5 | * | |
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | |
7 | * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; see the file COPYING. If not, see | |
21 | * http://www.gnu.org/licenses/. | |
22 | * | |
23 | * This file incorporates work covered by the following copyright and | |
24 | * permission notice: | |
25 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | |
26 | * | |
27 | * Permission to use, copy, modify, and/or distribute this software for any | |
28 | * purpose with or without fee is hereby granted, provided that the above | |
29 | * copyright notice and this permission notice appear in all copies. | |
30 | * | |
31 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
32 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
33 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
34 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
35 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
36 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
37 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
38 | */ | |
39 | ||
40 | #include <linux/init.h> | |
41 | #include <linux/slab.h> | |
42 | #include <linux/module.h> | |
43 | #include <linux/etherdevice.h> | |
44 | #include <linux/crc32.h> | |
45 | #include <net/mac80211.h> | |
46 | #include "carl9170.h" | |
47 | #include "hw.h" | |
48 | #include "cmd.h" | |
49 | ||
50 | static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len) | |
51 | { | |
52 | bool restart = false; | |
53 | enum carl9170_restart_reasons reason = CARL9170_RR_NO_REASON; | |
54 | ||
55 | if (len > 3) { | |
56 | if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) { | |
57 | ar->fw.err_counter++; | |
58 | if (ar->fw.err_counter > 3) { | |
59 | restart = true; | |
60 | reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS; | |
61 | } | |
62 | } | |
63 | ||
64 | if (memcmp(buf, CARL9170_BUG_MAGIC, 3) == 0) { | |
65 | ar->fw.bug_counter++; | |
66 | restart = true; | |
67 | reason = CARL9170_RR_FATAL_FIRMWARE_ERROR; | |
68 | } | |
69 | } | |
70 | ||
71 | wiphy_info(ar->hw->wiphy, "FW: %.*s\n", len, buf); | |
72 | ||
73 | if (restart) | |
74 | carl9170_restart(ar, reason); | |
75 | } | |
76 | ||
77 | static void carl9170_handle_ps(struct ar9170 *ar, struct carl9170_rsp *rsp) | |
78 | { | |
79 | u32 ps; | |
80 | bool new_ps; | |
81 | ||
82 | ps = le32_to_cpu(rsp->psm.state); | |
83 | ||
84 | new_ps = (ps & CARL9170_PSM_COUNTER) != CARL9170_PSM_WAKE; | |
85 | if (ar->ps.state != new_ps) { | |
86 | if (!new_ps) { | |
87 | ar->ps.sleep_ms = jiffies_to_msecs(jiffies - | |
88 | ar->ps.last_action); | |
89 | } | |
90 | ||
91 | ar->ps.last_action = jiffies; | |
92 | ||
93 | ar->ps.state = new_ps; | |
94 | } | |
95 | } | |
96 | ||
97 | static int carl9170_check_sequence(struct ar9170 *ar, unsigned int seq) | |
98 | { | |
99 | if (ar->cmd_seq < -1) | |
100 | return 0; | |
101 | ||
102 | /* | |
103 | * Initialize Counter | |
104 | */ | |
105 | if (ar->cmd_seq < 0) | |
106 | ar->cmd_seq = seq; | |
107 | ||
108 | /* | |
109 | * The sequence is strictly monotonic increasing and it never skips! | |
110 | * | |
111 | * Therefore we can safely assume that whenever we received an | |
112 | * unexpected sequence we have lost some valuable data. | |
113 | */ | |
114 | if (seq != ar->cmd_seq) { | |
115 | int count; | |
116 | ||
117 | count = (seq - ar->cmd_seq) % ar->fw.cmd_bufs; | |
118 | ||
119 | wiphy_err(ar->hw->wiphy, "lost %d command responses/traps! " | |
120 | "w:%d g:%d\n", count, ar->cmd_seq, seq); | |
121 | ||
122 | carl9170_restart(ar, CARL9170_RR_LOST_RSP); | |
123 | return -EIO; | |
124 | } | |
125 | ||
126 | ar->cmd_seq = (ar->cmd_seq + 1) % ar->fw.cmd_bufs; | |
127 | return 0; | |
128 | } | |
129 | ||
130 | static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer) | |
131 | { | |
132 | /* | |
133 | * Some commands may have a variable response length | |
134 | * and we cannot predict the correct length in advance. | |
135 | * So we only check if we provided enough space for the data. | |
136 | */ | |
137 | if (unlikely(ar->readlen != (len - 4))) { | |
138 | dev_warn(&ar->udev->dev, "received invalid command response:" | |
139 | "got %d, instead of %d\n", len - 4, ar->readlen); | |
140 | print_hex_dump_bytes("carl9170 cmd:", DUMP_PREFIX_OFFSET, | |
141 | ar->cmd_buf, (ar->cmd.hdr.len + 4) & 0x3f); | |
142 | print_hex_dump_bytes("carl9170 rsp:", DUMP_PREFIX_OFFSET, | |
143 | buffer, len); | |
144 | /* | |
145 | * Do not complete. The command times out, | |
146 | * and we get a stack trace from there. | |
147 | */ | |
148 | carl9170_restart(ar, CARL9170_RR_INVALID_RSP); | |
149 | } | |
150 | ||
151 | spin_lock(&ar->cmd_lock); | |
152 | if (ar->readbuf) { | |
153 | if (len >= 4) | |
154 | memcpy(ar->readbuf, buffer + 4, len - 4); | |
155 | ||
156 | ar->readbuf = NULL; | |
157 | } | |
158 | complete(&ar->cmd_wait); | |
159 | spin_unlock(&ar->cmd_lock); | |
160 | } | |
161 | ||
162 | void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) | |
163 | { | |
164 | struct carl9170_rsp *cmd = (void *) buf; | |
165 | struct ieee80211_vif *vif; | |
166 | ||
167 | if (carl9170_check_sequence(ar, cmd->hdr.seq)) | |
168 | return; | |
169 | ||
170 | if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) { | |
171 | if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG)) | |
172 | carl9170_cmd_callback(ar, len, buf); | |
173 | ||
174 | return; | |
175 | } | |
176 | ||
177 | if (unlikely(cmd->hdr.len != (len - 4))) { | |
178 | if (net_ratelimit()) { | |
179 | wiphy_err(ar->hw->wiphy, "FW: received over-/under" | |
180 | "sized event %x (%d, but should be %d).\n", | |
181 | cmd->hdr.cmd, cmd->hdr.len, len - 4); | |
182 | ||
183 | print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, | |
184 | buf, len); | |
185 | } | |
186 | ||
187 | return; | |
188 | } | |
189 | ||
190 | /* hardware event handlers */ | |
191 | switch (cmd->hdr.cmd) { | |
192 | case CARL9170_RSP_PRETBTT: | |
193 | /* pre-TBTT event */ | |
194 | rcu_read_lock(); | |
195 | vif = carl9170_get_main_vif(ar); | |
196 | ||
197 | if (!vif) { | |
198 | rcu_read_unlock(); | |
199 | break; | |
200 | } | |
201 | ||
202 | switch (vif->type) { | |
203 | case NL80211_IFTYPE_STATION: | |
204 | carl9170_handle_ps(ar, cmd); | |
205 | break; | |
206 | ||
207 | case NL80211_IFTYPE_AP: | |
208 | case NL80211_IFTYPE_ADHOC: | |
209 | carl9170_update_beacon(ar, true); | |
210 | break; | |
211 | ||
212 | default: | |
213 | break; | |
214 | } | |
215 | rcu_read_unlock(); | |
216 | ||
217 | break; | |
218 | ||
219 | ||
220 | case CARL9170_RSP_TXCOMP: | |
221 | /* TX status notification */ | |
222 | carl9170_tx_process_status(ar, cmd); | |
223 | break; | |
224 | ||
225 | case CARL9170_RSP_BEACON_CONFIG: | |
226 | /* | |
227 | * (IBSS) beacon send notification | |
228 | * bytes: 04 c2 XX YY B4 B3 B2 B1 | |
229 | * | |
230 | * XX always 80 | |
231 | * YY always 00 | |
232 | * B1-B4 "should" be the number of send out beacons. | |
233 | */ | |
234 | break; | |
235 | ||
236 | case CARL9170_RSP_ATIM: | |
237 | /* End of Atim Window */ | |
238 | break; | |
239 | ||
240 | case CARL9170_RSP_WATCHDOG: | |
241 | /* Watchdog Interrupt */ | |
242 | carl9170_restart(ar, CARL9170_RR_WATCHDOG); | |
243 | break; | |
244 | ||
245 | case CARL9170_RSP_TEXT: | |
246 | /* firmware debug */ | |
247 | carl9170_dbg_message(ar, (char *)buf + 4, len - 4); | |
248 | break; | |
249 | ||
250 | case CARL9170_RSP_HEXDUMP: | |
251 | wiphy_dbg(ar->hw->wiphy, "FW: HD %d\n", len - 4); | |
252 | print_hex_dump_bytes("FW:", DUMP_PREFIX_NONE, | |
253 | (char *)buf + 4, len - 4); | |
254 | break; | |
255 | ||
256 | case CARL9170_RSP_RADAR: | |
257 | if (!net_ratelimit()) | |
258 | break; | |
259 | ||
260 | wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this " | |
261 | "incident to linux-wireless@vger.kernel.org !\n"); | |
262 | break; | |
263 | ||
264 | case CARL9170_RSP_GPIO: | |
265 | #ifdef CONFIG_CARL9170_WPC | |
266 | if (ar->wps.pbc) { | |
267 | bool state = !!(cmd->gpio.gpio & cpu_to_le32( | |
268 | AR9170_GPIO_PORT_WPS_BUTTON_PRESSED)); | |
269 | ||
270 | if (state != ar->wps.pbc_state) { | |
271 | ar->wps.pbc_state = state; | |
272 | input_report_key(ar->wps.pbc, KEY_WPS_BUTTON, | |
273 | state); | |
274 | input_sync(ar->wps.pbc); | |
275 | } | |
276 | } | |
277 | #endif /* CONFIG_CARL9170_WPC */ | |
278 | break; | |
279 | ||
280 | case CARL9170_RSP_BOOT: | |
281 | complete(&ar->fw_boot_wait); | |
282 | break; | |
283 | ||
284 | default: | |
285 | wiphy_err(ar->hw->wiphy, "FW: received unhandled event %x\n", | |
286 | cmd->hdr.cmd); | |
287 | print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); | |
288 | break; | |
289 | } | |
290 | } | |
291 | ||
292 | static int carl9170_rx_mac_status(struct ar9170 *ar, | |
293 | struct ar9170_rx_head *head, struct ar9170_rx_macstatus *mac, | |
294 | struct ieee80211_rx_status *status) | |
295 | { | |
296 | struct ieee80211_channel *chan; | |
297 | u8 error, decrypt; | |
298 | ||
299 | BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); | |
300 | BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); | |
301 | ||
302 | error = mac->error; | |
303 | ||
304 | if (error & AR9170_RX_ERROR_WRONG_RA) { | |
305 | if (!ar->sniffer_enabled) | |
306 | return -EINVAL; | |
307 | } | |
308 | ||
309 | if (error & AR9170_RX_ERROR_PLCP) { | |
310 | if (!(ar->filter_state & FIF_PLCPFAIL)) | |
311 | return -EINVAL; | |
312 | ||
313 | status->flag |= RX_FLAG_FAILED_PLCP_CRC; | |
314 | } | |
315 | ||
316 | if (error & AR9170_RX_ERROR_FCS) { | |
317 | ar->tx_fcs_errors++; | |
318 | ||
319 | if (!(ar->filter_state & FIF_FCSFAIL)) | |
320 | return -EINVAL; | |
321 | ||
322 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | |
323 | } | |
324 | ||
325 | decrypt = ar9170_get_decrypt_type(mac); | |
326 | if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && | |
327 | decrypt != AR9170_ENC_ALG_NONE) { | |
328 | if ((decrypt == AR9170_ENC_ALG_TKIP) && | |
329 | (error & AR9170_RX_ERROR_MMIC)) | |
330 | status->flag |= RX_FLAG_MMIC_ERROR; | |
331 | ||
332 | status->flag |= RX_FLAG_DECRYPTED; | |
333 | } | |
334 | ||
335 | if (error & AR9170_RX_ERROR_DECRYPT && !ar->sniffer_enabled) | |
336 | return -ENODATA; | |
337 | ||
338 | error &= ~(AR9170_RX_ERROR_MMIC | | |
339 | AR9170_RX_ERROR_FCS | | |
340 | AR9170_RX_ERROR_WRONG_RA | | |
341 | AR9170_RX_ERROR_DECRYPT | | |
342 | AR9170_RX_ERROR_PLCP); | |
343 | ||
344 | /* drop any other error frames */ | |
345 | if (unlikely(error)) { | |
346 | /* TODO: update netdevice's RX dropped/errors statistics */ | |
347 | ||
348 | if (net_ratelimit()) | |
349 | wiphy_dbg(ar->hw->wiphy, "received frame with " | |
350 | "suspicious error code (%#x).\n", error); | |
351 | ||
352 | return -EINVAL; | |
353 | } | |
354 | ||
355 | chan = ar->channel; | |
356 | if (chan) { | |
357 | status->band = chan->band; | |
358 | status->freq = chan->center_freq; | |
359 | } | |
360 | ||
361 | switch (mac->status & AR9170_RX_STATUS_MODULATION) { | |
362 | case AR9170_RX_STATUS_MODULATION_CCK: | |
363 | if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) | |
364 | status->flag |= RX_FLAG_SHORTPRE; | |
365 | switch (head->plcp[0]) { | |
366 | case AR9170_RX_PHY_RATE_CCK_1M: | |
367 | status->rate_idx = 0; | |
368 | break; | |
369 | case AR9170_RX_PHY_RATE_CCK_2M: | |
370 | status->rate_idx = 1; | |
371 | break; | |
372 | case AR9170_RX_PHY_RATE_CCK_5M: | |
373 | status->rate_idx = 2; | |
374 | break; | |
375 | case AR9170_RX_PHY_RATE_CCK_11M: | |
376 | status->rate_idx = 3; | |
377 | break; | |
378 | default: | |
379 | if (net_ratelimit()) { | |
380 | wiphy_err(ar->hw->wiphy, "invalid plcp cck " | |
381 | "rate (%x).\n", head->plcp[0]); | |
382 | } | |
383 | ||
384 | return -EINVAL; | |
385 | } | |
386 | break; | |
387 | ||
388 | case AR9170_RX_STATUS_MODULATION_DUPOFDM: | |
389 | case AR9170_RX_STATUS_MODULATION_OFDM: | |
390 | switch (head->plcp[0] & 0xf) { | |
391 | case AR9170_TXRX_PHY_RATE_OFDM_6M: | |
392 | status->rate_idx = 0; | |
393 | break; | |
394 | case AR9170_TXRX_PHY_RATE_OFDM_9M: | |
395 | status->rate_idx = 1; | |
396 | break; | |
397 | case AR9170_TXRX_PHY_RATE_OFDM_12M: | |
398 | status->rate_idx = 2; | |
399 | break; | |
400 | case AR9170_TXRX_PHY_RATE_OFDM_18M: | |
401 | status->rate_idx = 3; | |
402 | break; | |
403 | case AR9170_TXRX_PHY_RATE_OFDM_24M: | |
404 | status->rate_idx = 4; | |
405 | break; | |
406 | case AR9170_TXRX_PHY_RATE_OFDM_36M: | |
407 | status->rate_idx = 5; | |
408 | break; | |
409 | case AR9170_TXRX_PHY_RATE_OFDM_48M: | |
410 | status->rate_idx = 6; | |
411 | break; | |
412 | case AR9170_TXRX_PHY_RATE_OFDM_54M: | |
413 | status->rate_idx = 7; | |
414 | break; | |
415 | default: | |
416 | if (net_ratelimit()) { | |
417 | wiphy_err(ar->hw->wiphy, "invalid plcp ofdm " | |
418 | "rate (%x).\n", head->plcp[0]); | |
419 | } | |
420 | ||
421 | return -EINVAL; | |
422 | } | |
423 | if (status->band == IEEE80211_BAND_2GHZ) | |
424 | status->rate_idx += 4; | |
425 | break; | |
426 | ||
427 | case AR9170_RX_STATUS_MODULATION_HT: | |
428 | if (head->plcp[3] & 0x80) | |
429 | status->flag |= RX_FLAG_40MHZ; | |
430 | if (head->plcp[6] & 0x80) | |
431 | status->flag |= RX_FLAG_SHORT_GI; | |
432 | ||
433 | status->rate_idx = clamp(0, 75, head->plcp[3] & 0x7f); | |
434 | status->flag |= RX_FLAG_HT; | |
435 | break; | |
436 | ||
437 | default: | |
438 | BUG(); | |
439 | return -ENOSYS; | |
440 | } | |
441 | ||
442 | return 0; | |
443 | } | |
444 | ||
445 | static void carl9170_rx_phy_status(struct ar9170 *ar, | |
446 | struct ar9170_rx_phystatus *phy, struct ieee80211_rx_status *status) | |
447 | { | |
448 | int i; | |
449 | ||
450 | BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); | |
451 | ||
452 | for (i = 0; i < 3; i++) | |
453 | if (phy->rssi[i] != 0x80) | |
454 | status->antenna |= BIT(i); | |
455 | ||
456 | /* post-process RSSI */ | |
457 | for (i = 0; i < 7; i++) | |
458 | if (phy->rssi[i] & 0x80) | |
459 | phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f; | |
460 | ||
461 | /* TODO: we could do something with phy_errors */ | |
462 | status->signal = ar->noise[0] + phy->rssi_combined; | |
463 | } | |
464 | ||
465 | static struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len) | |
466 | { | |
467 | struct sk_buff *skb; | |
468 | int reserved = 0; | |
469 | struct ieee80211_hdr *hdr = (void *) buf; | |
470 | ||
471 | if (ieee80211_is_data_qos(hdr->frame_control)) { | |
472 | u8 *qc = ieee80211_get_qos_ctl(hdr); | |
473 | reserved += NET_IP_ALIGN; | |
474 | ||
475 | if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) | |
476 | reserved += NET_IP_ALIGN; | |
477 | } | |
478 | ||
479 | if (ieee80211_has_a4(hdr->frame_control)) | |
480 | reserved += NET_IP_ALIGN; | |
481 | ||
482 | reserved = 32 + (reserved & NET_IP_ALIGN); | |
483 | ||
484 | skb = dev_alloc_skb(len + reserved); | |
485 | if (likely(skb)) { | |
486 | skb_reserve(skb, reserved); | |
487 | memcpy(skb_put(skb, len), buf, len); | |
488 | } | |
489 | ||
490 | return skb; | |
491 | } | |
492 | ||
493 | static u8 *carl9170_find_ie(u8 *data, unsigned int len, u8 ie) | |
494 | { | |
495 | struct ieee80211_mgmt *mgmt = (void *)data; | |
496 | u8 *pos, *end; | |
497 | ||
498 | pos = (u8 *)mgmt->u.beacon.variable; | |
499 | end = data + len; | |
500 | while (pos < end) { | |
501 | if (pos + 2 + pos[1] > end) | |
502 | return NULL; | |
503 | ||
504 | if (pos[0] == ie) | |
505 | return pos; | |
506 | ||
507 | pos += 2 + pos[1]; | |
508 | } | |
509 | return NULL; | |
510 | } | |
511 | ||
512 | /* | |
513 | * NOTE: | |
514 | * | |
515 | * The firmware is in charge of waking up the device just before | |
516 | * the AP is expected to transmit the next beacon. | |
517 | * | |
518 | * This leaves the driver with the important task of deciding when | |
519 | * to set the PHY back to bed again. | |
520 | */ | |
521 | static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) | |
522 | { | |
523 | struct ieee80211_hdr *hdr = (void *) data; | |
524 | struct ieee80211_tim_ie *tim_ie; | |
525 | u8 *tim; | |
526 | u8 tim_len; | |
527 | bool cam; | |
528 | ||
529 | if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS))) | |
530 | return; | |
531 | ||
532 | /* check if this really is a beacon */ | |
533 | if (!ieee80211_is_beacon(hdr->frame_control)) | |
534 | return; | |
535 | ||
536 | /* min. beacon length + FCS_LEN */ | |
537 | if (len <= 40 + FCS_LEN) | |
538 | return; | |
539 | ||
540 | /* and only beacons from the associated BSSID, please */ | |
541 | if (compare_ether_addr(hdr->addr3, ar->common.curbssid) || | |
542 | !ar->common.curaid) | |
543 | return; | |
544 | ||
545 | ar->ps.last_beacon = jiffies; | |
546 | ||
547 | tim = carl9170_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); | |
548 | if (!tim) | |
549 | return; | |
550 | ||
551 | if (tim[1] < sizeof(*tim_ie)) | |
552 | return; | |
553 | ||
554 | tim_len = tim[1]; | |
555 | tim_ie = (struct ieee80211_tim_ie *) &tim[2]; | |
556 | ||
557 | if (!WARN_ON_ONCE(!ar->hw->conf.ps_dtim_period)) | |
558 | ar->ps.dtim_counter = (tim_ie->dtim_count - 1) % | |
559 | ar->hw->conf.ps_dtim_period; | |
560 | ||
561 | /* Check whenever the PHY can be turned off again. */ | |
562 | ||
563 | /* 1. What about buffered unicast traffic for our AID? */ | |
564 | cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid); | |
565 | ||
566 | /* 2. Maybe the AP wants to send multicast/broadcast data? */ | |
567 | cam = !!(tim_ie->bitmap_ctrl & 0x01); | |
568 | ||
569 | if (!cam) { | |
570 | /* back to low-power land. */ | |
571 | ar->ps.off_override &= ~PS_OFF_BCN; | |
572 | carl9170_ps_check(ar); | |
573 | } else { | |
574 | /* force CAM */ | |
575 | ar->ps.off_override |= PS_OFF_BCN; | |
576 | } | |
577 | } | |
578 | ||
8f236d1b CL |
579 | static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) |
580 | { | |
581 | __le16 fc; | |
582 | ||
583 | if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) { | |
584 | /* | |
585 | * This frame is not part of an aMPDU. | |
586 | * Therefore it is not subjected to any | |
587 | * of the following content restrictions. | |
588 | */ | |
589 | return true; | |
590 | } | |
591 | ||
592 | /* | |
593 | * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts | |
594 | * certain frame types can be part of an aMPDU. | |
595 | * | |
596 | * In order to keep the processing cost down, I opted for a | |
597 | * stateless filter solely based on the frame control field. | |
598 | */ | |
599 | ||
600 | fc = ((struct ieee80211_hdr *)buf)->frame_control; | |
601 | if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc)) | |
602 | return true; | |
603 | ||
604 | if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) || | |
605 | ieee80211_is_back_req(fc)) | |
606 | return true; | |
607 | ||
608 | if (ieee80211_is_action(fc)) | |
609 | return true; | |
610 | ||
611 | return false; | |
612 | } | |
613 | ||
a84fab3c CL |
614 | /* |
615 | * If the frame alignment is right (or the kernel has | |
616 | * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there | |
617 | * is only a single MPDU in the USB frame, then we could | |
618 | * submit to mac80211 the SKB directly. However, since | |
619 | * there may be multiple packets in one SKB in stream | |
620 | * mode, and we need to observe the proper ordering, | |
621 | * this is non-trivial. | |
622 | */ | |
623 | ||
624 | static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | |
625 | { | |
626 | struct ar9170_rx_head *head; | |
627 | struct ar9170_rx_macstatus *mac; | |
628 | struct ar9170_rx_phystatus *phy = NULL; | |
629 | struct ieee80211_rx_status status; | |
630 | struct sk_buff *skb; | |
631 | int mpdu_len; | |
8f236d1b | 632 | u8 mac_status; |
a84fab3c CL |
633 | |
634 | if (!IS_STARTED(ar)) | |
635 | return; | |
636 | ||
c8a16c68 CL |
637 | if (unlikely(len < sizeof(*mac))) |
638 | goto drop; | |
a84fab3c CL |
639 | |
640 | mpdu_len = len - sizeof(*mac); | |
641 | ||
642 | mac = (void *)(buf + mpdu_len); | |
8f236d1b CL |
643 | mac_status = mac->status; |
644 | switch (mac_status & AR9170_RX_STATUS_MPDU) { | |
a84fab3c CL |
645 | case AR9170_RX_STATUS_MPDU_FIRST: |
646 | /* Aggregated MPDUs start with an PLCP header */ | |
647 | if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { | |
648 | head = (void *) buf; | |
649 | ||
650 | /* | |
651 | * The PLCP header needs to be cached for the | |
652 | * following MIDDLE + LAST A-MPDU packets. | |
653 | * | |
654 | * So, if you are wondering why all frames seem | |
655 | * to share a common RX status information, | |
656 | * then you have the answer right here... | |
657 | */ | |
658 | memcpy(&ar->rx_plcp, (void *) buf, | |
659 | sizeof(struct ar9170_rx_head)); | |
660 | ||
661 | mpdu_len -= sizeof(struct ar9170_rx_head); | |
662 | buf += sizeof(struct ar9170_rx_head); | |
663 | ||
664 | ar->rx_has_plcp = true; | |
665 | } else { | |
666 | if (net_ratelimit()) { | |
667 | wiphy_err(ar->hw->wiphy, "plcp info " | |
668 | "is clipped.\n"); | |
669 | } | |
670 | ||
c8a16c68 | 671 | goto drop; |
a84fab3c CL |
672 | } |
673 | break; | |
674 | ||
675 | case AR9170_RX_STATUS_MPDU_LAST: | |
676 | /* | |
677 | * The last frame of an A-MPDU has an extra tail | |
678 | * which does contain the phy status of the whole | |
679 | * aggregate. | |
680 | */ | |
681 | ||
682 | if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { | |
683 | mpdu_len -= sizeof(struct ar9170_rx_phystatus); | |
684 | phy = (void *)(buf + mpdu_len); | |
685 | } else { | |
686 | if (net_ratelimit()) { | |
687 | wiphy_err(ar->hw->wiphy, "frame tail " | |
688 | "is clipped.\n"); | |
689 | } | |
690 | ||
c8a16c68 | 691 | goto drop; |
a84fab3c CL |
692 | } |
693 | ||
694 | case AR9170_RX_STATUS_MPDU_MIDDLE: | |
695 | /* These are just data + mac status */ | |
696 | if (unlikely(!ar->rx_has_plcp)) { | |
697 | if (!net_ratelimit()) | |
698 | return; | |
699 | ||
700 | wiphy_err(ar->hw->wiphy, "rx stream does not start " | |
701 | "with a first_mpdu frame tag.\n"); | |
702 | ||
c8a16c68 | 703 | goto drop; |
a84fab3c CL |
704 | } |
705 | ||
706 | head = &ar->rx_plcp; | |
707 | break; | |
708 | ||
709 | case AR9170_RX_STATUS_MPDU_SINGLE: | |
710 | /* single mpdu has both: plcp (head) and phy status (tail) */ | |
711 | head = (void *) buf; | |
712 | ||
713 | mpdu_len -= sizeof(struct ar9170_rx_head); | |
714 | mpdu_len -= sizeof(struct ar9170_rx_phystatus); | |
715 | ||
716 | buf += sizeof(struct ar9170_rx_head); | |
717 | phy = (void *)(buf + mpdu_len); | |
718 | break; | |
719 | ||
720 | default: | |
721 | BUG_ON(1); | |
722 | break; | |
723 | } | |
724 | ||
725 | /* FC + DU + RA + FCS */ | |
c8a16c68 CL |
726 | if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN))) |
727 | goto drop; | |
a84fab3c CL |
728 | |
729 | memset(&status, 0, sizeof(status)); | |
c8a16c68 CL |
730 | if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) |
731 | goto drop; | |
a84fab3c | 732 | |
8f236d1b CL |
733 | if (!carl9170_ampdu_check(ar, buf, mac_status)) |
734 | goto drop; | |
735 | ||
a84fab3c CL |
736 | if (phy) |
737 | carl9170_rx_phy_status(ar, phy, &status); | |
738 | ||
739 | carl9170_ps_beacon(ar, buf, mpdu_len); | |
740 | ||
741 | skb = carl9170_rx_copy_data(buf, mpdu_len); | |
c8a16c68 CL |
742 | if (!skb) |
743 | goto drop; | |
744 | ||
745 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); | |
746 | ieee80211_rx(ar->hw, skb); | |
747 | return; | |
748 | ||
749 | drop: | |
750 | ar->rx_dropped++; | |
a84fab3c CL |
751 | } |
752 | ||
753 | static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf, | |
754 | const unsigned int resplen) | |
755 | { | |
756 | struct carl9170_rsp *cmd; | |
757 | int i = 0; | |
758 | ||
759 | while (i < resplen) { | |
760 | cmd = (void *) &respbuf[i]; | |
761 | ||
762 | i += cmd->hdr.len + 4; | |
763 | if (unlikely(i > resplen)) | |
764 | break; | |
765 | ||
766 | carl9170_handle_command_response(ar, cmd, cmd->hdr.len + 4); | |
767 | } | |
768 | ||
769 | if (unlikely(i != resplen)) { | |
770 | if (!net_ratelimit()) | |
771 | return; | |
772 | ||
773 | wiphy_err(ar->hw->wiphy, "malformed firmware trap:\n"); | |
774 | print_hex_dump_bytes("rxcmd:", DUMP_PREFIX_OFFSET, | |
775 | respbuf, resplen); | |
776 | } | |
777 | } | |
778 | ||
779 | static void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len) | |
780 | { | |
781 | unsigned int i = 0; | |
782 | ||
783 | /* weird thing, but this is the same in the original driver */ | |
784 | while (len > 2 && i < 12 && buf[0] == 0xff && buf[1] == 0xff) { | |
785 | i += 2; | |
786 | len -= 2; | |
787 | buf += 2; | |
788 | } | |
789 | ||
790 | if (unlikely(len < 4)) | |
791 | return; | |
792 | ||
793 | /* found the 6 * 0xffff marker? */ | |
794 | if (i == 12) | |
795 | carl9170_rx_untie_cmds(ar, buf, len); | |
796 | else | |
797 | carl9170_handle_mpdu(ar, buf, len); | |
798 | } | |
799 | ||
800 | static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) | |
801 | { | |
802 | unsigned int tlen, wlen = 0, clen = 0; | |
803 | struct ar9170_stream *rx_stream; | |
804 | u8 *tbuf; | |
805 | ||
806 | tbuf = buf; | |
807 | tlen = len; | |
808 | ||
809 | while (tlen >= 4) { | |
810 | rx_stream = (void *) tbuf; | |
811 | clen = le16_to_cpu(rx_stream->length); | |
812 | wlen = ALIGN(clen, 4); | |
813 | ||
814 | /* check if this is stream has a valid tag.*/ | |
815 | if (rx_stream->tag != cpu_to_le16(AR9170_RX_STREAM_TAG)) { | |
816 | /* | |
817 | * TODO: handle the highly unlikely event that the | |
818 | * corrupted stream has the TAG at the right position. | |
819 | */ | |
820 | ||
821 | /* check if the frame can be repaired. */ | |
822 | if (!ar->rx_failover_missing) { | |
823 | ||
824 | /* this is not "short read". */ | |
825 | if (net_ratelimit()) { | |
826 | wiphy_err(ar->hw->wiphy, | |
827 | "missing tag!\n"); | |
828 | } | |
829 | ||
830 | __carl9170_rx(ar, tbuf, tlen); | |
831 | return; | |
832 | } | |
833 | ||
834 | if (ar->rx_failover_missing > tlen) { | |
835 | if (net_ratelimit()) { | |
836 | wiphy_err(ar->hw->wiphy, | |
837 | "possible multi " | |
838 | "stream corruption!\n"); | |
839 | goto err_telluser; | |
840 | } else { | |
841 | goto err_silent; | |
842 | } | |
843 | } | |
844 | ||
845 | memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); | |
846 | ar->rx_failover_missing -= tlen; | |
847 | ||
848 | if (ar->rx_failover_missing <= 0) { | |
849 | /* | |
850 | * nested carl9170_rx_stream call! | |
851 | * | |
852 | * termination is guranteed, even when the | |
853 | * combined frame also have an element with | |
854 | * a bad tag. | |
855 | */ | |
856 | ||
857 | ar->rx_failover_missing = 0; | |
858 | carl9170_rx_stream(ar, ar->rx_failover->data, | |
859 | ar->rx_failover->len); | |
860 | ||
861 | skb_reset_tail_pointer(ar->rx_failover); | |
862 | skb_trim(ar->rx_failover, 0); | |
863 | } | |
864 | ||
865 | return; | |
866 | } | |
867 | ||
868 | /* check if stream is clipped */ | |
869 | if (wlen > tlen - 4) { | |
870 | if (ar->rx_failover_missing) { | |
871 | /* TODO: handle double stream corruption. */ | |
872 | if (net_ratelimit()) { | |
873 | wiphy_err(ar->hw->wiphy, "double rx " | |
874 | "stream corruption!\n"); | |
875 | goto err_telluser; | |
876 | } else { | |
877 | goto err_silent; | |
878 | } | |
879 | } | |
880 | ||
881 | /* | |
882 | * save incomplete data set. | |
883 | * the firmware will resend the missing bits when | |
884 | * the rx - descriptor comes round again. | |
885 | */ | |
886 | ||
887 | memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); | |
888 | ar->rx_failover_missing = clen - tlen; | |
889 | return; | |
890 | } | |
891 | __carl9170_rx(ar, rx_stream->payload, clen); | |
892 | ||
893 | tbuf += wlen + 4; | |
894 | tlen -= wlen + 4; | |
895 | } | |
896 | ||
897 | if (tlen) { | |
898 | if (net_ratelimit()) { | |
899 | wiphy_err(ar->hw->wiphy, "%d bytes of unprocessed " | |
900 | "data left in rx stream!\n", tlen); | |
901 | } | |
902 | ||
903 | goto err_telluser; | |
904 | } | |
905 | ||
906 | return; | |
907 | ||
908 | err_telluser: | |
909 | wiphy_err(ar->hw->wiphy, "damaged RX stream data [want:%d, " | |
910 | "data:%d, rx:%d, pending:%d ]\n", clen, wlen, tlen, | |
911 | ar->rx_failover_missing); | |
912 | ||
913 | if (ar->rx_failover_missing) | |
914 | print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, | |
915 | ar->rx_failover->data, | |
916 | ar->rx_failover->len); | |
917 | ||
918 | print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, | |
919 | buf, len); | |
920 | ||
921 | wiphy_err(ar->hw->wiphy, "please check your hardware and cables, if " | |
922 | "you see this message frequently.\n"); | |
923 | ||
924 | err_silent: | |
925 | if (ar->rx_failover_missing) { | |
926 | skb_reset_tail_pointer(ar->rx_failover); | |
927 | skb_trim(ar->rx_failover, 0); | |
928 | ar->rx_failover_missing = 0; | |
929 | } | |
930 | } | |
931 | ||
932 | void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len) | |
933 | { | |
934 | if (ar->fw.rx_stream) | |
935 | carl9170_rx_stream(ar, buf, len); | |
936 | else | |
937 | __carl9170_rx(ar, buf, len); | |
938 | } |