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