xref: /freebsd/sys/dev/rtwn/if_rtwn_cam.c (revision 7453645f2a9411a3f9d982b768bcc323f41cf906)
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