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