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 = 0x7f7f; 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 397 RTWN_ASSERT_LOCKED(sc); 398 399 /* Setup multicast filter. */ 400 rtwn_set_multi(sc); 401 402 /* Reject all control frames. */ 403 rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); 404 405 /* Reject all data frames. */ 406 rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); 407 408 /* Append generic Rx filter bits. */ 409 sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | 410 R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | 411 R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; 412 413 /* Update dynamic Rx filter parts. */ 414 rtwn_rxfilter_update(sc); 415 } 416 417 void 418 rtwn_rxfilter_set(struct rtwn_softc *sc) 419 { 420 if (!(sc->sc_flags & RTWN_RCR_LOCKED)) 421 rtwn_write_4(sc, R92C_RCR, sc->rcr); 422 } 423 424 void 425 rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable) 426 { 427 428 if (enable) 429 sc->rcr &= ~R92C_RCR_CBSSID_BCN; 430 else 431 sc->rcr |= R92C_RCR_CBSSID_BCN; 432 rtwn_rxfilter_set(sc); 433 } 434 435 void 436 rtwn_set_promisc(struct rtwn_softc *sc) 437 { 438 struct ieee80211com *ic = &sc->sc_ic; 439 uint32_t mask_all, mask_min; 440 441 RTWN_ASSERT_LOCKED(sc); 442 443 mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; 444 mask_min = R92C_RCR_APM; 445 446 if (sc->bcn_vaps == 0) 447 mask_min |= R92C_RCR_CBSSID_BCN; 448 if (sc->ap_vaps == 0) 449 mask_min |= R92C_RCR_CBSSID_DATA; 450 451 if (ic->ic_promisc == 0 && sc->mon_vaps == 0) { 452 if (sc->bcn_vaps != 0) 453 mask_all |= R92C_RCR_CBSSID_BCN; 454 if (sc->ap_vaps != 0) /* for Null data frames */ 455 mask_all |= R92C_RCR_CBSSID_DATA; 456 457 sc->rcr &= ~mask_all; 458 sc->rcr |= mask_min; 459 } else { 460 sc->rcr &= ~mask_min; 461 sc->rcr |= mask_all; 462 } 463 rtwn_rxfilter_set(sc); 464 } 465