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 void
rtwn_get_rates(struct rtwn_softc * sc,const struct ieee80211_rateset * rs,const struct ieee80211_htrateset * rs_ht,uint32_t * rates_p,int * maxrate_p,int basic_rates)56 rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs,
57 const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p,
58 int *maxrate_p, int basic_rates)
59 {
60 uint32_t rates;
61 uint8_t ridx;
62 int i, maxrate;
63
64 /* Get rates mask. */
65 rates = 0;
66 maxrate = 0;
67
68 /* This is for 11bg */
69 for (i = 0; i < rs->rs_nrates; i++) {
70 /* Convert 802.11 rate to HW rate index. */
71 ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i]));
72 if (ridx == RTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */
73 continue;
74 if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) ||
75 !basic_rates) {
76 rates |= 1 << ridx;
77 if (ridx > maxrate)
78 maxrate = ridx;
79 }
80 }
81
82 /* If we're doing 11n, enable 11n rates */
83 if (rs_ht != NULL && !basic_rates) {
84 for (i = 0; i < rs_ht->rs_nrates; i++) {
85 if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
86 continue;
87 /* 11n rates start at index 12 */
88 ridx = RTWN_RIDX_HT_MCS((rs_ht->rs_rates[i]) & 0xf);
89 rates |= (1 << ridx);
90
91 /* Guard against the rate table being oddly ordered */
92 if (ridx > maxrate)
93 maxrate = ridx;
94 }
95 }
96
97 RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
98 "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate);
99
100 if (rates_p != NULL)
101 *rates_p = rates;
102 if (maxrate_p != NULL)
103 *maxrate_p = maxrate;
104 }
105
106 void
rtwn_set_basicrates(struct rtwn_softc * sc,uint32_t rates)107 rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates)
108 {
109
110 RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates);
111
112 rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates);
113 }
114
115 static void
rtwn_update_avgrssi(struct rtwn_softc * sc,struct rtwn_node * un,int8_t rssi,int is_cck)116 rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int8_t rssi,
117 int is_cck)
118 {
119 int pwdb;
120
121 /* Convert antenna signal to percentage. */
122 if (rssi <= -100 || rssi >= 20)
123 pwdb = 0;
124 else if (rssi >= 0)
125 pwdb = 100;
126 else
127 pwdb = 100 + rssi;
128 if (is_cck) {
129 /* CCK gain is smaller than OFDM/MCS gain. */
130 pwdb += 6;
131 if (pwdb > 100)
132 pwdb = 100;
133 if (pwdb <= 14)
134 pwdb -= 4;
135 else if (pwdb <= 26)
136 pwdb -= 8;
137 else if (pwdb <= 34)
138 pwdb -= 6;
139 else if (pwdb <= 42)
140 pwdb -= 2;
141 }
142
143 if (un->avg_pwdb == -1) /* Init. */
144 un->avg_pwdb = pwdb;
145 else if (un->avg_pwdb < pwdb)
146 un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1;
147 else
148 un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20);
149
150 RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI,
151 "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb);
152 }
153
154 static int8_t
rtwn_get_rssi(struct rtwn_softc * sc,void * physt,int is_cck)155 rtwn_get_rssi(struct rtwn_softc *sc, void *physt, int is_cck)
156 {
157 int8_t rssi;
158
159 if (is_cck)
160 rssi = rtwn_get_rssi_cck(sc, physt);
161 else /* OFDM/HT. */
162 rssi = rtwn_get_rssi_ofdm(sc, physt);
163
164 return (rssi);
165 }
166
167 static uint32_t
rtwn_get_tsf_low(struct rtwn_softc * sc,int id)168 rtwn_get_tsf_low(struct rtwn_softc *sc, int id)
169 {
170 return (rtwn_read_4(sc, R92C_TSFTR(id)));
171 }
172
173 static uint32_t
rtwn_get_tsf_high(struct rtwn_softc * sc,int id)174 rtwn_get_tsf_high(struct rtwn_softc *sc, int id)
175 {
176 return (rtwn_read_4(sc, R92C_TSFTR(id) + 4));
177 }
178
179 static void
rtwn_get_tsf(struct rtwn_softc * sc,uint64_t * buf,int id)180 rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id)
181 {
182 /* NB: we cannot read it at once. */
183 *buf = rtwn_get_tsf_high(sc, id);
184 *buf <<= 32;
185 *buf += rtwn_get_tsf_low(sc, id);
186 }
187
188 static uint64_t
rtwn_extend_rx_tsf(struct rtwn_softc * sc,const struct rtwn_rx_stat_common * stat)189 rtwn_extend_rx_tsf(struct rtwn_softc *sc,
190 const struct rtwn_rx_stat_common *stat)
191 {
192 uint64_t tsft;
193 uint32_t rxdw3, tsfl, tsfl_curr;
194 int id;
195
196 rxdw3 = le32toh(stat->rxdw3);
197 tsfl = le32toh(stat->tsf_low);
198 id = MS(rxdw3, RTWN_RXDW3_BSSID01_FIT);
199
200 switch (id) {
201 case 1:
202 case 2:
203 id >>= 1;
204 tsfl_curr = rtwn_get_tsf_low(sc, id);
205 break;
206 default:
207 {
208 uint32_t tsfl0, tsfl1;
209
210 tsfl0 = rtwn_get_tsf_low(sc, 0);
211 tsfl1 = rtwn_get_tsf_low(sc, 1);
212
213 if (abs(tsfl0 - tsfl) < abs(tsfl1 - tsfl)) {
214 id = 0;
215 tsfl_curr = tsfl0;
216 } else {
217 id = 1;
218 tsfl_curr = tsfl1;
219 }
220 break;
221 }
222 }
223
224 tsft = rtwn_get_tsf_high(sc, id);
225 if (tsfl > tsfl_curr && tsfl > 0xffff0000)
226 tsft--;
227 tsft <<= 32;
228 tsft += tsfl;
229
230 return (tsft);
231 }
232
233 struct ieee80211_node *
rtwn_rx_common(struct rtwn_softc * sc,struct mbuf * m,void * desc)234 rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc)
235 {
236 struct ieee80211com *ic = &sc->sc_ic;
237 struct ieee80211_node *ni;
238 struct ieee80211_frame_min *wh;
239 struct ieee80211_rx_stats rxs;
240 struct rtwn_node *un;
241 struct rtwn_rx_stat_common *stat;
242 void *physt;
243 uint32_t rxdw0;
244 int8_t rssi;
245 int cipher, infosz, is_cck, pktlen, shift;
246
247 stat = desc;
248 rxdw0 = le32toh(stat->rxdw0);
249
250 cipher = MS(rxdw0, RTWN_RXDW0_CIPHER);
251 infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
252 pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
253 shift = MS(rxdw0, RTWN_RXDW0_SHIFT);
254
255 wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz));
256 if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
257 cipher != R92C_CAM_ALGO_NONE)
258 m->m_flags |= M_WEP;
259
260 if (pktlen >= sizeof(*wh)) {
261 ni = ieee80211_find_rxnode(ic, wh);
262 if (ni != NULL && (ni->ni_flags & IEEE80211_NODE_HT))
263 m->m_flags |= M_AMPDU;
264 } else
265 ni = NULL;
266 un = RTWN_NODE(ni);
267
268 if (infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST))
269 physt = (void *)mtodo(m, shift);
270 else
271 physt = (un != NULL) ? &un->last_physt : &sc->last_physt;
272
273 bzero(&rxs, sizeof(rxs));
274 rtwn_get_rx_stats(sc, &rxs, desc, physt);
275 if (rxs.c_pktflags & IEEE80211_RX_F_AMPDU) {
276 /* Next MPDU will come without PHY info. */
277 memcpy(&sc->last_physt, physt, sizeof(sc->last_physt));
278 if (un != NULL)
279 memcpy(&un->last_physt, physt, sizeof(sc->last_physt));
280 }
281
282 /* Add some common bits. */
283 /* NB: should not happen. */
284 if (rxdw0 & RTWN_RXDW0_CRCERR)
285 rxs.c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC;
286
287 rxs.r_flags |= IEEE80211_R_TSF_START; /* XXX undocumented */
288 rxs.r_flags |= IEEE80211_R_TSF64;
289 rxs.c_rx_tsf = rtwn_extend_rx_tsf(sc, stat);
290
291 /* Get RSSI from PHY status descriptor. */
292 is_cck = (rxs.c_pktflags & IEEE80211_RX_F_CCK) != 0;
293 rssi = rtwn_get_rssi(sc, physt, is_cck);
294
295 /* XXX TODO: we really need a rate-to-string method */
296 RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, rate %d\n",
297 __func__, rssi, rxs.c_rate);
298 if (un != NULL && infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST)) {
299 /* Update our average RSSI. */
300 rtwn_update_avgrssi(sc, un, rssi, is_cck);
301 }
302
303 rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI;
304 rxs.c_nf = RTWN_NOISE_FLOOR;
305 rxs.c_rssi = rssi - rxs.c_nf;
306 (void) ieee80211_add_rx_params(m, &rxs);
307
308 if (ieee80211_radiotap_active(ic)) {
309 struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
310
311 tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc);
312 tap->wr_tsft = htole64(rxs.c_rx_tsf);
313 tap->wr_rate = rxs.c_rate;
314 tap->wr_dbm_antsignal = rssi;
315 tap->wr_dbm_antnoise = rxs.c_nf;
316 }
317
318 /* Drop PHY descriptor. */
319 m_adj(m, infosz + shift);
320
321 return (ni);
322 }
323
324 void
rtwn_adhoc_recv_mgmt(struct ieee80211_node * ni,struct mbuf * m,int subtype,const struct ieee80211_rx_stats * rxs,int rssi,int nf)325 rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
326 const struct ieee80211_rx_stats *rxs,
327 int rssi, int nf)
328 {
329 struct ieee80211vap *vap = ni->ni_vap;
330 struct rtwn_softc *sc = vap->iv_ic->ic_softc;
331 struct rtwn_vap *uvp = RTWN_VAP(vap);
332 uint64_t ni_tstamp, curr_tstamp;
333
334 uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
335
336 if (vap->iv_state == IEEE80211_S_RUN &&
337 (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
338 subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
339 ni_tstamp = le64toh(ni->ni_tstamp.tsf);
340 RTWN_LOCK(sc);
341 rtwn_get_tsf(sc, &curr_tstamp, uvp->id);
342 RTWN_UNLOCK(sc);
343
344 if (ni_tstamp >= curr_tstamp)
345 (void) ieee80211_ibss_merge(ni);
346 }
347 }
348
349 static uint8_t
rtwn_get_multi_pos(const uint8_t maddr[])350 rtwn_get_multi_pos(const uint8_t maddr[])
351 {
352 uint64_t mask = 0x00004d101df481b4;
353 uint8_t pos = 0x27; /* initial value */
354 int i, j;
355
356 for (i = 0; i < IEEE80211_ADDR_LEN; i++)
357 for (j = (i == 0) ? 1 : 0; j < 8; j++)
358 if ((maddr[i] >> j) & 1)
359 pos ^= (mask >> (i * 8 + j - 1));
360
361 pos &= 0x3f;
362
363 return (pos);
364 }
365
366 static u_int
rtwm_hash_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)367 rtwm_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
368 {
369 uint32_t *mfilt = arg;
370 uint8_t pos;
371
372 pos = rtwn_get_multi_pos(LLADDR(sdl));
373 mfilt[pos / 32] |= (1 << (pos % 32));
374
375 return (1);
376 }
377
378 void
rtwn_set_multi(struct rtwn_softc * sc)379 rtwn_set_multi(struct rtwn_softc *sc)
380 {
381 struct ieee80211com *ic = &sc->sc_ic;
382 uint32_t mfilt[2];
383
384 RTWN_ASSERT_LOCKED(sc);
385
386 /* general structure was copied from ath(4). */
387 if (ic->ic_allmulti == 0) {
388 struct ieee80211vap *vap;
389
390 /*
391 * Merge multicast addresses to form the hardware filter.
392 */
393 mfilt[0] = mfilt[1] = 0;
394 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
395 if_foreach_llmaddr(vap->iv_ifp, rtwm_hash_maddr, mfilt);
396 } else
397 mfilt[0] = mfilt[1] = ~0;
398
399 rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]);
400 rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]);
401
402 RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n",
403 __func__, mfilt[0], mfilt[1]);
404 }
405
406 static void
rtwn_rxfilter_update_mgt(struct rtwn_softc * sc)407 rtwn_rxfilter_update_mgt(struct rtwn_softc *sc)
408 {
409 uint16_t filter;
410
411 filter = 0x7f7f;
412 if (sc->bcn_vaps == 0) { /* STA and/or MONITOR mode vaps */
413 filter &= ~(
414 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) |
415 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) |
416 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ));
417 }
418 if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) { /* AP vaps only */
419 filter &= ~(
420 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) |
421 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP));
422 }
423 rtwn_write_2(sc, R92C_RXFLTMAP0, filter);
424 }
425
426 void
rtwn_rxfilter_update(struct rtwn_softc * sc)427 rtwn_rxfilter_update(struct rtwn_softc *sc)
428 {
429
430 RTWN_ASSERT_LOCKED(sc);
431
432 /* Filter for management frames. */
433 rtwn_rxfilter_update_mgt(sc);
434
435 /* Update Rx filter. */
436 rtwn_set_promisc(sc);
437 }
438
439 void
rtwn_rxfilter_init(struct rtwn_softc * sc)440 rtwn_rxfilter_init(struct rtwn_softc *sc)
441 {
442
443 RTWN_ASSERT_LOCKED(sc);
444
445 /* Setup multicast filter. */
446 rtwn_set_multi(sc);
447
448 /* Reject all control frames. */
449 rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
450
451 /* Reject all data frames. */
452 rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000);
453
454 /* Append generic Rx filter bits. */
455 sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM |
456 R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS |
457 R92C_RCR_APP_ICV | R92C_RCR_APP_MIC;
458
459 /* Update dynamic Rx filter parts. */
460 rtwn_rxfilter_update(sc);
461 }
462
463 void
rtwn_rxfilter_set(struct rtwn_softc * sc)464 rtwn_rxfilter_set(struct rtwn_softc *sc)
465 {
466 if (!(sc->sc_flags & RTWN_RCR_LOCKED))
467 rtwn_write_4(sc, R92C_RCR, sc->rcr);
468 }
469
470 void
rtwn_set_rx_bssid_all(struct rtwn_softc * sc,int enable)471 rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable)
472 {
473
474 if (enable)
475 sc->rcr &= ~R92C_RCR_CBSSID_BCN;
476 else
477 sc->rcr |= R92C_RCR_CBSSID_BCN;
478 rtwn_rxfilter_set(sc);
479 }
480
481 void
rtwn_set_promisc(struct rtwn_softc * sc)482 rtwn_set_promisc(struct rtwn_softc *sc)
483 {
484 struct ieee80211com *ic = &sc->sc_ic;
485 uint32_t mask_all, mask_min;
486
487 RTWN_ASSERT_LOCKED(sc);
488
489 mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP;
490 mask_min = R92C_RCR_APM;
491
492 if (sc->bcn_vaps == 0)
493 mask_min |= R92C_RCR_CBSSID_BCN;
494 if (sc->ap_vaps == 0)
495 mask_min |= R92C_RCR_CBSSID_DATA;
496
497 if (ic->ic_promisc == 0 && sc->mon_vaps == 0) {
498 if (sc->bcn_vaps != 0)
499 mask_all |= R92C_RCR_CBSSID_BCN;
500 if (sc->ap_vaps != 0) /* for Null data frames */
501 mask_all |= R92C_RCR_CBSSID_DATA;
502
503 sc->rcr &= ~mask_all;
504 sc->rcr |= mask_min;
505 } else {
506 sc->rcr &= ~mask_min;
507 sc->rcr |= mask_all;
508 }
509 rtwn_rxfilter_set(sc);
510 }
511