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 #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
190 end:
191 *rxkeyix = *keyix;
192 return (1);
193 }
194
195 static int
196 rtwn_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
260 fail:
261 device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error);
262 return (error);
263 }
264
265 static void
266 rtwn_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
273 int
274 rtwn_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
293 static void
294 rtwn_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
312 static int
313 rtwn_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
353 int
354 rtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
355 {
356 return (rtwn_process_key(vap, k, 1));
357 }
358
359 int
360 rtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
361 {
362 return (rtwn_process_key(vap, k, 0));
363 }
Cache object: e387ce2facf0ccac6ac5401c6f79f170
|