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