1/* 2 * Wireless interface translation utility functions 3 * 4 * Copyright (C) 2015, 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 559751 2015-05-28 12:44:43Z $ 19 */ 20 21#include <typedefs.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25 26#include <sys/socket.h> 27#include <netinet/in.h> 28#include <arpa/inet.h> 29 30#include <bcmparams.h> 31#include <bcmnvram.h> 32#include <bcmutils.h> 33#include <netconf.h> 34#include <nvparse.h> 35#include <shutils.h> 36#include <wlutils.h> 37#include <wlif_utils.h> 38 39#ifndef MAX_NVPARSE 40#define MAX_NVPARSE 255 41#endif 42 43int 44get_wlname_by_mac(unsigned char *mac, char *wlname) 45{ 46 char eabuf[18]; 47 char tmptr[] = "wlXXXXX_hwaddr"; 48 char *wl_hw; 49 int i, j; 50 51 ether_etoa(mac, eabuf); 52 /* find out the wl name from mac */ 53 for (i = 0; i < MAX_NVPARSE; i++) { 54 sprintf(wlname, "wl%d", i); 55 sprintf(tmptr, "wl%d_hwaddr", i); 56 wl_hw = nvram_get(tmptr); 57 if (wl_hw) { 58 if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf))) 59 return 0; 60 } 61 62 for (j = 1; j < WL_MAXBSSCFG; j++) { 63 sprintf(wlname, "wl%d.%d", i, j); 64 sprintf(tmptr, "wl%d.%d_hwaddr", i, j); 65 wl_hw = nvram_get(tmptr); 66 if (wl_hw) { 67 if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf))) 68 return 0; 69 } 70 } 71 } 72 73 return -1; 74} 75 76bool 77wl_wlif_is_psta(char *ifname) 78{ 79 int32 psta = FALSE; 80 81 if (wl_probe(ifname) < 0) 82 return FALSE; 83 84 if (wl_iovar_getint(ifname, "psta_if", &psta) < 0) 85 return FALSE; 86 87 return psta ? TRUE : FALSE; 88} 89 90bool 91wl_wlif_is_dwds(char *ifname) 92{ 93 int32 wds_type = FALSE; 94 95 if (wl_probe(ifname) < 0) 96 return FALSE; 97 98 return (!wl_iovar_getint(ifname, "wds_type", &wds_type) && wds_type == WL_WDSIFTYPE_DWDS); 99} 100 101bool 102wl_wlif_is_psr_ap(char *ifname) 103{ 104 int32 psta = FALSE; 105 int32 psta_mode = 0; 106 107 if (wl_probe(ifname) < 0) 108 return FALSE; 109 110 wl_iovar_getint(ifname, "psta", &psta_mode); 111 if (psta_mode == 2) { 112 wl_iovar_getint(ifname, "psta_if", &psta); 113 if (!psta) { 114 return strncmp(ifname, "wl", 2) ? FALSE : TRUE; 115 } 116 } else 117 return FALSE; 118} 119 120/* 121 * Get LAN or WAN ifname by wl mac 122 * NOTE: We pass ifname in case of same mac in vifs (like URE TR mode) 123 */ 124char * 125get_ifname_by_wlmac(unsigned char *mac, char *name) 126{ 127 char nv_name[16], os_name[16], if_name[16]; 128 char tmptr[] = "lanXX_ifnames"; 129 char *ifnames, *ifname; 130 int i; 131 132 /* 133 * In case of URE mode, wl0.1 and wl0 have same mac, 134 * we need extra identity (name). 135 */ 136 if (name && !strncmp(name, "wl", 2)) 137 snprintf(nv_name, sizeof(nv_name), "%s", name); 138 else if (get_wlname_by_mac(mac, nv_name)) 139 return 0; 140 141 if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)) < 0) 142 return 0; 143 144 if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)) < 0) 145 return 0; 146 147 /* find for dpsta */ 148 if (wl_wlif_is_psta(os_name)) 149 return name; 150 151 ifnames = nvram_get("dpsta_ifnames"); 152 if (ifnames && (find_in_list(ifnames, nv_name) || find_in_list(ifnames, os_name))) { 153 /* find dpsta in which bridge */ 154 for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) { 155 sprintf(tmptr, "br%d_ifnames", i); 156 sprintf(if_name, "br%d", i); 157 ifnames = nvram_get(tmptr); 158 ifname = if_name; 159 160 if (ifnames) { 161 /* the name in ifnames may nvifname or osifname */ 162 if (find_in_list(ifnames, nv_name) || 163 find_in_list(ifnames, os_name)) 164 return ifname; 165 } 166 } 167 } 168 169 /* find for lan */ 170 for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) { 171 if (i == 0) { 172 ifnames = nvram_get("lan_ifnames"); 173 ifname = nvram_get("lan_ifname"); 174 if (ifname) { 175 /* the name in ifnames may nvifname or osifname */ 176 if (find_in_list(ifnames, nv_name) || 177 find_in_list(ifnames, os_name)) 178 return ifname; 179 } 180 } 181 else { 182 sprintf(if_name, "lan%d_ifnames", i); 183 sprintf(tmptr, "lan%d_ifname", i); 184 ifnames = nvram_get(if_name); 185 ifname = nvram_get(tmptr); 186 if (ifname) { 187 /* the name in ifnames may nvifname or osifname */ 188 if (find_in_list(ifnames, nv_name) || 189 find_in_list(ifnames, os_name)) 190 return ifname; 191 } 192 } 193 } 194 195 /* find for wan */ 196 ifnames = nvram_get("wan_ifnames"); 197 ifname = nvram_get("wan0_ifname"); 198 /* the name in ifnames may nvifname or osifname */ 199 if (find_in_list(ifnames, nv_name) || 200 find_in_list(ifnames, os_name)) 201 return ifname; 202 203 return 0; 204} 205 206#define CHECK_NAS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WPA_AUTH_PSK | \ 207 WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_PSK)) 208#define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK)) 209#define CHECK_RADIUS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WLIFU_AUTH_RADIUS | \ 210 WPA2_AUTH_UNSPECIFIED)) 211 212/* Get wireless security setting by interface name */ 213int 214get_wsec(wsec_info_t *info, unsigned char *mac, char *osifname) 215{ 216 int i, unit, wds = 0, wds_wsec = 0; 217 char nv_name[16], os_name[16], wl_prefix[16], comb[32], key[8]; 218 char wds_role[8], wds_ssid[48], wds_psk[80], wds_akms[16], wds_crypto[16], 219 remote[ETHER_ADDR_LEN]; 220 char akm[16], *akms, *akmnext, *value, *infra; 221 222 if (info == NULL || mac == NULL) 223 return WLIFU_ERR_INVALID_PARAMETER; 224 225 if (nvifname_to_osifname(osifname, os_name, sizeof(os_name))) { 226 if (get_wlname_by_mac(mac, nv_name)) 227 return WLIFU_ERR_INVALID_PARAMETER; 228 else if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name))) 229 return WLIFU_ERR_INVALID_PARAMETER; 230 } 231 else if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name))) 232 return WLIFU_ERR_INVALID_PARAMETER; 233 234 /* check if i/f exists and retrieve the i/f index */ 235 if (wl_probe(os_name) || 236 wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit))) 237 return WLIFU_ERR_NOT_WL_INTERFACE; 238 239 /* get wl_prefix. 240 * 241 * Due to DWDS and WDS may be enabled at the same time, 242 * checking whether this is WDS interface in order to 243 * get per WDS interface security settings from NVRAM. 244 */ 245 if (strstr(os_name, "wds") && (wl_wlif_is_dwds(os_name) == FALSE)) { 246 /* the wireless interface must be configured to run NAS */ 247 snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit); 248 wds = 1; 249 } 250 else if (wl_wlif_is_psta(os_name)) 251 snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit); 252 else if (osifname_to_nvifname(os_name, wl_prefix, sizeof(wl_prefix))) 253 return WLIFU_ERR_INVALID_PARAMETER; 254 255 strcat(wl_prefix, "_"); 256 memset(info, 0, sizeof(wsec_info_t)); 257 258 /* get wds setting */ 259 if (wds) { 260 /* remote address */ 261 if (wl_ioctl(os_name, WLC_WDS_GET_REMOTE_HWADDR, remote, ETHER_ADDR_LEN)) 262 return WLIFU_ERR_WL_REMOTE_HWADDR; 263 memcpy(info->remote, remote, ETHER_ADDR_LEN); 264 265 /* get per wds settings */ 266 for (i = 0; i < MAX_NVPARSE; i ++) { 267 char macaddr[18]; 268 uint8 ea[ETHER_ADDR_LEN]; 269 270 if (get_wds_wsec(unit, i, macaddr, wds_role, wds_crypto, wds_akms, wds_ssid, 271 wds_psk) && 272 ((ether_atoe(macaddr, ea) && !bcmp(ea, remote, ETHER_ADDR_LEN)) || 273 ((mac[0] == '*') && (mac[1] == '\0')))) { 274 /* found wds settings */ 275 wds_wsec = 1; 276 break; 277 } 278 } 279 } 280 281 /* interface unit */ 282 info->unit = unit; 283 /* interface os name */ 284 strcpy(info->osifname, os_name); 285 /* interface address */ 286 memcpy(info->ea, mac, ETHER_ADDR_LEN); 287 /* ssid */ 288 if (wds && wds_wsec) 289 strncpy(info->ssid, wds_ssid, MAX_SSID_LEN); 290 else { 291 value = nvram_safe_get(strcat_r(wl_prefix, "ssid", comb)); 292 strncpy(info->ssid, value, MAX_SSID_LEN); 293 } 294 /* auth */ 295 if (nvram_match(strcat_r(wl_prefix, "auth", comb), "1")) 296 info->auth = 1; 297 /* nas auth mode */ 298 value = nvram_safe_get(strcat_r(wl_prefix, "auth_mode", comb)); 299 info->akm = !strcmp(value, "radius") ? WLIFU_AUTH_RADIUS : 0; 300 if (wds && wds_wsec) 301 akms = wds_akms; 302 else 303 akms = nvram_safe_get(strcat_r(wl_prefix, "akm", comb)); 304 foreach(akm, akms, akmnext) { 305 if (!strcmp(akm, "wpa")) 306 info->akm |= WPA_AUTH_UNSPECIFIED; 307 if (!strcmp(akm, "psk")) 308 info->akm |= WPA_AUTH_PSK; 309 if (!strcmp(akm, "wpa2")) 310 info->akm |= WPA2_AUTH_UNSPECIFIED; 311 if (!strcmp(akm, "psk2")) 312 info->akm |= WPA2_AUTH_PSK; 313 } 314 /* wsec encryption */ 315 value = nvram_safe_get(strcat_r(wl_prefix, "wep", comb)); 316 info->wsec = !strcmp(value, "enabled") ? WEP_ENABLED : 0; 317 if (wds && wds_wsec) 318 value = wds_crypto; 319 else 320 value = nvram_safe_get(strcat_r(wl_prefix, "crypto", comb)); 321 if (CHECK_NAS(info->akm)) { 322 if (!strcmp(value, "tkip")) 323 info->wsec |= TKIP_ENABLED; 324 else if (!strcmp(value, "aes")) 325 info->wsec |= AES_ENABLED; 326 else if (!strcmp(value, "tkip+aes")) 327 info->wsec |= TKIP_ENABLED|AES_ENABLED; 328 } 329 /* nas role setting, may overwrite later in wds case */ 330 value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb)); 331 infra = nvram_safe_get(strcat_r(wl_prefix, "infra", comb)); 332 if (!strcmp(value, "ap")) { 333 info->flags |= WLIFU_WSEC_AUTH; 334 } 335 else if (!strcmp(value, "sta") || !strcmp(value, "wet") || 336 !strcmp(value, "psr") || !strcmp(value, "psta")) { 337 if (!strcmp(infra, "0")) { 338 /* IBSS, so we must act as Authenticator and Supplicant */ 339 info->flags |= WLIFU_WSEC_AUTH; 340 info->flags |= WLIFU_WSEC_SUPPL; 341 /* Adhoc Mode */ 342 info->ibss = TRUE; 343 } 344 else { 345 info->flags |= WLIFU_WSEC_SUPPL; 346 } 347 } 348 else if (!strcmp(value, "wds")) { 349 ; 350 } 351 else { 352 /* Unsupported network mode */ 353 return WLIFU_ERR_NOT_SUPPORT_MODE; 354 } 355 /* overwrite flags */ 356 if (wds) { 357 char buf[32]; 358 unsigned char *ptr, lrole; 359 360 /* did not find WDS link configuration, use wireless' */ 361 if (!wds_wsec) 362 strcpy(wds_role, "auto"); 363 364 /* get right role */ 365 if (!strcmp(wds_role, "sup")) 366 lrole = WL_WDS_WPA_ROLE_SUP; 367 else if (!strcmp(wds_role, "auth")) 368 lrole = WL_WDS_WPA_ROLE_AUTH; 369 else /* if (!strcmp(wds_role, "auto")) */ 370 lrole = WL_WDS_WPA_ROLE_AUTO; 371 372 strcpy(buf, "wds_wpa_role"); 373 ptr = (unsigned char *)buf + strlen(buf) + 1; 374 bcopy(info->remote, ptr, ETHER_ADDR_LEN); 375 ptr[ETHER_ADDR_LEN] = lrole; 376 if (wl_ioctl(os_name, WLC_SET_VAR, buf, sizeof(buf))) 377 return WLIFU_ERR_WL_WPA_ROLE; 378 else if (wl_ioctl(os_name, WLC_GET_VAR, buf, sizeof(buf))) 379 return WLIFU_ERR_WL_WPA_ROLE; 380 lrole = *buf; 381 382 /* overwrite these flags */ 383 info->flags = WLIFU_WSEC_WDS; 384 if (lrole == WL_WDS_WPA_ROLE_SUP) { 385 info->flags |= WLIFU_WSEC_SUPPL; 386 } 387 else if (lrole == WL_WDS_WPA_ROLE_AUTH) { 388 info->flags |= WLIFU_WSEC_AUTH; 389 } 390 else { 391 /* unable to determine WPA role */ 392 return WLIFU_ERR_WL_WPA_ROLE; 393 } 394 } 395 /* user-supplied psk passphrase */ 396 if (CHECK_PSK(info->akm)) { 397 if (wds && wds_wsec) { 398 strncpy((char *)info->psk, wds_psk, MAX_USER_KEY_LEN); 399 info->psk[MAX_USER_KEY_LEN] = 0; 400 } 401 else { 402 value = nvram_safe_get(strcat_r(wl_prefix, "wpa_psk", comb)); 403 strncpy((char *)info->psk, value, MAX_USER_KEY_LEN); 404 info->psk[MAX_USER_KEY_LEN] = 0; 405 } 406 } 407 /* user-supplied radius server secret */ 408 if (CHECK_RADIUS(info->akm)) 409 info->secret = nvram_safe_get(strcat_r(wl_prefix, "radius_key", comb)); 410 /* AP specific settings */ 411 value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb)); 412 if (!strcmp(value, "ap")) { 413 /* gtk rekey interval */ 414 if (CHECK_NAS(info->akm)) { 415 value = nvram_safe_get(strcat_r(wl_prefix, "wpa_gtk_rekey", comb)); 416 info->gtk_rekey_secs = (int)strtoul(value, NULL, 0); 417 } 418 /* wep key */ 419 if (info->wsec & WEP_ENABLED) { 420 /* key index */ 421 value = nvram_safe_get(strcat_r(wl_prefix, "key", comb)); 422 info->wep_index = (int)strtoul(value, NULL, 0); 423 /* key */ 424 sprintf(key, "key%s", nvram_safe_get(strcat_r(wl_prefix, "key", comb))); 425 info->wep_key = nvram_safe_get(strcat_r(wl_prefix, key, comb)); 426 } 427 /* radius server host/port */ 428 if (CHECK_RADIUS(info->akm)) { 429 /* update radius server address */ 430 info->radius_addr = nvram_safe_get(strcat_r(wl_prefix, "radius_ipaddr", 431 comb)); 432 value = nvram_safe_get(strcat_r(wl_prefix, "radius_port", comb)); 433 info->radius_port = htons((int)strtoul(value, NULL, 0)); 434 /* 802.1x session timeout/pmk cache duration */ 435 value = nvram_safe_get(strcat_r(wl_prefix, "net_reauth", comb)); 436 info->ssn_to = (int)strtoul(value, NULL, 0); 437 } 438 } 439 /* preauth */ 440 value = nvram_safe_get(strcat_r(wl_prefix, "preauth", comb)); 441 info->preauth = (int)strtoul(value, NULL, 0); 442 443 /* verbose */ 444 value = nvram_safe_get(strcat_r(wl_prefix, "nas_dbg", comb)); 445 info->debug = (int)strtoul(value, NULL, 0); 446 447 448 449 return WLIFU_WSEC_SUCCESS; 450} 451