source: rtems-libbsd/freebsd/sys/dev/rtwn/if_rtwn_rx.c @ 0cbb715

55-freebsd-126-freebsd-12
Last change on this file since 0cbb715 was 0cbb715, checked in by Christian Mauderer <Christian.Mauderer@…>, on 11/22/16 at 09:41:47

rtwn: Import from FreeBSD.

  • Property mode set to 100644
File size: 11.2 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*      $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $   */
4
5/*-
6 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
7 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
8 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include <sys/cdefs.h>
24__FBSDID("$FreeBSD$");
25
26#include <rtems/bsd/local/opt_wlan.h>
27
28#include <rtems/bsd/sys/param.h>
29#include <rtems/bsd/sys/lock.h>
30#include <sys/mutex.h>
31#include <sys/mbuf.h>
32#include <sys/kernel.h>
33#include <sys/socket.h>
34#include <sys/systm.h>
35#include <sys/malloc.h>
36#include <sys/queue.h>
37#include <sys/taskqueue.h>
38#include <sys/bus.h>
39#include <sys/endian.h>
40
41#include <net/if.h>
42#include <net/if_var.h>
43#include <net/ethernet.h>
44#include <net/if_dl.h>
45#include <net/if_media.h>
46
47#include <net80211/ieee80211_var.h>
48#include <net80211/ieee80211_radiotap.h>
49
50#include <dev/rtwn/if_rtwnreg.h>
51#include <dev/rtwn/if_rtwnvar.h>
52
53#include <dev/rtwn/if_rtwn_debug.h>
54#include <dev/rtwn/if_rtwn_ridx.h>
55#include <dev/rtwn/if_rtwn_rx.h>
56
57#include <dev/rtwn/rtl8192c/r92c_reg.h>
58#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
59
60
61void
62rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs,
63    const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p,
64    int *maxrate_p, int basic_rates)
65{
66        uint32_t rates;
67        uint8_t ridx;
68        int i, maxrate;
69
70        /* Get rates mask. */
71        rates = 0;
72        maxrate = 0;
73
74        /* This is for 11bg */
75        for (i = 0; i < rs->rs_nrates; i++) {
76                /* Convert 802.11 rate to HW rate index. */
77                ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i]));
78                if (ridx == RTWN_RIDX_UNKNOWN)  /* Unknown rate, skip. */
79                        continue;
80                if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) ||
81                    !basic_rates) {
82                        rates |= 1 << ridx;
83                        if (ridx > maxrate)
84                                maxrate = ridx;
85                }
86        }
87
88        /* If we're doing 11n, enable 11n rates */
89        if (rs_ht != NULL && !basic_rates) {
90                for (i = 0; i < rs_ht->rs_nrates; i++) {
91                        if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
92                                continue;
93                        /* 11n rates start at index 12 */
94                        ridx = RTWN_RIDX_MCS((rs_ht->rs_rates[i]) & 0xf);
95                        rates |= (1 << ridx);
96
97                        /* Guard against the rate table being oddly ordered */
98                        if (ridx > maxrate)
99                                maxrate = ridx;
100                }
101        }
102
103        RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
104            "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate);
105
106        if (rates_p != NULL)
107                *rates_p = rates;
108        if (maxrate_p != NULL)
109                *maxrate_p = maxrate;
110}
111
112void
113rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates)
114{
115
116        RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates);
117
118        rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates);
119}
120
121static void
122rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int rate)
123{
124        int pwdb;
125
126        /* Convert antenna signal to percentage. */
127        if (un->last_rssi <= -100 || un->last_rssi >= 20)
128                pwdb = 0;
129        else if (un->last_rssi >= 0)
130                pwdb = 100;
131        else
132                pwdb = 100 + un->last_rssi;
133        if (RTWN_RATE_IS_CCK(rate)) {
134                /* CCK gain is smaller than OFDM/MCS gain. */
135                pwdb += 6;
136                if (pwdb > 100)
137                        pwdb = 100;
138                if (pwdb <= 14)
139                        pwdb -= 4;
140                else if (pwdb <= 26)
141                        pwdb -= 8;
142                else if (pwdb <= 34)
143                        pwdb -= 6;
144                else if (pwdb <= 42)
145                        pwdb -= 2;
146        }
147
148        if (un->avg_pwdb == -1) /* Init. */
149                un->avg_pwdb = pwdb;
150        else if (un->avg_pwdb < pwdb)
151                un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1;
152        else
153                un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20);
154
155        RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI,
156            "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb);
157}
158
159static int8_t
160rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt)
161{
162        int8_t rssi;
163
164        if (RTWN_RATE_IS_CCK(rate))
165                rssi = rtwn_get_rssi_cck(sc, physt);
166        else    /* OFDM/HT. */
167                rssi = rtwn_get_rssi_ofdm(sc, physt);
168
169        return (rssi);
170}
171
172static uint32_t
173rtwn_get_tsf_low(struct rtwn_softc *sc, int id)
174{
175        return (rtwn_read_4(sc, R92C_TSFTR(id)));
176}
177
178static uint32_t
179rtwn_get_tsf_high(struct rtwn_softc *sc, int id)
180{
181        return (rtwn_read_4(sc, R92C_TSFTR(id) + 4));
182}
183
184static void
185rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id)
186{
187        /* NB: we cannot read it at once. */
188        *buf = rtwn_get_tsf_high(sc, id);
189        *buf <<= 32;
190        *buf += rtwn_get_tsf_low(sc, id);
191}
192
193struct ieee80211_node *
194rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc,
195    int8_t *rssi)
196{
197        struct ieee80211com *ic = &sc->sc_ic;
198        struct ieee80211_node *ni;
199        struct ieee80211_frame_min *wh;
200        struct rtwn_node *un;
201        struct r92c_rx_stat *stat;
202        uint32_t rxdw0, rxdw3;
203        int cipher, infosz, pktlen, rate, shift;
204
205        stat = desc;
206        rxdw0 = le32toh(stat->rxdw0);
207        rxdw3 = le32toh(stat->rxdw3);
208
209        cipher = MS(rxdw0, R92C_RXDW0_CIPHER);
210        infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
211        pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
212        shift = MS(rxdw0, R92C_RXDW0_SHIFT);
213        rate = MS(rxdw3, R92C_RXDW3_RATE);
214
215        wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz));
216        if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
217            cipher != R92C_CAM_ALGO_NONE)
218                m->m_flags |= M_WEP;
219
220        if (pktlen >= sizeof(*wh))
221                ni = ieee80211_find_rxnode(ic, wh);
222        else
223                ni = NULL;
224        un = RTWN_NODE(ni);
225
226        /* Get RSSI from PHY status descriptor if present. */
227        if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
228                *rssi = rtwn_get_rssi(sc, rate, mtod(m, void *));
229                RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, ridx %d\n",
230                    __func__, *rssi, rate);
231
232                sc->last_rssi = *rssi;
233                if (un != NULL) {
234                        un->last_rssi = *rssi;
235
236                        /* Update our average RSSI. */
237                        rtwn_update_avgrssi(sc, un, rate);
238                }
239        } else
240                *rssi = (un != NULL) ? un->last_rssi : sc->last_rssi;
241
242        if (ieee80211_radiotap_active(ic)) {
243                struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
244                int id = RTWN_VAP_ID_INVALID;
245
246                if (ni != NULL)
247                        id = RTWN_VAP(ni->ni_vap)->id;
248                if (id == RTWN_VAP_ID_INVALID)
249                        id = 0;
250
251                tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc);
252                tap->wr_tsft = rtwn_get_tsf_high(sc, id);
253                if (le32toh(stat->tsf_low) > rtwn_get_tsf_low(sc, id))
254                        tap->wr_tsft--;
255                tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32;
256                tap->wr_tsft += stat->tsf_low;
257
258                /* XXX 20/40? */
259
260                /* Map HW rate index to 802.11 rate. */
261                if (rate < RTWN_RIDX_MCS(0))
262                        tap->wr_rate = ridx2rate[rate];
263                else    /* MCS0~15. */
264                        tap->wr_rate = IEEE80211_RATE_MCS | (rate - 12);
265
266                tap->wr_dbm_antsignal = *rssi;
267                tap->wr_dbm_antnoise = RTWN_NOISE_FLOOR;
268        }
269
270        /* Drop PHY descriptor. */
271        m_adj(m, infosz + shift);
272
273        return (ni);
274}
275
276void
277rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
278    const struct ieee80211_rx_stats *rxs,
279    int rssi, int nf)
280{
281        struct ieee80211vap *vap = ni->ni_vap;
282        struct rtwn_softc *sc = vap->iv_ic->ic_softc;
283        struct rtwn_vap *uvp = RTWN_VAP(vap);
284        uint64_t ni_tstamp, curr_tstamp;
285
286        uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
287
288        if (vap->iv_state == IEEE80211_S_RUN &&
289            (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
290            subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
291                ni_tstamp = le64toh(ni->ni_tstamp.tsf);
292                RTWN_LOCK(sc);
293                rtwn_get_tsf(sc, &curr_tstamp, uvp->id);
294                RTWN_UNLOCK(sc);
295
296                if (ni_tstamp >= curr_tstamp)
297                        (void) ieee80211_ibss_merge(ni);
298        }
299}
300
301static uint8_t
302rtwn_get_multi_pos(const uint8_t maddr[])
303{
304        uint64_t mask = 0x00004d101df481b4;
305        uint8_t pos = 0x27;     /* initial value */
306        int i, j;
307
308        for (i = 0; i < IEEE80211_ADDR_LEN; i++)
309                for (j = (i == 0) ? 1 : 0; j < 8; j++)
310                        if ((maddr[i] >> j) & 1)
311                                pos ^= (mask >> (i * 8 + j - 1));
312
313        pos &= 0x3f;
314
315        return (pos);
316}
317
318void
319rtwn_set_multi(struct rtwn_softc *sc)
320{
321        struct ieee80211com *ic = &sc->sc_ic;
322        uint32_t mfilt[2];
323
324        RTWN_ASSERT_LOCKED(sc);
325
326        /* general structure was copied from ath(4). */
327        if (ic->ic_allmulti == 0) {
328                struct ieee80211vap *vap;
329                struct ifnet *ifp;
330                struct ifmultiaddr *ifma;
331
332                /*
333                 * Merge multicast addresses to form the hardware filter.
334                 */
335                mfilt[0] = mfilt[1] = 0;
336                TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
337                        ifp = vap->iv_ifp;
338                        if_maddr_rlock(ifp);
339                        TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
340                                caddr_t dl;
341                                uint8_t pos;
342
343                                dl = LLADDR((struct sockaddr_dl *)
344                                    ifma->ifma_addr);
345                                pos = rtwn_get_multi_pos(dl);
346
347                                mfilt[pos / 32] |= (1 << (pos % 32));
348                        }
349                        if_maddr_runlock(ifp);
350                }
351        } else
352                mfilt[0] = mfilt[1] = ~0;
353
354
355        rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]);
356        rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]);
357
358        RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n",
359            __func__, mfilt[0], mfilt[1]);
360}
361
362static void
363rtwn_rxfilter_update_mgt(struct rtwn_softc *sc)
364{
365        uint16_t filter;
366
367        filter = 0x7f7f;
368        if (sc->bcn_vaps == 0) {        /* STA and/or MONITOR mode vaps */
369                filter &= ~(
370                    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) |
371                    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) |
372                    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ));
373        }
374        if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) {  /* AP vaps only */
375                filter &= ~(
376                    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) |
377                    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP));
378        }
379        rtwn_write_2(sc, R92C_RXFLTMAP0, filter);
380}
381
382void
383rtwn_rxfilter_update(struct rtwn_softc *sc)
384{
385
386        RTWN_ASSERT_LOCKED(sc);
387
388        /* Filter for management frames. */
389        rtwn_rxfilter_update_mgt(sc);
390
391        /* Update Rx filter. */
392        rtwn_set_promisc(sc);
393}
394
395void
396rtwn_rxfilter_init(struct rtwn_softc *sc)
397{
398
399        RTWN_ASSERT_LOCKED(sc);
400
401        /* Setup multicast filter. */
402        rtwn_set_multi(sc);
403
404        /* Reject all control frames. */
405        rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
406
407        /* Reject all data frames. */
408        rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000);
409
410        /* Append generic Rx filter bits. */
411        sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM |
412            R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS |
413            R92C_RCR_APP_ICV | R92C_RCR_APP_MIC;
414
415        /* Update dynamic Rx filter parts. */
416        rtwn_rxfilter_update(sc);
417}
418
419void
420rtwn_rxfilter_set(struct rtwn_softc *sc)
421{
422        if (!(sc->sc_flags & RTWN_RCR_LOCKED))
423                rtwn_write_4(sc, R92C_RCR, sc->rcr);
424}
425
426void
427rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable)
428{
429
430        if (enable)
431                sc->rcr &= ~R92C_RCR_CBSSID_BCN;
432        else
433                sc->rcr |= R92C_RCR_CBSSID_BCN;
434        rtwn_rxfilter_set(sc);
435}
436
437void
438rtwn_set_promisc(struct rtwn_softc *sc)
439{
440        struct ieee80211com *ic = &sc->sc_ic;
441        uint32_t mask_all, mask_min;
442
443        RTWN_ASSERT_LOCKED(sc);
444
445        mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP;
446        mask_min = R92C_RCR_APM;
447
448        if (sc->bcn_vaps == 0)
449                mask_min |= R92C_RCR_CBSSID_BCN;
450        if (sc->ap_vaps == 0)
451                mask_min |= R92C_RCR_CBSSID_DATA;
452
453        if (ic->ic_promisc == 0 && sc->mon_vaps == 0) {
454                if (sc->bcn_vaps != 0)
455                        mask_all |= R92C_RCR_CBSSID_BCN;
456                if (sc->ap_vaps != 0)   /* for Null data frames */
457                        mask_all |= R92C_RCR_CBSSID_DATA;
458
459                sc->rcr &= ~mask_all;
460                sc->rcr |= mask_min;
461        } else {
462                sc->rcr &= ~mask_min;
463                sc->rcr |= mask_all;
464        }
465        rtwn_rxfilter_set(sc);
466}
Note: See TracBrowser for help on using the repository browser.