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