]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/rtwn/if_rtwn_rx.c
Merge ^/head r307383 through r307735.
[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 #include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
57
58
59 void
60 rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs,
61     const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p,
62     int *maxrate_p, int basic_rates)
63 {
64         uint32_t rates;
65         uint8_t ridx;
66         int i, maxrate;
67
68         /* Get rates mask. */
69         rates = 0;
70         maxrate = 0;
71
72         /* This is for 11bg */
73         for (i = 0; i < rs->rs_nrates; i++) {
74                 /* Convert 802.11 rate to HW rate index. */
75                 ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i]));
76                 if (ridx == RTWN_RIDX_UNKNOWN)  /* Unknown rate, skip. */
77                         continue;
78                 if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) ||
79                     !basic_rates) {
80                         rates |= 1 << ridx;
81                         if (ridx > maxrate)
82                                 maxrate = ridx;
83                 }
84         }
85
86         /* If we're doing 11n, enable 11n rates */
87         if (rs_ht != NULL && !basic_rates) {
88                 for (i = 0; i < rs_ht->rs_nrates; i++) {
89                         if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
90                                 continue;
91                         /* 11n rates start at index 12 */
92                         ridx = RTWN_RIDX_MCS((rs_ht->rs_rates[i]) & 0xf);
93                         rates |= (1 << ridx);
94
95                         /* Guard against the rate table being oddly ordered */
96                         if (ridx > maxrate)
97                                 maxrate = ridx;
98                 }
99         }
100
101         RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
102             "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate);
103
104         if (rates_p != NULL)
105                 *rates_p = rates;
106         if (maxrate_p != NULL)
107                 *maxrate_p = maxrate;
108 }
109
110 void
111 rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates)
112 {
113
114         RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates);
115
116         rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates);
117 }
118
119 static void
120 rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int rate)
121 {
122         int pwdb;
123
124         /* Convert antenna signal to percentage. */
125         if (un->last_rssi <= -100 || un->last_rssi >= 20)
126                 pwdb = 0;
127         else if (un->last_rssi >= 0)
128                 pwdb = 100;
129         else
130                 pwdb = 100 + un->last_rssi;
131         if (RTWN_RATE_IS_CCK(rate)) {
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, int rate, void *physt)
159 {
160         int8_t rssi;
161
162         if (RTWN_RATE_IS_CCK(rate))
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 struct ieee80211_node *
192 rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc,
193     int8_t *rssi)
194 {
195         struct ieee80211com *ic = &sc->sc_ic;
196         struct ieee80211_node *ni;
197         struct ieee80211_frame_min *wh;
198         struct rtwn_node *un;
199         struct r92c_rx_stat *stat;
200         uint32_t rxdw0, rxdw3;
201         int cipher, infosz, pktlen, rate, shift;
202
203         stat = desc;
204         rxdw0 = le32toh(stat->rxdw0);
205         rxdw3 = le32toh(stat->rxdw3);
206
207         cipher = MS(rxdw0, R92C_RXDW0_CIPHER);
208         infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
209         pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
210         shift = MS(rxdw0, R92C_RXDW0_SHIFT);
211         rate = MS(rxdw3, R92C_RXDW3_RATE);
212
213         wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz));
214         if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
215             cipher != R92C_CAM_ALGO_NONE)
216                 m->m_flags |= M_WEP;
217
218         if (pktlen >= sizeof(*wh))
219                 ni = ieee80211_find_rxnode(ic, wh);
220         else
221                 ni = NULL;
222         un = RTWN_NODE(ni);
223
224         /* Get RSSI from PHY status descriptor if present. */
225         if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
226                 *rssi = rtwn_get_rssi(sc, rate, mtod(m, void *));
227                 RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, ridx %d\n",
228                     __func__, *rssi, rate);
229
230                 sc->last_rssi = *rssi;
231                 if (un != NULL) {
232                         un->last_rssi = *rssi;
233
234                         /* Update our average RSSI. */
235                         rtwn_update_avgrssi(sc, un, rate);
236                 }
237         } else
238                 *rssi = (un != NULL) ? un->last_rssi : sc->last_rssi;
239
240         if (ieee80211_radiotap_active(ic)) {
241                 struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
242                 int id = RTWN_VAP_ID_INVALID;
243
244                 if (ni != NULL)
245                         id = RTWN_VAP(ni->ni_vap)->id;
246                 if (id == RTWN_VAP_ID_INVALID)
247                         id = 0;
248
249                 tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc);
250                 tap->wr_tsft = rtwn_get_tsf_high(sc, id);
251                 if (le32toh(stat->tsf_low) > rtwn_get_tsf_low(sc, id))
252                         tap->wr_tsft--;
253                 tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32;
254                 tap->wr_tsft += stat->tsf_low;
255
256                 /* XXX 20/40? */
257
258                 /* Map HW rate index to 802.11 rate. */
259                 if (rate < RTWN_RIDX_MCS(0))
260                         tap->wr_rate = ridx2rate[rate];
261                 else    /* MCS0~15. */
262                         tap->wr_rate = IEEE80211_RATE_MCS | (rate - 12);
263
264                 tap->wr_dbm_antsignal = *rssi;
265                 tap->wr_dbm_antnoise = RTWN_NOISE_FLOOR;
266         }
267
268         /* Drop PHY descriptor. */
269         m_adj(m, infosz + shift);
270
271         return (ni);
272 }
273
274 void
275 rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
276     const struct ieee80211_rx_stats *rxs,
277     int rssi, int nf)
278 {
279         struct ieee80211vap *vap = ni->ni_vap;
280         struct rtwn_softc *sc = vap->iv_ic->ic_softc;
281         struct rtwn_vap *uvp = RTWN_VAP(vap);
282         uint64_t ni_tstamp, curr_tstamp;
283
284         uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
285
286         if (vap->iv_state == IEEE80211_S_RUN &&
287             (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
288             subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
289                 ni_tstamp = le64toh(ni->ni_tstamp.tsf);
290                 RTWN_LOCK(sc);
291                 rtwn_get_tsf(sc, &curr_tstamp, uvp->id);
292                 RTWN_UNLOCK(sc);
293
294                 if (ni_tstamp >= curr_tstamp)
295                         (void) ieee80211_ibss_merge(ni);
296         }
297 }
298
299 static uint8_t
300 rtwn_get_multi_pos(const uint8_t maddr[])
301 {
302         uint64_t mask = 0x00004d101df481b4;
303         uint8_t pos = 0x27;     /* initial value */
304         int i, j;
305
306         for (i = 0; i < IEEE80211_ADDR_LEN; i++)
307                 for (j = (i == 0) ? 1 : 0; j < 8; j++)
308                         if ((maddr[i] >> j) & 1)
309                                 pos ^= (mask >> (i * 8 + j - 1));
310
311         pos &= 0x3f;
312
313         return (pos);
314 }
315
316 void
317 rtwn_set_multi(struct rtwn_softc *sc)
318 {
319         struct ieee80211com *ic = &sc->sc_ic;
320         uint32_t mfilt[2];
321
322         RTWN_ASSERT_LOCKED(sc);
323
324         /* general structure was copied from ath(4). */
325         if (ic->ic_allmulti == 0) {
326                 struct ieee80211vap *vap;
327                 struct ifnet *ifp;
328                 struct ifmultiaddr *ifma;
329
330                 /*
331                  * Merge multicast addresses to form the hardware filter.
332                  */
333                 mfilt[0] = mfilt[1] = 0;
334                 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
335                         ifp = vap->iv_ifp;
336                         if_maddr_rlock(ifp);
337                         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
338                                 caddr_t dl;
339                                 uint8_t pos;
340
341                                 dl = LLADDR((struct sockaddr_dl *)
342                                     ifma->ifma_addr);
343                                 pos = rtwn_get_multi_pos(dl);
344
345                                 mfilt[pos / 32] |= (1 << (pos % 32));
346                         }
347                         if_maddr_runlock(ifp);
348                 }
349         } else
350                 mfilt[0] = mfilt[1] = ~0;
351
352
353         rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]);
354         rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]);
355
356         RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n",
357             __func__, mfilt[0], mfilt[1]);
358 }
359
360 static void
361 rtwn_rxfilter_update_mgt(struct rtwn_softc *sc)
362 {
363         uint16_t filter;
364
365         filter = 0x7f3f;
366         if (sc->bcn_vaps == 0) {        /* STA and/or MONITOR mode vaps */
367                 filter &= ~(
368                     R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) |
369                     R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) |
370                     R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ));
371         }
372         if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) {  /* AP vaps only */
373                 filter &= ~(
374                     R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) |
375                     R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP));
376         }
377         rtwn_write_2(sc, R92C_RXFLTMAP0, filter);
378 }
379
380 void
381 rtwn_rxfilter_update(struct rtwn_softc *sc)
382 {
383
384         RTWN_ASSERT_LOCKED(sc);
385
386         /* Filter for management frames. */
387         rtwn_rxfilter_update_mgt(sc);
388
389         /* Update Rx filter. */
390         rtwn_set_promisc(sc);
391 }
392
393 void
394 rtwn_rxfilter_init(struct rtwn_softc *sc)
395 {
396         uint32_t rcr;
397
398         RTWN_ASSERT_LOCKED(sc);
399
400         /* Setup multicast filter. */
401         rtwn_set_multi(sc);
402
403         /* Reject all control frames. */
404         rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
405
406         /* Reject all data frames. */
407         rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000);
408
409         rcr = sc->rcr;
410         rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM |
411                R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS |
412                R92C_RCR_APP_ICV | R92C_RCR_APP_MIC;
413
414         /* Set Rx filter. */
415         rtwn_write_4(sc, R92C_RCR, rcr);
416
417         /* Update dynamic Rx filter parts. */
418         rtwn_rxfilter_update(sc);
419 }
420
421 void
422 rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable)
423 {
424         if (enable)
425                 rtwn_setbits_4(sc, R92C_RCR, R92C_RCR_CBSSID_BCN, 0);
426         else
427                 rtwn_setbits_4(sc, R92C_RCR, 0, R92C_RCR_CBSSID_BCN);
428 }
429
430 void
431 rtwn_set_promisc(struct rtwn_softc *sc)
432 {
433         struct ieee80211com *ic = &sc->sc_ic;
434         uint32_t mask1, mask2;
435
436         RTWN_ASSERT_LOCKED(sc);
437
438         mask1 = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP;
439         mask2 = R92C_RCR_APM;
440
441         if (sc->vaps_running != 0) {
442                 if (sc->bcn_vaps == 0)
443                         mask2 |= R92C_RCR_CBSSID_BCN;
444                 if (sc->ap_vaps == 0)
445                         mask2 |= R92C_RCR_CBSSID_DATA;
446         }
447
448         if (ic->ic_promisc == 0 && sc->mon_vaps == 0)
449                 rtwn_setbits_4(sc, R92C_RCR, mask1, mask2);
450         else
451                 rtwn_setbits_4(sc, R92C_RCR, mask2, mask1);
452 }