1*7453645fSAndriy Voskoboinyk /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ 2*7453645fSAndriy Voskoboinyk 3*7453645fSAndriy Voskoboinyk /*- 4*7453645fSAndriy Voskoboinyk * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 5*7453645fSAndriy Voskoboinyk * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> 6*7453645fSAndriy Voskoboinyk * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> 7*7453645fSAndriy Voskoboinyk * 8*7453645fSAndriy Voskoboinyk * Permission to use, copy, modify, and distribute this software for any 9*7453645fSAndriy Voskoboinyk * purpose with or without fee is hereby granted, provided that the above 10*7453645fSAndriy Voskoboinyk * copyright notice and this permission notice appear in all copies. 11*7453645fSAndriy Voskoboinyk * 12*7453645fSAndriy Voskoboinyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13*7453645fSAndriy Voskoboinyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14*7453645fSAndriy Voskoboinyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15*7453645fSAndriy Voskoboinyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16*7453645fSAndriy Voskoboinyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17*7453645fSAndriy Voskoboinyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18*7453645fSAndriy Voskoboinyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19*7453645fSAndriy Voskoboinyk */ 20*7453645fSAndriy Voskoboinyk 21*7453645fSAndriy Voskoboinyk #include <sys/cdefs.h> 22*7453645fSAndriy Voskoboinyk __FBSDID("$FreeBSD$"); 23*7453645fSAndriy Voskoboinyk 24*7453645fSAndriy Voskoboinyk #include "opt_wlan.h" 25*7453645fSAndriy Voskoboinyk 26*7453645fSAndriy Voskoboinyk #include <sys/param.h> 27*7453645fSAndriy Voskoboinyk #include <sys/lock.h> 28*7453645fSAndriy Voskoboinyk #include <sys/mutex.h> 29*7453645fSAndriy Voskoboinyk #include <sys/mbuf.h> 30*7453645fSAndriy Voskoboinyk #include <sys/kernel.h> 31*7453645fSAndriy Voskoboinyk #include <sys/socket.h> 32*7453645fSAndriy Voskoboinyk #include <sys/systm.h> 33*7453645fSAndriy Voskoboinyk #include <sys/malloc.h> 34*7453645fSAndriy Voskoboinyk #include <sys/queue.h> 35*7453645fSAndriy Voskoboinyk #include <sys/taskqueue.h> 36*7453645fSAndriy Voskoboinyk #include <sys/bus.h> 37*7453645fSAndriy Voskoboinyk #include <sys/endian.h> 38*7453645fSAndriy Voskoboinyk 39*7453645fSAndriy Voskoboinyk #include <net/if.h> 40*7453645fSAndriy Voskoboinyk #include <net/ethernet.h> 41*7453645fSAndriy Voskoboinyk #include <net/if_media.h> 42*7453645fSAndriy Voskoboinyk 43*7453645fSAndriy Voskoboinyk #include <net80211/ieee80211_var.h> 44*7453645fSAndriy Voskoboinyk #include <net80211/ieee80211_radiotap.h> 45*7453645fSAndriy Voskoboinyk 46*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnreg.h> 47*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnvar.h> 48*7453645fSAndriy Voskoboinyk 49*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_cam.h> 50*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_debug.h> 51*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_task.h> 52*7453645fSAndriy Voskoboinyk 53*7453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8192c/r92c_reg.h> 54*7453645fSAndriy Voskoboinyk 55*7453645fSAndriy Voskoboinyk 56*7453645fSAndriy Voskoboinyk void 57*7453645fSAndriy Voskoboinyk rtwn_init_cam(struct rtwn_softc *sc) 58*7453645fSAndriy Voskoboinyk { 59*7453645fSAndriy Voskoboinyk /* Invalidate all CAM entries. */ 60*7453645fSAndriy Voskoboinyk rtwn_write_4(sc, R92C_CAMCMD, 61*7453645fSAndriy Voskoboinyk R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR); 62*7453645fSAndriy Voskoboinyk } 63*7453645fSAndriy Voskoboinyk 64*7453645fSAndriy Voskoboinyk static int 65*7453645fSAndriy Voskoboinyk rtwn_cam_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data) 66*7453645fSAndriy Voskoboinyk { 67*7453645fSAndriy Voskoboinyk int error; 68*7453645fSAndriy Voskoboinyk 69*7453645fSAndriy Voskoboinyk error = rtwn_write_4(sc, R92C_CAMWRITE, data); 70*7453645fSAndriy Voskoboinyk if (error != 0) 71*7453645fSAndriy Voskoboinyk return (error); 72*7453645fSAndriy Voskoboinyk error = rtwn_write_4(sc, R92C_CAMCMD, 73*7453645fSAndriy Voskoboinyk R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE | 74*7453645fSAndriy Voskoboinyk SM(R92C_CAMCMD_ADDR, addr)); 75*7453645fSAndriy Voskoboinyk 76*7453645fSAndriy Voskoboinyk return (error); 77*7453645fSAndriy Voskoboinyk } 78*7453645fSAndriy Voskoboinyk 79*7453645fSAndriy Voskoboinyk void 80*7453645fSAndriy Voskoboinyk rtwn_init_seccfg(struct rtwn_softc *sc) 81*7453645fSAndriy Voskoboinyk { 82*7453645fSAndriy Voskoboinyk uint16_t seccfg; 83*7453645fSAndriy Voskoboinyk 84*7453645fSAndriy Voskoboinyk /* Select decryption / encryption flags. */ 85*7453645fSAndriy Voskoboinyk seccfg = 0; 86*7453645fSAndriy Voskoboinyk switch (sc->sc_hwcrypto) { 87*7453645fSAndriy Voskoboinyk case RTWN_CRYPTO_SW: 88*7453645fSAndriy Voskoboinyk break; /* nothing to do */ 89*7453645fSAndriy Voskoboinyk case RTWN_CRYPTO_PAIR: 90*7453645fSAndriy Voskoboinyk /* NB: TXUCKEY_DEF / RXUCKEY_DEF are required for RTL8192C */ 91*7453645fSAndriy Voskoboinyk seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF | 92*7453645fSAndriy Voskoboinyk R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA | 93*7453645fSAndriy Voskoboinyk R92C_SECCFG_MC_SRCH_DIS; 94*7453645fSAndriy Voskoboinyk break; 95*7453645fSAndriy Voskoboinyk case RTWN_CRYPTO_FULL: 96*7453645fSAndriy Voskoboinyk seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF | 97*7453645fSAndriy Voskoboinyk R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA | 98*7453645fSAndriy Voskoboinyk R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF; 99*7453645fSAndriy Voskoboinyk break; 100*7453645fSAndriy Voskoboinyk default: 101*7453645fSAndriy Voskoboinyk KASSERT(0, ("%s: case %d was not handled\n", __func__, 102*7453645fSAndriy Voskoboinyk sc->sc_hwcrypto)); 103*7453645fSAndriy Voskoboinyk break; 104*7453645fSAndriy Voskoboinyk } 105*7453645fSAndriy Voskoboinyk 106*7453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, "%s: seccfg %04X, hwcrypto %d\n", 107*7453645fSAndriy Voskoboinyk __func__, seccfg, sc->sc_hwcrypto); 108*7453645fSAndriy Voskoboinyk 109*7453645fSAndriy Voskoboinyk rtwn_write_2(sc, R92C_SECCFG, seccfg); 110*7453645fSAndriy Voskoboinyk } 111*7453645fSAndriy Voskoboinyk 112*7453645fSAndriy Voskoboinyk int 113*7453645fSAndriy Voskoboinyk rtwn_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, 114*7453645fSAndriy Voskoboinyk ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) 115*7453645fSAndriy Voskoboinyk { 116*7453645fSAndriy Voskoboinyk struct rtwn_softc *sc = vap->iv_ic->ic_softc; 117*7453645fSAndriy Voskoboinyk int i, start; 118*7453645fSAndriy Voskoboinyk 119*7453645fSAndriy Voskoboinyk if (&vap->iv_nw_keys[0] <= k && 120*7453645fSAndriy Voskoboinyk k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { 121*7453645fSAndriy Voskoboinyk *keyix = k - vap->iv_nw_keys; 122*7453645fSAndriy Voskoboinyk if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) 123*7453645fSAndriy Voskoboinyk k->wk_flags |= IEEE80211_KEY_SWCRYPT; 124*7453645fSAndriy Voskoboinyk else { 125*7453645fSAndriy Voskoboinyk RTWN_LOCK(sc); 126*7453645fSAndriy Voskoboinyk if (isset(sc->keys_bmap, *keyix)) { 127*7453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, 128*7453645fSAndriy Voskoboinyk "%s: group key slot %d is already used!\n", 129*7453645fSAndriy Voskoboinyk __func__, *keyix); 130*7453645fSAndriy Voskoboinyk /* XXX recover? */ 131*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 132*7453645fSAndriy Voskoboinyk return (0); 133*7453645fSAndriy Voskoboinyk } 134*7453645fSAndriy Voskoboinyk 135*7453645fSAndriy Voskoboinyk setbit(sc->keys_bmap, *keyix); 136*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 137*7453645fSAndriy Voskoboinyk } 138*7453645fSAndriy Voskoboinyk 139*7453645fSAndriy Voskoboinyk goto end; 140*7453645fSAndriy Voskoboinyk } 141*7453645fSAndriy Voskoboinyk 142*7453645fSAndriy Voskoboinyk start = sc->cam_entry_limit; 143*7453645fSAndriy Voskoboinyk switch (sc->sc_hwcrypto) { 144*7453645fSAndriy Voskoboinyk case RTWN_CRYPTO_SW: 145*7453645fSAndriy Voskoboinyk k->wk_flags |= IEEE80211_KEY_SWCRYPT; 146*7453645fSAndriy Voskoboinyk *keyix = 0; 147*7453645fSAndriy Voskoboinyk goto end; 148*7453645fSAndriy Voskoboinyk case RTWN_CRYPTO_PAIR: 149*7453645fSAndriy Voskoboinyk /* all slots for pairwise keys. */ 150*7453645fSAndriy Voskoboinyk start = 0; 151*7453645fSAndriy Voskoboinyk RTWN_LOCK(sc); 152*7453645fSAndriy Voskoboinyk if (sc->sc_flags & RTWN_FLAG_CAM_FIXED) 153*7453645fSAndriy Voskoboinyk start = 4; 154*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 155*7453645fSAndriy Voskoboinyk break; 156*7453645fSAndriy Voskoboinyk case RTWN_CRYPTO_FULL: 157*7453645fSAndriy Voskoboinyk /* first 4 - for group keys, others for pairwise. */ 158*7453645fSAndriy Voskoboinyk start = 4; 159*7453645fSAndriy Voskoboinyk break; 160*7453645fSAndriy Voskoboinyk default: 161*7453645fSAndriy Voskoboinyk KASSERT(0, ("%s: case %d was not handled!\n", 162*7453645fSAndriy Voskoboinyk __func__, sc->sc_hwcrypto)); 163*7453645fSAndriy Voskoboinyk break; 164*7453645fSAndriy Voskoboinyk } 165*7453645fSAndriy Voskoboinyk 166*7453645fSAndriy Voskoboinyk RTWN_LOCK(sc); 167*7453645fSAndriy Voskoboinyk for (i = start; i < sc->cam_entry_limit; i++) { 168*7453645fSAndriy Voskoboinyk if (isclr(sc->keys_bmap, i)) { 169*7453645fSAndriy Voskoboinyk setbit(sc->keys_bmap, i); 170*7453645fSAndriy Voskoboinyk *keyix = i; 171*7453645fSAndriy Voskoboinyk break; 172*7453645fSAndriy Voskoboinyk } 173*7453645fSAndriy Voskoboinyk } 174*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 175*7453645fSAndriy Voskoboinyk if (i == sc->cam_entry_limit) { 176*7453645fSAndriy Voskoboinyk #if __FreeBSD_version > 1200008 177*7453645fSAndriy Voskoboinyk /* XXX check and remove keys with the same MAC address */ 178*7453645fSAndriy Voskoboinyk k->wk_flags |= IEEE80211_KEY_SWCRYPT; 179*7453645fSAndriy Voskoboinyk *keyix = 0; 180*7453645fSAndriy Voskoboinyk #else 181*7453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, 182*7453645fSAndriy Voskoboinyk "%s: no free space in the key table\n", __func__); 183*7453645fSAndriy Voskoboinyk return (0); 184*7453645fSAndriy Voskoboinyk #endif 185*7453645fSAndriy Voskoboinyk } 186*7453645fSAndriy Voskoboinyk 187*7453645fSAndriy Voskoboinyk end: 188*7453645fSAndriy Voskoboinyk *rxkeyix = *keyix; 189*7453645fSAndriy Voskoboinyk return (1); 190*7453645fSAndriy Voskoboinyk } 191*7453645fSAndriy Voskoboinyk 192*7453645fSAndriy Voskoboinyk static int 193*7453645fSAndriy Voskoboinyk rtwn_key_set_cb0(struct rtwn_softc *sc, const struct ieee80211_key *k) 194*7453645fSAndriy Voskoboinyk { 195*7453645fSAndriy Voskoboinyk uint8_t algo, keyid; 196*7453645fSAndriy Voskoboinyk int i, error; 197*7453645fSAndriy Voskoboinyk 198*7453645fSAndriy Voskoboinyk if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL && 199*7453645fSAndriy Voskoboinyk k->wk_keyix < IEEE80211_WEP_NKID) 200*7453645fSAndriy Voskoboinyk keyid = k->wk_keyix; 201*7453645fSAndriy Voskoboinyk else 202*7453645fSAndriy Voskoboinyk keyid = 0; 203*7453645fSAndriy Voskoboinyk 204*7453645fSAndriy Voskoboinyk /* Map net80211 cipher to HW crypto algorithm. */ 205*7453645fSAndriy Voskoboinyk switch (k->wk_cipher->ic_cipher) { 206*7453645fSAndriy Voskoboinyk case IEEE80211_CIPHER_WEP: 207*7453645fSAndriy Voskoboinyk if (k->wk_keylen < 8) 208*7453645fSAndriy Voskoboinyk algo = R92C_CAM_ALGO_WEP40; 209*7453645fSAndriy Voskoboinyk else 210*7453645fSAndriy Voskoboinyk algo = R92C_CAM_ALGO_WEP104; 211*7453645fSAndriy Voskoboinyk break; 212*7453645fSAndriy Voskoboinyk case IEEE80211_CIPHER_TKIP: 213*7453645fSAndriy Voskoboinyk algo = R92C_CAM_ALGO_TKIP; 214*7453645fSAndriy Voskoboinyk break; 215*7453645fSAndriy Voskoboinyk case IEEE80211_CIPHER_AES_CCM: 216*7453645fSAndriy Voskoboinyk algo = R92C_CAM_ALGO_AES; 217*7453645fSAndriy Voskoboinyk break; 218*7453645fSAndriy Voskoboinyk default: 219*7453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, "%s: unknown cipher %u\n", 220*7453645fSAndriy Voskoboinyk __func__, k->wk_cipher->ic_cipher); 221*7453645fSAndriy Voskoboinyk return (EINVAL); 222*7453645fSAndriy Voskoboinyk } 223*7453645fSAndriy Voskoboinyk 224*7453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, 225*7453645fSAndriy Voskoboinyk "%s: keyix %u, keyid %u, algo %u/%u, flags %04X, len %u, " 226*7453645fSAndriy Voskoboinyk "macaddr %s\n", __func__, k->wk_keyix, keyid, 227*7453645fSAndriy Voskoboinyk k->wk_cipher->ic_cipher, algo, k->wk_flags, k->wk_keylen, 228*7453645fSAndriy Voskoboinyk ether_sprintf(k->wk_macaddr)); 229*7453645fSAndriy Voskoboinyk 230*7453645fSAndriy Voskoboinyk /* Clear high bits. */ 231*7453645fSAndriy Voskoboinyk rtwn_cam_write(sc, R92C_CAM_CTL6(k->wk_keyix), 0); 232*7453645fSAndriy Voskoboinyk rtwn_cam_write(sc, R92C_CAM_CTL7(k->wk_keyix), 0); 233*7453645fSAndriy Voskoboinyk 234*7453645fSAndriy Voskoboinyk /* Write key. */ 235*7453645fSAndriy Voskoboinyk for (i = 0; i < 4; i++) { 236*7453645fSAndriy Voskoboinyk error = rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 237*7453645fSAndriy Voskoboinyk le32dec(&k->wk_key[i * 4])); 238*7453645fSAndriy Voskoboinyk if (error != 0) 239*7453645fSAndriy Voskoboinyk goto fail; 240*7453645fSAndriy Voskoboinyk } 241*7453645fSAndriy Voskoboinyk 242*7453645fSAndriy Voskoboinyk /* Write CTL0 last since that will validate the CAM entry. */ 243*7453645fSAndriy Voskoboinyk error = rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 244*7453645fSAndriy Voskoboinyk le32dec(&k->wk_macaddr[2])); 245*7453645fSAndriy Voskoboinyk if (error != 0) 246*7453645fSAndriy Voskoboinyk goto fail; 247*7453645fSAndriy Voskoboinyk error = rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 248*7453645fSAndriy Voskoboinyk SM(R92C_CAM_ALGO, algo) | 249*7453645fSAndriy Voskoboinyk SM(R92C_CAM_KEYID, keyid) | 250*7453645fSAndriy Voskoboinyk SM(R92C_CAM_MACLO, le16dec(&k->wk_macaddr[0])) | 251*7453645fSAndriy Voskoboinyk R92C_CAM_VALID); 252*7453645fSAndriy Voskoboinyk if (error != 0) 253*7453645fSAndriy Voskoboinyk goto fail; 254*7453645fSAndriy Voskoboinyk 255*7453645fSAndriy Voskoboinyk return (0); 256*7453645fSAndriy Voskoboinyk 257*7453645fSAndriy Voskoboinyk fail: 258*7453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error); 259*7453645fSAndriy Voskoboinyk return (error); 260*7453645fSAndriy Voskoboinyk } 261*7453645fSAndriy Voskoboinyk 262*7453645fSAndriy Voskoboinyk static void 263*7453645fSAndriy Voskoboinyk rtwn_key_set_cb(struct rtwn_softc *sc, union sec_param *data) 264*7453645fSAndriy Voskoboinyk { 265*7453645fSAndriy Voskoboinyk const struct ieee80211_key *k = &data->key; 266*7453645fSAndriy Voskoboinyk 267*7453645fSAndriy Voskoboinyk (void) rtwn_key_set_cb0(sc, k); 268*7453645fSAndriy Voskoboinyk } 269*7453645fSAndriy Voskoboinyk 270*7453645fSAndriy Voskoboinyk int 271*7453645fSAndriy Voskoboinyk rtwn_init_static_keys(struct rtwn_softc *sc, struct rtwn_vap *rvp) 272*7453645fSAndriy Voskoboinyk { 273*7453645fSAndriy Voskoboinyk int i, error; 274*7453645fSAndriy Voskoboinyk 275*7453645fSAndriy Voskoboinyk if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) 276*7453645fSAndriy Voskoboinyk return (0); /* nothing to do */ 277*7453645fSAndriy Voskoboinyk 278*7453645fSAndriy Voskoboinyk for (i = 0; i < IEEE80211_WEP_NKID; i++) { 279*7453645fSAndriy Voskoboinyk const struct ieee80211_key *k = rvp->keys[i]; 280*7453645fSAndriy Voskoboinyk if (k != NULL) { 281*7453645fSAndriy Voskoboinyk error = rtwn_key_set_cb0(sc, k); 282*7453645fSAndriy Voskoboinyk if (error != 0) 283*7453645fSAndriy Voskoboinyk return (error); 284*7453645fSAndriy Voskoboinyk } 285*7453645fSAndriy Voskoboinyk } 286*7453645fSAndriy Voskoboinyk 287*7453645fSAndriy Voskoboinyk return (0); 288*7453645fSAndriy Voskoboinyk } 289*7453645fSAndriy Voskoboinyk 290*7453645fSAndriy Voskoboinyk static void 291*7453645fSAndriy Voskoboinyk rtwn_key_del_cb(struct rtwn_softc *sc, union sec_param *data) 292*7453645fSAndriy Voskoboinyk { 293*7453645fSAndriy Voskoboinyk struct ieee80211_key *k = &data->key; 294*7453645fSAndriy Voskoboinyk int i; 295*7453645fSAndriy Voskoboinyk 296*7453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, 297*7453645fSAndriy Voskoboinyk "%s: keyix %u, flags %04X, macaddr %s\n", __func__, 298*7453645fSAndriy Voskoboinyk k->wk_keyix, k->wk_flags, ether_sprintf(k->wk_macaddr)); 299*7453645fSAndriy Voskoboinyk 300*7453645fSAndriy Voskoboinyk rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 0); 301*7453645fSAndriy Voskoboinyk rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 0); 302*7453645fSAndriy Voskoboinyk 303*7453645fSAndriy Voskoboinyk /* Clear key. */ 304*7453645fSAndriy Voskoboinyk for (i = 0; i < 4; i++) 305*7453645fSAndriy Voskoboinyk rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 0); 306*7453645fSAndriy Voskoboinyk clrbit(sc->keys_bmap, k->wk_keyix); 307*7453645fSAndriy Voskoboinyk } 308*7453645fSAndriy Voskoboinyk 309*7453645fSAndriy Voskoboinyk static int 310*7453645fSAndriy Voskoboinyk rtwn_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k, 311*7453645fSAndriy Voskoboinyk int set) 312*7453645fSAndriy Voskoboinyk { 313*7453645fSAndriy Voskoboinyk struct rtwn_softc *sc = vap->iv_ic->ic_softc; 314*7453645fSAndriy Voskoboinyk 315*7453645fSAndriy Voskoboinyk if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { 316*7453645fSAndriy Voskoboinyk /* Not for us. */ 317*7453645fSAndriy Voskoboinyk return (1); 318*7453645fSAndriy Voskoboinyk } 319*7453645fSAndriy Voskoboinyk 320*7453645fSAndriy Voskoboinyk if (&vap->iv_nw_keys[0] <= k && 321*7453645fSAndriy Voskoboinyk k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { 322*7453645fSAndriy Voskoboinyk #if __FreeBSD_version <= 1200008 323*7453645fSAndriy Voskoboinyk struct ieee80211_key *k1 = &vap->iv_nw_keys[k->wk_keyix]; 324*7453645fSAndriy Voskoboinyk 325*7453645fSAndriy Voskoboinyk if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) { 326*7453645fSAndriy Voskoboinyk k1->wk_flags |= IEEE80211_KEY_SWCRYPT; 327*7453645fSAndriy Voskoboinyk return (k->wk_cipher->ic_setkey(k1)); 328*7453645fSAndriy Voskoboinyk } else { 329*7453645fSAndriy Voskoboinyk #else 330*7453645fSAndriy Voskoboinyk if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL) { 331*7453645fSAndriy Voskoboinyk #endif 332*7453645fSAndriy Voskoboinyk struct rtwn_vap *rvp = RTWN_VAP(vap); 333*7453645fSAndriy Voskoboinyk 334*7453645fSAndriy Voskoboinyk RTWN_LOCK(sc); 335*7453645fSAndriy Voskoboinyk rvp->keys[k->wk_keyix] = (set ? k : NULL); 336*7453645fSAndriy Voskoboinyk if ((sc->sc_flags & RTWN_RUNNING) == 0) { 337*7453645fSAndriy Voskoboinyk if (!set) 338*7453645fSAndriy Voskoboinyk clrbit(sc->keys_bmap, k->wk_keyix); 339*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 340*7453645fSAndriy Voskoboinyk return (1); 341*7453645fSAndriy Voskoboinyk } 342*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 343*7453645fSAndriy Voskoboinyk } 344*7453645fSAndriy Voskoboinyk } 345*7453645fSAndriy Voskoboinyk 346*7453645fSAndriy Voskoboinyk return (!rtwn_cmd_sleepable(sc, k, sizeof(*k), 347*7453645fSAndriy Voskoboinyk set ? rtwn_key_set_cb : rtwn_key_del_cb)); 348*7453645fSAndriy Voskoboinyk } 349*7453645fSAndriy Voskoboinyk 350*7453645fSAndriy Voskoboinyk int 351*7453645fSAndriy Voskoboinyk rtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) 352*7453645fSAndriy Voskoboinyk { 353*7453645fSAndriy Voskoboinyk return (rtwn_process_key(vap, k, 1)); 354*7453645fSAndriy Voskoboinyk } 355*7453645fSAndriy Voskoboinyk 356*7453645fSAndriy Voskoboinyk int 357*7453645fSAndriy Voskoboinyk rtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) 358*7453645fSAndriy Voskoboinyk { 359*7453645fSAndriy Voskoboinyk return (rtwn_process_key(vap, k, 0)); 360*7453645fSAndriy Voskoboinyk } 361