K2.6 patches and update.
[tomato.git] / release / src-rt / wl / nas / nas_wksp.c
blob316bf084de29bb242d7d7a3bab16bf2229a06dce
1 /*
2 * NAS WorKSPace - NAS application common code
4 * Copyright (C) 2010, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
12 * $Id: nas_wksp.c 245219 2011-03-09 02:06:06Z kenlo $
15 #include <bcmcrypto/passhash.h>
16 #include <bcmcrypto/sha1.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
21 #include <bcmtimer.h>
23 #include <nas.h>
24 #include <wpa.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <assert.h>
34 #include <typedefs.h>
35 #include <bcmutils.h>
36 #include <wlutils.h>
37 #include <wlioctl.h>
38 #include <shutils.h>
39 #include <proto/eap.h>
41 #include <nas.h>
42 #include <nas_wksp.h>
43 #include <nas_radius.h>
44 #include <nas_wksp_radius.h>
45 #include <netconf.h>
46 #include <nvparse.h>
47 #include <eapd.h>
48 #include <security_ipc.h>
50 /* debug stuff */
51 #ifdef BCMDBG
52 #ifndef NAS_WKSP_DEBUG
53 #define NAS_WKSP_DEBUG 0
54 #endif
55 int debug_nwksp = NAS_WKSP_DEBUG;
56 #endif /* #if BCMDBG */
59 * Locally used globals
61 static char NAS_OPT_LIST[] = "B:g:h:i:I:k:r:K:l:m:N:p:s:t:v:w:d:ADS";
62 static int nas_wksp_inited = 0;
65 * Build command line in argc/argv form for NAS configuration.
66 * This is a template provided for convenience. Program who
67 * needs the functionality can make a copy of this template
68 * into its own code space.
70 #include <bcmutils.h>
71 #include <shutils.h>
75 * Parse command line and populate nas_wksp_t structure which consists of
76 * nas_t wpa_t and all the auxiliary stuff that needed for all NAS instances.
78 #if __ECOS
79 /* interface to option facilities */
80 extern int getopt(int argc, char **argv, char *ostr);
81 extern void initopt(void);
82 extern char *optarg;
83 #endif
85 /* print NAS command line usage */
86 void
87 nas_wksp_display_usage(void)
89 #ifdef BCMDBG
90 printf("\nUsage: nas [options]\n\n");
91 printf("\t-i <interface> Wireless interface name\n");
92 #if defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL)
93 printf("\t-A Authenticator\n");
94 printf("\t-S Supplicant\n");
95 #endif /* #if defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL) */
96 #ifdef NAS_WKSP_BUILD_NAS_AUTH
97 printf("\t-g <interval> WPA GTK rotation interval (ms)\n");
98 printf("\t-h <address> RADIUS server IP address\n");
99 printf("\t-p <port> RADIUS server UDP port\n");
100 #endif /* #ifdef NAS_WKSP_BUILD_NAS_AUTH */
101 printf("\t-k <secret> WPA pre-shared key\n");
102 printf("\t-r <secret> RADIUS server secret\n");
103 printf("\t-m <authentication> Authentication protocol - %d:WPA | %d:WPA-PSK | %d:802.1x\n",
104 WPA, WPA_PSK, RADIUS);
105 #ifdef BCMWPA2
106 printf("\t %d:WPA2 | %d:WPA2-PSK\n",
107 WPA2, WPA2_PSK);
108 #endif
109 printf("\t-s <SSID> Service Set Identity\n");
110 printf("\t-w <encryption> Crypto algorithm - %d:WEP | %d:TKIP | %d:AES\n",
111 WEP_ENABLED, TKIP_ENABLED, AES_ENABLED);
112 printf("\t-I <index> WEP key index - 2 | 3\n");
113 printf("\t-K <key> WEP key\n");
114 printf("\t-t <duration> Radius Session timeout/PMK Caching duration (ms)\n");
115 printf("\t-N <NasID> NAS id\n");
116 #ifdef BCMDBG
117 printf("\t-v <debug> Verbose mode - 0:off | 1:console\n");
118 #endif /* #ifdef BCMDBG */
119 printf("\nThe -i <interface> option must be present before any other per interface options "
120 "to specify the wireless interface\n");
121 printf("\n");
122 #endif /* #ifdef BCMDBG */
126 * Parse command line and populate nas_wksp_t structure.
127 * It takes short form options only as described in function usage().
128 * Field 'nwcbs' in 'nwksp' indicates the number of elements populated
129 * upon return.
132 nas_wksp_parse_cmd(int argc, char *argv[], nas_wksp_t *nwksp)
134 nas_wpa_cb_t *nwcb = NULL; /* pointer to current nas_wpa_cb_t */
135 int i = -1; /* index of current interface */
136 int opt;
137 int unit;
139 #if defined(__ECOS)
140 initopt();
141 #endif
143 /* parse command line parameters */
144 while ((opt = getopt(argc, argv, NAS_OPT_LIST)) != EOF) {
145 switch (opt) {
146 case 'i':
147 if (i + 1 >= NAS_WKSP_MAX_NUM_INTERFACES) {
148 NASDBG("too many interfaces specified\n");
149 return -1;
151 break;
152 #ifdef BCMDBG
153 case 'v':
154 break;
155 #endif
156 default:
157 if (i < 0) {
158 NASDBG("no I/F specified\n");
159 return -1;
161 break;
164 /* save parameters in user-provided structure */
165 switch (opt) {
166 /* i/f dependant parameters */
167 case 'i':
168 /* check if i/f exists and retrieve the i/f index */
169 if (wl_probe(optarg) ||
170 wl_ioctl(optarg, WLC_GET_INSTANCE, &unit, sizeof(unit))) {
171 NASDBG("%s: not a wireless interface\n", optarg);
172 break;
174 /* ignore errorous interface and reuse nas_wpa_cb_t */
175 if (i >= 0 && (nwcb->flags & NAS_WPA_CB_FLAG_ERROR))
176 NASMSG("%s: error parsing options, ignored\n", nwcb->nas.interface);
177 /* advance nas_wpa_cb_t index & alloc new nas_wpa_cb_t */
178 else if ((++ i) < NAS_WKSP_MAX_NUM_INTERFACES) {
179 nwcb = (nas_wpa_cb_t *)malloc(sizeof(nas_wpa_cb_t));
180 assert(nwcb);
182 /* init nas_wpa_cb_t */
183 memset(nwcb, 0, sizeof(nwcb[0]));
184 nwcb->nwksp = nwksp;
185 nwcb->unit = unit;
186 #if !defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL)
187 nwcb->flags |= NAS_WPA_CB_FLAG_SUPPL;
188 nwcb->nas.flags |= NAS_FLAG_SUPPLICANT;
189 #endif /* #if !defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL) */
190 #if defined(NAS_WKSP_BUILD_NAS_AUTH) && !defined(NAS_WKSP_BUILD_NAS_SUPPL)
191 nwcb->flags |= NAS_WPA_CB_FLAG_AUTH;
192 nwcb->nas.flags |= NAS_FLAG_AUTHENTICATOR;
193 #endif /* #if defined(NAS_WKSP_BUILD_NAS_AUTH) && !defined(NAS_WKSP_BUILD_NAS_SUPPL) */
194 nwcb->nas.wan = NAS_WKSP_UNK_FILE_DESC;
195 nwcb->nas.server.sin_port = htons(RADIUS_PORT);
196 nwcb->nas.wsec = TKIP_ENABLED|AES_ENABLED;
197 nwcb->nas.wpa = &nwcb->wpa;
198 nwcb->nas.appl = nwcb;
199 #ifdef BCMDBG
200 nwcb->nas.debug = 1;
201 #endif
202 #ifdef BCMWPA2
203 nwcb->nas.disable_preauth = 0;
204 #endif
205 nwcb->nas.ssn_to = 36000; /* 10hrs */
206 nwcb->wpa.nas = &nwcb->nas;
207 strncpy(nwcb->nas.interface, optarg, IFNAMSIZ);
208 NASDBG("nas[%d].interface %s\n", i, optarg);
209 /* Get interface address */
210 if (wl_hwaddr(nwcb->nas.interface, nwcb->nas.ea.octet)) {
211 NASDBG("%s: failed to get hwaddr\n", nwcb->nas.interface);
212 nwcb->flags |= NAS_WPA_CB_FLAG_ERROR;
213 break;
215 NASDBG("nas[%d].hwaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
217 nwcb->nas.ea.octet[0], nwcb->nas.ea.octet[1],
218 nwcb->nas.ea.octet[2], nwcb->nas.ea.octet[3],
219 nwcb->nas.ea.octet[4], nwcb->nas.ea.octet[5]);
220 nwksp->nwcb[i] = nwcb;
221 break;
222 case 'k':
223 /* Save key parameter. What contraints to apply
224 * are unknown until mode is also known.
226 strncpy((char *)nwcb->psk, optarg, NAS_WKSP_MAX_USER_KEY_LEN);
227 nwcb->psk[NAS_WKSP_MAX_USER_KEY_LEN] = 0;
228 NASDBG("nas[%d].psk %s\n", i, optarg);
229 break;
230 case 'r':
231 /* Save key parameter. What contraints to apply
232 * are unknown until mode is also known.
234 strncpy((char *)nwcb->secret, optarg, NAS_WKSP_MAX_USER_KEY_LEN);
235 nwcb->secret[NAS_WKSP_MAX_USER_KEY_LEN] = 0;
236 NASDBG("nas[%d].secret %s\n", i, optarg);
237 break;
238 case 'm':
239 /* update auth mode */
240 nwcb->nas.mode = (int)strtoul(optarg, NULL, 0);
241 NASDBG("nas[%d].mode %s\n", i, optarg);
242 break;
243 #if defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL)
244 case 'A':
245 /* nas as authenticator */
246 nwcb->flags |= NAS_WPA_CB_FLAG_AUTH;
247 nwcb->nas.flags |= NAS_FLAG_AUTHENTICATOR;
248 NASDBG("nas[%d].role authenticator\n", i);
249 break;
250 case 'S':
251 /* nas as supplicant */
252 nwcb->flags |= NAS_WPA_CB_FLAG_SUPPL;
253 nwcb->nas.flags |= NAS_FLAG_SUPPLICANT;
254 NASDBG("nas[%d].role supplicant\n", i);
255 break;
256 #endif /* #if defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL) */
257 #ifdef NAS_WKSP_BUILD_NAS_AUTH
258 case 'g':
259 /* update group key rekey interval */
260 nwcb->wpa.gtk_rekey_secs = (int)strtoul(optarg, NULL, 0);
261 NASDBG("nas[%d].gtk.rekey %s\n", i, optarg);
262 break;
263 case 'h':
264 #ifdef NAS_RADIUS
265 /* update radius server address */
266 nwcb->nas.server.sin_family = AF_INET;
267 nwcb->nas.server.sin_addr.s_addr = inet_addr(optarg);
268 NASDBG("nas[%d].server.address %s\n", i, optarg);
269 #endif /* #ifdef NAS_RADIUS */
270 break;
271 case 'p':
272 /* update radius server port number */
273 nwcb->nas.server.sin_port = htons((int)strtoul(optarg, NULL, 0));
274 NASDBG("nas[%d].server.port %s\n", i, optarg);
275 break;
276 #endif /* #ifdef NAS_WKSP_BUILD_NAS_AUTH */
277 case 's':
278 /* update ssid info */
279 strncpy(nwcb->nas.ssid, optarg, DOT11_MAX_SSID_LEN);
280 NASDBG("nas[%d].ssid %s\n", i, optarg);
281 break;
282 case 'w':
283 /* update wsec value */
284 nwcb->nas.wsec = (int)strtoul(optarg, NULL, 0);
285 NASDBG("nas[%d].wsec %s\n", i, optarg);
286 break;
287 case 'D':
288 /* nas in WDS mode */
289 nwcb->flags |= NAS_WPA_CB_FLAG_WDS;
290 nwcb->nas.flags |= NAS_FLAG_WDS;
291 NASDBG("nas[%d].flags %08x\n", i, nwcb->nas.flags);
292 /* remote address */
293 if (wl_ioctl(nwcb->nas.interface, WLC_WDS_GET_REMOTE_HWADDR,
294 nwcb->nas.remote, sizeof(nwcb->nas.remote))) {
295 NASDBG("%s: failed to get remote hwaddr\n", nwcb->nas.interface);
296 nwcb->flags |= NAS_WPA_CB_FLAG_ERROR;
297 break;
299 NASDBG("nas[%d].remote %02x:%02x:%02x:%02x:%02x:%02x\n",
301 nwcb->nas.remote[0], nwcb->nas.remote[1],
302 nwcb->nas.remote[2], nwcb->nas.remote[3],
303 nwcb->nas.remote[4], nwcb->nas.remote[5]);
304 break;
305 #ifdef BCMDBG
306 case 'v':
307 /* verbose - 0:no | others:yes */
308 /* for workspace */
309 if (i < 0) {
310 debug_nwksp = (int)strtoul(optarg, NULL, 0);
312 /* for nas */
313 else
314 nwcb->nas.debug = (bool)strtoul(optarg, NULL, 0);
315 break;
316 #endif
318 case 'I':
319 /* WEP key index */
320 nwcb->index = (int)strtoul(optarg, NULL, 0);
321 NASDBG("nas[%d].wep.index %s\n", i, optarg);
322 break;
324 case 'K':
325 /* WEP key */
326 strncpy((char *)nwcb->wep, optarg, NAS_WKSP_MAX_USER_KEY_LEN);
327 nwcb->wep[NAS_WKSP_MAX_USER_KEY_LEN] = 0;
328 NASDBG("nas[%d].wep %s\n", i, optarg);
329 break;
330 case 't':
331 nwcb->nas.ssn_to = (int)strtoul(optarg, NULL, 0);
332 NASDBG("nas[%d].ssn.timeout %s\n", i, optarg);
333 break;
334 #ifdef BCMWPA2
335 case 'd':
336 nwcb->nas.disable_preauth = strtoul(optarg, NULL, 0) == 0;
337 NASDBG("nas[%d].disable_preauth %d\n", i, nwcb->nas.disable_preauth);
338 break;
339 #endif
340 case 'N':
341 strncpy(nwcb->nas.nas_id, optarg, MAX_NAS_ID_LEN);
342 NASDBG("nas[%d].nas_id %s\n", i, optarg);
343 break;
344 default:
345 /* display wrong option and quit */
346 NASDBG("unknown option -%c, ignored\n", opt);
347 break;
351 /* return to caller # of i/f */
352 nwksp->nwcbs = i + 1;
354 return 0;
357 /* listen to sockets and call handlers to process packets */
359 nas_wksp_main_loop(nas_wksp_t *nwksp)
361 int ret;
363 /* init nas */
364 ret = nas_wksp_init(nwksp);
366 /* nas wksp initialization finished */
367 nas_wksp_inited = 1;
368 if (ret) {
369 NASMSG("Unable to initialize NAS. Quitting...\n");
370 nas_wksp_free_workspace(nwksp);
371 return -1;
374 #if !defined(DEBUG) && !defined(__ECOS)
375 /* Daemonize */
376 if (daemon(1, 1) == -1) {
377 /* clean up nas workspace */
378 nas_wksp_cleanup(nwksp);
379 /* free workspace context */
380 nas_wksp_free_workspace(nwksp);
381 perror("nas_wksp_main_loop: daemon\n");
382 exit(errno);
384 #endif
386 while (1) {
387 /* check user command for shutdown */
388 if (nwksp->flags & NAS_WKSP_FLAG_SHUTDOWN) {
389 /* clean up nas workspace */
390 nas_wksp_cleanup(nwksp);
392 /* free workspace context */
393 nas_wksp_free_workspace(nwksp);
395 NASDBG("NAS shutdown...\n");
396 return 0;
399 /* do packets dispatch */
400 nas_wksp_dispatch_packet(nwksp);
404 /* listen to sockets and call handlers to process packets */
405 void
406 nas_wksp_dispatch_packet(nas_wksp_t *nwksp)
408 fd_set fdset;
409 int i, len, width, status, bytes;
410 nas_wpa_cb_t *nwcb = NULL;
411 uint8 *pkt;
412 bcm_event_t *pvt_data;
413 struct timeval tv;
415 /* init file descriptor set */
416 FD_ZERO(&nwksp->fdset);
417 nwksp->fdmax = -1;
419 /* build file descriptor set now to save time later */
420 if (nwksp->eapd != NAS_WKSP_UNK_FILE_DESC) {
421 FD_SET(nwksp->eapd, &nwksp->fdset);
422 if (nwksp->eapd > nwksp->fdmax)
423 nwksp->fdmax = nwksp->eapd;
425 for (i = 0; i < nwksp->nwcbs; i ++) {
426 nwcb = nwksp->nwcb[i];
428 /* ignore the interface if there was any error */
429 if (nwcb->flags & NAS_WPA_CB_FLAG_ERROR) {
430 /* NASMSG("%s: ignore i/f due to error(s)\n", nwcb->nas.interface); */
431 continue;
433 #ifdef NAS_WKSP_BUILD_NAS_AUTH
434 if (nwcb->nas.wan != NAS_WKSP_UNK_FILE_DESC) {
435 FD_SET(nwcb->nas.wan, &nwksp->fdset);
436 if (nwcb->nas.wan > nwksp->fdmax)
437 nwksp->fdmax = nwcb->nas.wan;
439 #endif /* #ifdef NAS_WKSP_BUILD_NAS_AUTH */
441 /* check if there is any sockets in the fd set */
442 if (nwksp->fdmax == -1) {
443 /* do shutdown procedure */
444 nwksp->flags = NAS_WKSP_FLAG_SHUTDOWN;
445 NASMSG("Threr is no any sockets in the fd set, shutdown...\n");
446 return;
449 pkt = nwksp->packet;
450 len = sizeof(nwksp->packet);
451 width = nwksp->fdmax + 1;
452 fdset = nwksp->fdset;
453 /* set timeout value */
454 tv.tv_sec = 1;
455 tv.tv_usec = 0;
457 /* enable timer handling */
458 bcm_timer_module_enable(nwksp->timer, 1);
460 /* listen to data availible on all sockets */
461 status = select(width, &fdset, NULL, NULL, &tv);
463 /* disable timer handling */
464 bcm_timer_module_enable(nwksp->timer, 0);
466 /* got something */
467 if (status > 0) {
468 /* the data is driver indication message or encapsulated 802.1x frame */
469 if (nwksp->eapd != NAS_WKSP_UNK_FILE_DESC && FD_ISSET(nwksp->eapd, &fdset)) {
470 char *ifname = (char *)pkt;
471 eapol_header_t *eapol = (eapol_header_t *)(ifname + IFNAMSIZ);
473 if ((bytes = recv(nwksp->eapd, pkt, len, 0)) > 0) {
474 /* strip prepend ifname */
475 bytes -= IFNAMSIZ;
477 /* dispatch message to eapol, preauth, brcmevent */
478 switch (ntohs(eapol->eth.ether_type)) {
479 case ETHER_TYPE_802_1X: /* eapol */
480 NASDBG("recv eapol packet from socket %d\n", nwksp->eapd);
482 nwcb = nas_wksp_find_nwcb(nwksp, eapol->eth.ether_dhost,
483 ifname, NAS_WKSP_NWCB_AUTO);
484 if (!nwcb)
485 return;
487 /* dispatch eapol for auth or suppl */
488 nas_eapol_message_dispatch(nwcb, (void *)eapol, bytes);
489 break;
490 #ifdef BCMWPA2
491 case ETHER_TYPE_802_1X_PREAUTH: /* preauth */
492 NASDBG("recv preauth packet from socket %d\n",
493 nwksp->eapd);
495 nwcb = nas_wksp_find_nwcb(nwksp, eapol->eth.ether_dhost,
496 NULL, NAS_WKSP_NWCB_AUTO);
497 if (!nwcb)
498 return;
500 preauth_dispatch(&nwcb->nas, eapol);
501 break;
502 #endif /* BCMWPA2 */
503 case ETHER_TYPE_BRCM: /* brcmevent */
504 NASDBG("recv brcmevent packet from eapd Socket"
505 "%d\n", nwksp->eapd);
507 /* make sure to interpret only messages destined to NAS */
508 if (nas_validate_wlpvt_message(bytes, (uint8 *)eapol))
509 return;
511 pvt_data = (bcm_event_t *)(ifname + IFNAMSIZ);
512 nwcb = nas_wksp_find_nwcb(nwksp,
513 pvt_data->eth.ether_dhost,
514 pvt_data->event.ifname,
515 NAS_WKSP_NWCB_AUTO);
517 if (!nwcb)
518 return;
520 /* do not process eapol message in brcmevent */
521 nas_handle_wlpvt_messages(nwcb, (void *)pvt_data, bytes);
522 break;
523 } /* switch(ntohs(eapol->eth.ether_type)) */
524 } /* if ((bytes = recv(nwksp->eapd, pkt, len, 0)) > 0) */
525 } /* FD_ISSET(nwksp->eapd, &fdset) */
527 #ifdef NAS_WKSP_BUILD_NAS_AUTH
528 /* process radius data from individual interfaces */
529 for (i = 0; i < nwksp->nwcbs; i ++) {
530 nwcb = nwksp->nwcb[i];
531 /* the data is radius message */
532 if ((nwcb->nas.wan != NAS_WKSP_UNK_FILE_DESC) &&
533 FD_ISSET(nwcb->nas.wan, &fdset)) {
534 if (recv(nwcb->nas.wan, pkt, len, 0) <= 0) {
535 NASMSG("%s: recv radius error %d from socket %d\n",
536 nwcb->nas.interface, errno, nwcb->nas.wan);
537 /* Reopen the socket to the radius server if possible */
538 if (NAS_RADIUS_OPEN(nwksp, nwcb) != 0) {
539 NASMSG("%s: open radius connection failed\n",
540 nwcb->nas.interface);
542 continue; /* Skip this attempt */
545 NASDBG("%s: recv radius packet from socket %d\n",
546 nwcb->nas.interface, nwcb->nas.wan);
547 RADIUS_DISPATCH(&nwcb->nas, (void *)pkt);
550 #endif /* #ifdef NAS_WKSP_BUILD_NAS_AUTH */
554 return;
557 /* establish connection to EAPD to
558 * receive wpa, eapol and preauth.
561 nas_wksp_open_eapd(nas_wksp_t *nwksp)
563 int reuse = 1;
564 struct sockaddr_in sockaddr;
566 /* open loopback socket to communicate with EAPD */
567 memset(&sockaddr, 0, sizeof(sockaddr));
568 sockaddr.sin_family = AF_INET;
569 sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
570 sockaddr.sin_port = htons(EAPD_WKSP_NAS_UDP_SPORT);
571 if ((nwksp->eapd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
572 NASDBG("eapd: Unable to create loopback socket\n");
573 goto exit0;
575 #if defined(__ECOS)
576 if (setsockopt(nwksp->eapd, SOL_SOCKET, SO_REUSEPORT, (char*)&reuse, sizeof(reuse)) < 0) {
577 NASDBG("eapd: Unable to setsockopt to loopback socket %d.\n", nwksp->eapd);
578 goto exit1;
580 #else
581 if (setsockopt(nwksp->eapd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0) {
582 NASDBG("eapd: Unable to setsockopt to loopback socket %d.\n", nwksp->eapd);
583 goto exit1;
585 #endif
586 if (bind(nwksp->eapd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
587 NASDBG("eapd: Unable to bind to loopback socket %d\n", nwksp->eapd);
588 goto exit1;
590 NASDBG("eapd: opened loopback socket %d\n", nwksp->eapd);
591 return 0;
593 /* error handling */
594 exit1:
595 close(nwksp->eapd);
597 exit0:
598 nwksp->eapd = NAS_WKSP_UNK_FILE_DESC;
599 NASDBG("eapd: failed to open loopback socket\n");
600 return errno;
603 void
604 nas_wksp_close_eapd(nas_wksp_t *nwksp)
606 /* clsoe eapd socket */
607 if (nwksp->eapd != NAS_WKSP_UNK_FILE_DESC) {
608 NASDBG("eapd: close loopback socket %d\n", nwksp->eapd);
609 close(nwksp->eapd);
610 nwksp->eapd = NAS_WKSP_UNK_FILE_DESC;
612 return;
615 /* transmit eapol message thru the socket */
616 static int
617 nas_wksp_eapd_send_packet(nas_t *nas, struct iovec *frags, int nfrags)
619 nas_wpa_cb_t *nwcb = (nas_wpa_cb_t *)nas->appl;
620 nas_wksp_t *nwksp = nwcb->nwksp;
621 struct ether_header *eth;
622 struct msghdr mh;
623 struct sockaddr_in to;
624 struct iovec *iov;
625 int i, rc = 0;
627 if (!nfrags || !nfrags)
628 return -1;
630 if (frags->iov_len < sizeof(struct ether_header))
631 return -1;
633 /* allocate iov buffer */
634 iov = malloc(sizeof(struct iovec) * (nfrags + 1));
635 if (iov == NULL)
636 return -1;
638 eth = (struct ether_header*) frags->iov_base;
640 to.sin_addr.s_addr = inet_addr(EAPD_WKSP_UDP_ADDR);
641 to.sin_family = AF_INET;
642 to.sin_port = htons(EAPD_WKSP_NAS_UDP_RPORT);
644 /* Save incoming interface name */
645 iov[0].iov_base = (void *)&nas->interface;
646 iov[0].iov_len = IFNAMSIZ;
648 for (i = 1; i <= nfrags; i++) {
649 iov[i].iov_base = frags[i-1].iov_base;
650 iov[i].iov_len = frags[i-1].iov_len;
653 memset(&mh, 0, sizeof(mh));
654 mh.msg_name = (void *)&to;
655 mh.msg_namelen = sizeof(to);
656 mh.msg_iov = iov;
657 mh.msg_iovlen = nfrags + 1;
659 if (sendmsg(nwksp->eapd, &mh, 0) < 0)
660 rc = errno;
662 free(iov);
663 return rc;
666 /* transmit eapol message thru the socket */
668 nas_eapol_send_packet(nas_t *nas, struct iovec *frags, int nfrags)
670 return (nas_wksp_eapd_send_packet(nas, frags, nfrags));
673 #ifdef BCMWPA2
674 /* transmit preauth message thru the socket */
675 int nas_preauth_send_packet(nas_t *nas, struct iovec *frags, int nfrags)
677 return (nas_wksp_eapd_send_packet(nas, frags, nfrags));
679 #endif /* BCMWPA2 */
681 /* allocate NAS workspace for <nifs> interfaces/instances */
682 nas_wksp_t *
683 nas_wksp_alloc_workspace(void)
685 nas_wksp_t *nwksp = (nas_wksp_t *)malloc(sizeof(nas_wksp_t));
686 if (!nwksp)
687 return NULL;
689 memset(nwksp, 0, sizeof(nas_wksp_t));
692 NASDBG("allocated NAS workspace %d bytes\n", sizeof(nas_wksp_t));
693 return nwksp;
696 /* free memory taken by NAS workspace */
697 void
698 nas_wksp_free_workspace(nas_wksp_t *nwksp)
700 int i;
701 NASDBG("free NAS workspace %08x\n", (int)nwksp);
702 for (i = 0; i < nwksp->nwcbs; i ++)
703 if (nwksp->nwcb[i])
704 free(nwksp->nwcb[i]);
705 free(nwksp);
708 #define NAS_WKSP_MODULE_TIMER 0
710 * Init the timer event queue (used only by WPA stuff,
711 * up to one per supplicant plus:
712 * the group rekey timer
713 * MIC failure throttling timer
714 * 4-way handshake initiator for wds
715 * pmk timer for WPA2
717 #define NAS_WKSP_MAX_NUM_TIMER (MAX_SUPPLICANTS + 4)
719 /* init one nas instance */
720 static int
721 nas_init_nas(nas_wksp_t *nwksp, nas_wpa_cb_t *nwcb)
723 uint8 *data, *key;
724 int len;
726 #if !NAS_WKSP_MODULE_TIMER
727 nwcb->nas.timer = nwksp->timer;
728 #else
729 bcm_timer_module_init(NAS_WKSP_MAX_NUM_TIMER, &nwcb->nas.timer);
730 #endif /* #if NAS_WKSP_MODULE_TIMER */
732 /* check if mode is supported */
733 if (!(CHECK_AUTH(nwcb->nas.mode))) {
734 NASDBG("%s: auth mode %d is not supported\n", nwcb->nas.interface, nwcb->nas.mode);
735 nwcb->flags |= NAS_WPA_CB_FLAG_ERROR;
736 return 0;
739 /* check if wsec is supported */
740 if (!nwcb->nas.wsec ||
741 (nwcb->nas.wsec & (AES_ENABLED | TKIP_ENABLED | WEP_ENABLED)) != nwcb->nas.wsec) {
742 NASDBG("%s: wsec 0x%x is not supported\n", nwcb->nas.interface, nwcb->nas.wsec);
743 nwcb->flags |= NAS_WPA_CB_FLAG_ERROR;
744 return 0;
747 /* validate gtk rotation and gtk index */
748 if (nwcb->flags & NAS_WPA_CB_FLAG_AUTH) {
749 if ((CHECK_NAS(nwcb->nas.mode)) &&
750 WSEC_WEP_ENABLED(nwcb->nas.wsec)) {
751 if (nwcb->wpa.gtk_rekey_secs) {
752 NASDBG("%s: GTK rotation is not allowed when WEP is enabled,"
753 " disabled\n",
754 nwcb->nas.interface);
755 nwcb->wpa.gtk_rekey_secs = 0;
757 if (nwcb->index != (GTK_INDEX_1 + 1) && nwcb->index != (GTK_INDEX_2 + 1)) {
758 NASDBG("%s: GTK index %d is invalid when WEP is enabled, using %d"
759 " instead\n",
760 nwcb->nas.interface, nwcb->index, GTK_INDEX_1 + 1);
761 nwcb->index = GTK_INDEX_1 + 1;
764 else if (nwcb->index &&
765 nwcb->index != (GTK_INDEX_1 + 1) && nwcb->index != (GTK_INDEX_2 + 1)) {
766 NASDBG("%s: GTK index %d is invalid when used with mode %d, using %d"
767 " instead\n",
768 nwcb->nas.interface, nwcb->index, nwcb->nas.mode, GTK_INDEX_1 + 1);
769 nwcb->index = GTK_INDEX_1 + 1;
773 /* nas type is Wireless IEEE 802.11 */
774 nwcb->nas.type = NAS_PORT_TYPE_WIRELESS_IEEE80211;
776 /* default key index and size */
777 nwcb->wpa.gtk_index = GTK_INDEX_1;
778 #ifdef MFP
779 nwcb->wpa.igtk.id = IGTK_INDEX_1;
780 #endif
782 if (nwcb->nas.mode & RADIUS)
783 nwcb->wpa.gtk_len = WEP128_KEY_SIZE;
785 /* apply key constraints according to the mode */
786 /* PSK pre-shared key */
787 if (CHECK_PSK(nwcb->nas.mode)) {
788 uint8 *num = NULL;
789 key = nwcb->psk;
790 len = strlen((char *)key);
791 nwcb->nas.key.data = data = nwcb->wpa.pmk;
792 /* numeric key must be 256-bit. */
793 if (len == NAS_WKSP_PSK_LEN)
794 num = key;
795 /* allow leading hex radix for a proper size number */
796 else if ((len == NAS_WKSP_PSK_LEN + 2) &&
797 (!strncmp((char *)key, "0x", 2) || !strncmp((char *)key, "0X", 2)))
798 num = key + 2;
799 if (num) {
800 int j = 0;
801 char hex[] = "XX";
802 do {
803 hex[0] = *num++;
804 hex[1] = *num++;
805 if (!isxdigit((int)hex[0]) ||
806 !isxdigit((int)hex[1])) {
807 NASDBG("%s: numeric PSK %s not 256-bit hex number\n",
808 nwcb->nas.interface, key);
809 nwcb->flags |= NAS_WPA_CB_FLAG_ERROR;
810 break;
812 *data++ = (uint8)strtoul(hex, NULL, 16);
813 } while (++j < NAS_WKSP_PSK_LEN/2);
814 nwcb->nas.key.length = NAS_WKSP_PSK_LEN/2;
815 } else {
816 unsigned char output[2*SHA1HashSize];
817 if ((len < NAS_WKSP_PASSPHRASE_MIN) ||
818 (len > NAS_WKSP_PASSPHRASE_MAX)) {
819 NASDBG("%s: %s length illegal\n", nwcb->nas.interface, key);
820 nwcb->flags |= NAS_WPA_CB_FLAG_ERROR;
821 return 0;
824 /* perform password to hash conversion */
825 if (passhash((char *)key, len, (uchar *)nwcb->nas.ssid,
826 strlen(nwcb->nas.ssid), output)) {
827 NASDBG("%s: PSK password hash failed\n", nwcb->nas.interface);
828 nwcb->flags |= NAS_WPA_CB_FLAG_ERROR;
829 return 0;
831 memcpy(data, output, PMK_LEN);
832 nwcb->nas.key.length = PMK_LEN;
834 nwcb->wpa.pmk_len = nwcb->nas.key.length;
837 /* RADIUS secret */
838 if (CHECK_RADIUS(nwcb->nas.mode)) {
839 key = nwcb->secret;
840 len = strlen((char *)key);
841 if (len > NAS_WKSP_MAX_USER_KEY_LEN) {
842 NASDBG("%s: %s too long, truncated\n", nwcb->nas.interface, key);
843 len = NAS_WKSP_MAX_USER_KEY_LEN;
845 nwcb->nas.secret.data = key;
846 nwcb->nas.secret.length = len;
849 /* init mode-specific keys */
850 if (CHECK_NAS(nwcb->nas.mode)) {
851 /* generate the initial global_key_counter and gmk */
852 initialize_global_key_counter(&nwcb->wpa);
853 initialize_gmk(&nwcb->wpa);
856 /* get default key size, key index */
857 if (!nwcb->wpa.gtk_rekey_secs) {
859 * Honor statically configured WEP key. Key index
860 * should be either 2 or 3.
862 if (WSEC_WEP_ENABLED(nwcb->nas.wsec) &&
863 nwcb->index && strlen((char *)nwcb->wep)) {
865 uint8 wep[NAS_WKSP_MAX_USER_KEY_LEN + 1];
866 char hex[] = "XX";
867 key = nwcb->wep;
868 data = wep;
870 switch (strlen((char *)key)) {
871 case WEP1_KEY_SIZE:
872 case WEP128_KEY_SIZE:
873 len = strlen((char *)key);
874 strcpy((char *)wep, (char *) key);
875 break;
876 case WEP1_KEY_HEX_SIZE:
877 case WEP128_KEY_HEX_SIZE:
878 len = strlen((char *)key) / 2;
879 while (*key) {
880 strncpy(hex, (char *) key, 2);
881 *data++ = (uint8)strtoul(hex, NULL, 16);
882 key += 2;
884 break;
885 default:
886 len = 0;
887 break;
890 /* wlconf will apply wep first */
891 if (len) {
892 bcopy(wep, nwcb->wpa.gtk, len);
893 nwcb->wpa.gtk_index = nwcb->index - 1;
894 nwcb->wpa.gtk_len = len;
895 nwcb->nas.flags |= NAS_FLAG_GTK_PLUMBED;
897 else {
898 NASDBG("%s: unable to plumb WEP key!\n",
899 nwcb->nas.interface);
900 nwcb->flags |= NAS_WPA_CB_FLAG_ERROR;
901 return 0;
905 * When doing WPA (WEP is not enabled) or doing
906 * 802.1x without static WEP key, honor the key index.
908 else if (nwcb->index)
909 nwcb->wpa.gtk_index = nwcb->index - 1;
912 /* AP specific setup */
913 if (nwcb->flags & NAS_WPA_CB_FLAG_AUTH) {
914 /* grab WPA capabilities, used in IE contruction */
915 nas_get_wpacap(&nwcb->nas, nwcb->wpa.cap);
919 /* tell nas to start */
920 if (nwcb->flags & NAS_WPA_CB_FLAG_ERROR) {
921 NASDBG("%s: unable to start NAS due to early error",
922 nwcb->nas.interface);
923 return 0;
926 nas_start(&nwcb->nas);
928 return 0;
931 /* init all NAS instances */
932 static int
933 nas_wksp_init_nas(nas_wksp_t *nwksp)
935 nas_wpa_cb_t *nwcb;
936 int i;
938 for (i = 0; i < nwksp->nwcbs; i ++) {
939 nwcb = nwksp->nwcb[i];
940 assert(nwcb);
942 nas_init_nas(nwksp, nwcb);
945 return 0;
948 /* cleanup one nas instance */
949 static void
950 nas_cleanup_nas(nas_wksp_t *nwksp, nas_wpa_cb_t *nwcb)
952 wpa_reset_countermeasures(nwcb->nas.wpa);
954 #if !NAS_WKSP_MODULE_TIMER
955 nwcb->nas.timer = 0;
956 #else
957 bcm_timer_module_cleanup(nwcb->nas.timer);
958 #endif
960 return;
963 /* cleanup all nas instances */
964 static void
965 nas_wksp_cleanup_nas(nas_wksp_t *nwksp)
967 nas_wpa_cb_t *nwcb;
968 int i;
970 /* init each instance */
971 for (i = 0; i < nwksp->nwcbs; i ++) {
972 nwcb = nwksp->nwcb[i];
973 assert(nwcb);
975 nas_cleanup_nas(nwksp, nwcb);
980 * Common NAS application level routines that can be used under different
981 * OSs. These functions need to be re-implemented only when the application
982 * needs a different low level control over how NAS behaves than this
983 * implementation.
985 /* init NAS workspace */
987 nas_wksp_init(nas_wksp_t *nwksp)
989 #if !NAS_WKSP_MODULE_TIMER
990 if (bcm_timer_module_init(NAS_WKSP_MAX_NUM_TIMER*NAS_WKSP_MAX_NUM_INTERFACES,
991 &nwksp->timer)) {
992 NASMSG("bcm_timer_module_init failed\n");
994 #endif /* #if !NAS_WKSP_MODULE_TIMER */
996 /* open connection to receive eapd messages */
997 nas_wksp_open_eapd(nwksp);
999 #ifdef NAS_WKSP_BUILD_NAS_AUTH
1000 /* open connection to receive radius messages */
1001 (void)NAS_WKSP_OPEN_RADIUS(nwksp);
1002 #endif /* #ifdef NAS_WKSP_BUILD_NAS_AUTH */
1004 /* init each instance */
1005 nas_wksp_init_nas(nwksp);
1007 return 0;
1010 /* cleanup NAS workspace */
1011 void
1012 nas_wksp_cleanup(nas_wksp_t *nwksp)
1014 /* stop running nas */
1015 nas_wksp_cleanup_nas(nwksp);
1017 #ifdef NAS_WKSP_BUILD_NAS_AUTH
1018 /* disconnect from radius server */
1019 NAS_WKSP_CLOSE_RADIUS(nwksp);
1020 #endif /* #ifdef NAS_WKSP_BUILD_NAS_AUTH */
1022 #if !NAS_WKSP_MODULE_TIMER
1023 bcm_timer_module_cleanup(nwksp->timer);
1024 #endif /* #if !NAS_WKSP_MODULE_TIMER */
1026 nas_wksp_close_eapd(nwksp);
1029 #ifdef NAS_WKSP_ON_DEMAND
1030 static nas_wpa_cb_t*
1031 nas_get_wsec(nas_wksp_t *nwksp, uint8 *mac, char *osifname)
1033 int ret;
1034 wsec_info_t info;
1035 nas_wpa_cb_t *nwcb = NULL;
1037 if ((ret = get_wsec(&info, (char *) mac, osifname)) != WLIFU_WSEC_SUCCESS) {
1038 if (ret != WLIFU_ERR_NOT_SUPPORT_MODE)
1039 NASDBG("Get wireless security settings failed,"
1040 "mac=0x%02x:%02x:%02x:%02x:%02x:%02x osifname = %s err %d\n",
1041 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
1042 osifname ? : "NULL", ret);
1043 return NULL;
1046 nwcb = (nas_wpa_cb_t *)malloc(sizeof(nas_wpa_cb_t));
1047 if (!nwcb) {
1048 NASMSG("Memory allocate failed for adding new nwcb\n");
1049 return NULL;
1051 memset(nwcb, 0, sizeof(nas_wpa_cb_t));
1053 /* Set default values */
1054 nwcb->nwksp = nwksp;
1055 #if !defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL)
1056 nwcb->flags |= NAS_WPA_CB_FLAG_SUPPL;
1057 nwcb->nas.flags |= NAS_FLAG_SUPPLICANT;
1058 #endif /* #if !defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL) */
1059 #if defined(NAS_WKSP_BUILD_NAS_AUTH) && !defined(NAS_WKSP_BUILD_NAS_SUPPL)
1060 nwcb->flags |= NAS_WPA_CB_FLAG_AUTH;
1061 nwcb->nas.flags |= NAS_FLAG_AUTHENTICATOR;
1062 #endif /* #if defined(NAS_WKSP_BUILD_NAS_AUTH) && !defined(NAS_WKSP_BUILD_NAS_SUPPL) */
1063 nwcb->nas.wan = NAS_WKSP_UNK_FILE_DESC;
1064 nwcb->nas.server.sin_port = htons(RADIUS_PORT);
1065 nwcb->nas.wsec = TKIP_ENABLED|AES_ENABLED;
1066 nwcb->nas.wpa = &nwcb->wpa;
1067 nwcb->nas.appl = nwcb;
1068 #ifdef BCMDBG
1069 nwcb->nas.debug = 1;
1070 #endif
1071 #ifdef BCMWPA2
1072 nwcb->nas.disable_preauth = 0;
1073 #endif
1074 nwcb->nas.ssn_to = 36000; /* 10hrs */
1075 nwcb->wpa.nas = &nwcb->nas;
1077 /* interface unit */
1078 nwcb->unit = info.unit;
1079 NASDBG("new nwcb's unit %d\n", nwcb->unit);
1080 /* interface name */
1081 strncpy(nwcb->nas.interface, info.osifname, IFNAMSIZ);
1082 NASDBG("new nwcb's nas interface %s\n", nwcb->nas.interface);
1083 /* interface address */
1084 memcpy(nwcb->nas.ea.octet, info.ea, ETHER_ADDR_LEN);
1085 NASDBG("new nwcb's nas hwaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
1086 nwcb->nas.ea.octet[0], nwcb->nas.ea.octet[1],
1087 nwcb->nas.ea.octet[2], nwcb->nas.ea.octet[3],
1088 nwcb->nas.ea.octet[4], nwcb->nas.ea.octet[5]);
1089 /* ssid info */
1090 strncpy(nwcb->nas.ssid, info.ssid, DOT11_MAX_SSID_LEN);
1091 NASDBG("new nwcb's nas ssid %s\n", nwcb->nas.ssid);
1092 /* nas auth mode */
1093 nwcb->nas.mode = info.akm;
1094 NASDBG("new nwcb's nas auth mode %d\n", nwcb->nas.mode);
1095 if (!nwcb->nas.mode) {
1096 NASDBG("%s: Ignored interface. Invalid NAS mode\n", info.osifname);
1097 free(nwcb);
1098 return NULL;
1100 /* wsec encryption */
1101 nwcb->nas.wsec = info.wsec;
1102 NASDBG("new nwcb's nas wsec encryption mode %d\n", nwcb->nas.wsec);
1103 if (!nwcb->nas.wsec) {
1104 NASDBG("%s: Ignored interface. Invalid WSEC\n", info.osifname);
1105 free(nwcb);
1106 return NULL;
1109 /* nas role setting */
1110 #if defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL)
1111 nwcb->flags = info.flags;
1112 nwcb->nas.flags = info.flags;
1113 #endif /* #if defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL) */
1114 if (info.flags & NAS_WPA_CB_FLAG_WDS) {
1115 nwcb->flags = info.flags;
1116 nwcb->nas.flags = info.flags;
1118 NASDBG("new nwcb's nas flags %d\n", nwcb->nas.flags);
1120 /* remote address */
1121 memcpy(nwcb->nas.remote, info.remote, ETHER_ADDR_LEN);
1122 NASDBG("new nwcb's nas remote %02x:%02x:%02x:%02x:%02x:%02x\n",
1123 nwcb->nas.remote[0], nwcb->nas.remote[1],
1124 nwcb->nas.remote[2], nwcb->nas.remote[3],
1125 nwcb->nas.remote[4], nwcb->nas.remote[5]);
1126 /* user-supplied psk passphrase */
1127 if (info.psk) {
1128 strncpy((char *)nwcb->psk, info.psk, NAS_WKSP_MAX_USER_KEY_LEN);
1129 nwcb->psk[NAS_WKSP_MAX_USER_KEY_LEN] = 0;
1130 NASDBG("new nwcb's psk %s\n", nwcb->psk);
1132 /* user-supplied radius server secret */
1133 if (info.secret) {
1134 strncpy((char *)nwcb->secret, info.secret, NAS_WKSP_MAX_USER_KEY_LEN);
1135 nwcb->secret[NAS_WKSP_MAX_USER_KEY_LEN] = 0;
1136 NASDBG("new nwcb's secret %s\n", nwcb->secret);
1138 #ifdef NAS_WKSP_BUILD_NAS_AUTH
1139 nwcb->wpa.gtk_rekey_secs = info.gtk_rekey_secs;
1140 NASDBG("new nwcb's wpa gtk_rekey_sec %d\n", nwcb->wpa.gtk_rekey_secs);
1141 /* key index */
1142 nwcb->index = info.wep_index;
1143 NASDBG("new nwcb's wep index %d\n", nwcb->index);
1144 /* wep key */
1145 if (info.wep_key) {
1146 strncpy((char *)nwcb->wep, info.wep_key, NAS_WKSP_MAX_USER_KEY_LEN);
1147 nwcb->wep[NAS_WKSP_MAX_USER_KEY_LEN] = 0;
1148 NASDBG("new nwcb's wep %s\n", nwcb->wep);
1150 /* radius server host/port */
1151 #ifdef NAS_RADIUS
1152 /* update radius server address */
1153 if (info.radius_addr) {
1154 nwcb->nas.server.sin_family = AF_INET;
1155 nwcb->nas.server.sin_addr.s_addr = inet_addr(info.radius_addr);
1156 /* update radius server port number */
1157 nwcb->nas.server.sin_port = info.radius_port;
1158 NASDBG("new nwcb's nas radius server address %s, port %d\n",
1159 info.radius_addr, nwcb->nas.server.sin_port);
1161 #endif /* NAS_RADIUS */
1162 /* 802.1x session timeout/pmk cache duration */
1163 nwcb->nas.ssn_to = info.ssn_to;
1164 NASDBG("new nwcb's nas ssn timeout %d\n", nwcb->nas.ssn_to);
1165 #endif /* #ifdef NAS_WKSP_BUILD_NAS_AUTH */
1167 #ifdef BCMDBG
1168 /* verbose - 0:no | others:yes */
1169 nwcb->nas.debug = info.debug;
1170 NASDBG("new nwcb's nas debug %d\n", nwcb->nas.debug);
1171 #endif
1173 #ifdef BCMWPA2
1174 nwcb->nas.disable_preauth = (info.preauth == 0) ? 1 : 0;
1175 NASDBG("new nwcb's nas disable_preauth %d\n", nwcb->nas.disable_preauth);
1176 #endif
1179 /* nas id */
1180 if (info.nas_id) {
1181 strncpy(nwcb->nas.nas_id, info.nas_id, MAX_NAS_ID_LEN);
1182 NASDBG("new nwcb's nas nas_id %s\n", nwcb->nas.nas_id);
1186 /* save to list */
1187 nwksp->nwcb[nwksp->nwcbs++] = nwcb;
1189 return nwcb;
1192 /* add new NAS instance */
1193 nas_wpa_cb_t *
1194 nas_wksp_add_nwcb(nas_wksp_t *nwksp, uint8 *mac, char *osifname)
1196 nas_wpa_cb_t *nwcb = NULL;
1198 /* retrieve wireless security infomation for this interface */
1199 if (nwksp->nwcbs < NAS_WKSP_MAX_NUM_INTERFACES) {
1200 if (!(nwcb = nas_get_wsec(nwksp, mac, osifname))) {
1201 return NULL;
1204 #ifdef NAS_WKSP_BUILD_NAS_AUTH
1205 /* open connection to receive radius messages */
1206 if (CHECK_RADIUS(nwcb->nas.mode)) {
1207 /* open connection to radius server */
1208 if (NAS_RADIUS_OPEN(nwksp, nwcb) != 0)
1209 NASMSG("%s: open radius connection failed\n", nwcb->nas.interface);
1211 #endif /* #ifdef NAS_WKSP_BUILD_NAS_AUTH */
1213 /* init new instance */
1214 nas_init_nas(nwksp, nwcb);
1217 return nwcb;
1219 #endif /* #ifdef NAS_WKSP_ON_DEMAND */
1221 /* find NAS instance based on MAC address and i/f name */
1222 nas_wpa_cb_t *
1223 nas_wksp_find_nwcb(nas_wksp_t *nwksp, uint8 *mac, char *osifname, int mode)
1225 #ifdef BCMDBG
1226 char eabuf[ETHER_ADDR_STR_LEN];
1227 #endif
1228 nas_wpa_cb_t *nwcb = NULL;
1229 int i;
1231 for (i = 0; i < nwksp->nwcbs; i ++) {
1232 nwcb = nwksp->nwcb[i];
1233 assert(nwcb);
1235 if (!bcmp(mac, nwcb->nas.ea.octet, ETHER_ADDR_LEN)) {
1236 if (!osifname) {
1237 NASDBG("%s *: found %08x\n",
1238 ether_etoa((uchar *)mac, eabuf), (uint)nwcb);
1239 return nwcb;
1241 else if (!strncmp(nwcb->nas.interface, osifname, BCM_MSG_IFNAME_MAX)) {
1242 NASDBG("%s %s: found %08x\n",
1243 ether_etoa((uchar *)mac, eabuf), osifname, (uint)nwcb);
1244 return nwcb;
1249 if (mode == NAS_WKSP_NWCB_SEARCH_ENTER)
1250 nwcb = NAS_WKSP_ADD_NWCB(nwksp, mac, osifname);
1252 if (!nwcb)
1253 NASDBG("%s %s: find error\n", ether_etoa((uchar *)mac, eabuf), osifname ? : "*");
1255 return nwcb;
1259 ** Return values are really improtant here please make sure you look
1260 ** thr'u the code before changing it. vx code depends on the return values.
1261 ** returnvalues
1262 ** 0,our packet otherwise not our packet
1265 nas_validate_wlpvt_message(int bytes, uint8 *dpkt)
1267 bcm_event_t *pvt_data;
1269 /* the message should be at least the header to even look at it */
1270 if (bytes < sizeof(bcm_event_t) + 2) {
1271 NASDBG("nas_validate_wlpvt_message: invalid length of message\n");
1272 goto error_exit;
1274 pvt_data = (bcm_event_t *)dpkt;
1275 if (ntohs(pvt_data->bcm_hdr.subtype) != BCMILCP_SUBTYPE_VENDOR_LONG) {
1276 NASDBG("%s: nas_validate_wlpvt_message: not vendor specifictype\n",
1277 pvt_data->event.ifname);
1278 goto error_exit;
1280 if (pvt_data->bcm_hdr.version != BCMILCP_BCM_SUBTYPEHDR_VERSION) {
1281 NASDBG("%s: nas_validate_wlpvt_message: subtype header version mismatch\n",
1282 pvt_data->event.ifname);
1283 goto error_exit;
1285 if (ntohs(pvt_data->bcm_hdr.length) < BCMILCP_BCM_SUBTYPEHDR_MINLENGTH) {
1286 NASDBG("%s: nas_validate_wlpvt_message: subtype hdr length not even minimum\n",
1287 pvt_data->event.ifname);
1288 goto error_exit;
1290 if (bcmp(&pvt_data->bcm_hdr.oui[0], BRCM_OUI, DOT11_OUI_LEN) != 0) {
1291 NASDBG("%s: nas_validate_wlpvt_message: not BRCM OUI\n", pvt_data->event.ifname);
1292 goto error_exit;
1294 /* check for wl nas message types */
1295 switch (ntohs(pvt_data->bcm_hdr.usr_subtype)) {
1296 case BCMILCP_BCM_SUBTYPE_EVENT:
1297 /* wl nas message */
1298 /* if (pvt_data->version != BCM_MSG_VERSION) {
1299 * atleast a debug message
1302 break;
1303 default:
1304 goto error_exit;
1305 break;
1307 return 0; /* good packet may be this is destined to us */
1308 error_exit:
1309 return -1;
1312 void
1313 nas_eapol_message_dispatch(nas_wpa_cb_t *nwcb, void *eapol, int bytes)
1315 nas_t *nas = &nwcb->nas;
1317 #if defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL)
1318 if (nwcb->flags & NAS_WPA_CB_FLAG_AUTH)
1319 eapol_dispatch(nas, eapol);
1320 else
1321 eapol_sup_dispatch(nas, eapol);
1322 #elif defined(NAS_WKSP_BUILD_NAS_AUTH) /* Only support authenticator */
1323 eapol_dispatch(nas, eapol);
1324 #else /* Only support supplicant */
1325 eapol_sup_dispatch(nas, eapol);
1326 #endif /* #if defined(NAS_WKSP_BUILD_NAS_AUTH) && defined(NAS_WKSP_BUILD_NAS_SUPPL) */
1328 return;
1332 nas_handle_wlpvt_messages(nas_wpa_cb_t *nwcb, void *pkt, int bytes)
1334 bcm_event_t *dpkt;
1336 dpkt = (bcm_event_t *)pkt;
1337 NASDBG("received event of type : %d\n", ntohs(dpkt->event.event_type));
1338 switch (ntohs(dpkt->bcm_hdr.usr_subtype)) {
1339 case BCMILCP_BCM_SUBTYPE_EVENT:
1340 /* ingore EAPOL message encapsulated ini bcmevent packet */
1341 if ((ntohl(dpkt->event.event_type) != WLC_E_EAPOL_MSG)) {
1342 NASDBG("%s: recved wl wpa packet interface bytes: %d\n",
1343 dpkt->event.ifname, bytes);
1344 driver_message_dispatch(&nwcb->nas, dpkt);
1346 break;
1348 default: /* not a NAS supported message so return an error */
1349 NASDBG("%s: ERROR: recved unknown packet interface subtype "
1350 "0x%x bytes: %d\n", dpkt->event.ifname,
1351 ntohs(dpkt->bcm_hdr.usr_subtype), bytes);
1352 return -1;
1355 return 0;
1358 void
1359 nas_wksp_clear_inited()
1361 nas_wksp_inited = 0;
1364 int nas_wksp_is_inited()
1366 return nas_wksp_inited;