The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/rtwn/if_rtwn_rx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3a6637415fb57bc737b272f19d0ae0c3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.