Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / shared / wlif_utils.c
blob44ada66e0bef1aa068452ce457e638d54cc1e56f
1 /*
2 * Wireless interface translation utility functions
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: wlif_utils.c 349051 2012-08-06 22:19:21Z $
21 #include <typedefs.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h> // for va_list
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
31 #include <bcmparams.h>
32 #include <bcmnvram.h>
33 #include <bcmutils.h>
34 #include <netconf.h>
35 #include <nvparse.h>
36 #include <shutils.h>
37 #include <wlutils.h>
38 #include <wlif_utils.h>
40 #include "shared.h"
42 #ifndef MAX_NVPARSE
43 #define MAX_NVPARSE 255
44 #endif
46 /* wireless interface name descriptors */
47 typedef struct _wlif_name_desc {
48 char *name; /* wlif name */
49 bool wds; /* wds interface */
50 bool subunit; /* subunit existance */
51 } wlif_name_desc_t;
53 wlif_name_desc_t wlif_name_array[] = {
54 /* name wds subunit */
55 /* PARIMARY */
56 #if defined(linux)
57 { "eth", 0, 0}, /* primary */
58 #else
59 { "wl", 0, 0}, /* primary */
60 #endif
62 /* MBSS */
63 { "wl", 0, 1}, /* mbss */
65 /* WDS */
66 { "wds", 1, 1} /* wds */
70 * Translate virtual interface mac to spoof mac
71 * Rule:
72 * 00:aa:bb:cc:dd:ee 00:00:00:x:y:z
73 * wl0 ------------ [wlx/wlx.y/wdsx.y]0.1 ------ x=1/2/3, y=0, z=1
74 * +----------- [wlx/wlx.y/wdsx.y]0.2 ------ x=1/2/3, y=0, z=2
75 * wl1 ------------ [wlx/wlx.y/wdsx.y]1.1 ------ x=1/2/3, y=1, z=1
76 * +----------- [wlx/wlx.y/wdsx.y]1.2 ------ x=1/2/3, y=1, z=2
78 * URE ON : wds/mbss not support and wlx.y have same mac as wlx
79 * URE OFF : wlx.y have unique mac and wdsx.y have same mac as wlx
82 int
83 get_spoof_mac(const char *osifname, char *mac, int maclen)
85 char nvifname[16];
86 int i, unit, subunit;
87 wlif_name_desc_t *wlif_name;
89 if (osifname == NULL ||
90 mac == NULL ||
91 maclen < ETHER_ADDR_LEN)
92 return -1;
93 if (osifname_to_nvifname(osifname, nvifname, sizeof(nvifname)) < 0)
94 return -1;
96 /* translate to spoof mac */
97 if (!get_ifname_unit(nvifname, &unit, &subunit)) {
98 memset(mac, 0, maclen);
99 for (i = 0; i < ARRAYSIZE(wlif_name_array); i++) {
100 wlif_name = &wlif_name_array[i];
101 if (!strncmp(osifname, wlif_name->name, strlen(wlif_name->name))) {
102 if (subunit >= 0 && wlif_name->subunit)
103 break;
104 else if (subunit < 0 && !wlif_name->subunit) {
105 subunit = 0; /* reset to zero */
106 break;
111 /* not found */
112 if (i == ARRAYSIZE(wlif_name_array))
113 return -1;
115 /* translate it */
116 mac[3] = i+1;
117 mac[4] = unit;
118 mac[5] = subunit;
120 return 0;
123 return -1;
127 get_spoof_ifname(char *mac, char *osifname, int osifnamelen)
129 int idx, unit, subunit;
130 char nvifname[16];
131 wlif_name_desc_t *wlif_name;
133 if (osifname == NULL ||
134 mac == NULL)
135 return -1;
137 if (mac[0] != 0 || mac[1] != 0 ||
138 mac[2] != 0)
139 return -1; /* is a real mac, fast check */
141 idx = mac[3];
142 idx --; /* map to wlif_name_array index */
143 unit = mac[4];
144 subunit = mac[5];
145 if (idx < 0 || idx >= ARRAYSIZE(wlif_name_array))
146 return -1;
148 /* get nvname format */
149 wlif_name = &wlif_name_array[idx];
150 if (wlif_name->subunit)
151 snprintf(nvifname, sizeof(nvifname), "%s%d.%d", (wlif_name->wds) ? "wds" : "wl",
152 unit, subunit);
153 else
154 snprintf(nvifname, sizeof(nvifname), "wl%d", unit);
156 /* translate to osifname */
157 if (nvifname_to_osifname(nvifname, osifname, osifnamelen) < 0)
158 return -1;
160 return 0;
164 get_real_mac(char *mac, int maclen)
166 int idx, unit, subunit;
167 char *ptr, ifname[32];
168 wlif_name_desc_t *wlif_name;
170 if (mac == NULL ||
171 maclen < ETHER_ADDR_LEN)
172 return -1;
174 if (mac[0] != 0 || mac[1] != 0 ||
175 mac[2] != 0)
176 return 0; /* is a real mac, fast path */
178 idx = mac[3];
179 idx --; /* map to wlif_name_array index */
180 unit = mac[4];
181 subunit = mac[5];
182 if (idx < 0 || idx >= ARRAYSIZE(wlif_name_array))
183 return -1;
185 /* get wlx.y mac addr */
186 wlif_name = &wlif_name_array[idx];
187 if (wlif_name->subunit && !wlif_name->wds)
188 snprintf(ifname, sizeof(ifname), "wl%d.%d_hwaddr", unit, subunit);
189 else
190 snprintf(ifname, sizeof(ifname), "wl%d_hwaddr", unit);
192 ptr = nvram_get(ifname);
193 if (ptr == NULL)
194 return -1;
196 ether_atoe(ptr, mac);
197 return 0;
200 unsigned char *
201 get_wlmacstr_by_unit(char *unit)
203 char tmptr[] = "wlXXXXX_hwaddr";
204 char *macaddr;
206 sprintf(tmptr, "wl%s_hwaddr", unit);
208 macaddr = nvram_get(tmptr);
210 if (!macaddr)
211 return NULL;
213 return macaddr;
217 get_lan_mac(unsigned char *mac)
219 unsigned char *lanmac_str = nvram_get("lan_hwaddr");
221 if (mac)
222 memset(mac, 0, 6);
224 if (!lanmac_str || mac == NULL)
225 return -1;
227 ether_atoe(lanmac_str, mac);
229 return 0;
233 get_wlname_by_mac(unsigned char *mac, char *wlname)
235 char eabuf[18];
236 char tmptr[] = "wlXXXXX_hwaddr";
237 char *wl_hw;
238 int i, j;
240 ether_etoa(mac, eabuf);
241 /* find out the wl name from mac */
242 for (i = 0; i < MAX_NVPARSE; i++) {
243 sprintf(wlname, "wl%d", i);
244 sprintf(tmptr, "wl%d_hwaddr", i);
245 wl_hw = nvram_get(tmptr);
246 if (wl_hw) {
247 if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf)))
248 return 0;
251 for (j = 1; j < WL_MAXBSSCFG; j++) {
252 sprintf(wlname, "wl%d.%d", i, j);
253 sprintf(tmptr, "wl%d.%d_hwaddr", i, j);
254 wl_hw = nvram_get(tmptr);
255 if (wl_hw) {
256 if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf)))
257 return 0;
262 return -1;
265 bool
266 wl_wlif_is_psta(char *ifname)
268 int32 psta = FALSE;
270 if (wl_probe(ifname) < 0)
271 return FALSE;
273 wl_iovar_getint(ifname, "psta_if", &psta);
275 return psta ? TRUE : FALSE;
279 * Get LAN or WAN ifname by wl mac
280 * NOTE: We pass ifname in case of same mac in vifs (like URE TR mode)
282 char *
283 get_ifname_by_wlmac(unsigned char *mac, char *name)
285 char nv_name[16], os_name[16], if_name[16];
286 char tmptr[] = "lanXX_ifnames";
287 char *ifnames, *ifname;
288 int i;
291 * In case of URE mode, wl0.1 and wl0 have same mac,
292 * we need extra identity (name).
294 if (name && !strncmp(name, "wl", 2))
295 snprintf(nv_name, sizeof(nv_name), "%s", name);
296 else if (get_wlname_by_mac(mac, nv_name))
297 return 0;
299 if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)) < 0)
300 return 0;
302 if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)) < 0)
303 return 0;
305 /* find for lan */
306 for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) {
307 if (i == 0) {
308 ifnames = nvram_get("lan_ifnames");
309 ifname = nvram_get("lan_ifname");
310 if (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;
317 else {
318 sprintf(if_name, "lan%d_ifnames", i);
319 sprintf(tmptr, "lan%d_ifname", i);
320 ifnames = nvram_get(if_name);
321 ifname = nvram_get(tmptr);
322 if (ifname) {
323 /* the name in ifnames may nvifname or osifname */
324 if (find_in_list(ifnames, nv_name) ||
325 find_in_list(ifnames, os_name))
326 return ifname;
331 /* find for wan */
332 ifnames = nvram_get("wan_ifnames");
333 ifname = nvram_get("wan0_ifname");
334 /* the name in ifnames may nvifname or osifname */
335 if (find_in_list(ifnames, nv_name) ||
336 find_in_list(ifnames, os_name))
337 return ifname;
339 return 0;
342 #define CHECK_NAS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WPA_AUTH_PSK | \
343 WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_PSK))
344 #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
345 #define CHECK_RADIUS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WLIFU_AUTH_RADIUS | \
346 WPA2_AUTH_UNSPECIFIED))
348 /* Get wireless security setting by interface name */
350 get_wsec(wsec_info_t *info, unsigned char *mac, char *osifname)
352 int i, unit, wds = 0, wds_wsec = 0, dwds = 0;
353 char nv_name[16], os_name[16], wl_prefix[16], comb[32], key[8];
354 char wds_role[8], wds_ssid[48], wds_psk[80], wds_akms[16], wds_crypto[16],
355 remote[ETHER_ADDR_LEN];
356 char akm[16], *akms, *akmnext, *value, *infra;
358 if (info == NULL || mac == NULL)
359 return WLIFU_ERR_INVALID_PARAMETER;
361 if (nvifname_to_osifname(osifname, os_name, sizeof(os_name))) {
362 if (get_wlname_by_mac(mac, nv_name))
363 return WLIFU_ERR_INVALID_PARAMETER;
364 else if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)))
365 return WLIFU_ERR_INVALID_PARAMETER;
367 else if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)))
368 return WLIFU_ERR_INVALID_PARAMETER;
370 /* check if i/f exists and retrieve the i/f index */
371 if (wl_probe(os_name) ||
372 wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
373 return WLIFU_ERR_NOT_WL_INTERFACE;
375 /* get wl_prefix */
376 if (strstr(os_name, "wds")) {
377 /* the wireless interface must be configured to run NAS */
378 snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
379 wds = 1;
381 else if (wl_wlif_is_psta(os_name))
382 snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
383 else if (osifname_to_nvifname(os_name, wl_prefix, sizeof(wl_prefix)))
384 return WLIFU_ERR_INVALID_PARAMETER;
386 strcat(wl_prefix, "_");
387 memset(info, 0, sizeof(wsec_info_t));
389 /* if dwds is enabled then dont configure the wds interface */
390 dwds = atoi(nvram_safe_get(strcat_r(wl_prefix, "dwds", comb)));
391 if (dwds)
392 wds = 0;
394 /* get wds setting */
395 if (wds) {
396 /* remote address */
397 if (wl_ioctl(os_name, WLC_WDS_GET_REMOTE_HWADDR, remote, ETHER_ADDR_LEN))
398 return WLIFU_ERR_WL_REMOTE_HWADDR;
399 memcpy(info->remote, remote, ETHER_ADDR_LEN);
401 /* get per wds settings */
402 for (i = 0; i < MAX_NVPARSE; i ++) {
403 char macaddr[18];
404 uint8 ea[ETHER_ADDR_LEN];
406 if (get_wds_wsec(unit, i, macaddr, wds_role, wds_crypto, wds_akms, wds_ssid,
407 wds_psk) &&
408 ((ether_atoe(macaddr, ea) && !bcmp(ea, remote, ETHER_ADDR_LEN)) ||
409 ((mac[0] == '*') && (mac[1] == '\0')))) {
410 /* found wds settings */
411 wds_wsec = 1;
412 break;
417 /* interface unit */
418 info->unit = unit;
419 /* interface os name */
420 strcpy(info->osifname, os_name);
421 /* interface address */
422 memcpy(info->ea, mac, ETHER_ADDR_LEN);
423 /* ssid */
424 if (wds && wds_wsec)
425 strncpy(info->ssid, wds_ssid, MAX_SSID_LEN);
426 else {
427 value = nvram_safe_get(strcat_r(wl_prefix, "ssid", comb));
428 strncpy(info->ssid, value, MAX_SSID_LEN);
430 /* auth */
431 if (nvram_match(strcat_r(wl_prefix, "auth", comb), "1"))
432 info->auth = 1;
433 /* nas auth mode */
434 value = nvram_safe_get(strcat_r(wl_prefix, "auth_mode", comb));
435 info->akm = !strcmp(value, "radius") ? WLIFU_AUTH_RADIUS : 0;
436 if (wds && wds_wsec)
437 akms = wds_akms;
438 else
439 akms = nvram_safe_get(strcat_r(wl_prefix, "akm", comb));
440 foreach(akm, akms, akmnext) {
441 if (!strcmp(akm, "wpa"))
442 info->akm |= WPA_AUTH_UNSPECIFIED;
443 if (!strcmp(akm, "psk"))
444 info->akm |= WPA_AUTH_PSK;
445 if (!strcmp(akm, "wpa2"))
446 info->akm |= WPA2_AUTH_UNSPECIFIED;
447 if (!strcmp(akm, "psk2"))
448 info->akm |= WPA2_AUTH_PSK;
450 /* wsec encryption */
451 value = nvram_safe_get(strcat_r(wl_prefix, "wep", comb));
452 info->wsec = !strcmp(value, "enabled") ? WEP_ENABLED : 0;
453 if (wds && wds_wsec)
454 value = wds_crypto;
455 else
456 value = nvram_safe_get(strcat_r(wl_prefix, "crypto", comb));
457 if (CHECK_NAS(info->akm)) {
458 if (!strcmp(value, "tkip"))
459 info->wsec |= TKIP_ENABLED;
460 else if (!strcmp(value, "aes"))
461 info->wsec |= AES_ENABLED;
462 else if (!strcmp(value, "tkip+aes"))
463 info->wsec |= TKIP_ENABLED|AES_ENABLED;
465 /* nas role setting, may overwrite later in wds case */
466 value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
467 infra = nvram_safe_get(strcat_r(wl_prefix, "infra", comb));
468 if (!strcmp(value, "ap")) {
469 info->flags |= WLIFU_WSEC_AUTH;
471 else if (!strcmp(value, "sta") || !strcmp(value, "wet") ||
472 !strcmp(value, "psr") || !strcmp(value, "psta")) {
473 if (!strcmp(infra, "0")) {
474 /* IBSS, so we must act as Authenticator and Supplicant */
475 info->flags |= WLIFU_WSEC_AUTH;
476 info->flags |= WLIFU_WSEC_SUPPL;
477 /* Adhoc Mode */
478 info->ibss = TRUE;
480 else {
481 info->flags |= WLIFU_WSEC_SUPPL;
484 else if (!strcmp(value, "wds")) {
487 else {
488 /* Unsupported network mode */
489 return WLIFU_ERR_NOT_SUPPORT_MODE;
491 /* overwrite flags */
492 if (wds) {
493 char buf[32];
494 unsigned char *ptr, lrole;
496 /* did not find WDS link configuration, use wireless' */
497 if (!wds_wsec)
498 strcpy(wds_role, "auto");
500 /* get right role */
501 if (!strcmp(wds_role, "sup"))
502 lrole = WL_WDS_WPA_ROLE_SUP;
503 else if (!strcmp(wds_role, "auth"))
504 lrole = WL_WDS_WPA_ROLE_AUTH;
505 else /* if (!strcmp(wds_role, "auto")) */
506 lrole = WL_WDS_WPA_ROLE_AUTO;
508 strcpy(buf, "wds_wpa_role");
509 ptr = (unsigned char *)buf + strlen(buf) + 1;
510 bcopy(info->remote, ptr, ETHER_ADDR_LEN);
511 ptr[ETHER_ADDR_LEN] = lrole;
512 if (wl_ioctl(os_name, WLC_SET_VAR, buf, sizeof(buf)))
513 return WLIFU_ERR_WL_WPA_ROLE;
514 else if (wl_ioctl(os_name, WLC_GET_VAR, buf, sizeof(buf)))
515 return WLIFU_ERR_WL_WPA_ROLE;
516 lrole = *buf;
518 /* overwrite these flags */
519 info->flags = WLIFU_WSEC_WDS;
520 if (lrole == WL_WDS_WPA_ROLE_SUP) {
521 info->flags |= WLIFU_WSEC_SUPPL;
523 else if (lrole == WL_WDS_WPA_ROLE_AUTH) {
524 info->flags |= WLIFU_WSEC_AUTH;
526 else {
527 /* unable to determine WPA role */
528 return WLIFU_ERR_WL_WPA_ROLE;
531 /* user-supplied psk passphrase */
532 if (CHECK_PSK(info->akm)) {
533 if (wds && wds_wsec) {
534 strncpy((char *)info->psk, wds_psk, MAX_USER_KEY_LEN);
535 info->psk[MAX_USER_KEY_LEN] = 0;
537 else {
538 value = nvram_safe_get(strcat_r(wl_prefix, "wpa_psk", comb));
539 strncpy((char *)info->psk, value, MAX_USER_KEY_LEN);
540 info->psk[MAX_USER_KEY_LEN] = 0;
543 /* user-supplied radius server secret */
544 if (CHECK_RADIUS(info->akm))
545 info->secret = nvram_safe_get(strcat_r(wl_prefix, "radius_key", comb));
546 /* AP specific settings */
547 value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
548 if (!strcmp(value, "ap")) {
549 /* gtk rekey interval */
550 if (CHECK_NAS(info->akm)) {
551 value = nvram_safe_get(strcat_r(wl_prefix, "wpa_gtk_rekey", comb));
552 info->gtk_rekey_secs = (int)strtoul(value, NULL, 0);
554 /* wep key */
555 if (info->wsec & WEP_ENABLED) {
556 /* key index */
557 value = nvram_safe_get(strcat_r(wl_prefix, "key", comb));
558 info->wep_index = (int)strtoul(value, NULL, 0);
559 /* key */
560 sprintf(key, "key%s", nvram_safe_get(strcat_r(wl_prefix, "key", comb)));
561 info->wep_key = nvram_safe_get(strcat_r(wl_prefix, key, comb));
563 /* radius server host/port */
564 if (CHECK_RADIUS(info->akm)) {
565 /* update radius server address */
566 info->radius_addr = nvram_safe_get(strcat_r(wl_prefix, "radius_ipaddr",
567 comb));
568 value = nvram_safe_get(strcat_r(wl_prefix, "radius_port", comb));
569 info->radius_port = htons((int)strtoul(value, NULL, 0));
570 /* 802.1x session timeout/pmk cache duration */
571 value = nvram_safe_get(strcat_r(wl_prefix, "net_reauth", comb));
572 info->ssn_to = (int)strtoul(value, NULL, 0);
575 /* preauth */
576 value = nvram_safe_get(strcat_r(wl_prefix, "preauth", comb));
577 info->preauth = (int)strtoul(value, NULL, 0);
579 /* verbose */
580 value = nvram_safe_get(strcat_r(wl_prefix, "nas_dbg", comb));
581 info->debug = (int)strtoul(value, NULL, 0);
585 return WLIFU_WSEC_SUCCESS;