Add PPTP runtime and GUI
[tomato.git] / release / src / router / shared / wlif_utils.c
blob69b46562c22c2ace6c800ae1f526e7d151bdd138
1 /*
2 * Wireless interface translation utility functions
4 * Copyright (C) 2008, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id: wlif_utils.c,v 1.4 2008/10/02 04:09:46 Exp $
15 #include <typedefs.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <string.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
25 #include <bcmparams.h>
26 #include <bcmnvram.h>
27 #include <bcmutils.h>
28 #include <shutils.h>
29 #include <wlutils.h>
30 #include <wlif_utils.h>
32 #include "shared.h"
34 #define MAX_NVPARSE 255
36 /* wireless interface name descriptors */
37 typedef struct _wlif_name_desc {
38 char *name; /* wlif name */
39 bool wds; /* wds interface */
40 bool subunit; /* subunit existance */
41 } wlif_name_desc_t;
43 wlif_name_desc_t wlif_name_array[] = {
44 /* name wds subunit */
45 /* PARIMARY */
46 #if defined(linux)
47 { "eth", 0, 0}, /* primary */
48 #else
49 { "wl", 0, 0}, /* primary */
50 #endif
52 /* MBSS */
53 { "wl", 0, 1}, /* mbss */
55 /* WDS */
56 { "wds", 1, 1} /* wds */
60 * Translate virtual interface mac to spoof mac
61 * Rule:
62 * 00:aa:bb:cc:dd:ee 00:00:00:x:y:z
63 * wl0 ------------ [wlx/wlx.y/wdsx.y]0.1 ------ x=1/2/3, y=0, z=1
64 * +----------- [wlx/wlx.y/wdsx.y]0.2 ------ x=1/2/3, y=0, z=2
65 * wl1 ------------ [wlx/wlx.y/wdsx.y]1.1 ------ x=1/2/3, y=1, z=1
66 * +----------- [wlx/wlx.y/wdsx.y]1.2 ------ x=1/2/3, y=1, z=2
68 * URE ON : wds/mbss not support and wlx.y have same mac as wlx
69 * URE OFF : wlx.y have unique mac and wdsx.y have same mac as wlx
72 int
73 get_spoof_mac(const char *osifname, char *mac, int maclen)
75 char nvifname[16];
76 int i, unit, subunit;
77 wlif_name_desc_t *wlif_name;
79 if (osifname == NULL ||
80 mac == NULL ||
81 maclen < ETHER_ADDR_LEN)
82 return -1;
83 if (osifname_to_nvifname(osifname, nvifname, sizeof(nvifname)) < 0)
84 return -1;
86 /* translate to spoof mac */
87 if (!get_ifname_unit(nvifname, &unit, &subunit)) {
88 memset(mac, 0, maclen);
89 for (i = 0; i < ARRAYSIZE(wlif_name_array); i++) {
90 wlif_name = &wlif_name_array[i];
91 if (!strncmp(osifname, wlif_name->name, strlen(wlif_name->name))) {
92 if (subunit >= 0 && wlif_name->subunit)
93 break;
94 else if (subunit < 0 && !wlif_name->subunit) {
95 subunit = 0; /* reset to zero */
96 break;
101 /* not found */
102 if (i == ARRAYSIZE(wlif_name_array))
103 return -1;
105 /* translate it */
106 mac[3] = i+1;
107 mac[4] = unit;
108 mac[5] = subunit;
110 return 0;
113 return -1;
117 get_spoof_ifname(char *mac, char *osifname, int osifnamelen)
119 int idx, unit, subunit;
120 char nvifname[16];
121 wlif_name_desc_t *wlif_name;
123 if (osifname == NULL ||
124 mac == NULL)
125 return -1;
127 if (mac[0] != 0 || mac[1] != 0 ||
128 mac[2] != 0)
129 return -1; /* is a real mac, fast check */
131 idx = mac[3];
132 idx --; /* map to wlif_name_array index */
133 unit = mac[4];
134 subunit = mac[5];
135 if (idx < 0 || idx >= ARRAYSIZE(wlif_name_array))
136 return -1;
138 /* get nvname format */
139 wlif_name = &wlif_name_array[idx];
140 if (wlif_name->subunit)
141 snprintf(nvifname, sizeof(nvifname), "%s%d.%d", (wlif_name->wds) ? "wds" : "wl",
142 unit, subunit);
143 else
144 snprintf(nvifname, sizeof(nvifname), "wl%d", unit);
146 /* translate to osifname */
147 if (nvifname_to_osifname(nvifname, osifname, osifnamelen) < 0)
148 return -1;
150 return 0;
154 get_real_mac(char *mac, int maclen)
156 int idx, unit, subunit;
157 char *ptr, ifname[32];
158 wlif_name_desc_t *wlif_name;
160 if (mac == NULL ||
161 maclen < ETHER_ADDR_LEN)
162 return -1;
164 if (mac[0] != 0 || mac[1] != 0 ||
165 mac[2] != 0)
166 return 0; /* is a real mac, fast path */
168 idx = mac[3];
169 idx --; /* map to wlif_name_array index */
170 unit = mac[4];
171 subunit = mac[5];
172 if (idx < 0 || idx >= ARRAYSIZE(wlif_name_array))
173 return -1;
175 /* get wlx.y mac addr */
176 wlif_name = &wlif_name_array[idx];
177 if (wlif_name->subunit && !wlif_name->wds)
178 snprintf(ifname, sizeof(ifname), "wl%d.%d_hwaddr", unit, subunit);
179 else
180 snprintf(ifname, sizeof(ifname), "wl%d_hwaddr", unit);
182 ptr = nvram_get(ifname);
183 if (ptr == NULL)
184 return -1;
186 ether_atoe(ptr, mac);
187 return 0;
190 unsigned char *
191 get_wlmacstr_by_unit(char *unit)
193 char tmptr[] = "wlXXXXX_hwaddr";
194 char *macaddr;
196 sprintf(tmptr, "wl%s_hwaddr", unit);
198 macaddr = nvram_get(tmptr);
200 if (!macaddr)
201 return NULL;
203 return macaddr;
207 get_lan_mac(unsigned char *mac)
209 unsigned char *lanmac_str = nvram_get("lan_hwaddr");
211 if (mac)
212 memset(mac, 0, 6);
214 if (!lanmac_str || mac == NULL)
215 return -1;
217 ether_atoe(lanmac_str, mac);
219 return 0;
223 get_wlname_by_mac(unsigned char *mac, char *wlname)
225 char eabuf[18];
226 char tmptr[] = "wlXXXXX_hwaddr";
227 char *wl_hw;
228 int i, j;
230 ether_etoa(mac, eabuf);
231 /* find out the wl name from mac */
232 for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) {
233 sprintf(wlname, "wl%d", i);
234 sprintf(tmptr, "wl%d_hwaddr", i);
235 wl_hw = nvram_get(tmptr);
236 if (wl_hw) {
237 if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf)))
238 return 0;
241 for (j = 1; j < WL_MAXBSSCFG; j++) {
242 sprintf(wlname, "wl%d.%d", i, j);
243 sprintf(tmptr, "wl%d.%d_hwaddr", i, j);
244 wl_hw = nvram_get(tmptr);
245 if (wl_hw) {
246 if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf)))
247 return 0;
252 return -1;
256 * Get LAN or WAN ifname by wl mac
257 * NOTE: We pass ifname in case of same mac in vifs (like URE TR mode)
259 char *
260 get_ifname_by_wlmac(unsigned char *mac, char *name)
262 char nv_name[16], os_name[16], if_name[16];
263 char tmptr[] = "lanXX_ifnames";
264 char *ifnames, *ifname;
265 int i;
268 * In case of URE mode, wl0.1 and wl0 have same mac,
269 * we need extra identity (name).
271 if (name && !strncmp(name, "wl", 2))
272 snprintf(nv_name, sizeof(nv_name), "%s", name);
273 else if (get_wlname_by_mac(mac, nv_name))
274 return 0;
276 if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)) < 0)
277 return 0;
279 if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)) < 0)
280 return 0;
282 /* find for lan */
283 for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) {
284 if (i == 0) {
285 ifnames = nvram_get("lan_ifnames");
286 ifname = nvram_get("lan_ifname");
287 if (ifname) {
288 /* the name in ifnames may nvifname or osifname */
289 if (find_in_list(ifnames, nv_name) ||
290 find_in_list(ifnames, os_name))
291 return ifname;
294 else {
295 sprintf(if_name, "lan%d_ifnames", i);
296 sprintf(tmptr, "lan%d_ifname", i);
297 ifnames = nvram_get(if_name);
298 ifname = nvram_get(tmptr);
299 if (ifname) {
300 /* the name in ifnames may nvifname or osifname */
301 if (find_in_list(ifnames, nv_name) ||
302 find_in_list(ifnames, os_name))
303 return ifname;
308 /* find for wan */
309 ifnames = nvram_get("wan_ifnames");
310 ifname = nvram_get("wan0_ifname");
311 /* the name in ifnames may nvifname or osifname */
312 if (find_in_list(ifnames, nv_name) ||
313 find_in_list(ifnames, os_name))
314 return ifname;
316 return 0;
319 #ifdef BCMWPA2
320 #define CHECK_NAS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WPA_AUTH_PSK | \
321 WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_PSK))
322 #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
323 #define CHECK_RADIUS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WLIFU_AUTH_RADIUS | \
324 WPA2_AUTH_UNSPECIFIED))
325 #else
326 #define CHECK_NAS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WPA_AUTH_PSK))
327 #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK))
328 #define CHECK_RADIUS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WLIFU_AUTH_RADIUS))
329 #endif
331 #if 0
333 * wl_wds<N> is authentication protocol dependant.
334 * when auth is "psk":
335 * wl_wds<N>=mac,role,crypto,auth,ssid,passphrase
337 bool
338 get_wds_wsec(int unit, int which, unsigned char *mac, char *role,
339 char *crypto, char *auth, ...)
341 char name[] = "wlXXXXXXX_wdsXXXXXXX", value[1000], *next;
343 snprintf(name, sizeof(name), "wl%d_wds%d", unit, which);
344 strncpy(value, nvram_safe_get(name), sizeof(value));
345 next = value;
347 /* separate mac */
348 strcpy((char *)mac, strsep(&next, ","));
349 if (!next)
350 return FALSE;
352 /* separate role */
353 strcpy(role, strsep(&next, ","));
354 if (!next)
355 return FALSE;
357 /* separate crypto */
358 strcpy(crypto, strsep(&next, ","));
359 if (!next)
360 return FALSE;
362 /* separate auth */
363 strcpy(auth, strsep(&next, ","));
364 if (!next)
365 return FALSE;
367 if (!strcmp(auth, "psk")) {
368 va_list va;
370 va_start(va, auth);
372 /* separate ssid */
373 strcpy(va_arg(va, char *), strsep(&next, ","));
374 if (!next)
375 goto fail;
377 /* separate passphrase */
378 strcpy(va_arg(va, char *), next);
380 va_end(va);
381 return TRUE;
382 fail:
383 va_end(va);
384 return FALSE;
387 return FALSE;
389 #endif // 0
391 /* Get wireless security setting by interface name */
393 get_wsec(wsec_info_t *info, char *mac, char *osifname)
395 int unit, wds = 0, wds_wsec = 0;
396 char nv_name[16], os_name[16], wl_prefix[16], comb[32], key[8];
397 char wds_role[8], wds_ssid[48], wds_psk[80], wds_akms[16], wds_crypto[16],
398 remote[ETHER_ADDR_LEN];
399 char akm[16], *akms, *akmnext, *value, *infra;
401 if (info == NULL || mac == NULL)
402 return WLIFU_ERR_INVALID_PARAMETER;
404 if (nvifname_to_osifname(osifname, os_name, sizeof(os_name))) {
405 if (get_wlname_by_mac(mac, nv_name))
406 return WLIFU_ERR_INVALID_PARAMETER;
407 else if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)))
408 return WLIFU_ERR_INVALID_PARAMETER;
410 else if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)))
411 return WLIFU_ERR_INVALID_PARAMETER;
413 /* check if i/f exists and retrieve the i/f index */
414 if (wl_probe(os_name) ||
415 wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
416 return WLIFU_ERR_NOT_WL_INTERFACE;
418 /* get wl_prefix */
419 if (strstr(os_name, "wds")) {
420 /* the wireless interface must be configured to run NAS */
421 snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
422 wds = 1;
424 else if (osifname_to_nvifname(os_name, wl_prefix, sizeof(wl_prefix)))
425 return WLIFU_ERR_INVALID_PARAMETER;
427 strcat(wl_prefix, "_");
428 memset(info, 0, sizeof(wsec_info_t));
430 /* get wsd setting */
431 if (wds) {
432 /* remote address */
433 if (wl_ioctl(os_name, WLC_WDS_GET_REMOTE_HWADDR, remote, ETHER_ADDR_LEN))
434 return WLIFU_ERR_WL_REMOTE_HWADDR;
435 memcpy(info->remote, remote, ETHER_ADDR_LEN);
436 #if 0
437 int i;
438 /* get per wds settings */
439 for (i = 0; i < MAX_NVPARSE; i ++) {
440 char macaddr[18];
441 uint8 ea[ETHER_ADDR_LEN];
443 if (get_wds_wsec(unit, i, macaddr, wds_role, wds_crypto, wds_akms, wds_ssid,
444 wds_psk) &&
445 ((ether_atoe(macaddr, ea) && !bcmp(ea, remote, ETHER_ADDR_LEN)) ||
446 (!strcmp(mac, "*")))) {
447 /* found wds settings */
448 wds_wsec = 1;
449 break;
452 #endif // 0
455 /* interface unit */
456 info->unit = unit;
457 /* interface os name */
458 strcpy(info->osifname, os_name);
459 /* interface address */
460 memcpy(info->ea, mac, ETHER_ADDR_LEN);
461 /* ssid */
462 if (wds && wds_wsec)
463 strncpy(info->ssid, wds_ssid, MAX_SSID_LEN);
464 else {
465 value = nvram_safe_get(strcat_r(wl_prefix, "ssid", comb));
466 strncpy(info->ssid, value, MAX_SSID_LEN);
468 /* auth */
469 if (nvram_match(strcat_r(wl_prefix, "auth", comb), "1"))
470 info->auth = 1;
471 /* nas auth mode */
472 value = nvram_safe_get(strcat_r(wl_prefix, "auth_mode", comb));
473 info->akm = !strcmp(value, "radius") ? WLIFU_AUTH_RADIUS : 0;
474 if (wds && wds_wsec)
475 akms = wds_akms;
476 else
477 akms = nvram_safe_get(strcat_r(wl_prefix, "akm", comb));
478 foreach(akm, akms, akmnext) {
479 if (!strcmp(akm, "wpa"))
480 info->akm |= WPA_AUTH_UNSPECIFIED;
481 if (!strcmp(akm, "psk"))
482 info->akm |= WPA_AUTH_PSK;
483 #ifdef BCMWPA2
484 if (!strcmp(akm, "wpa2"))
485 info->akm |= WPA2_AUTH_UNSPECIFIED;
486 if (!strcmp(akm, "psk2"))
487 info->akm |= WPA2_AUTH_PSK;
488 #endif
490 /* wsec encryption */
491 value = nvram_safe_get(strcat_r(wl_prefix, "wep", comb));
492 info->wsec = !strcmp(value, "enabled") ? WEP_ENABLED : 0;
493 if (wds && wds_wsec)
494 value = wds_crypto;
495 else
496 value = nvram_safe_get(strcat_r(wl_prefix, "crypto", comb));
497 if (CHECK_NAS(info->akm)) {
498 if (!strcmp(value, "tkip"))
499 info->wsec |= TKIP_ENABLED;
500 else if (!strcmp(value, "aes"))
501 info->wsec |= AES_ENABLED;
502 else if (!strcmp(value, "tkip+aes"))
503 info->wsec |= TKIP_ENABLED|AES_ENABLED;
505 /* nas role setting, may overwrite later in wds case */
506 value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
507 infra = nvram_safe_get(strcat_r(wl_prefix, "infra", comb));
508 if (!strcmp(value, "ap")) {
509 info->flags |= WLIFU_WSEC_AUTH;
511 else if (!strcmp(value, "sta") || !strcmp(value, "wet")) {
512 if (!strcmp(infra, "0")) {
513 /* IBSS, so we must act as Authenticator and Supplicant */
514 info->flags |= WLIFU_WSEC_AUTH;
515 info->flags |= WLIFU_WSEC_SUPPL;
516 /* Adhoc Mode */
517 info->ibss = TRUE;
519 else {
520 info->flags |= WLIFU_WSEC_SUPPL;
523 else if (!strcmp(value, "wds")) {
526 else {
527 /* Unsupported network mode */
528 return WLIFU_ERR_NOT_SUPPORT_MODE;
530 /* overwrite flags */
531 if (wds) {
532 unsigned char buf[32], *ptr, lrole;
534 /* did not find WDS link configuration, use wireless' */
535 if (!wds_wsec)
536 strcpy(wds_role, "auto");
538 /* get right role */
539 if (!strcmp(wds_role, "sup"))
540 lrole = WL_WDS_WPA_ROLE_SUP;
541 else if (!strcmp(wds_role, "auth"))
542 lrole = WL_WDS_WPA_ROLE_AUTH;
543 else /* if (!strcmp(wds_role, "auto")) */
544 lrole = WL_WDS_WPA_ROLE_AUTO;
546 strcpy(buf, "wds_wpa_role");
547 ptr = buf + strlen(buf) + 1;
548 bcopy(info->remote, ptr, ETHER_ADDR_LEN);
549 ptr[ETHER_ADDR_LEN] = lrole;
550 if (wl_ioctl(os_name, WLC_SET_VAR, buf, sizeof(buf)))
551 return WLIFU_ERR_WL_WPA_ROLE;
552 else if (wl_ioctl(os_name, WLC_GET_VAR, buf, sizeof(buf)))
553 return WLIFU_ERR_WL_WPA_ROLE;
554 lrole = *buf;
556 /* overwrite these flags */
557 info->flags = WLIFU_WSEC_WDS;
558 if (lrole == WL_WDS_WPA_ROLE_SUP) {
559 info->flags |= WLIFU_WSEC_SUPPL;
561 else if (lrole == WL_WDS_WPA_ROLE_AUTH) {
562 info->flags |= WLIFU_WSEC_AUTH;
564 else {
565 /* unable to determine WPA role */
566 return WLIFU_ERR_WL_WPA_ROLE;
569 /* user-supplied psk passphrase */
570 if (CHECK_PSK(info->akm)) {
571 if (wds && wds_wsec) {
572 strncpy((char *)info->psk, wds_psk, MAX_USER_KEY_LEN);
573 info->psk[MAX_USER_KEY_LEN] = 0;
575 else {
576 value = nvram_safe_get(strcat_r(wl_prefix, "wpa_psk", comb));
577 strncpy((char *)info->psk, value, MAX_USER_KEY_LEN);
578 info->psk[MAX_USER_KEY_LEN] = 0;
581 /* user-supplied radius server secret */
582 if (CHECK_RADIUS(info->akm))
583 info->secret = nvram_safe_get(strcat_r(wl_prefix, "radius_key", comb));
584 /* AP specific settings */
585 value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
586 if (!strcmp(value, "ap")) {
587 /* gtk rekey interval */
588 if (CHECK_NAS(info->akm)) {
589 value = nvram_safe_get(strcat_r(wl_prefix, "wpa_gtk_rekey", comb));
590 info->gtk_rekey_secs = (int)strtoul(value, NULL, 0);
592 /* wep key */
593 if (info->wsec & WEP_ENABLED) {
594 /* key index */
595 value = nvram_safe_get(strcat_r(wl_prefix, "key", comb));
596 info->wep_index = (int)strtoul(value, NULL, 0);
597 /* key */
598 sprintf(key, "key%s", nvram_safe_get(strcat_r(wl_prefix, "key", comb)));
599 info->wep_key = nvram_safe_get(strcat_r(wl_prefix, key, comb));
601 /* radius server host/port */
602 if (CHECK_RADIUS(info->akm)) {
603 /* update radius server address */
604 info->radius_addr = nvram_safe_get(strcat_r(wl_prefix, "radius_ipaddr",
605 comb));
606 value = nvram_safe_get(strcat_r(wl_prefix, "radius_port", comb));
607 info->radius_port = htons((int)strtoul(value, NULL, 0));
608 /* 802.1x session timeout/pmk cache duration */
609 value = nvram_safe_get(strcat_r(wl_prefix, "net_reauth", comb));
610 info->ssn_to = (int)strtoul(value, NULL, 0);
613 /* preauth */
614 value = nvram_safe_get(strcat_r(wl_prefix, "preauth", comb));
615 info->preauth = (int)strtoul(value, NULL, 0);
617 /* verbose */
618 value = nvram_safe_get(strcat_r(wl_prefix, "nas_dbg", comb));
619 info->debug = (int)strtoul(value, NULL, 0);
621 return WLIFU_WSEC_SUCCESS;