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