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 void 370 rtwn_set_multi(struct rtwn_softc *sc) 371 { 372 struct ieee80211com *ic = &sc->sc_ic; 373 uint32_t mfilt[2]; 374 375 RTWN_ASSERT_LOCKED(sc); 376 377 /* general structure was copied from ath(4). */ 378 if (ic->ic_allmulti == 0) { 379 struct ieee80211vap *vap; 380 struct ifnet *ifp; 381 struct ifmultiaddr *ifma; 382 383 /* 384 * Merge multicast addresses to form the hardware filter. 385 */ 386 mfilt[0] = mfilt[1] = 0; 387 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 388 ifp = vap->iv_ifp; 389 if_maddr_rlock(ifp); 390 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 391 caddr_t dl; 392 uint8_t pos; 393 394 dl = LLADDR((struct sockaddr_dl *) 395 ifma->ifma_addr); 396 pos = rtwn_get_multi_pos(dl); 397 398 mfilt[pos / 32] |= (1 << (pos % 32)); 399 } 400 if_maddr_runlock(ifp); 401 } 402 } else 403 mfilt[0] = mfilt[1] = ~0; 404 405 406 rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]); 407 rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]); 408 409 RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n", 410 __func__, mfilt[0], mfilt[1]); 411 } 412 413 static void 414 rtwn_rxfilter_update_mgt(struct rtwn_softc *sc) 415 { 416 uint16_t filter; 417 418 filter = 0x7f7f; 419 if (sc->bcn_vaps == 0) { /* STA and/or MONITOR mode vaps */ 420 filter &= ~( 421 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) | 422 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) | 423 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ)); 424 } 425 if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) { /* AP vaps only */ 426 filter &= ~( 427 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | 428 R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP)); 429 } 430 rtwn_write_2(sc, R92C_RXFLTMAP0, filter); 431 } 432 433 void 434 rtwn_rxfilter_update(struct rtwn_softc *sc) 435 { 436 437 RTWN_ASSERT_LOCKED(sc); 438 439 /* Filter for management frames. */ 440 rtwn_rxfilter_update_mgt(sc); 441 442 /* Update Rx filter. */ 443 rtwn_set_promisc(sc); 444 } 445 446 void 447 rtwn_rxfilter_init(struct rtwn_softc *sc) 448 { 449 450 RTWN_ASSERT_LOCKED(sc); 451 452 /* Setup multicast filter. */ 453 rtwn_set_multi(sc); 454 455 /* Reject all control frames. */ 456 rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); 457 458 /* Reject all data frames. */ 459 rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); 460 461 /* Append generic Rx filter bits. */ 462 sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | 463 R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | 464 R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; 465 466 /* Update dynamic Rx filter parts. */ 467 rtwn_rxfilter_update(sc); 468 } 469 470 void 471 rtwn_rxfilter_set(struct rtwn_softc *sc) 472 { 473 if (!(sc->sc_flags & RTWN_RCR_LOCKED)) 474 rtwn_write_4(sc, R92C_RCR, sc->rcr); 475 } 476 477 void 478 rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable) 479 { 480 481 if (enable) 482 sc->rcr &= ~R92C_RCR_CBSSID_BCN; 483 else 484 sc->rcr |= R92C_RCR_CBSSID_BCN; 485 rtwn_rxfilter_set(sc); 486 } 487 488 void 489 rtwn_set_promisc(struct rtwn_softc *sc) 490 { 491 struct ieee80211com *ic = &sc->sc_ic; 492 uint32_t mask_all, mask_min; 493 494 RTWN_ASSERT_LOCKED(sc); 495 496 mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; 497 mask_min = R92C_RCR_APM; 498 499 if (sc->bcn_vaps == 0) 500 mask_min |= R92C_RCR_CBSSID_BCN; 501 if (sc->ap_vaps == 0) 502 mask_min |= R92C_RCR_CBSSID_DATA; 503 504 if (ic->ic_promisc == 0 && sc->mon_vaps == 0) { 505 if (sc->bcn_vaps != 0) 506 mask_all |= R92C_RCR_CBSSID_BCN; 507 if (sc->ap_vaps != 0) /* for Null data frames */ 508 mask_all |= R92C_RCR_CBSSID_DATA; 509 510 sc->rcr &= ~mask_all; 511 sc->rcr |= mask_min; 512 } else { 513 sc->rcr &= ~mask_min; 514 sc->rcr |= mask_all; 515 } 516 rtwn_rxfilter_set(sc); 517 } 518