1/* 2 * Wireless interface translation utility functions 3 * 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. 17 * 18 * $Id: wlif_utils.c 415105 2013-07-28 03:40:28Z $ 19 */ 20 21#include <typedefs.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25#include <stdarg.h> // for va_list 26 27#include <sys/socket.h> 28#include <netinet/in.h> 29#include <arpa/inet.h> 30 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> 39 40#include "shared.h" 41 42#ifndef MAX_NVPARSE 43#define MAX_NVPARSE 16 44#endif 45 46/* wireless interface name descriptors */ 47typedef struct _wlif_name_desc { 48 char *name; /* wlif name */ 49 bool wds; /* wds interface */ 50 bool subunit; /* subunit existance */ 51} wlif_name_desc_t; 52 53wlif_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 61 62/* MBSS */ 63 { "wl", 0, 1}, /* mbss */ 64 65/* WDS */ 66 { "wds", 1, 1} /* wds */ 67}; 68 69/* 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 77 * 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 80 * 81 */ 82int 83get_spoof_mac(const char *osifname, char *mac, int maclen) 84{ 85 char nvifname[16]; 86 int i, unit, subunit; 87 wlif_name_desc_t *wlif_name; 88 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; 95 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; 107 } 108 } 109 } 110 111 /* not found */ 112 if (i == ARRAYSIZE(wlif_name_array)) 113 return -1; 114 115 /* translate it */ 116 mac[3] = i+1; 117 mac[4] = unit; 118 mac[5] = subunit; 119 120 return 0; 121 } 122 123 return -1; 124} 125 126int 127get_spoof_ifname(char *mac, char *osifname, int osifnamelen) 128{ 129 int idx, unit, subunit; 130 char nvifname[16]; 131 wlif_name_desc_t *wlif_name; 132 133 if (osifname == NULL || 134 mac == NULL) 135 return -1; 136 137 if (mac[0] != 0 || mac[1] != 0 || 138 mac[2] != 0) 139 return -1; /* is a real mac, fast check */ 140 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; 147 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); 155 156 /* translate to osifname */ 157 if (nvifname_to_osifname(nvifname, osifname, osifnamelen) < 0) 158 return -1; 159 160 return 0; 161} 162 163int 164get_real_mac(char *mac, int maclen) 165{ 166 int idx, unit, subunit; 167 char *ptr, ifname[32]; 168 wlif_name_desc_t *wlif_name; 169 170 if (mac == NULL || 171 maclen < ETHER_ADDR_LEN) 172 return -1; 173 174 if (mac[0] != 0 || mac[1] != 0 || 175 mac[2] != 0) 176 return 0; /* is a real mac, fast path */ 177 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; 184 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); 191 192 ptr = nvram_get(ifname); 193 if (ptr == NULL) 194 return -1; 195 196 ether_atoe(ptr, (unsigned char *) mac); 197 return 0; 198} 199 200unsigned char * 201get_wlmacstr_by_unit(char *unit) 202{ 203 char tmptr[] = "wlXXXXX_hwaddr"; 204 char *macaddr; 205 206 sprintf(tmptr, "wl%s_hwaddr", unit); 207 208 macaddr = nvram_get(tmptr); 209 210 if (!macaddr) 211 return NULL; 212 213 return (unsigned char *) macaddr; 214} 215 216int 217get_lan_mac(unsigned char *mac) 218{ 219 char *lanmac_str = nvram_get("lan_hwaddr"); 220 221 if (mac) 222 memset(mac, 0, 6); 223 224 if (!lanmac_str || mac == NULL) 225 return -1; 226 227 ether_atoe(lanmac_str, mac); 228 229 return 0; 230} 231 232int 233get_wlname_by_mac(unsigned char *mac, char *wlname) 234{ 235 char eabuf[18]; 236 char tmptr[] = "wlXXXXX_hwaddr"; 237 char *wl_hw; 238 int i, j; 239 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; 249 } 250 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; 258 } 259 } 260 } 261 262 return -1; 263} 264 265bool 266wl_wlif_is_psta(char *ifname) 267{ 268 int32 psta = FALSE; 269 270 if (wl_probe(ifname) < 0) 271 return FALSE; 272 273 if (wl_iovar_getint(ifname, "psta_if", &psta) < 0) 274 return FALSE; 275 276 return psta ? TRUE : FALSE; 277} 278 279bool 280wl_wlif_is_dwds(char *ifname) 281{ 282#ifdef RTCONFIG_BCMARM 283 int32 wds_type = FALSE; 284 285 if (wl_probe(ifname) < 0) 286 return FALSE; 287 288 return (!wl_iovar_getint(ifname, "wds_type", &wds_type) && wds_type == WL_WDSIFTYPE_DWDS); 289#else 290 return FALSE; 291#endif 292} 293 294/* 295 * Get LAN or WAN ifname by wl mac 296 * NOTE: We pass ifname in case of same mac in vifs (like URE TR mode) 297 */ 298char * 299get_ifname_by_wlmac(unsigned char *mac, char *name) 300{ 301 char nv_name[16], os_name[16], if_name[16]; 302 char tmptr[] = "lanXX_ifnames"; 303 char *ifnames, *ifname; 304 int i; 305 306 /* 307 * In case of URE mode, wl0.1 and wl0 have same mac, 308 * we need extra identity (name). 309 */ 310 if (name && !strncmp(name, "wl", 2)) 311 snprintf(nv_name, sizeof(nv_name), "%s", name); 312 else if (get_wlname_by_mac(mac, nv_name)) 313 return 0; 314 315 if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)) < 0) 316 return 0; 317 318 if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)) < 0) 319 return 0; 320 321 /* find for lan */ 322 for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) { 323 if (i == 0) { 324 ifnames = nvram_get("lan_ifnames"); 325 ifname = nvram_get("lan_ifname"); 326 if (ifname) { 327 /* the name in ifnames may nvifname or osifname */ 328 if (find_in_list(ifnames, nv_name) || 329 find_in_list(ifnames, os_name)) 330 return ifname; 331 } 332 } 333 else { 334 sprintf(if_name, "lan%d_ifnames", i); 335 sprintf(tmptr, "lan%d_ifname", i); 336 ifnames = nvram_get(if_name); 337 ifname = nvram_get(tmptr); 338 if (ifname) { 339 /* the name in ifnames may nvifname or osifname */ 340 if (find_in_list(ifnames, nv_name) || 341 find_in_list(ifnames, os_name)) 342 return ifname; 343 } 344 } 345 } 346 347 /* find for wan */ 348 ifnames = nvram_get("wan_ifnames"); 349 ifname = nvram_get("wan0_ifname"); 350 /* the name in ifnames may nvifname or osifname */ 351 if (find_in_list(ifnames, nv_name) || 352 find_in_list(ifnames, os_name)) 353 return ifname; 354 355 return 0; 356} 357 358#define CHECK_NAS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WPA_AUTH_PSK | \ 359 WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_PSK)) 360#define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK)) 361#define CHECK_RADIUS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WLIFU_AUTH_RADIUS | \ 362 WPA2_AUTH_UNSPECIFIED)) 363 364/* Get wireless security setting by interface name */ 365int 366get_wsec(wsec_info_t *info, unsigned char *mac, char *osifname) 367{ 368 int i, unit, wds = 0, wds_wsec = 0; 369 char nv_name[16], os_name[16], wl_prefix[16], comb[32], key[8]; 370 char wds_role[8], wds_ssid[48], wds_psk[80], wds_akms[16], wds_crypto[16], 371 remote[ETHER_ADDR_LEN]; 372 char akm[16], *akms, *akmnext, *value, *infra; 373 374 if (info == NULL || mac == NULL) 375 return WLIFU_ERR_INVALID_PARAMETER; 376 377 if (nvifname_to_osifname(osifname, os_name, sizeof(os_name))) { 378 if (get_wlname_by_mac(mac, nv_name)) 379 return WLIFU_ERR_INVALID_PARAMETER; 380 else if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name))) 381 return WLIFU_ERR_INVALID_PARAMETER; 382 } 383 else if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name))) 384 return WLIFU_ERR_INVALID_PARAMETER; 385 386 /* check if i/f exists and retrieve the i/f index */ 387 if (wl_probe(os_name) || 388 wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit))) 389 return WLIFU_ERR_NOT_WL_INTERFACE; 390 391 /* get wl_prefix. 392 * 393 * Due to DWDS and WDS may be enabled at the same time, 394 * checking whether this is WDS interface in order to 395 * get per WDS interface security settings from NVRAM. 396 */ 397 if (strstr(os_name, "wds") && (wl_wlif_is_dwds(os_name) == FALSE)) { 398 /* the wireless interface must be configured to run NAS */ 399 snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit); 400 wds = 1; 401 } 402 else if (wl_wlif_is_psta(os_name)) 403 snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit); 404 else if (osifname_to_nvifname(os_name, wl_prefix, sizeof(wl_prefix))) 405 return WLIFU_ERR_INVALID_PARAMETER; 406 407 strcat(wl_prefix, "_"); 408 memset(info, 0, sizeof(wsec_info_t)); 409 410 411 /* get wds setting */ 412 if (wds) { 413 /* remote address */ 414 if (wl_ioctl(os_name, WLC_WDS_GET_REMOTE_HWADDR, remote, ETHER_ADDR_LEN)) 415 return WLIFU_ERR_WL_REMOTE_HWADDR; 416 memcpy(info->remote, remote, ETHER_ADDR_LEN); 417 418 /* get per wds settings */ 419 for (i = 0; i < MAX_NVPARSE; i ++) { 420 char macaddr[18]; 421 uint8 ea[ETHER_ADDR_LEN]; 422 423 if (get_wds_wsec(unit, i, macaddr, wds_role, wds_crypto, wds_akms, wds_ssid, 424 wds_psk) && 425 ((ether_atoe(macaddr, ea) && !bcmp(ea, remote, ETHER_ADDR_LEN)) || 426 ((mac[0] == '*') && (mac[1] == '\0')))) { 427 /* found wds settings */ 428 wds_wsec = 1; 429 break; 430 } 431 } 432 } 433 434 /* interface unit */ 435 info->unit = unit; 436 /* interface os name */ 437 strcpy(info->osifname, os_name); 438 /* interface address */ 439 memcpy(info->ea, mac, ETHER_ADDR_LEN); 440 /* ssid */ 441 if (wds && wds_wsec) 442 strncpy(info->ssid, wds_ssid, MAX_SSID_LEN); 443 else { 444 value = nvram_safe_get(strcat_r(wl_prefix, "ssid", comb)); 445 strncpy(info->ssid, value, MAX_SSID_LEN); 446 } 447 /* auth */ 448 if (nvram_match(strcat_r(wl_prefix, "auth", comb), "1")) 449 info->auth = 1; 450 /* nas auth mode */ 451 value = nvram_safe_get(strcat_r(wl_prefix, "auth_mode", comb)); 452 info->akm = !strcmp(value, "radius") ? WLIFU_AUTH_RADIUS : 0; 453 if (wds && wds_wsec) 454 akms = wds_akms; 455 else 456 akms = nvram_safe_get(strcat_r(wl_prefix, "akm", comb)); 457 foreach(akm, akms, akmnext) { 458 if (!strcmp(akm, "wpa")) 459 info->akm |= WPA_AUTH_UNSPECIFIED; 460 if (!strcmp(akm, "psk")) 461 info->akm |= WPA_AUTH_PSK; 462 if (!strcmp(akm, "wpa2")) 463 info->akm |= WPA2_AUTH_UNSPECIFIED; 464 if (!strcmp(akm, "psk2")) 465 info->akm |= WPA2_AUTH_PSK; 466 } 467 /* wsec encryption */ 468 value = nvram_safe_get(strcat_r(wl_prefix, "wep", comb)); 469 info->wsec = !strcmp(value, "enabled") ? WEP_ENABLED : 0; 470 if (wds && wds_wsec) 471 value = wds_crypto; 472 else 473 value = nvram_safe_get(strcat_r(wl_prefix, "crypto", comb)); 474 if (CHECK_NAS(info->akm)) { 475 if (!strcmp(value, "tkip")) 476 info->wsec |= TKIP_ENABLED; 477 else if (!strcmp(value, "aes")) 478 info->wsec |= AES_ENABLED; 479 else if (!strcmp(value, "tkip+aes")) 480 info->wsec |= TKIP_ENABLED|AES_ENABLED; 481 } 482 /* nas role setting, may overwrite later in wds case */ 483 value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb)); 484 infra = nvram_safe_get(strcat_r(wl_prefix, "infra", comb)); 485 if (!strcmp(value, "ap")) { 486 info->flags |= WLIFU_WSEC_AUTH; 487 } 488 else if (!strcmp(value, "sta") || !strcmp(value, "wet") || 489 !strcmp(value, "psr") || !strcmp(value, "psta")) { 490 if (!strcmp(infra, "0")) { 491 /* IBSS, so we must act as Authenticator and Supplicant */ 492 info->flags |= WLIFU_WSEC_AUTH; 493 info->flags |= WLIFU_WSEC_SUPPL; 494 /* Adhoc Mode */ 495 info->ibss = TRUE; 496 } 497 else { 498 info->flags |= WLIFU_WSEC_SUPPL; 499 } 500 } 501 else if (!strcmp(value, "wds")) { 502 ; 503 } 504 else { 505 /* Unsupported network mode */ 506 return WLIFU_ERR_NOT_SUPPORT_MODE; 507 } 508 /* overwrite flags */ 509 if (wds) { 510 char buf[32]; 511 unsigned char *ptr, lrole; 512 513 /* did not find WDS link configuration, use wireless' */ 514 if (!wds_wsec) 515 strcpy(wds_role, "auto"); 516 517 /* get right role */ 518 if (!strcmp(wds_role, "sup")) 519 lrole = WL_WDS_WPA_ROLE_SUP; 520 else if (!strcmp(wds_role, "auth")) 521 lrole = WL_WDS_WPA_ROLE_AUTH; 522 else /* if (!strcmp(wds_role, "auto")) */ 523 lrole = WL_WDS_WPA_ROLE_AUTO; 524 525 strcpy(buf, "wds_wpa_role"); 526 ptr = (unsigned char *)buf + strlen(buf) + 1; 527 bcopy(info->remote, ptr, ETHER_ADDR_LEN); 528 ptr[ETHER_ADDR_LEN] = lrole; 529 if (wl_ioctl(os_name, WLC_SET_VAR, buf, sizeof(buf))) 530 return WLIFU_ERR_WL_WPA_ROLE; 531 else if (wl_ioctl(os_name, WLC_GET_VAR, buf, sizeof(buf))) 532 return WLIFU_ERR_WL_WPA_ROLE; 533 lrole = *buf; 534 535 /* overwrite these flags */ 536 info->flags = WLIFU_WSEC_WDS; 537 if (lrole == WL_WDS_WPA_ROLE_SUP) { 538 info->flags |= WLIFU_WSEC_SUPPL; 539 } 540 else if (lrole == WL_WDS_WPA_ROLE_AUTH) { 541 info->flags |= WLIFU_WSEC_AUTH; 542 } 543 else { 544 /* unable to determine WPA role */ 545 return WLIFU_ERR_WL_WPA_ROLE; 546 } 547 } 548 /* user-supplied psk passphrase */ 549 if (CHECK_PSK(info->akm)) { 550 if (wds && wds_wsec) { 551 strncpy((char *)info->psk, wds_psk, MAX_USER_KEY_LEN); 552 info->psk[MAX_USER_KEY_LEN] = 0; 553 } 554 else { 555 value = nvram_safe_get(strcat_r(wl_prefix, "wpa_psk", comb)); 556 strncpy((char *)info->psk, value, MAX_USER_KEY_LEN); 557 info->psk[MAX_USER_KEY_LEN] = 0; 558 } 559 } 560 /* user-supplied radius server secret */ 561 if (CHECK_RADIUS(info->akm)) 562 info->secret = nvram_safe_get(strcat_r(wl_prefix, "radius_key", comb)); 563 /* AP specific settings */ 564 value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb)); 565 if (!strcmp(value, "ap")) { 566 /* gtk rekey interval */ 567 if (CHECK_NAS(info->akm)) { 568 value = nvram_safe_get(strcat_r(wl_prefix, "wpa_gtk_rekey", comb)); 569 info->gtk_rekey_secs = (int)strtoul(value, NULL, 0); 570 } 571 /* wep key */ 572 if (info->wsec & WEP_ENABLED) { 573 /* key index */ 574 value = nvram_safe_get(strcat_r(wl_prefix, "key", comb)); 575 info->wep_index = (int)strtoul(value, NULL, 0); 576 /* key */ 577 sprintf(key, "key%s", nvram_safe_get(strcat_r(wl_prefix, "key", comb))); 578 info->wep_key = nvram_safe_get(strcat_r(wl_prefix, key, comb)); 579 } 580 /* radius server host/port */ 581 if (CHECK_RADIUS(info->akm)) { 582 /* update radius server address */ 583 info->radius_addr = nvram_safe_get(strcat_r(wl_prefix, "radius_ipaddr", 584 comb)); 585 value = nvram_safe_get(strcat_r(wl_prefix, "radius_port", comb)); 586 info->radius_port = htons((int)strtoul(value, NULL, 0)); 587 /* 802.1x session timeout/pmk cache duration */ 588 value = nvram_safe_get(strcat_r(wl_prefix, "net_reauth", comb)); 589 info->ssn_to = (int)strtoul(value, NULL, 0); 590 } 591 } 592 /* preauth */ 593 value = nvram_safe_get(strcat_r(wl_prefix, "preauth", comb)); 594 info->preauth = (int)strtoul(value, NULL, 0); 595 596 /* verbose */ 597 value = nvram_safe_get(strcat_r(wl_prefix, "nas_dbg", comb)); 598 info->debug = (int)strtoul(value, NULL, 0); 599 600 /* get mfp setting */ 601 info->mfp = atoi(nvram_safe_get(strcat_r(wl_prefix, "mfp", comb))); 602 603 return WLIFU_WSEC_SUCCESS; 604} 605