2 * Wireless interface translation utility functions
4 * Copyright (C) 2008, Broadcom Corporation
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 $
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
25 #include <bcmparams.h>
30 #include <wlif_utils.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 */
43 wlif_name_desc_t wlif_name_array
[] = {
44 /* name wds subunit */
47 { "eth", 0, 0}, /* primary */
49 { "wl", 0, 0}, /* primary */
53 { "wl", 0, 1}, /* mbss */
56 { "wds", 1, 1} /* wds */
60 * Translate virtual interface mac to spoof mac
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
73 get_spoof_mac(const char *osifname
, char *mac
, int maclen
)
77 wlif_name_desc_t
*wlif_name
;
79 if (osifname
== NULL
||
81 maclen
< ETHER_ADDR_LEN
)
83 if (osifname_to_nvifname(osifname
, nvifname
, sizeof(nvifname
)) < 0)
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
)
94 else if (subunit
< 0 && !wlif_name
->subunit
) {
95 subunit
= 0; /* reset to zero */
102 if (i
== ARRAYSIZE(wlif_name_array
))
117 get_spoof_ifname(char *mac
, char *osifname
, int osifnamelen
)
119 int idx
, unit
, subunit
;
121 wlif_name_desc_t
*wlif_name
;
123 if (osifname
== NULL
||
127 if (mac
[0] != 0 || mac
[1] != 0 ||
129 return -1; /* is a real mac, fast check */
132 idx
--; /* map to wlif_name_array index */
135 if (idx
< 0 || idx
>= ARRAYSIZE(wlif_name_array
))
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",
144 snprintf(nvifname
, sizeof(nvifname
), "wl%d", unit
);
146 /* translate to osifname */
147 if (nvifname_to_osifname(nvifname
, osifname
, osifnamelen
) < 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
;
161 maclen
< ETHER_ADDR_LEN
)
164 if (mac
[0] != 0 || mac
[1] != 0 ||
166 return 0; /* is a real mac, fast path */
169 idx
--; /* map to wlif_name_array index */
172 if (idx
< 0 || idx
>= ARRAYSIZE(wlif_name_array
))
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
);
180 snprintf(ifname
, sizeof(ifname
), "wl%d_hwaddr", unit
);
182 ptr
= nvram_get(ifname
);
186 ether_atoe(ptr
, mac
);
191 get_wlmacstr_by_unit(char *unit
)
193 char tmptr
[] = "wlXXXXX_hwaddr";
196 sprintf(tmptr
, "wl%s_hwaddr", unit
);
198 macaddr
= nvram_get(tmptr
);
207 get_lan_mac(unsigned char *mac
)
209 unsigned char *lanmac_str
= nvram_get("lan_hwaddr");
214 if (!lanmac_str
|| mac
== NULL
)
217 ether_atoe(lanmac_str
, mac
);
223 get_wlname_by_mac(unsigned char *mac
, char *wlname
)
226 char tmptr
[] = "wlXXXXX_hwaddr";
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
);
237 if (!strncasecmp(wl_hw
, eabuf
, sizeof(eabuf
)))
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
);
246 if (!strncasecmp(wl_hw
, eabuf
, sizeof(eabuf
)))
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)
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
;
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
))
276 if (nvifname_to_osifname(nv_name
, os_name
, sizeof(os_name
)) < 0)
279 if (osifname_to_nvifname(os_name
, nv_name
, sizeof(nv_name
)) < 0)
283 for (i
= 0; i
< WLIFU_MAX_NO_BRIDGE
; i
++) {
285 ifnames
= nvram_get("lan_ifnames");
286 ifname
= nvram_get("lan_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
))
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
);
300 /* the name in ifnames may nvifname or osifname */
301 if (find_in_list(ifnames
, nv_name
) ||
302 find_in_list(ifnames
, os_name
))
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
))
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))
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))
333 * wl_wds<N> is authentication protocol dependant.
334 * when auth is "psk":
335 * wl_wds<N>=mac,role,crypto,auth,ssid,passphrase
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
));
348 strcpy((char *)mac
, strsep(&next
, ","));
353 strcpy(role
, strsep(&next
, ","));
357 /* separate crypto */
358 strcpy(crypto
, strsep(&next
, ","));
363 strcpy(auth
, strsep(&next
, ","));
367 if (!strcmp(auth
, "psk")) {
373 strcpy(va_arg(va
, char *), strsep(&next
, ","));
377 /* separate passphrase */
378 strcpy(va_arg(va
, char *), next
);
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
;
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
);
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 */
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
);
438 /* get per wds settings */
439 for (i
= 0; i
< MAX_NVPARSE
; i
++) {
441 uint8 ea
[ETHER_ADDR_LEN
];
443 if (get_wds_wsec(unit
, i
, macaddr
, wds_role
, wds_crypto
, wds_akms
, wds_ssid
,
445 ((ether_atoe(macaddr
, ea
) && !bcmp(ea
, remote
, ETHER_ADDR_LEN
)) ||
446 (!strcmp(mac
, "*")))) {
447 /* found wds settings */
457 /* interface os name */
458 strcpy(info
->osifname
, os_name
);
459 /* interface address */
460 memcpy(info
->ea
, mac
, ETHER_ADDR_LEN
);
463 strncpy(info
->ssid
, wds_ssid
, MAX_SSID_LEN
);
465 value
= nvram_safe_get(strcat_r(wl_prefix
, "ssid", comb
));
466 strncpy(info
->ssid
, value
, MAX_SSID_LEN
);
469 if (nvram_match(strcat_r(wl_prefix
, "auth", comb
), "1"))
472 value
= nvram_safe_get(strcat_r(wl_prefix
, "auth_mode", comb
));
473 info
->akm
= !strcmp(value
, "radius") ? WLIFU_AUTH_RADIUS
: 0;
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
;
484 if (!strcmp(akm
, "wpa2"))
485 info
->akm
|= WPA2_AUTH_UNSPECIFIED
;
486 if (!strcmp(akm
, "psk2"))
487 info
->akm
|= WPA2_AUTH_PSK
;
490 /* wsec encryption */
491 value
= nvram_safe_get(strcat_r(wl_prefix
, "wep", comb
));
492 info
->wsec
= !strcmp(value
, "enabled") ? WEP_ENABLED
: 0;
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
;
520 info
->flags
|= WLIFU_WSEC_SUPPL
;
523 else if (!strcmp(value
, "wds")) {
527 /* Unsupported network mode */
528 return WLIFU_ERR_NOT_SUPPORT_MODE
;
530 /* overwrite flags */
532 unsigned char buf
[32], *ptr
, lrole
;
534 /* did not find WDS link configuration, use wireless' */
536 strcpy(wds_role
, "auto");
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
;
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
;
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;
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);
593 if (info
->wsec
& WEP_ENABLED
) {
595 value
= nvram_safe_get(strcat_r(wl_prefix
, "key", comb
));
596 info
->wep_index
= (int)strtoul(value
, NULL
, 0);
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",
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);
614 value
= nvram_safe_get(strcat_r(wl_prefix
, "preauth", comb
));
615 info
->preauth
= (int)strtoul(value
, NULL
, 0);
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
;