2 * Wireless interface translation utility functions
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
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.
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 $
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>
38 #include <wlif_utils.h>
43 #define MAX_NVPARSE 255
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 */
53 wlif_name_desc_t wlif_name_array
[] = {
54 /* name wds subunit */
57 { "eth", 0, 0}, /* primary */
59 { "wl", 0, 0}, /* primary */
63 { "wl", 0, 1}, /* mbss */
66 { "wds", 1, 1} /* wds */
70 * Translate virtual interface mac to spoof mac
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
83 get_spoof_mac(const char *osifname
, char *mac
, int maclen
)
87 wlif_name_desc_t
*wlif_name
;
89 if (osifname
== NULL
||
91 maclen
< ETHER_ADDR_LEN
)
93 if (osifname_to_nvifname(osifname
, nvifname
, sizeof(nvifname
)) < 0)
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
)
104 else if (subunit
< 0 && !wlif_name
->subunit
) {
105 subunit
= 0; /* reset to zero */
112 if (i
== ARRAYSIZE(wlif_name_array
))
127 get_spoof_ifname(char *mac
, char *osifname
, int osifnamelen
)
129 int idx
, unit
, subunit
;
131 wlif_name_desc_t
*wlif_name
;
133 if (osifname
== NULL
||
137 if (mac
[0] != 0 || mac
[1] != 0 ||
139 return -1; /* is a real mac, fast check */
142 idx
--; /* map to wlif_name_array index */
145 if (idx
< 0 || idx
>= ARRAYSIZE(wlif_name_array
))
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",
154 snprintf(nvifname
, sizeof(nvifname
), "wl%d", unit
);
156 /* translate to osifname */
157 if (nvifname_to_osifname(nvifname
, osifname
, osifnamelen
) < 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
;
171 maclen
< ETHER_ADDR_LEN
)
174 if (mac
[0] != 0 || mac
[1] != 0 ||
176 return 0; /* is a real mac, fast path */
179 idx
--; /* map to wlif_name_array index */
182 if (idx
< 0 || idx
>= ARRAYSIZE(wlif_name_array
))
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
);
190 snprintf(ifname
, sizeof(ifname
), "wl%d_hwaddr", unit
);
192 ptr
= nvram_get(ifname
);
196 ether_atoe(ptr
, mac
);
201 get_wlmacstr_by_unit(char *unit
)
203 char tmptr
[] = "wlXXXXX_hwaddr";
206 sprintf(tmptr
, "wl%s_hwaddr", unit
);
208 macaddr
= nvram_get(tmptr
);
217 get_lan_mac(unsigned char *mac
)
219 unsigned char *lanmac_str
= nvram_get("lan_hwaddr");
224 if (!lanmac_str
|| mac
== NULL
)
227 ether_atoe(lanmac_str
, mac
);
233 get_wlname_by_mac(unsigned char *mac
, char *wlname
)
236 char tmptr
[] = "wlXXXXX_hwaddr";
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
);
247 if (!strncasecmp(wl_hw
, eabuf
, sizeof(eabuf
)))
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
);
256 if (!strncasecmp(wl_hw
, eabuf
, sizeof(eabuf
)))
266 wl_wlif_is_psta(char *ifname
)
270 if (wl_probe(ifname
) < 0)
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)
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
;
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
))
299 if (nvifname_to_osifname(nv_name
, os_name
, sizeof(os_name
)) < 0)
302 if (osifname_to_nvifname(os_name
, nv_name
, sizeof(nv_name
)) < 0)
306 for (i
= 0; i
< WLIFU_MAX_NO_BRIDGE
; i
++) {
308 ifnames
= nvram_get("lan_ifnames");
309 ifname
= nvram_get("lan_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
))
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
);
323 /* the name in ifnames may nvifname or osifname */
324 if (find_in_list(ifnames
, nv_name
) ||
325 find_in_list(ifnames
, os_name
))
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
))
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
;
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
);
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
)));
394 /* get wds setting */
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
++) {
404 uint8 ea
[ETHER_ADDR_LEN
];
406 if (get_wds_wsec(unit
, i
, macaddr
, wds_role
, wds_crypto
, wds_akms
, wds_ssid
,
408 ((ether_atoe(macaddr
, ea
) && !bcmp(ea
, remote
, ETHER_ADDR_LEN
)) ||
409 ((mac
[0] == '*') && (mac
[1] == '\0')))) {
410 /* found wds settings */
419 /* interface os name */
420 strcpy(info
->osifname
, os_name
);
421 /* interface address */
422 memcpy(info
->ea
, mac
, ETHER_ADDR_LEN
);
425 strncpy(info
->ssid
, wds_ssid
, MAX_SSID_LEN
);
427 value
= nvram_safe_get(strcat_r(wl_prefix
, "ssid", comb
));
428 strncpy(info
->ssid
, value
, MAX_SSID_LEN
);
431 if (nvram_match(strcat_r(wl_prefix
, "auth", comb
), "1"))
434 value
= nvram_safe_get(strcat_r(wl_prefix
, "auth_mode", comb
));
435 info
->akm
= !strcmp(value
, "radius") ? WLIFU_AUTH_RADIUS
: 0;
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;
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
;
481 info
->flags
|= WLIFU_WSEC_SUPPL
;
484 else if (!strcmp(value
, "wds")) {
488 /* Unsupported network mode */
489 return WLIFU_ERR_NOT_SUPPORT_MODE
;
491 /* overwrite flags */
494 unsigned char *ptr
, lrole
;
496 /* did not find WDS link configuration, use wireless' */
498 strcpy(wds_role
, "auto");
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
;
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
;
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;
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);
555 if (info
->wsec
& WEP_ENABLED
) {
557 value
= nvram_safe_get(strcat_r(wl_prefix
, "key", comb
));
558 info
->wep_index
= (int)strtoul(value
, NULL
, 0);
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",
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);
576 value
= nvram_safe_get(strcat_r(wl_prefix
, "preauth", comb
));
577 info
->preauth
= (int)strtoul(value
, NULL
, 0);
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
;