K2.6 patches and update.
[tomato.git] / release / src-rt / wl / nas / nas.c
blobe16cce3ab0bdf539ec50f3cc6f465483e952d324
1 /*
2 * 802.1x EAPOL to RADIUS proxy (Network Access Server)
4 * See
6 * IEEE Std 802.1X-2001
7 * RFC 2284: PPP Extensible Authentication Protocol (EAP)
8 * RFC 2548: Microsoft Vendor-specific RADIUS Attributes
9 * RFC 2716: PPP EAP TLS Authentication Protocol
10 * RFC 2865: Remote Authentication Dial In User Service (RADIUS)
11 * RFC 2869: RADIUS Extensions
12 * RFC 3079: Deriving Keys for use with Microsoft Point-to-Point Encryption (MPPE)
13 * IEEE 802.1X RADIUS Usage Guidelines
14 * RADIUS Master Session Key Attribute
15 * Making IEEE 802.11 Networks Enterprise-Ready
16 * Recommendations for IEEE 802.11 Access Points
18 * Copyright (C) 2010, Broadcom Corporation
19 * All Rights Reserved.
21 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
22 * the contents of this file may not be disclosed to third parties, copied
23 * or duplicated in any form, in whole or in part, without the prior
24 * written permission of Broadcom Corporation.
26 * $Id: nas.c 241388 2011-02-18 03:33:22Z stakita $
29 #include <typedefs.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <time.h>
37 #include <ctype.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <netinet/in.h>
43 #include <net/if.h>
44 #include <net/if_arp.h>
45 #include <arpa/inet.h>
47 #if defined(linux)
48 #include <sys/time.h>
49 #elif defined(__ECOS)
50 extern int gettimeofday(struct timeval *tv, struct timezone *tz);
51 #endif
53 #include <bcmutils.h>
54 #include <bcmtimer.h>
55 #include <bcmendian.h>
56 #include <shutils.h>
57 #include <proto/ethernet.h>
58 #include <proto/eapol.h>
59 #include <proto/eap.h>
61 #include "nas.h"
62 #include "wpa.h"
64 #include "radius.h"
65 #include "nas_radius.h"
67 #include "global.h"
68 #include <bcmcrypto/md5.h>
69 #include <bcmcrypto/rc4.h>
71 #ifdef BCMWPA2
72 #define CHECK_EAPOL_KEY(key) (((key) == EAPOL_WPA_KEY) || ((key) == EAPOL_WPA2_KEY))
73 #else
74 #define CHECK_EAPOL_KEY(key) ((key) == EAPOL_WPA_KEY)
75 #endif
77 static void eapol_canned(nas_t *nas, nas_sta_t *sta, unsigned char code,
78 unsigned char type);
79 static void eapol_dispatch_ex(nas_t *nas, eapol_header_t *eapol, int preauth);
81 static void toss_sta(nas_t *nas, nas_sta_t *sta, int reason, int driver_signal);
83 void
84 send_identity_req(nas_t *nas, nas_sta_t *sta)
86 eapol_header_t eapol;
88 dbg(nas, "send Identity Request");
89 memcpy(eapol.eth.ether_shost, &sta->ea, ETHER_ADDR_LEN);
90 memcpy(eapol.eth.ether_dhost, &nas->ea, ETHER_ADDR_LEN);
91 eapol.eth.ether_type = HTON16(ETHER_TYPE_802_1X);
92 eapol.version = sta->eapol_version;
93 eapol.type = EAPOL_START;
94 eapol.length = 0;
95 eapol_dispatch(nas, &eapol);
98 void
99 cleanup_sta(nas_t *nas, nas_sta_t *sta, int reason, int driver_signal)
101 unsigned char toss = 1;
102 #ifdef BCMDBG
103 char eabuf[ETHER_ADDR_STR_LEN];
104 #endif
106 if (sta == NULL) {
107 dbg(nas, "called with NULL STA ponter");
108 return;
111 /* De-Authenticate supplicant only once, and ignore further
112 * response from supplicant. We put supplicant in DISCONNECTED
113 * state, till we either receive handshake from supplicant or the
114 * wds_td initiator timer expires, either of the events put
115 * supplicant sta back in START state.
116 * Cleanup of supplicant sta is not required in case of WDS,
117 * Because, Removing WDS config leades to rc restart anyway, which
118 * restarts the whole NAS story.
120 if ((nas->flags & NAS_FLAG_WDS) && (nas->flags & NAS_FLAG_AUTHENTICATOR)) {
121 if (!driver_signal && (sta->suppl.state != WPA_DISCONNECTED))
122 sta->suppl.state = WPA_DISCONNECTED;
123 if (!driver_signal && (sta->suppl.state == WPA_DISCONNECTED))
124 driver_signal = 1;
125 /* Dont toss supplicant sta in case of WDS, the initiator
126 * timer will trigger fake assoc.
128 toss = 0;
131 /* If this is because of a driver message, telling the driver again
132 * is unnecessary (and could loop).
134 if (!driver_signal) {
135 dbg(nas, "deauthenticating %s", ether_etoa((uchar *)&sta->ea, eabuf));
136 nas_deauthenticate(nas, &sta->ea, reason);
138 /* Be careful not to leak timer descriptors. */
139 wpa_stop_retx(sta);
141 #ifdef BCMWPA2
142 /* Respect the PMK caching if the STA is associate and Authenticated with WPA2 AKM */
143 if ((sta->mode & WPA2) && (sta->pae.state == AUTHENTICATED) && sta->pae.ssnto) {
144 dbg(nas, "keep STA %s", ether_etoa((uchar *)&sta->ea, eabuf));
145 sta->suppl.state = WPA_PTKSTART;
146 return;
148 #endif /* BCMWPA2 */
149 if (toss) toss_sta(nas, sta, 0, 1);
150 return;
153 /* Just clean up the STA */
155 static void
156 toss_sta(nas_t *nas, nas_sta_t *sta, int reason, int driver_signal)
158 nas_sta_t *sta_list;
159 uint hash;
160 #ifdef BCMDBG
161 char eabuf[ETHER_ADDR_STR_LEN];
162 #endif
163 if (sta == NULL) {
164 dbg(nas, "called with NULL STA ponter");
165 return;
167 /* If this is because of a driver message, telling the driver again
168 * is unnecessary (and could loop).
170 if (!driver_signal) {
171 dbg(nas, "deauthenticating %s", ether_etoa((uchar *)&sta->ea, eabuf));
172 nas_deauthenticate(nas, &sta->ea, reason);
174 /* Be careful not to leak timer descriptors. */
175 wpa_stop_retx(sta);
176 dbg(nas, "cleanup STA %s", ether_etoa((uchar *)&sta->ea, eabuf));
177 /* Remove this one from its hashed list. */
178 hash = pae_hash(&sta->ea);
179 sta_list = nas->sta_hashed[hash];
181 if (sta_list == sta) {
182 /* It was the head, so its next is the new head. */
183 nas->sta_hashed[hash] = sta->next;
185 } else {
186 /* Find the one that points to it and change the pointer. */
187 while ((sta_list != NULL) && (sta_list->next != sta))
188 sta_list = sta_list->next;
189 if (sta_list == NULL) {
190 dbg(nas, "sta %s not in hash list",
191 ether_etoa((uchar *)&sta->ea, eabuf));
192 } else {
193 sta_list->next = sta->next;
197 sta->used = FALSE;
198 return;
202 * Search for or create a STA struct.
203 * If `enter' is not set, do not create it when one is not found.
205 nas_sta_t *
206 lookup_sta(nas_t *nas, struct ether_addr *ea, sta_lookup_mode_t mode)
208 unsigned int hash;
209 nas_sta_t *sta;
210 time_t now, oldest;
212 hash = pae_hash(ea);
214 /* Search for entry in the hash table */
215 for (sta = nas->sta_hashed[hash];
216 sta && memcmp(&sta->ea, ea, ETHER_ADDR_LEN);
217 sta = sta->next);
219 /* One second resolution is probably good enough. */
220 (void) time(&now);
222 /* Allocate a new entry */
223 if (!sta) {
224 int i, old_idx = -1;
226 /* Don't make an unwanted entry. */
227 if (mode == SEARCH_ONLY)
228 return NULL;
230 oldest = now;
231 for (i = 0; i < MAX_SUPPLICANTS; i++) {
232 if (!nas->sta[i].used)
233 break;
234 else if (nas->sta[i].last_use < oldest) {
235 oldest = nas->sta[i].last_use;
236 old_idx = i;
240 if (i < MAX_SUPPLICANTS) {
241 sta = &nas->sta[i];
242 } else if (old_idx == -1) {
243 /* Full up with all the same timestamp?! Can
244 * this really happen?
246 return NULL;
247 } else {
248 /* Didn't find one unused, so age out LRU entry. */
249 sta = &nas->sta[old_idx];
250 toss_sta(nas, sta, DOT11_RC_BUSY, 0);
253 if ((sta != NULL) && (sta->pae.radius.request != NULL)) {
254 free(sta->pae.radius.request);
256 /* Initialize entry */
257 memset(sta, 0, (sizeof(nas_sta_t)));
258 memcpy(&sta->ea, ea, ETHER_ADDR_LEN);
259 sta->used = TRUE;
260 sta->nas = nas;
261 /* initialize EAPOL version */
262 sta->eapol_version = WPA_EAPOL_VERSION;
264 /* Initial STA state:
265 * Cheaper and harmless not to distiguish NAS mode.
267 if (nas->flags & NAS_FLAG_AUTHENTICATOR)
268 sta->suppl.state = sta->suppl.retry_state = WPA_AUTHENTICATION2;
269 #ifdef BCMSUPPL
270 if (nas->flags & NAS_FLAG_SUPPLICANT)
271 sta->suppl.state = sta->suppl.retry_state = WPA_SUP_AUTHENTICATION;
272 sta->suppl.pk_state = EAPOL_SUP_PK_UNKNOWN;
273 #endif
274 sta->pae.state = INITIALIZE;
276 /* initial mode/wsec/algom. assoc proc will override them */
277 if ((nas->mode & RADIUS) && (nas->wsec & WEP_ENABLED)) {
278 sta->mode = RADIUS;
279 sta->wsec = WEP_ENABLED;
280 sta->algo = CRYPTO_ALGO_WEP128;
282 else {
283 sta->mode = 0;
284 sta->wsec = 0;
285 sta->algo = 0;
287 dbg(nas, "mode %d wsec %d algo %d", sta->mode, sta->wsec, sta->algo);
289 /* Add entry to the cache */
290 sta->next = nas->sta_hashed[hash];
291 nas->sta_hashed[hash] = sta;
292 sta->flags = 0;
294 sta->last_use = now;
295 return sta;
298 /* Transition to new PAE state */
299 void
300 pae_state(nas_t *nas, nas_sta_t *sta, int state)
302 #ifdef BCMDBG
303 char eabuf[ETHER_ADDR_STR_LEN];
304 #endif
305 sta->pae.state = state;
307 /* New PAE state */
308 switch (sta->pae.state) {
310 case AUTHENTICATED:
311 dbg(nas, "Authenticated %s", ether_etoa((uchar *)&sta->ea, eabuf));
312 eapol_canned(nas, sta, EAP_SUCCESS, 0);
313 sta->pae.id++;
314 sta->rxauths = 0;
315 break;
317 case HELD:
318 dbg(nas, "Held %s", ether_etoa((uchar *)&sta->ea, eabuf));
319 eapol_canned(nas, sta, EAP_FAILURE, 0);
320 sta->pae.id++;
321 /* hold off for the quiet period */
322 sta->quiet_while = STA_QUIETWHILE_MAX;
324 break;
326 case ABORTING:
327 dbg(nas, "Aborting %s", ether_etoa((uchar *)&sta->ea, eabuf));
328 if (sta->pae.radius.username.data)
329 free(sta->pae.radius.username.data);
330 memset(&sta->pae.radius.username, 0,
331 sizeof(sta->pae.radius.username));
332 if (sta->pae.radius.state.data)
333 free(sta->pae.radius.state.data);
334 memset(&sta->pae.radius.state, 0,
335 sizeof(sta->pae.radius.state));
336 if (sta->pae.radius.request)
337 free(sta->pae.radius.request);
338 sta->pae.radius.request = NULL;
339 sta->pae.id++;
341 break;
343 case DISCONNECTED:
344 dbg(nas, "Disconnected %s", ether_etoa((uchar *)&sta->ea, eabuf));
345 eapol_canned(nas, sta, EAP_FAILURE, 0);
346 sta->pae.id++;
347 sta->pae.state = CONNECTING;
348 sta->rxauths = 0;
349 /* Fall through */
351 case CONNECTING:
352 dbg(nas, "Connecting %s", ether_etoa((uchar *)&sta->ea, eabuf));
353 sta->pae.flags = 0; /* reset flags */
354 sta->pae.ssnto = 0; /* session timeout */
355 eapol_canned(nas, sta, EAP_REQUEST, EAP_IDENTITY);
356 sta->rxauths++;
357 sta->tx_when = STA_TXPERIOD_MAX;
358 break;
360 case AUTHENTICATING:
361 dbg(nas, "Authenticating %s", ether_etoa((uchar *)&sta->ea, eabuf));
362 sta->auth_while = STA_AUTHWHILE_MAX;
363 break;
365 default:
366 dbg(nas, "Unexpected state %d %s", sta->pae.state,
367 ether_etoa((uchar *)&sta->ea, eabuf));
368 break;
372 void
373 fix_wpa(nas_t *nas, nas_sta_t *sta, char *key, int len)
375 eapol_header_t eapol;
376 eapol_wpa_key_header_t wpa_key;
377 unsigned char buffer[sizeof(eapol) + sizeof(wpa_key)];
378 wpa_t *wpa = (wpa_t *)nas->wpa;
380 dbg(nas, "use MPPE recv key as PMK");
381 /* Use the RADIUS key for a PMK. */
382 if (len > PMK_LEN)
383 len = PMK_LEN;
384 memcpy(sta->suppl.pmk, key, len);
385 sta->suppl.pmk_len = len;
386 #ifdef BCMWPA2
387 /* generate pmkid */
388 if (sta->mode & WPA2) {
389 nas_wpa_calc_pmkid(wpa, sta);
390 if (sta->flags & STA_FLAG_PRE_AUTH) {
391 /* Once Pre authed don't worry about this variable */
392 sta->flags &= ~STA_FLAG_PRE_AUTH;
393 return;
396 #endif /* BCMWPA2 */
398 /* Fake enough of an EAPOL key message to make WPA happy. */
399 memcpy(&eapol.eth.ether_shost, &sta->ea, ETHER_ADDR_LEN);
400 memcpy(&eapol.eth.ether_dhost, &nas->ea, ETHER_ADDR_LEN);
401 eapol.eth.ether_type = htons(ETHER_TYPE_802_1X);
402 eapol.version = sta->eapol_version;
403 eapol.type = EAPOL_KEY;
404 eapol.length = EAPOL_WPA_KEY_LEN;
405 memset(&wpa_key, 0, sizeof(wpa_key));
406 #ifdef BCMWPA2
407 if (sta->mode & (WPA2_PSK | WPA2))
408 wpa_key.type = EAPOL_WPA2_KEY;
409 else
410 #endif
411 wpa_key.type = EAPOL_WPA_KEY;
412 wpa_key.key_info = htons(WPA_KEY_PAIRWISE | WPA_KEY_REQ);
413 /* Put the message pieces together. (They probably were together,
414 * but it's not valid to assume so.
416 memcpy(buffer, &eapol, sizeof(eapol));
417 memcpy(&buffer[offsetof(eapol_header_t, body)], &wpa_key,
418 sizeof(wpa_key));
420 /* WPA state should be okay now to start 4-way handshake. */
421 if (process_wpa(wpa, (eapol_header_t *)buffer, sta)) {
422 cleanup_sta(nas, sta, DOT11_RC_8021X_AUTH_FAIL, 0);
427 /* Send a canned EAPOL packet */
428 static void
429 eapol_canned(nas_t *nas, nas_sta_t *sta, unsigned char code, unsigned char type)
431 eapol_header_t eapol;
432 eap_header_t eap;
433 struct iovec frags[2];
435 memcpy(&eapol.eth.ether_dhost, &sta->ea, ETHER_ADDR_LEN);
436 memcpy(&eapol.eth.ether_shost, &nas->ea, ETHER_ADDR_LEN);
437 #ifdef BCMWPA2
438 if (sta->flags & STA_FLAG_PRE_AUTH)
439 eapol.eth.ether_type = htons(ETHER_TYPE_802_1X_PREAUTH);
440 else
441 #endif
442 eapol.eth.ether_type = htons(ETHER_TYPE_802_1X);
443 eapol.version = sta->eapol_version;
444 eapol.type = EAP_PACKET;
445 eapol.length = htons(type ? (EAP_HEADER_LEN + 1) : EAP_HEADER_LEN);
447 eap.code = code;
448 eap.id = sta->pae.id;
449 eap.length = eapol.length;
450 eap.type = type;
452 frags[0].iov_base = (caddr_t) &eapol;
453 frags[0].iov_len = EAPOL_HEADER_LEN;
454 frags[1].iov_base = (caddr_t) &eap;
455 frags[1].iov_len = ntohs(eapol.length);
457 #ifdef BCMWPA2
458 if (sta->flags & STA_FLAG_PRE_AUTH)
459 nas_preauth_send_packet(nas, frags, 2);
460 else
461 #endif
462 nas_eapol_send_packet(nas, frags, 2);
465 #define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */
467 /* How to multiply by 4294.967296 quickly (and not quite exactly)
468 * without using floating point or greater than 32-bit integers.
469 * If you want to fix the last 12 microseconds of error, add in
470 * (2911*(x))>>28)
472 #define NTPFRAC(x) (4294*(x) + ((1981*(x))>>11))
474 /* Send a EAPOL-Key packet */
475 void
476 eapol_key(nas_t *nas, nas_sta_t *sta,
477 unsigned char *send_key, int send_key_len,
478 unsigned char *recv_key, int recv_key_len,
479 unsigned char *key, int key_len, int index, int unicast)
481 struct iovec packet;
482 eapol_header_t *eapol;
483 eapol_key_header_t *body;
485 struct timeval tv;
486 struct timezone tz;
487 unsigned short length;
488 unsigned int replay[2];
489 unsigned char rc4_seed[48] = { 0 };
490 rc4_ks_t rc4_key;
492 /* Allocate packet */
493 packet.iov_len = EAPOL_HEADER_LEN + EAPOL_KEY_HEADER_LEN;
494 if (key)
495 packet.iov_len += key_len;
496 if (!(packet.iov_base = (caddr_t) malloc(packet.iov_len))) {
497 perror("malloc");
498 return;
501 /* Fill EAPOL header */
502 eapol = (eapol_header_t *) packet.iov_base;
503 memcpy(&eapol->eth.ether_dhost, &sta->ea, ETHER_ADDR_LEN);
504 memcpy(&eapol->eth.ether_shost, &nas->ea, ETHER_ADDR_LEN);
505 #ifdef BCMWPA2
506 if (sta->flags & STA_FLAG_PRE_AUTH)
507 eapol->eth.ether_type = htons(ETHER_TYPE_802_1X_PREAUTH);
508 else
509 #endif
510 eapol->eth.ether_type = htons(ETHER_TYPE_802_1X);
511 eapol->version = sta->eapol_version;
512 eapol->type = EAPOL_KEY;
513 eapol->length = htons(packet.iov_len - EAPOL_HEADER_LEN);
515 /* Fill EAPOL-Key header */
516 body = (eapol_key_header_t *) eapol->body;
517 body->type = EAPOL_RC4_KEY;
519 /* Length field is unaligned */
520 length = htons(key_len);
521 memcpy(&body->length, &length, sizeof(body->length));
523 /* Replay Counter field is unaligned */
524 gettimeofday(&tv, &tz);
526 * keep track timestamp locally in case gettimeofday() does not return
527 * correct usec value, for example, on vx. It is ok to not adjust
528 * tv.tv_sec since tv.tv_usec is not going to overflow anyway.
530 if (tv.tv_usec == sta->rc4keyusec && tv.tv_sec == sta->rc4keysec) {
531 tv.tv_usec += sta->rc4keycntr;
532 sta->rc4keycntr ++;
534 else {
535 sta->rc4keysec = tv.tv_sec;
536 sta->rc4keyusec = tv.tv_usec;
537 sta->rc4keycntr = 1;
539 replay[0] = htonl(tv.tv_sec + JAN_1970);
540 replay[1] = htonl(NTPFRAC(tv.tv_usec));
541 memcpy(body->replay, replay, sizeof(body->replay));
543 /* Fill Key IV */
544 nas_rand128(body->iv);
546 /* Fill Key Index */
547 body->index = index;
548 if (unicast)
549 body->index |= EAPOL_KEY_UNICAST;
551 /* Encrypt Key */
552 if (key) {
553 memcpy(rc4_seed, body->iv, 16);
554 memcpy(&rc4_seed[16], recv_key, recv_key_len);
555 prepare_key(rc4_seed, 16 + recv_key_len, &rc4_key);
556 memcpy(body->key, key, key_len);
557 rc4(body->key, key_len, &rc4_key);
560 /* Calculate HMAC-MD5 checksum with null signature */
561 if (send_key) {
562 memset(body->signature, 0, 16);
563 hmac_md5(&eapol->version, packet.iov_len - OFFSETOF(eapol_header_t, version),
564 send_key, send_key_len, body->signature);
567 #ifdef BCMWPA2
568 if (sta->flags & STA_FLAG_PRE_AUTH)
569 nas_preauth_send_packet(nas, &packet, 1);
570 else
571 #endif
572 nas_eapol_send_packet(nas, &packet, 1);
573 free(packet.iov_base);
576 #ifdef BCMDBG
577 /* Make a debug message lucid for those who don't know types by number */
578 static char *
579 eapol_msg_type_name(int type_no)
581 char *name;
583 switch (type_no) {
584 case EAP_PACKET:
585 name = "EAP";
586 break;
587 case EAPOL_START:
588 name = "EAPOL start";
589 break;
590 case EAPOL_LOGOFF:
591 name = "EAPOL logoff";
592 break;
593 case EAPOL_KEY:
594 name = "EAPOL key";
595 break;
596 case EAPOL_ASF:
597 name = "EAPOL ASF";
598 break;
599 default:
600 name = "unexpected type";
601 break;
603 return name;
605 #endif /* BCMDBG */
607 void
608 eapol_dispatch(nas_t *nas, eapol_header_t *eapol)
610 eapol_dispatch_ex(nas, eapol, 0);
613 #ifdef BCMWPA2
614 void
615 preauth_dispatch(nas_t *nas, eapol_header_t *eapol)
617 if (!nas->disable_preauth)
618 eapol_dispatch_ex(nas, eapol, 1);
620 #endif /* BCMWPA2 */
622 static void
623 eapol_dispatch_ex(nas_t *nas, eapol_header_t *eapol, int preauth)
625 nas_sta_t *sta;
626 eap_header_t *eap;
627 #ifdef BCMDBG
628 char eabuf[ETHER_ADDR_STR_LEN];
629 #endif
631 /* Validate EAPOL version */
632 if (!eapol) {
633 dbg(nas, "Missing EAPOL header");
634 return;
637 sta = lookup_sta(nas, (struct ether_addr *) eapol->eth.ether_shost,
638 SEARCH_ENTER);
639 if (!sta) {
640 dbg(nas, "no STA struct available");
641 return;
643 if (sta->pae.state == HELD) {
644 dbg(nas, "nothing done since in HELD state");
645 return;
647 dbg(nas, "%s message from %s", eapol_msg_type_name(eapol->type),
648 ether_etoa((uchar *)&sta->ea, eabuf));
649 if (eapol->version < sta->eapol_version) {
650 dbg(nas, "EAPOL version %d packet received, current version is %d", eapol->version,
651 sta->eapol_version);
654 #ifdef BCMWPA2
655 if (!preauth) {
656 #endif /* BCMWPA2 */
657 /* If this is a WPA key pkt then process it accordingly */
658 if ((eapol->type == EAPOL_KEY) &&
659 (CHECK_EAPOL_KEY(eapol->body[0]))) {
661 * Expect to do this only for WPA_PSK or for WPA either very
662 * early or after RADIUS acceptance.
664 if ((CHECK_NAS(sta->mode)) &&
665 ((sta->pae.state == AUTHENTICATED) ||
666 (sta->pae.state == INITIALIZE))) {
667 /* process WPA key pkt */
668 if (process_wpa(nas->wpa, eapol, sta)) {
669 /* Something wrong in WPA. Lose this sta. */
670 cleanup_sta(nas, sta, DOT11_RC_8021X_AUTH_FAIL, 0);
672 return;
674 /* return; */
677 /* break out if STA is only PSK */
678 if (CHECK_PSK(sta->mode))
679 return;
680 #ifdef BCMWPA2
681 sta->flags &= ~STA_FLAG_PRE_AUTH;
684 * instead of passing the state variable saying whether this data is from a pre auth
685 * sta or from a normal store the variable in the sta struct and
686 * would be reset once the message is handled ... state variable makes sense
687 * only for this one message.
689 else {
690 sta->flags |= STA_FLAG_PRE_AUTH;
691 sta->mode = WPA2;
692 sta->eapol_version = WPA2_EAPOL_VERSION;
694 #endif /* BCMWPA2 */
696 /* EAPOL event : Radius support */
697 switch (eapol->type) {
699 case EAP_PACKET:
700 dbg(nas, "EAP Packet.Preauth=%d", preauth);
701 if (ntohs(eapol->length) >= (EAP_HEADER_LEN + 1)) {
702 eap = (eap_header_t *) eapol->body;
703 dbg(nas, "STA State=%d EAP Packet Type=%d Id=%d code=%d",
704 sta->pae.state, eap->type, eap->id, eap->code);
706 switch (eap->type) {
708 case EAP_IDENTITY:
709 /* Bogus packet */
710 if (eap->id != sta->pae.id ||
711 eap->code != EAP_RESPONSE) {
712 dbg(nas, "bogus EAP packet id %d code %d, expected %d",
713 eap->id, eap->code, sta->pae.id);
714 break;
717 if (sta->pae.state == AUTHENTICATING) {
718 dbg(nas, "NAS currently authenticating STA. "
719 "Tossing packet id=%d code=%d.",
720 eap->id, eap->code);
722 break;
724 /* Record identity */
725 if (ntohs(eap->length) > (EAP_HEADER_LEN + 1)) {
726 if (sta->pae.radius.username.data)
727 free(sta->pae.radius.username.data);
728 sta->pae.radius.username.length = ntohs(eap->length) -
729 EAP_HEADER_LEN - 1;
730 if (!(sta->pae.radius.username.data =
731 malloc(sta->pae.radius.username.length))) {
732 perror("malloc");
733 return;
734 } else
735 memcpy(sta->pae.radius.username.data, eap->data,
736 sta->pae.radius.username.length);
738 pae_state(nas, sta, AUTHENTICATING);
739 /* Fall through */
741 default:
742 /* Bogus packet */
744 /* Forward to authentication server */
745 RADIUS_FORWARD(nas, sta, eap);
746 break;
749 break;
751 case EAPOL_START:
752 dbg(nas, "Start");
753 sta->pae.id = 0; /* reset counter */
754 switch (sta->pae.state) {
755 case AUTHENTICATING:
756 pae_state(nas, sta, ABORTING);
757 /* Fall through */
759 default:
760 pae_state(nas, sta, CONNECTING);
761 break;
763 sta->suppl.state = sta->suppl.retry_state = WPA_PTKSTART;
764 break;
766 case EAPOL_LOGOFF:
767 dbg(nas, "Logoff");
768 switch (sta->pae.state) {
769 default:
770 dbg(nas, "Unexpected pae state %d", sta->pae.state);
771 /* Fall through */
772 case AUTHENTICATING:
773 pae_state(nas, sta, ABORTING);
774 /* Fall through */
776 case CONNECTING:
777 case AUTHENTICATED:
778 pae_state(nas, sta, DISCONNECTED);
779 dbg(nas, "deauthenticating %s", ether_etoa((uchar *)&sta->ea, eabuf));
780 nas_deauthorize(nas, &sta->ea);
781 break;
783 break;
785 case EAPOL_KEY:
786 dbg(nas, "Key");
787 break;
789 case EAPOL_ASF:
790 dbg(nas, "Encapsulated ASF Alert");
791 break;
793 default:
794 dbg(nas, "unknown EAPOL type %d", eapol->type);
795 break;
799 #ifdef BCMSUPPL
800 void
801 eapol_sup_dispatch(nas_t *nas, eapol_header_t *eapol)
803 nas_sta_t *sta;
804 #ifdef BCMDBG
805 char eabuf[ETHER_ADDR_STR_LEN];
806 #endif
808 if (!eapol) {
809 dbg(nas, "Missing EAPOL header");
810 return;
813 sta = lookup_sta(nas, (struct ether_addr *) eapol->eth.ether_shost,
814 SEARCH_ENTER);
815 if (!sta) {
816 dbg(nas, "No STA struct available");
817 return;
820 dbg(nas, "%s message from %s", eapol_msg_type_name(eapol->type),
821 ether_etoa((uchar *)&sta->ea, eabuf));
822 if (eapol->version < sta->eapol_version) {
823 dbg(nas, "EAPOL version %d packet received, current version is %d", eapol->version,
824 sta->eapol_version);
827 /* If this is a WPA key pkt then process it accordingly */
828 if ((eapol->type == EAPOL_KEY) &&
829 (CHECK_EAPOL_KEY(eapol->body[0]))) {
830 /* Expect to do this only for WPA_PSK or for WPA either very
831 * early or after RADIUS acceptance.
833 if ((CHECK_NAS(sta->mode)) &&
834 ((sta->pae.state == AUTHENTICATED) || (sta->pae.state == INITIALIZE))) {
835 /* process WPA key pkt */
836 if (process_sup_wpa(nas->wpa, eapol, sta)) {
837 /* Something wrong in WPA. Lose this pae. */
838 cleanup_sta(nas, sta, DOT11_RC_8021X_AUTH_FAIL, 0);
840 return;
844 err(nas, "unknown EAPOL type %d", eapol->type);
846 #endif /* BCMSUPPL */
848 #ifdef BCMDBG
849 /* Make a debug message lucid for those who don't know types by number */
850 static char *
851 driver_msg_name(int type)
853 switch (type) {
854 case WLC_E_LINK:
855 return "LINK";
856 case WLC_E_ASSOC_IND:
857 return "ASSOC";
858 case WLC_E_REASSOC_IND:
859 return "REASSOC";
860 case WLC_E_DISASSOC_IND:
861 return "DISASSOC";
862 case WLC_E_MIC_ERROR:
863 return "MIC error";
864 default:
865 return "unknown";
868 #endif /* BCMDBG */
870 void
871 driver_message_dispatch(nas_t *nas, bcm_event_t *dpkt)
873 wl_event_msg_t *event = &(dpkt->event);
874 int type = ntohl(event->event_type);
875 uint8 *addr = (uint8 *)&(event->addr);
876 nas_sta_t *sta;
877 #ifdef BCMDBG
878 char eabuf[ETHER_ADDR_STR_LEN];
879 #endif
881 /* !!!THESE ARE THE MESSAGES WE CARE!!! */
882 dbg(nas, "received event of type : %d\n", type);
883 switch (type) {
884 case WLC_E_LINK:
885 /* WLC_E_LINK evnet on WDS is use for trigger nas_start */
886 if (nas->flags & NAS_FLAG_WDS)
887 return;
888 /* authenticator is not interested in LINK event */
889 if (nas->flags & NAS_FLAG_AUTHENTICATOR)
890 return;
891 /* and the supplicant is only interested in link up */
892 if (!(ntohs(event->flags) & WLC_EVENT_MSG_LINK)) {
893 return;
895 case WLC_E_ASSOC_IND:
896 case WLC_E_REASSOC_IND:
897 case WLC_E_DISASSOC_IND:
898 case WLC_E_MIC_ERROR:
899 break;
900 default:
901 /* quietly discard unwanted events */
902 return;
905 dbg(nas, "start");
907 dbg(nas, "driver %s message received for %s", driver_msg_name(type),
908 ether_etoa(addr, eabuf));
910 /* Look for the STA struct, but don't create one if the goal is
911 * to remove it.
913 sta = lookup_sta(nas, (struct ether_addr *)addr,
914 type == WLC_E_DISASSOC_IND ? SEARCH_ONLY : SEARCH_ENTER);
916 switch (type) {
918 case WLC_E_LINK:
919 case WLC_E_ASSOC_IND:
920 case WLC_E_REASSOC_IND:
921 if (!(CHECK_NAS(nas->mode))) {
922 dbg(nas, "Unexpected driver %s message in mode %d", driver_msg_name(type),
923 nas->mode);
924 return;
926 if (wpa_driver_assoc_msg(nas->wpa, dpkt, sta) == 0)
927 break;
929 /* clean-up stuff if there was a problem. */
930 if (sta)
931 cleanup_sta(nas, sta, 0, 1);
933 break;
935 case WLC_E_DISASSOC_IND:
936 if (wpa_driver_disassoc_msg(nas->wpa, dpkt, sta) == 0)
937 break;
939 /* clean-up stuff if there was a problem. */
940 if (sta)
941 cleanup_sta(nas, sta, 0, 1);
943 break;
945 case WLC_E_MIC_ERROR:
946 if ((ntohs(event->flags) & WLC_EVENT_MSG_GROUP) &&
947 (nas->flags & NAS_FLAG_AUTHENTICATOR)) {
948 dbg(nas, "GTK MIC error notification received by AP");
949 return;
954 If an error is attributed to a STA we don't know about,
955 just let it go.
957 Otherwise, call wpa_mic_error for processing
961 if (sta != NULL) {
962 dbg(nas, "PTK MIC error notification received by AP");
963 wpa_mic_error(nas->wpa, sta, TRUE);
965 else {
966 dbg(nas,
967 "PTK MIC error notification received by AP but not from a known STA");
970 break;
972 default:
973 dbg(nas, "Tossing unexpected event #%u", type);
976 dbg(nas, "done");
979 static void
980 nas_watchdog(bcm_timer_id td, nas_t *nas)
982 nas_sta_t *sta;
983 int i;
984 #ifdef BCMDBG
985 char eabuf[ETHER_ADDR_STR_LEN];
986 #endif
987 for (i = 0; i < MAX_SUPPLICANTS; i ++) {
988 for (sta = nas->sta_hashed[i]; sta; sta = sta->next) {
989 #ifdef BCMDBG
990 if (nas->auth_blockout_time) {
991 if (sta->pae.flags & PAE_FLAG_RADIUS_ACCESS_REJECT)
992 dbg(nas, "blocking %s, time remaining = %d",
993 ether_etoa((uchar *)&sta->ea, eabuf), sta->quiet_while);
995 #endif
996 /* check for time out */
997 switch (sta->pae.state) {
998 case AUTHENTICATED:
999 if (!sta->pae.ssnto)
1000 break;
1001 sta->pae.ssnto--;
1002 /* timed out */
1003 if (sta->pae.ssnto)
1004 continue;
1005 /* send Identity Request */
1006 dbg(nas, "ID req to %s\n", ether_etoa((uchar *)&sta->ea, eabuf));
1007 send_identity_req(nas, sta);
1008 break;
1009 case HELD:
1010 if (sta->quiet_while && --sta->quiet_while == 0)
1011 pae_state(nas, sta, CONNECTING);
1012 break;
1013 case CONNECTING:
1014 if (sta->tx_when && --sta->tx_when == 0) {
1015 if (sta->rxauths > STA_REAUTH_MAX)
1016 pae_state(nas, sta, DISCONNECTED);
1017 else
1018 pae_state(nas, sta, CONNECTING);
1020 break;
1021 case AUTHENTICATING:
1022 if (sta->auth_while && --sta->auth_while == 0) {
1023 pae_state(nas, sta, ABORTING);
1024 pae_state(nas, sta, CONNECTING);
1026 break;
1027 default:
1028 break;
1034 static void
1035 nas_start_watchdog(nas_t *nas)
1037 itimer_status_t ts;
1039 if (nas->watchdog_td)
1040 TIMER_DELETE(nas->watchdog_td);
1042 ts = wpa_set_itimer(nas->timer, &nas->watchdog_td,
1043 (bcm_timer_cb)nas_watchdog,
1044 (int)nas, 1, 0);
1045 if (ts != ITIMER_OK)
1046 dbg(nas, "Session timeout timer set failed, code %d", ts);
1049 void
1050 nas_start(nas_t *nas)
1052 nas_sta_t *sta;
1054 /* reset all STAs */
1055 bzero((void *)nas->sta, sizeof(nas->sta));
1056 bzero((void *)nas->sta_hashed, sizeof(nas->sta_hashed));
1057 nas->MIC_failures = 0;
1058 nas->MIC_countermeasures = 0;
1059 nas->prev_MIC_error = 0;
1061 /* start session count down timer */
1062 if (CHECK_RADIUS(nas->mode))
1063 nas_start_watchdog(nas);
1065 /* initiate/request pairwise key exchange */
1066 if (!(nas->flags & NAS_FLAG_WDS))
1067 return;
1069 sta = lookup_sta(nas, (struct ether_addr *)nas->remote,
1070 SEARCH_ENTER);
1071 if (!sta) {
1072 #ifdef BCMDBG
1073 char eabuf[ETHER_ADDR_STR_LEN];
1074 #endif
1075 dbg(nas, "sta %s not available", ether_etoa(nas->remote, eabuf));
1076 return;
1079 /* Assume the peer use the same cipher and akm */
1080 if (CHECK_PSK(nas->mode)) {
1081 sta->suppl.pmk_len = nas->wpa->pmk_len;
1082 bcopy(nas->wpa->pmk, sta->suppl.pmk, nas->wpa->pmk_len);
1085 * There is no beacon/proberesp/assocreq across WDS, therefore
1086 * we have no way to know what cipher and akm the peer is configured
1087 * for. But assuming the peer uses the same configuration seems
1088 * reasonable. No WEP when doing WPA over WDS.
1090 wpa_set_suppl(nas->wpa, sta, nas->mode, nas->wsec, CRYPTO_ALGO_OFF);
1092 #ifdef BCMSUPPL
1093 if (nas->flags & NAS_FLAG_SUPPLICANT)
1094 wpa_request(nas->wpa, sta);
1095 #endif
1096 if (nas->flags & NAS_FLAG_AUTHENTICATOR)
1097 wpa_start(nas->wpa, sta);
1101 nas_handle_error(nas_t *nas, int error)
1103 /* Handle the Error cases one by one */
1104 err(nas, "NAS encountered a non recoverable Error, so resetting the board\n");
1105 nas_reset_board();
1106 while (1);
1107 return 1;