xref: /freebsd/sys/dev/rtwn/if_rtwn_cam.c (revision 9768746b)
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/ethernet.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_cam.h>
50 #include <dev/rtwn/if_rtwn_debug.h>
51 #include <dev/rtwn/if_rtwn_task.h>
52 
53 #include <dev/rtwn/rtl8192c/r92c_reg.h>
54 
55 void
56 rtwn_init_cam(struct rtwn_softc *sc)
57 {
58 	/* Invalidate all CAM entries. */
59 	rtwn_write_4(sc, R92C_CAMCMD,
60 	    R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR);
61 }
62 
63 static int
64 rtwn_cam_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data)
65 {
66 	int error;
67 
68 	error = rtwn_write_4(sc, R92C_CAMWRITE, data);
69 	if (error != 0)
70 		return (error);
71 	error = rtwn_write_4(sc, R92C_CAMCMD,
72 	    R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE |
73 	    SM(R92C_CAMCMD_ADDR, addr));
74 
75 	return (error);
76 }
77 
78 void
79 rtwn_init_seccfg(struct rtwn_softc *sc)
80 {
81 	uint16_t seccfg;
82 
83 	/* Select decryption / encryption flags. */
84 	seccfg = 0;
85 	switch (sc->sc_hwcrypto) {
86 	case RTWN_CRYPTO_SW:
87 		break;	/* nothing to do */
88 	case RTWN_CRYPTO_PAIR:
89 		/* NB: TXUCKEY_DEF / RXUCKEY_DEF are required for RTL8192C */
90 		seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF |
91 		    R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA |
92 		    R92C_SECCFG_MC_SRCH_DIS;
93 		break;
94 	case RTWN_CRYPTO_FULL:
95 		seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF |
96 		    R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA |
97 		    R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF;
98 		break;
99 	default:
100 		KASSERT(0, ("%s: case %d was not handled\n", __func__,
101 		    sc->sc_hwcrypto));
102 		break;
103 	}
104 
105 	RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, "%s: seccfg %04X, hwcrypto %d\n",
106 	    __func__, seccfg, sc->sc_hwcrypto);
107 
108 	rtwn_write_2(sc, R92C_SECCFG, seccfg);
109 }
110 
111 int
112 rtwn_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
113     ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
114 {
115 	struct rtwn_softc *sc = vap->iv_ic->ic_softc;
116 	int i, start;
117 
118 	if (&vap->iv_nw_keys[0] <= k &&
119 	    k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) {
120 		*keyix = ieee80211_crypto_get_key_wepidx(vap, k);
121 		if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL)
122 			k->wk_flags |= IEEE80211_KEY_SWCRYPT;
123 		else {
124 			RTWN_LOCK(sc);
125 			if (isset(sc->keys_bmap, *keyix)) {
126 				device_printf(sc->sc_dev,
127 				    "%s: group key slot %d is already used!\n",
128 				    __func__, *keyix);
129 				/* XXX recover? */
130 				RTWN_UNLOCK(sc);
131 				return (0);
132 			}
133 
134 			setbit(sc->keys_bmap, *keyix);
135 			RTWN_UNLOCK(sc);
136 		}
137 
138 		goto end;
139 	}
140 
141 	start = sc->cam_entry_limit;
142 	switch (sc->sc_hwcrypto) {
143 	case RTWN_CRYPTO_SW:
144 		k->wk_flags |= IEEE80211_KEY_SWCRYPT;
145 		*keyix = 0;
146 		goto end;
147 	case RTWN_CRYPTO_PAIR:
148 		/* all slots for pairwise keys. */
149 		start = 0;
150 		RTWN_LOCK(sc);
151 		if (sc->sc_flags & RTWN_FLAG_CAM_FIXED)
152 			start = 4;
153 		RTWN_UNLOCK(sc);
154 		break;
155 	case RTWN_CRYPTO_FULL:
156 		/* first 4 - for group keys, others for pairwise. */
157 		start = 4;
158 		break;
159 	default:
160 		KASSERT(0, ("%s: case %d was not handled!\n",
161 		    __func__, sc->sc_hwcrypto));
162 		break;
163 	}
164 
165 	RTWN_LOCK(sc);
166 	for (i = start; i < sc->cam_entry_limit; i++) {
167 		if (isclr(sc->keys_bmap, i)) {
168 			setbit(sc->keys_bmap, i);
169 			*keyix = i;
170 			break;
171 		}
172 	}
173 	RTWN_UNLOCK(sc);
174 	if (i == sc->cam_entry_limit) {
175 		/* XXX check and remove keys with the same MAC address */
176 		k->wk_flags |= IEEE80211_KEY_SWCRYPT;
177 		*keyix = 0;
178 	}
179 
180 end:
181 	*rxkeyix = *keyix;
182 	return (1);
183 }
184 
185 static int
186 rtwn_key_set_cb0(struct rtwn_softc *sc, const struct ieee80211_key *k)
187 {
188 	uint8_t algo, keyid;
189 	int i, error;
190 
191 	if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL &&
192 	    k->wk_keyix < IEEE80211_WEP_NKID)
193 		keyid = k->wk_keyix;
194 	else
195 		keyid = 0;
196 
197 	/* Map net80211 cipher to HW crypto algorithm. */
198 	switch (k->wk_cipher->ic_cipher) {
199 	case IEEE80211_CIPHER_WEP:
200 		if (k->wk_keylen < 8)
201 			algo = R92C_CAM_ALGO_WEP40;
202 		else
203 			algo = R92C_CAM_ALGO_WEP104;
204 		break;
205 	case IEEE80211_CIPHER_TKIP:
206 		algo = R92C_CAM_ALGO_TKIP;
207 		break;
208 	case IEEE80211_CIPHER_AES_CCM:
209 		algo = R92C_CAM_ALGO_AES;
210 		break;
211 	default:
212 		device_printf(sc->sc_dev, "%s: unknown cipher %u\n",
213 		    __func__, k->wk_cipher->ic_cipher);
214 		return (EINVAL);
215 	}
216 
217 	RTWN_DPRINTF(sc, RTWN_DEBUG_KEY,
218 	    "%s: keyix %u, keyid %u, algo %u/%u, flags %04X, len %u, "
219 	    "macaddr %s\n", __func__, k->wk_keyix, keyid,
220 	    k->wk_cipher->ic_cipher, algo, k->wk_flags, k->wk_keylen,
221 	    ether_sprintf(k->wk_macaddr));
222 
223 	/* Clear high bits. */
224 	rtwn_cam_write(sc, R92C_CAM_CTL6(k->wk_keyix), 0);
225 	rtwn_cam_write(sc, R92C_CAM_CTL7(k->wk_keyix), 0);
226 
227 	/* Write key. */
228 	for (i = 0; i < 4; i++) {
229 		error = rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i),
230 		    le32dec(&k->wk_key[i * 4]));
231 		if (error != 0)
232 			goto fail;
233 	}
234 
235 	/* Write CTL0 last since that will validate the CAM entry. */
236 	error = rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix),
237 	    le32dec(&k->wk_macaddr[2]));
238 	if (error != 0)
239 		goto fail;
240 	error = rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix),
241 	    SM(R92C_CAM_ALGO, algo) |
242 	    SM(R92C_CAM_KEYID, keyid) |
243 	    SM(R92C_CAM_MACLO, le16dec(&k->wk_macaddr[0])) |
244 	    R92C_CAM_VALID);
245 	if (error != 0)
246 		goto fail;
247 
248 	return (0);
249 
250 fail:
251 	device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error);
252 	return (error);
253 }
254 
255 static void
256 rtwn_key_set_cb(struct rtwn_softc *sc, union sec_param *data)
257 {
258 	const struct ieee80211_key *k = &data->key;
259 
260 	(void) rtwn_key_set_cb0(sc, k);
261 }
262 
263 int
264 rtwn_init_static_keys(struct rtwn_softc *sc, struct rtwn_vap *rvp)
265 {
266 	int i, error;
267 
268 	if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL)
269 		return (0);		/* nothing to do */
270 
271 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
272 		const struct ieee80211_key *k = rvp->keys[i];
273 		if (k != NULL) {
274 			error = rtwn_key_set_cb0(sc, k);
275 			if (error != 0)
276 				return (error);
277 		}
278 	}
279 
280 	return (0);
281 }
282 
283 static void
284 rtwn_key_del_cb(struct rtwn_softc *sc, union sec_param *data)
285 {
286 	struct ieee80211_key *k = &data->key;
287 	int i;
288 
289 	RTWN_DPRINTF(sc, RTWN_DEBUG_KEY,
290 	    "%s: keyix %u, flags %04X, macaddr %s\n", __func__,
291 	    k->wk_keyix, k->wk_flags, ether_sprintf(k->wk_macaddr));
292 
293 	rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 0);
294 	rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 0);
295 
296 	/* Clear key. */
297 	for (i = 0; i < 4; i++)
298 		rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 0);
299 	clrbit(sc->keys_bmap, k->wk_keyix);
300 }
301 
302 static int
303 rtwn_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k,
304     int set)
305 {
306 	struct rtwn_softc *sc = vap->iv_ic->ic_softc;
307 
308 	if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
309 		/* Not for us. */
310 		return (1);
311 	}
312 
313 	if (&vap->iv_nw_keys[0] <= k &&
314 	    k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) {
315 		if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL) {
316 			struct rtwn_vap *rvp = RTWN_VAP(vap);
317 
318 			RTWN_LOCK(sc);
319 			rvp->keys[k->wk_keyix] = (set ? k : NULL);
320 			if ((sc->sc_flags & RTWN_RUNNING) == 0) {
321 				if (!set)
322 					clrbit(sc->keys_bmap, k->wk_keyix);
323 				RTWN_UNLOCK(sc);
324 				return (1);
325 			}
326 			RTWN_UNLOCK(sc);
327 		}
328 	}
329 
330 	return (!rtwn_cmd_sleepable(sc, k, sizeof(*k),
331 	    set ? rtwn_key_set_cb : rtwn_key_del_cb));
332 }
333 
334 int
335 rtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
336 {
337 	return (rtwn_process_key(vap, k, 1));
338 }
339 
340 int
341 rtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
342 {
343 	return (rtwn_process_key(vap, k, 0));
344 }
345