1 /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <sys/cdefs.h>
22 #include "opt_wlan.h"
23
24 #include <sys/param.h>
25 #include <sys/lock.h>
26 #include <sys/mutex.h>
27 #include <sys/mbuf.h>
28 #include <sys/kernel.h>
29 #include <sys/socket.h>
30 #include <sys/systm.h>
31 #include <sys/malloc.h>
32 #include <sys/queue.h>
33 #include <sys/taskqueue.h>
34 #include <sys/bus.h>
35 #include <sys/endian.h>
36
37 #include <net/if.h>
38 #include <net/if_var.h>
39 #include <net/ethernet.h>
40 #include <net/if_dl.h>
41 #include <net/if_media.h>
42
43 #include <net80211/ieee80211_var.h>
44 #include <net80211/ieee80211_radiotap.h>
45
46 #include <dev/rtwn/if_rtwnreg.h>
47 #include <dev/rtwn/if_rtwnvar.h>
48
49 #include <dev/rtwn/if_rtwn_debug.h>
50 #include <dev/rtwn/if_rtwn_ridx.h>
51 #include <dev/rtwn/if_rtwn_rx.h>
52
53 #include <dev/rtwn/rtl8192c/r92c_reg.h>
54
55 /*
56 * Get the driver rate set for the current operating rateset(s).
57 *
58 * rates_p is set to a mask of 11abg ridx values (not HW rate values.)
59 * htrates_p is set to a mask of 11n ridx values (not HW rate values),
60 * starting at MCS0 == bit 0.
61 *
62 * maxrate_p is set to the ridx value.
63 *
64 * If basic_rates is 1 then only the 11abg basic rate logic will
65 * be applied; the HT rateset will be applied to 11n rates.
66 */
67 void
rtwn_get_rates(struct rtwn_softc * sc,const struct ieee80211_rateset * rs,const struct ieee80211_htrateset * rs_ht,uint32_t * rates_p,uint32_t * htrates_p,int * maxrate_p,int basic_rates)68 rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs,
69 const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p,
70 uint32_t *htrates_p, int *maxrate_p, int basic_rates)
71 {
72 uint32_t rates = 0, htrates = 0;
73 uint8_t ridx;
74 int i, maxrate;
75
76 /* Get rates mask. */
77 rates = 0;
78 maxrate = 0;
79
80 /* This is for 11abg */
81 for (i = 0; i < rs->rs_nrates; i++) {
82 /* Convert 802.11 rate to HW rate index. */
83 ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i]));
84 if (ridx == RTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */
85 continue;
86 if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) ||
87 !basic_rates) {
88 rates |= 1 << ridx;
89 if (ridx > maxrate)
90 maxrate = ridx;
91 }
92 }
93
94 /* If we're doing 11n, enable 11n rates */
95 if (rs_ht != NULL) {
96 for (i = 0; i < rs_ht->rs_nrates; i++) {
97 uint8_t rate = rs_ht->rs_rates[i] & 0x7f;
98 bool is_basic = rs_ht->rs_rates[i] &
99 IEEE80211_RATE_BASIC;
100 /* Only do up to 2-stream rates for now */
101 if ((rate) > 0xf)
102 continue;
103
104 if (basic_rates && is_basic == false)
105 continue;
106
107 ridx = rate & 0xf;
108 htrates |= (1 << ridx);
109
110 /* Guard against the rate table being oddly ordered */
111 if (RTWN_RIDX_HT_MCS(ridx) > maxrate)
112 maxrate = RTWN_RIDX_HT_MCS(ridx);
113 }
114 }
115
116 RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
117 "%s: rates 0x%08X htrates 0x%08X, maxrate %d\n",
118 __func__, rates, htrates, maxrate);
119
120 if (rates_p != NULL)
121 *rates_p = rates;
122 if (htrates_p != NULL)
123 *htrates_p = htrates;
124 if (maxrate_p != NULL)
125 *maxrate_p = maxrate;
126 }
127
128 void
rtwn_set_basicrates(struct rtwn_softc * sc,uint32_t rates)129 rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates)
130 {
131
132 RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates);
133
134 rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates);
135 }
136
137 /*
138 * Configure the initial RTS rate to use.
139 */
140 void
rtwn_set_rts_rate(struct rtwn_softc * sc,uint32_t rates)141 rtwn_set_rts_rate(struct rtwn_softc *sc, uint32_t rates)
142 {
143 uint8_t ridx;
144
145 /*
146 * We shouldn't set the initial RTS/CTS generation rate
147 * as the highest available rate - that may end up
148 * with trying to configure something like MCS1 RTS/CTS.
149 *
150 * Instead, choose a suitable low OFDM/CCK rate based
151 * on the basic rate bitmask. Assume the caller
152 * has filtered out CCK modes in 5GHz.
153 */
154 rates &= (1 << RTWN_RIDX_CCK1) | (1 << RTWN_RIDX_CCK55) |
155 (1 << RTWN_RIDX_CCK11) | (1 << RTWN_RIDX_OFDM6) |
156 (1 << RTWN_RIDX_OFDM9) | (1 << RTWN_RIDX_OFDM12) |
157 (1 << RTWN_RIDX_OFDM18) | (1 << RTWN_RIDX_OFDM24);
158 if (rates == 0) {
159 device_printf(sc->sc_dev,
160 "WARNING: no configured basic RTS rate!\n");
161 return;
162 }
163 ridx = fls(rates) - 1;
164
165 RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
166 "%s: mask=0x%08x, ridx=%d\n",
167 __func__, rates, ridx);
168
169 rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, ridx);
170 }
171
172 static void
rtwn_update_avgrssi(struct rtwn_softc * sc,struct rtwn_node * un,int8_t rssi,int is_cck)173 rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int8_t rssi,
174 int is_cck)
175 {
176 int pwdb;
177
178 /* Convert antenna signal to percentage. */
179 if (rssi <= -100 || rssi >= 20)
180 pwdb = 0;
181 else if (rssi >= 0)
182 pwdb = 100;
183 else
184 pwdb = 100 + rssi;
185 if (is_cck) {
186 /* CCK gain is smaller than OFDM/MCS gain. */
187 pwdb += 6;
188 if (pwdb > 100)
189 pwdb = 100;
190 if (pwdb <= 14)
191 pwdb -= 4;
192 else if (pwdb <= 26)
193 pwdb -= 8;
194 else if (pwdb <= 34)
195 pwdb -= 6;
196 else if (pwdb <= 42)
197 pwdb -= 2;
198 }
199
200 if (un->avg_pwdb == -1) /* Init. */
201 un->avg_pwdb = pwdb;
202 else if (un->avg_pwdb < pwdb)
203 un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1;
204 else
205 un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20);
206
207 RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI,
208 "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb);
209 }
210
211 static int8_t
rtwn_get_rssi(struct rtwn_softc * sc,void * physt,int is_cck)212 rtwn_get_rssi(struct rtwn_softc *sc, void *physt, int is_cck)
213 {
214 int8_t rssi;
215
216 if (is_cck)
217 rssi = rtwn_get_rssi_cck(sc, physt);
218 else /* OFDM/HT. */
219 rssi = rtwn_get_rssi_ofdm(sc, physt);
220
221 return (rssi);
222 }
223
224 static uint32_t
rtwn_get_tsf_low(struct rtwn_softc * sc,int id)225 rtwn_get_tsf_low(struct rtwn_softc *sc, int id)
226 {
227 return (rtwn_read_4(sc, R92C_TSFTR(id)));
228 }
229
230 static uint32_t
rtwn_get_tsf_high(struct rtwn_softc * sc,int id)231 rtwn_get_tsf_high(struct rtwn_softc *sc, int id)
232 {
233 return (rtwn_read_4(sc, R92C_TSFTR(id) + 4));
234 }
235
236 static void
rtwn_get_tsf(struct rtwn_softc * sc,uint64_t * buf,int id)237 rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id)
238 {
239 /* NB: we cannot read it at once. */
240 *buf = rtwn_get_tsf_high(sc, id);
241 *buf <<= 32;
242 *buf += rtwn_get_tsf_low(sc, id);
243 }
244
245 static uint64_t
rtwn_extend_rx_tsf(struct rtwn_softc * sc,const struct rtwn_rx_stat_common * stat)246 rtwn_extend_rx_tsf(struct rtwn_softc *sc,
247 const struct rtwn_rx_stat_common *stat)
248 {
249 uint64_t tsft;
250 uint32_t rxdw3, tsfl, tsfl_curr;
251 int id;
252
253 rxdw3 = le32toh(stat->rxdw3);
254 tsfl = le32toh(stat->tsf_low);
255 id = MS(rxdw3, RTWN_RXDW3_BSSID01_FIT);
256
257 switch (id) {
258 case 1:
259 case 2:
260 id >>= 1;
261 tsfl_curr = rtwn_get_tsf_low(sc, id);
262 break;
263 default:
264 {
265 uint32_t tsfl0, tsfl1;
266
267 tsfl0 = rtwn_get_tsf_low(sc, 0);
268 tsfl1 = rtwn_get_tsf_low(sc, 1);
269
270 if (abs(tsfl0 - tsfl) < abs(tsfl1 - tsfl)) {
271 id = 0;
272 tsfl_curr = tsfl0;
273 } else {
274 id = 1;
275 tsfl_curr = tsfl1;
276 }
277 break;
278 }
279 }
280
281 tsft = rtwn_get_tsf_high(sc, id);
282 if (tsfl > tsfl_curr && tsfl > 0xffff0000)
283 tsft--;
284 tsft <<= 32;
285 tsft += tsfl;
286
287 return (tsft);
288 }
289
290 struct ieee80211_node *
rtwn_rx_common(struct rtwn_softc * sc,struct mbuf * m,void * desc)291 rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc)
292 {
293 struct ieee80211com *ic = &sc->sc_ic;
294 struct ieee80211_node *ni;
295 struct ieee80211_frame_min *wh;
296 struct ieee80211_rx_stats rxs;
297 struct rtwn_node *un;
298 struct rtwn_rx_stat_common *stat;
299 void *physt;
300 uint32_t rxdw0;
301 int8_t rssi;
302 int cipher, infosz, is_cck, pktlen, shift;
303
304 stat = desc;
305 rxdw0 = le32toh(stat->rxdw0);
306
307 cipher = MS(rxdw0, RTWN_RXDW0_CIPHER);
308 infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
309 pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
310 shift = MS(rxdw0, RTWN_RXDW0_SHIFT);
311
312 wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz));
313 if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
314 cipher != R92C_CAM_ALGO_NONE)
315 m->m_flags |= M_WEP;
316
317 if (pktlen >= sizeof(*wh)) {
318 ni = ieee80211_find_rxnode(ic, wh);
319 if (ni != NULL && (ni->ni_flags & IEEE80211_NODE_HT))
320 m->m_flags |= M_AMPDU;
321 } else
322 ni = NULL;
323 un = RTWN_NODE(ni);
324
325 if (infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST))
326 physt = (void *)mtodo(m, shift);
327 else
328 physt = (un != NULL) ? &un->last_physt : &sc->last_physt;
329
330 bzero(&rxs, sizeof(rxs));
331 rtwn_get_rx_stats(sc, &rxs, desc, physt);
332 if (rxs.c_pktflags & IEEE80211_RX_F_AMPDU) {
333 /* Next MPDU will come without PHY info. */
334 memcpy(&sc->last_physt, physt, sizeof(sc->last_physt));
335 if (un != NULL)
336 memcpy(&un->last_physt, physt, sizeof(sc->last_physt));
337 }
338
339 /* Add some common bits. */
340 /* NB: should not happen. */
341 if (rxdw0 & RTWN_RXDW0_CRCERR)
342 rxs.c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC;
343
344 rxs.r_flags |= IEEE80211_R_TSF_START; /* XXX undocumented */
345
346 /*
347 * Doing the TSF64 extension on USB is expensive, especially
348 * if it's being done on every MPDU in an AMPDU burst.
349 */
350 if (sc->sc_ena_tsf64) {
351 rxs.r_flags |= IEEE80211_R_TSF64;
352 rxs.c_rx_tsf = rtwn_extend_rx_tsf(sc, stat);
353 } else {
354 rxs.r_flags |= IEEE80211_R_TSF32;
355 rxs.c_rx_tsf = le32toh(stat->tsf_low);
356 }
357
358 /* Get RSSI from PHY status descriptor. */
359 is_cck = (rxs.c_pktflags & IEEE80211_RX_F_CCK) != 0;
360 rssi = rtwn_get_rssi(sc, physt, is_cck);
361
362 /* XXX TODO: we really need a rate-to-string method */
363 RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, rate %d\n",
364 __func__, rssi, rxs.c_rate);
365 if (un != NULL && infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST)) {
366 /* Update our average RSSI. */
367 rtwn_update_avgrssi(sc, un, rssi, is_cck);
368 }
369
370 rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI;
371 rxs.c_nf = RTWN_NOISE_FLOOR;
372 rxs.c_rssi = rssi - rxs.c_nf;
373 (void) ieee80211_add_rx_params(m, &rxs);
374
375 if (ieee80211_radiotap_active(ic)) {
376 struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
377
378 tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc);
379 tap->wr_tsft = htole64(rxs.c_rx_tsf);
380 tap->wr_rate = rxs.c_rate;
381 tap->wr_dbm_antsignal = rssi;
382 tap->wr_dbm_antnoise = rxs.c_nf;
383 }
384
385 /* Drop PHY descriptor. */
386 m_adj(m, infosz + shift);
387
388 /* If APPFCS, drop FCS */
389 if (sc->rcr & R92C_RCR_APPFCS)
390 m_adj(m, -IEEE80211_CRC_LEN);
391
392 return (ni);
393 }
394
395 void
rtwn_adhoc_recv_mgmt(struct ieee80211_node * ni,struct mbuf * m,int subtype,const struct ieee80211_rx_stats * rxs,int rssi,int nf)396 rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
397 const struct ieee80211_rx_stats *rxs,
398 int rssi, int nf)
399 {
400 struct ieee80211vap *vap = ni->ni_vap;
401 struct rtwn_softc *sc = vap->iv_ic->ic_softc;
402 struct rtwn_vap *uvp = RTWN_VAP(vap);
403 uint64_t ni_tstamp, curr_tstamp;
404
405 uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
406
407 if (vap->iv_state == IEEE80211_S_RUN &&
408 (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
409 subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
410 ni_tstamp = le64toh(ni->ni_tstamp.tsf);
411 RTWN_LOCK(sc);
412 rtwn_get_tsf(sc, &curr_tstamp, uvp->id);
413 RTWN_UNLOCK(sc);
414
415 if (ni_tstamp >= curr_tstamp)
416 (void) ieee80211_ibss_merge(ni);
417 }
418 }
419
420 static uint8_t
rtwn_get_multi_pos(const uint8_t maddr[])421 rtwn_get_multi_pos(const uint8_t maddr[])
422 {
423 uint64_t mask = 0x00004d101df481b4;
424 uint8_t pos = 0x27; /* initial value */
425 int i, j;
426
427 for (i = 0; i < IEEE80211_ADDR_LEN; i++)
428 for (j = (i == 0) ? 1 : 0; j < 8; j++)
429 if ((maddr[i] >> j) & 1)
430 pos ^= (mask >> (i * 8 + j - 1));
431
432 pos &= 0x3f;
433
434 return (pos);
435 }
436
437 static u_int
rtwm_hash_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)438 rtwm_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
439 {
440 uint32_t *mfilt = arg;
441 uint8_t pos;
442
443 pos = rtwn_get_multi_pos(LLADDR(sdl));
444 mfilt[pos / 32] |= (1 << (pos % 32));
445
446 return (1);
447 }
448
449 void
rtwn_set_multi(struct rtwn_softc * sc)450 rtwn_set_multi(struct rtwn_softc *sc)
451 {
452 struct ieee80211com *ic = &sc->sc_ic;
453 uint32_t mfilt[2];
454
455 RTWN_ASSERT_LOCKED(sc);
456
457 /* general structure was copied from ath(4). */
458 if (ic->ic_allmulti == 0) {
459 struct ieee80211vap *vap;
460
461 /*
462 * Merge multicast addresses to form the hardware filter.
463 */
464 mfilt[0] = mfilt[1] = 0;
465 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
466 if_foreach_llmaddr(vap->iv_ifp, rtwm_hash_maddr, mfilt);
467 } else
468 mfilt[0] = mfilt[1] = ~0;
469
470 rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]);
471 rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]);
472
473 RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n",
474 __func__, mfilt[0], mfilt[1]);
475 }
476
477 static void
rtwn_rxfilter_update_mgt(struct rtwn_softc * sc)478 rtwn_rxfilter_update_mgt(struct rtwn_softc *sc)
479 {
480 uint16_t filter;
481
482 filter = 0x7f7f;
483 if (sc->bcn_vaps == 0) { /* STA and/or MONITOR mode vaps */
484 filter &= ~(
485 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) |
486 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) |
487 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ));
488 }
489 if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) { /* AP vaps only */
490 filter &= ~(
491 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) |
492 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP));
493 }
494 rtwn_write_2(sc, R92C_RXFLTMAP0, filter);
495 }
496
497 void
rtwn_rxfilter_update(struct rtwn_softc * sc)498 rtwn_rxfilter_update(struct rtwn_softc *sc)
499 {
500
501 RTWN_ASSERT_LOCKED(sc);
502
503 /* Filter for management frames. */
504 rtwn_rxfilter_update_mgt(sc);
505
506 /* Update Rx filter. */
507 rtwn_set_promisc(sc);
508 }
509
510 void
rtwn_rxfilter_init(struct rtwn_softc * sc)511 rtwn_rxfilter_init(struct rtwn_softc *sc)
512 {
513
514 RTWN_ASSERT_LOCKED(sc);
515
516 /* Setup multicast filter. */
517 rtwn_set_multi(sc);
518
519 /* Reject all control frames. */
520 rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
521
522 /* Reject all data frames. */
523 rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000);
524
525 /* Append generic Rx filter bits. */
526 sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM |
527 R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS |
528 R92C_RCR_APP_ICV | R92C_RCR_APP_MIC;
529
530 /*
531 * Add FCS, to work around occasional 4 byte truncation
532 * with some frames. This is more problematic on RTL8812/
533 * RTL8821 because they're also doing L3/L4 checksum offload
534 * and hardware encryption, so both are tagged as "passed"
535 * before the frame is truncated.
536 */
537 sc->rcr |= R92C_RCR_APPFCS;
538
539 /* Update dynamic Rx filter parts. */
540 rtwn_rxfilter_update(sc);
541 }
542
543 void
rtwn_rxfilter_set(struct rtwn_softc * sc)544 rtwn_rxfilter_set(struct rtwn_softc *sc)
545 {
546 if (!(sc->sc_flags & RTWN_RCR_LOCKED))
547 rtwn_write_4(sc, R92C_RCR, sc->rcr);
548 }
549
550 void
rtwn_set_rx_bssid_all(struct rtwn_softc * sc,int enable)551 rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable)
552 {
553
554 if (enable)
555 sc->rcr &= ~R92C_RCR_CBSSID_BCN;
556 else
557 sc->rcr |= R92C_RCR_CBSSID_BCN;
558 rtwn_rxfilter_set(sc);
559 }
560
561 void
rtwn_set_promisc(struct rtwn_softc * sc)562 rtwn_set_promisc(struct rtwn_softc *sc)
563 {
564 struct ieee80211com *ic = &sc->sc_ic;
565 uint32_t mask_all, mask_min;
566
567 RTWN_ASSERT_LOCKED(sc);
568
569 mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP;
570 mask_min = R92C_RCR_APM;
571
572 if (sc->bcn_vaps == 0)
573 mask_min |= R92C_RCR_CBSSID_BCN;
574 if (sc->ap_vaps == 0)
575 mask_min |= R92C_RCR_CBSSID_DATA;
576
577 if (ic->ic_promisc == 0 && sc->mon_vaps == 0) {
578 if (sc->bcn_vaps != 0)
579 mask_all |= R92C_RCR_CBSSID_BCN;
580 if (sc->ap_vaps != 0) /* for Null data frames */
581 mask_all |= R92C_RCR_CBSSID_DATA;
582
583 sc->rcr &= ~mask_all;
584 sc->rcr |= mask_min;
585 } else {
586 sc->rcr &= ~mask_min;
587 sc->rcr |= mask_all;
588 }
589
590 /*
591 * Add FCS, to work around occasional 4 byte truncation.
592 * See the previous comment above R92C_RCR_APPFCS.
593 */
594 sc->rcr |= R92C_RCR_APPFCS;
595
596 rtwn_rxfilter_set(sc);
597 }
598