proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / dev / netif / awi / awi_wep.c
CommitLineData
984263bc
MD
1/* $NetBSD: awi_wep.c,v 1.4 2000/08/14 11:28:03 onoe Exp $ */
2/* $FreeBSD: src/sys/dev/awi/awi_wep.c,v 1.3.2.2 2003/01/23 21:06:42 sam Exp $ */
dadab5e9 3/* $DragonFly: src/sys/dev/netif/awi/Attic/awi_wep.c,v 1.4 2003/06/25 03:55:46 dillon Exp $ */
984263bc
MD
4
5/*
6 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Atsushi Onoe.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41/*
42 * WEP support framework for the awi driver.
43 *
44 * No actual encryption capability is provided here, but any can be added
45 * to awi_wep_algo table below.
46 *
47 * Note that IEEE802.11 specification states WEP uses RC4 with 40bit key,
48 * which is a proprietary encryption algorithm available under license
49 * from RSA Data Security Inc. Using another algorithm, includes null
50 * encryption provided here, the awi driver cannot be able to communicate
51 * with other stations.
52 */
53
54#include <sys/param.h>
55#include <sys/systm.h>
56#include <sys/kernel.h>
57#include <sys/mbuf.h>
58#include <sys/malloc.h>
59#include <sys/proc.h>
60#include <sys/socket.h>
61#include <sys/errno.h>
62#include <sys/sockio.h>
63#if defined(__FreeBSD__) && __FreeBSD__ >= 4
64#include <sys/bus.h>
65#else
66#include <sys/device.h>
67#endif
68
69#include <net/if.h>
70#include <net/if_dl.h>
71#ifdef __FreeBSD__
72#include <net/ethernet.h>
73#include <net/if_arp.h>
74#else
75#include <net/if_ether.h>
76#endif
77#include <net/if_media.h>
78#include <net/if_ieee80211.h>
79
80#include <machine/cpu.h>
81#include <machine/bus.h>
82#ifdef __FreeBSD__
83#include <machine/clock.h>
84#endif
85
86#ifdef __NetBSD__
87#include <dev/ic/am79c930reg.h>
88#include <dev/ic/am79c930var.h>
89#include <dev/ic/awireg.h>
90#include <dev/ic/awivar.h>
91
92#include <crypto/arc4/arc4.h>
93#endif
94
95#ifdef __FreeBSD__
96#include <dev/awi/am79c930reg.h>
97#include <dev/awi/am79c930var.h>
98#include <dev/awi/awireg.h>
99#include <dev/awi/awivar.h>
100
101#include <crypto/rc4/rc4.h>
102static __inline int
103arc4_ctxlen(void)
104{
105 return sizeof(struct rc4_state);
106}
107
108static __inline void
109arc4_setkey(void *ctx, u_int8_t *key, int keylen)
110{
111 rc4_init(ctx, key, keylen);
112}
113
114static __inline void
115arc4_encrypt(void *ctx, u_int8_t *dst, u_int8_t *src, int len)
116{
117 rc4_crypt(ctx, src, dst, len);
118}
119#endif
120
121static void awi_crc_init __P((void));
122static u_int32_t awi_crc_update __P((u_int32_t crc, u_int8_t *buf, int len));
123
124static int awi_null_ctxlen __P((void));
125static void awi_null_setkey __P((void *ctx, u_int8_t *key, int keylen));
126static void awi_null_copy __P((void *ctx, u_int8_t *dst, u_int8_t *src, int len));
127
128/* XXX: the order should be known to wiconfig/user */
129
130static struct awi_wep_algo awi_wep_algo[] = {
131/* 0: no wep */
132 { "no" }, /* dummy for no wep */
133
134/* 1: normal wep (arc4) */
135 { "arc4", arc4_ctxlen, arc4_setkey,
136 arc4_encrypt, arc4_encrypt },
137
138/* 2: debug wep (null) */
139 { "null", awi_null_ctxlen, awi_null_setkey,
140 awi_null_copy, awi_null_copy },
141 /* dummy for wep without encryption */
142};
143
144int
145awi_wep_setnwkey(sc, nwkey)
146 struct awi_softc *sc;
147 struct ieee80211_nwkey *nwkey;
148{
149 int i, len, error;
150 u_int8_t keybuf[AWI_MAX_KEYLEN];
151
152 if (nwkey->i_defkid <= 0 ||
153 nwkey->i_defkid > IEEE80211_WEP_NKID)
154 return EINVAL;
155 error = 0;
156 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
157 if (nwkey->i_key[i].i_keydat == NULL)
158 continue;
159 len = nwkey->i_key[i].i_keylen;
160 if (len > sizeof(keybuf)) {
161 error = EINVAL;
162 break;
163 }
164 error = copyin(nwkey->i_key[i].i_keydat, keybuf, len);
165 if (error)
166 break;
167 error = awi_wep_setkey(sc, i, keybuf, len);
168 if (error)
169 break;
170 }
171 if (error == 0) {
172 sc->sc_wep_defkid = nwkey->i_defkid - 1;
173 error = awi_wep_setalgo(sc, nwkey->i_wepon);
174 if (error == 0 && sc->sc_enabled) {
175 awi_stop(sc);
176 error = awi_init(sc);
177 }
178 }
179 return error;
180}
181
182int
183awi_wep_getnwkey(sc, nwkey)
184 struct awi_softc *sc;
185 struct ieee80211_nwkey *nwkey;
186{
187 int i, len, error, suerr;
188 u_int8_t keybuf[AWI_MAX_KEYLEN];
189
190 nwkey->i_wepon = awi_wep_getalgo(sc);
191 nwkey->i_defkid = sc->sc_wep_defkid + 1;
192 /* do not show any keys to non-root user */
193#ifdef __FreeBSD__
dadab5e9 194 suerr = suser(curthread); /* note: EPERM if no proc */
984263bc
MD
195#else
196 suerr = suser(curproc->p_ucred, &curproc->p_acflag);
197#endif
198 error = 0;
199 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
200 if (nwkey->i_key[i].i_keydat == NULL)
201 continue;
202 if (suerr) {
203 error = suerr;
204 break;
205 }
206 len = sizeof(keybuf);
207 error = awi_wep_getkey(sc, i, keybuf, &len);
208 if (error)
209 break;
210 if (nwkey->i_key[i].i_keylen < len) {
211 error = ENOSPC;
212 break;
213 }
214 nwkey->i_key[i].i_keylen = len;
215 error = copyout(keybuf, nwkey->i_key[i].i_keydat, len);
216 if (error)
217 break;
218 }
219 return error;
220}
221
222int
223awi_wep_getalgo(sc)
224 struct awi_softc *sc;
225{
226
227 if (sc->sc_wep_algo == NULL)
228 return 0;
229 return sc->sc_wep_algo - awi_wep_algo;
230}
231
232int
233awi_wep_setalgo(sc, algo)
234 struct awi_softc *sc;
235 int algo;
236{
237 struct awi_wep_algo *awa;
238 int ctxlen;
239
240 awi_crc_init(); /* XXX: not belongs here */
241 if (algo < 0 || algo > sizeof(awi_wep_algo)/sizeof(awi_wep_algo[0]))
242 return EINVAL;
243 awa = &awi_wep_algo[algo];
244 if (awa->awa_name == NULL)
245 return EINVAL;
246 if (awa->awa_ctxlen == NULL) {
247 awa = NULL;
248 ctxlen = 0;
249 } else
250 ctxlen = awa->awa_ctxlen();
251 if (sc->sc_wep_ctx != NULL) {
252 free(sc->sc_wep_ctx, M_DEVBUF);
253 sc->sc_wep_ctx = NULL;
254 }
255 if (ctxlen) {
256 sc->sc_wep_ctx = malloc(ctxlen, M_DEVBUF, M_NOWAIT);
257 if (sc->sc_wep_ctx == NULL)
258 return ENOMEM;
259 }
260 sc->sc_wep_algo = awa;
261 return 0;
262}
263
264int
265awi_wep_setkey(sc, kid, key, keylen)
266 struct awi_softc *sc;
267 int kid;
268 unsigned char *key;
269 int keylen;
270{
271
272 if (kid < 0 || kid >= IEEE80211_WEP_NKID)
273 return EINVAL;
274 if (keylen < 0 || keylen + IEEE80211_WEP_IVLEN > AWI_MAX_KEYLEN)
275 return EINVAL;
276 sc->sc_wep_keylen[kid] = keylen;
277 if (keylen > 0)
278 memcpy(sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, key, keylen);
279 return 0;
280}
281
282int
283awi_wep_getkey(sc, kid, key, keylen)
284 struct awi_softc *sc;
285 int kid;
286 unsigned char *key;
287 int *keylen;
288{
289
290 if (kid < 0 || kid >= IEEE80211_WEP_NKID)
291 return EINVAL;
292 if (*keylen < sc->sc_wep_keylen[kid])
293 return ENOSPC;
294 *keylen = sc->sc_wep_keylen[kid];
295 if (*keylen > 0)
296 memcpy(key, sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, *keylen);
297 return 0;
298}
299
300struct mbuf *
301awi_wep_encrypt(sc, m0, txflag)
302 struct awi_softc *sc;
303 struct mbuf *m0;
304 int txflag;
305{
306 struct mbuf *m, *n, *n0;
307 struct ieee80211_frame *wh;
308 struct awi_wep_algo *awa;
309 int left, len, moff, noff, keylen, kid;
310 u_int32_t iv, crc;
311 u_int8_t *key, *ivp;
312 void *ctx;
313 u_int8_t crcbuf[IEEE80211_WEP_CRCLEN];
314
315 n0 = NULL;
316 awa = sc->sc_wep_algo;
317 if (awa == NULL)
318 goto fail;
319 ctx = sc->sc_wep_ctx;
320 m = m0;
321 left = m->m_pkthdr.len;
322 MGET(n, M_DONTWAIT, m->m_type);
323 n0 = n;
324 if (n == NULL)
325 goto fail;
326 M_MOVE_PKTHDR(n, m);
327 len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
328 if (txflag) {
329 n->m_pkthdr.len += len;
330 } else {
331 n->m_pkthdr.len -= len;
332 left -= len;
333 }
334 n->m_len = MHLEN;
335 if (n->m_pkthdr.len >= MINCLSIZE) {
336 MCLGET(n, M_DONTWAIT);
337 if (n->m_flags & M_EXT)
338 n->m_len = n->m_ext.ext_size;
339 }
340 len = sizeof(struct ieee80211_frame);
341 memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len);
342 left -= len;
343 moff = len;
344 noff = len;
345 if (txflag) {
346 kid = sc->sc_wep_defkid;
347 wh = mtod(n, struct ieee80211_frame *);
348 wh->i_fc[1] |= IEEE80211_FC1_WEP;
349 iv = random();
350 /*
351 * store IV, byte order is not the matter since it's random.
352 * assuming IEEE80211_WEP_IVLEN is 3
353 */
354 ivp = mtod(n, u_int8_t *) + noff;
355 ivp[0] = (iv >> 16) & 0xff;
356 ivp[1] = (iv >> 8) & 0xff;
357 ivp[2] = iv & 0xff;
358 ivp[3] = kid & 0x03; /* clear pad and keyid */
359 noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
360 } else {
361 ivp = mtod(m, u_int8_t *) + moff;
362 moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
363 kid = ivp[IEEE80211_WEP_IVLEN] & 0x03;
364 }
365 key = sc->sc_wep_key[kid];
366 keylen = sc->sc_wep_keylen[kid];
367 /* assuming IEEE80211_WEP_IVLEN is 3 */
368 key[0] = ivp[0];
369 key[1] = ivp[1];
370 key[2] = ivp[2];
371 awa->awa_setkey(ctx, key, IEEE80211_WEP_IVLEN + keylen);
372
373 /* encrypt with calculating CRC */
374 crc = ~0;
375 while (left > 0) {
376 len = m->m_len - moff;
377 if (len == 0) {
378 m = m->m_next;
379 moff = 0;
380 continue;
381 }
382 if (len > n->m_len - noff) {
383 len = n->m_len - noff;
384 if (len == 0) {
385 MGET(n->m_next, M_DONTWAIT, n->m_type);
386 if (n->m_next == NULL)
387 goto fail;
388 n = n->m_next;
389 n->m_len = MLEN;
390 if (left >= MINCLSIZE) {
391 MCLGET(n, M_DONTWAIT);
392 if (n->m_flags & M_EXT)
393 n->m_len = n->m_ext.ext_size;
394 }
395 noff = 0;
396 continue;
397 }
398 }
399 if (len > left)
400 len = left;
401 if (txflag) {
402 awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff,
403 mtod(m, caddr_t) + moff, len);
404 crc = awi_crc_update(crc, mtod(m, caddr_t) + moff, len);
405 } else {
406 awa->awa_decrypt(ctx, mtod(n, caddr_t) + noff,
407 mtod(m, caddr_t) + moff, len);
408 crc = awi_crc_update(crc, mtod(n, caddr_t) + noff, len);
409 }
410 left -= len;
411 moff += len;
412 noff += len;
413 }
414 crc = ~crc;
415 if (txflag) {
416 LE_WRITE_4(crcbuf, crc);
417 if (n->m_len >= noff + sizeof(crcbuf))
418 n->m_len = noff + sizeof(crcbuf);
419 else {
420 n->m_len = noff;
421 MGET(n->m_next, M_DONTWAIT, n->m_type);
422 if (n->m_next == NULL)
423 goto fail;
424 n = n->m_next;
425 n->m_len = sizeof(crcbuf);
426 noff = 0;
427 }
428 awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf,
429 sizeof(crcbuf));
430 } else {
431 n->m_len = noff;
432 for (noff = 0; noff < sizeof(crcbuf); noff += len) {
433 len = sizeof(crcbuf) - noff;
434 if (len > m->m_len - moff)
435 len = m->m_len - moff;
436 if (len > 0)
437 awa->awa_decrypt(ctx, crcbuf + noff,
438 mtod(m, caddr_t) + moff, len);
439 m = m->m_next;
440 moff = 0;
441 }
442 if (crc != LE_READ_4(crcbuf))
443 goto fail;
444 }
445 m_freem(m0);
446 return n0;
447
448 fail:
449 m_freem(m0);
450 m_freem(n0);
451 return NULL;
452}
453
454/*
455 * CRC 32 -- routine from RFC 2083
456 */
457
458/* Table of CRCs of all 8-bit messages */
459static u_int32_t awi_crc_table[256];
460static int awi_crc_table_computed = 0;
461
462/* Make the table for a fast CRC. */
463static void
464awi_crc_init()
465{
466 u_int32_t c;
467 int n, k;
468
469 if (awi_crc_table_computed)
470 return;
471 for (n = 0; n < 256; n++) {
472 c = (u_int32_t)n;
473 for (k = 0; k < 8; k++) {
474 if (c & 1)
475 c = 0xedb88320UL ^ (c >> 1);
476 else
477 c = c >> 1;
478 }
479 awi_crc_table[n] = c;
480 }
481 awi_crc_table_computed = 1;
482}
483
484/*
485 * Update a running CRC with the bytes buf[0..len-1]--the CRC
486 * should be initialized to all 1's, and the transmitted value
487 * is the 1's complement of the final running CRC
488 */
489
490static u_int32_t
491awi_crc_update(crc, buf, len)
492 u_int32_t crc;
493 u_int8_t *buf;
494 int len;
495{
496 u_int8_t *endbuf;
497
498 for (endbuf = buf + len; buf < endbuf; buf++)
499 crc = awi_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
500 return crc;
501}
502
503/*
504 * Null -- do nothing but copy.
505 */
506
507static int
508awi_null_ctxlen()
509{
510
511 return 0;
512}
513
514static void
515awi_null_setkey(ctx, key, keylen)
516 void *ctx;
517 u_char *key;
518 int keylen;
519{
520}
521
522static void
523awi_null_copy(ctx, dst, src, len)
524 void *ctx;
525 u_char *dst;
526 u_char *src;
527 int len;
528{
529
530 memcpy(dst, src, len);
531}