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