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_media.h> 41 42 #include <net80211/ieee80211_var.h> 43 #include <net80211/ieee80211_radiotap.h> 44 #include <net80211/ieee80211_ratectl.h> 45 #ifdef IEEE80211_SUPPORT_SUPERG 46 #include <net80211/ieee80211_superg.h> 47 #endif 48 49 #include <dev/rtwn/if_rtwnreg.h> 50 #include <dev/rtwn/if_rtwnvar.h> 51 52 #include <dev/rtwn/if_rtwn_beacon.h> 53 #include <dev/rtwn/if_rtwn_debug.h> 54 #include <dev/rtwn/if_rtwn_ridx.h> 55 #include <dev/rtwn/if_rtwn_tx.h> 56 57 void 58 rtwn_drain_mbufq(struct rtwn_softc *sc) 59 { 60 struct mbuf *m; 61 struct ieee80211_node *ni; 62 RTWN_ASSERT_LOCKED(sc); 63 while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 64 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 65 m->m_pkthdr.rcvif = NULL; 66 ieee80211_free_node(ni); 67 m_freem(m); 68 } 69 } 70 71 #ifdef IEEE80211_SUPPORT_SUPERG 72 void 73 rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data) 74 { 75 struct ieee80211com *ic = &sc->sc_ic; 76 77 RTWN_UNLOCK(sc); 78 ieee80211_ff_flush_all(ic); 79 RTWN_LOCK(sc); 80 } 81 #endif 82 83 static uint8_t 84 rtwn_get_cipher(u_int ic_cipher) 85 { 86 uint8_t cipher; 87 88 switch (ic_cipher) { 89 case IEEE80211_CIPHER_NONE: 90 cipher = RTWN_TXDW1_CIPHER_NONE; 91 break; 92 case IEEE80211_CIPHER_WEP: 93 case IEEE80211_CIPHER_TKIP: 94 cipher = RTWN_TXDW1_CIPHER_RC4; 95 break; 96 case IEEE80211_CIPHER_AES_CCM: 97 cipher = RTWN_TXDW1_CIPHER_AES; 98 break; 99 default: 100 KASSERT(0, ("%s: unknown cipher %d\n", __func__, 101 ic_cipher)); 102 return (RTWN_TXDW1_CIPHER_SM4); 103 } 104 105 return (cipher); 106 } 107 108 static uint8_t 109 rtwn_tx_ratectl_to_ridx(struct rtwn_softc *sc, struct ieee80211_node *ni, 110 struct ieee80211_node_txrate *txr) 111 { 112 /* TODO: this should be based on the node channel */ 113 struct ieee80211com *ic = &sc->sc_ic; 114 uint8_t ridx; 115 116 switch (txr->type) { 117 case IEEE80211_NODE_TXRATE_LEGACY: 118 case IEEE80211_NODE_TXRATE_HT: 119 ridx = rate2ridx(txr->dot11rate); 120 break; 121 case IEEE80211_NODE_TXRATE_VHT: 122 ridx = RTWN_RIDX_VHT_MCS(txr->nss - 1, txr->mcs); 123 break; 124 default: 125 if (ic->ic_curmode != IEEE80211_MODE_11B) 126 ridx = RTWN_RIDX_OFDM36; 127 else 128 ridx = RTWN_RIDX_CCK55; 129 break; 130 } 131 132 return (ridx); 133 } 134 135 static int 136 rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, 137 struct mbuf *m) 138 { 139 const struct ieee80211_txparam *tp = ni->ni_txparms; 140 struct ieee80211com *ic = &sc->sc_ic; 141 struct ieee80211vap *vap = ni->ni_vap; 142 struct ieee80211_key *k = NULL; 143 struct ieee80211_frame *wh; 144 struct rtwn_tx_desc_common *txd; 145 struct rtwn_tx_buf buf; 146 uint8_t ridx, type; 147 bool force_rate = false; 148 u_int cipher; 149 int ismcast; 150 151 RTWN_ASSERT_LOCKED(sc); 152 153 wh = mtod(m, struct ieee80211_frame *); 154 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 155 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 156 157 /* Choose a TX rate index. */ 158 if (type == IEEE80211_FC0_TYPE_MGT || 159 type == IEEE80211_FC0_TYPE_CTL || 160 (m->m_flags & M_EAPOL) != 0) { 161 ridx = rate2ridx(tp->mgmtrate); 162 force_rate = true; 163 } else if (ismcast) { 164 ridx = rate2ridx(tp->mcastrate); 165 force_rate = true; 166 } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 167 ridx = rate2ridx(tp->ucastrate); 168 force_rate = true; 169 } else { 170 if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { 171 struct ieee80211_node_txrate txr = { 0 }; 172 /* XXX pass pktlen */ 173 ieee80211_ratectl_rate(ni, NULL, 0); 174 ieee80211_node_get_txrate(ni, &txr); 175 ridx = rtwn_tx_ratectl_to_ridx(sc, ni, &txr); 176 } else { 177 if (ni->ni_flags & IEEE80211_NODE_HT) 178 ridx = rate2ridx(IEEE80211_RATE_MCS | 0x4); /* MCS4 */ 179 else if (ic->ic_curmode != IEEE80211_MODE_11B) 180 ridx = RTWN_RIDX_OFDM36; 181 else 182 ridx = RTWN_RIDX_CCK55; 183 } 184 } 185 186 /* seqno allocate, only if AMPDU isn't running */ 187 if ((m->m_flags & M_AMPDU_MPDU) == 0) 188 ieee80211_output_seqno_assign(ni, -1, m); 189 190 cipher = IEEE80211_CIPHER_NONE; 191 if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 192 k = ieee80211_crypto_encap(ni, m); 193 if (k == NULL) { 194 device_printf(sc->sc_dev, 195 "ieee80211_crypto_encap returns NULL.\n"); 196 return (ENOBUFS); 197 } 198 if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) 199 cipher = k->wk_cipher->ic_cipher; 200 201 /* in case packet header moved, reset pointer */ 202 wh = mtod(m, struct ieee80211_frame *); 203 } 204 205 /* Fill Tx descriptor. */ 206 txd = (struct rtwn_tx_desc_common *)&buf; 207 memset(txd, 0, sc->txdesc_len); 208 txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); 209 210 rtwn_fill_tx_desc(sc, ni, m, txd, ridx, force_rate, tp->maxretry); 211 212 if (ieee80211_radiotap_active_vap(vap)) { 213 struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; 214 215 tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); 216 if (k != NULL) 217 tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 218 ieee80211_radiotap_tx(vap, m); 219 } 220 221 return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); 222 } 223 224 static int 225 rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, 226 struct mbuf *m, const struct ieee80211_bpf_params *params) 227 { 228 struct ieee80211vap *vap = ni->ni_vap; 229 struct ieee80211_key *k = NULL; 230 struct ieee80211_frame *wh; 231 struct rtwn_tx_desc_common *txd; 232 struct rtwn_tx_buf buf; 233 uint8_t type; 234 u_int cipher; 235 236 /* seqno allocate, only if AMPDU isn't running */ 237 if ((m->m_flags & M_AMPDU_MPDU) == 0) 238 ieee80211_output_seqno_assign(ni, -1, m); 239 240 /* Encrypt the frame if need be. */ 241 cipher = IEEE80211_CIPHER_NONE; 242 if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 243 /* Retrieve key for TX. */ 244 k = ieee80211_crypto_encap(ni, m); 245 if (k == NULL) { 246 device_printf(sc->sc_dev, 247 "ieee80211_crypto_encap returns NULL.\n"); 248 return (ENOBUFS); 249 } 250 if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) 251 cipher = k->wk_cipher->ic_cipher; 252 } 253 254 wh = mtod(m, struct ieee80211_frame *); 255 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 256 257 /* Fill Tx descriptor. */ 258 txd = (struct rtwn_tx_desc_common *)&buf; 259 memset(txd, 0, sc->txdesc_len); 260 txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); 261 262 rtwn_fill_tx_desc_raw(sc, ni, m, txd, params); 263 264 if (ieee80211_radiotap_active_vap(vap)) { 265 struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; 266 267 tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); 268 if (k != NULL) 269 tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 270 ieee80211_radiotap_tx(vap, m); 271 } 272 273 return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); 274 } 275 276 int 277 rtwn_transmit(struct ieee80211com *ic, struct mbuf *m) 278 { 279 struct rtwn_softc *sc = ic->ic_softc; 280 int error; 281 282 RTWN_LOCK(sc); 283 if ((sc->sc_flags & RTWN_RUNNING) == 0) { 284 RTWN_UNLOCK(sc); 285 return (ENXIO); 286 } 287 error = mbufq_enqueue(&sc->sc_snd, m); 288 if (error) { 289 RTWN_UNLOCK(sc); 290 return (error); 291 } 292 rtwn_start(sc); 293 RTWN_UNLOCK(sc); 294 295 return (0); 296 } 297 298 void 299 rtwn_start(struct rtwn_softc *sc) 300 { 301 struct ieee80211_node *ni; 302 struct mbuf *m; 303 304 RTWN_ASSERT_LOCKED(sc); 305 306 /* Ensure no work is scheduled during reset/teardown */ 307 if ((sc->sc_flags & RTWN_RUNNING) == 0) 308 return; 309 310 while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 311 if (sc->qfullmsk != 0) { 312 mbufq_prepend(&sc->sc_snd, m); 313 break; 314 } 315 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 316 m->m_pkthdr.rcvif = NULL; 317 318 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, 319 "%s: called; m %p, ni %p\n", __func__, m, ni); 320 321 if (rtwn_tx_data(sc, ni, m) != 0) { 322 if_inc_counter(ni->ni_vap->iv_ifp, 323 IFCOUNTER_OERRORS, 1); 324 m_freem(m); 325 #ifdef D4054 326 ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0); 327 #endif 328 ieee80211_free_node(ni); 329 break; 330 } 331 } 332 } 333 334 int 335 rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 336 const struct ieee80211_bpf_params *params) 337 { 338 struct ieee80211com *ic = ni->ni_ic; 339 struct rtwn_softc *sc = ic->ic_softc; 340 int error; 341 342 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n", 343 __func__, m, ni); 344 345 /* prevent management frames from being sent if we're not ready */ 346 RTWN_LOCK(sc); 347 if (!(sc->sc_flags & RTWN_RUNNING)) { 348 error = ENETDOWN; 349 goto end; 350 } 351 352 if (sc->qfullmsk != 0) { 353 error = ENOBUFS; 354 goto end; 355 } 356 357 if (params == NULL) { 358 /* 359 * Legacy path; interpret frame contents to decide 360 * precisely how to send the frame. 361 */ 362 error = rtwn_tx_data(sc, ni, m); 363 } else { 364 /* 365 * Caller supplied explicit parameters to use in 366 * sending the frame. 367 */ 368 error = rtwn_tx_raw(sc, ni, m, params); 369 } 370 371 end: 372 if (error != 0) { 373 if (m->m_flags & M_TXCB) 374 ieee80211_process_callback(ni, m, 1); 375 m_freem(m); 376 } 377 378 RTWN_UNLOCK(sc); 379 380 return (error); 381 } 382