1/* 2 * Wireless network adapter utilities 3 * 4 * Copyright (C) 2014, 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: wl.c 470880 2014-04-16 22:00:58Z $ 19 */ 20#include <typedefs.h> 21#include <string.h> 22#include <stdio.h> 23#include <unistd.h> 24#include <errno.h> 25#include <sys/ioctl.h> 26#if defined(__ECOS) 27#include <sys/socket.h> 28#endif 29#include <net/if.h> 30 31#include <bcmutils.h> 32#include <wlutils.h> 33#include <bcmconfig.h> 34 35int 36wl_probe(char *name) 37{ 38 int ret, val; 39 40#if defined(linux) || defined(__ECOS) 41 char buf[DEV_TYPE_LEN]; 42 if ((ret = wl_get_dev_type(name, buf, DEV_TYPE_LEN)) < 0) 43 return ret; 44 /* Check interface */ 45 if (strncmp(buf, "wl", 2)) 46 return -1; 47#else 48 /* Check interface */ 49 if ((ret = wl_ioctl(name, WLC_GET_MAGIC, &val, sizeof(val)))) 50 return ret; 51#endif 52 if ((ret = wl_ioctl(name, WLC_GET_VERSION, &val, sizeof(val)))) 53 return ret; 54 if (val > WLC_IOCTL_VERSION) 55 return -1; 56 57 return ret; 58} 59 60#ifdef __CONFIG_DHDAP__ 61#include <dhdioctl.h> 62/* 63 * Probe the specified interface. 64 * @param name interface name 65 * @return 0 if using dhd driver 66 * <0 otherwise 67 */ 68int 69dhd_probe(char *name) 70{ 71 int ret, val; 72 val = 0; 73 /* Check interface */ 74 ret = dhd_ioctl(name, DHD_GET_MAGIC, &val, sizeof(val)); 75 if (val == WLC_IOCTL_MAGIC) { 76 ret = 1; /* is_dhd = !dhd_probe(), so ret 1 for WL */ 77 } else if (val == DHD_IOCTL_MAGIC) { 78 ret = 0; 79 } else { 80 if (ret < 0) { 81 perror("dhd_ioctl"); 82 } 83 ret = 1; /* default: WL mode */ 84 } 85 return ret; 86} 87#endif /* __CONFIG_DHDAP__ */ 88 89int 90wl_iovar_getbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen) 91{ 92 int err; 93 uint namelen; 94 uint iolen; 95 uint wlc_cmd = WLC_GET_VAR; 96 97 namelen = strlen(iovar) + 1; /* length of iovar name plus null */ 98 iolen = namelen + paramlen; 99 100 /* check for overflow */ 101 if (iolen > buflen) 102 return (BCME_BUFTOOSHORT); 103 104 memcpy(bufptr, iovar, namelen); /* copy iovar name including null */ 105 memcpy((int8*)bufptr + namelen, param, paramlen); 106 107 err = wl_ioctl(ifname, wlc_cmd, bufptr, buflen); 108 109 return (err); 110} 111 112#ifdef __CONFIG_DHDAP__ 113int 114dhd_iovar_setbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen) 115{ 116 uint namelen; 117 uint iolen; 118 119 namelen = strlen(iovar) + 1; /* length of iovar name plus null */ 120 iolen = namelen + paramlen; 121 122 /* check for overflow */ 123 if (iolen > buflen) 124 return (BCME_BUFTOOSHORT); 125 126 memcpy(bufptr, iovar, namelen); /* copy iovar name including null */ 127 memcpy((int8*)bufptr + namelen, param, paramlen); 128 129 return dhd_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); 130} 131#endif /* __CONFIG_DHDAP__ */ 132 133int 134wl_iovar_setbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen) 135{ 136 uint namelen; 137 uint iolen; 138 139 namelen = strlen(iovar) + 1; /* length of iovar name plus null */ 140 iolen = namelen + paramlen; 141 142 /* check for overflow */ 143 if (iolen > buflen) 144 return (BCME_BUFTOOSHORT); 145 146 memcpy(bufptr, iovar, namelen); /* copy iovar name including null */ 147 memcpy((int8*)bufptr + namelen, param, paramlen); 148 149 return wl_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); 150} 151 152#ifdef __CONFIG_DHDAP__ 153int 154dhd_iovar_set(char *ifname, char *iovar, void *param, int paramlen) 155{ 156 char smbuf[WLC_IOCTL_SMLEN]; 157 158 return dhd_iovar_setbuf(ifname, iovar, param, paramlen, smbuf, sizeof(smbuf)); 159} 160#endif /* __CONFIG_DHDAP__ */ 161 162int 163wl_iovar_set(char *ifname, char *iovar, void *param, int paramlen) 164{ 165 char smbuf[WLC_IOCTL_SMLEN]; 166 167 return wl_iovar_setbuf(ifname, iovar, param, paramlen, smbuf, sizeof(smbuf)); 168} 169 170int 171wl_iovar_get(char *ifname, char *iovar, void *bufptr, int buflen) 172{ 173 char smbuf[WLC_IOCTL_SMLEN]; 174 int ret; 175 176 /* use the return buffer if it is bigger than what we have on the stack */ 177 if (buflen > sizeof(smbuf)) { 178 ret = wl_iovar_getbuf(ifname, iovar, NULL, 0, bufptr, buflen); 179 } else { 180 ret = wl_iovar_getbuf(ifname, iovar, NULL, 0, smbuf, sizeof(smbuf)); 181 if (ret == 0) 182 memcpy(bufptr, smbuf, buflen); 183 } 184 185 return ret; 186} 187 188#ifdef __CONFIG_DHDAP__ 189/* 190 * set named driver variable to int value 191 * calling example: dhd_iovar_setint(ifname, "arate", rate) 192*/ 193int 194dhd_iovar_setint(char *ifname, char *iovar, int val) 195{ 196 return dhd_iovar_set(ifname, iovar, &val, sizeof(val)); 197} 198#endif /* __CONFIG_DHDAP__ */ 199 200/* 201 * set named driver variable to int value 202 * calling example: wl_iovar_setint(ifname, "arate", rate) 203*/ 204int 205wl_iovar_setint(char *ifname, char *iovar, int val) 206{ 207 return wl_iovar_set(ifname, iovar, &val, sizeof(val)); 208} 209 210/* 211 * get named driver variable to int value and return error indication 212 * calling example: wl_iovar_getint(ifname, "arate", &rate) 213 */ 214int 215wl_iovar_getint(char *ifname, char *iovar, int *val) 216{ 217 return wl_iovar_get(ifname, iovar, val, sizeof(int)); 218} 219 220/* 221 * format a bsscfg indexed iovar buffer 222 */ 223static int 224wl_bssiovar_mkbuf(char *iovar, int bssidx, void *param, int paramlen, void *bufptr, int buflen, 225 int *plen) 226{ 227 char *prefix = "bsscfg:"; 228 int8* p; 229 uint prefixlen; 230 uint namelen; 231 uint iolen; 232 233 prefixlen = strlen(prefix); /* length of bsscfg prefix */ 234 namelen = strlen(iovar) + 1; /* length of iovar name + null */ 235 iolen = prefixlen + namelen + sizeof(int) + paramlen; 236 237 /* check for overflow */ 238 if (buflen < 0 || iolen > (uint)buflen) { 239 *plen = 0; 240 return BCME_BUFTOOSHORT; 241 } 242 243 p = (int8*)bufptr; 244 245 /* copy prefix, no null */ 246 memcpy(p, prefix, prefixlen); 247 p += prefixlen; 248 249 /* copy iovar name including null */ 250 memcpy(p, iovar, namelen); 251 p += namelen; 252 253 /* bss config index as first param */ 254 memcpy(p, &bssidx, sizeof(int32)); 255 p += sizeof(int32); 256 257 /* parameter buffer follows */ 258 if (paramlen) 259 memcpy(p, param, paramlen); 260 261 *plen = iolen; 262 return 0; 263} 264 265/* 266 * set named & bss indexed driver variable to buffer value 267 */ 268int 269wl_bssiovar_setbuf(char *ifname, char *iovar, int bssidx, void *param, int paramlen, void *bufptr, 270 int buflen) 271{ 272 int err; 273 int iolen; 274 275 err = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &iolen); 276 if (err) 277 return err; 278 279 return wl_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); 280} 281 282#ifdef __CONFIG_DHDAP__ 283int 284dhd_ioctl(char *name, int cmd, void *buf, int len) 285{ 286 struct ifreq ifr; 287 dhd_ioctl_t ioc; 288 int ret = 0; 289 int s; 290 char buffer[WLC_IOCTL_SMLEN]; 291 292 /* open socket to kernel */ 293 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 294 perror("socket"); 295 return -1; 296 } 297 298 /* do it */ 299 if (cmd == WLC_SET_VAR) { 300 cmd = DHD_SET_VAR; 301 } else if (cmd == WLC_GET_VAR) { 302 cmd = DHD_GET_VAR; 303 } 304 305 ioc.cmd = cmd; 306 ioc.buf = buf; 307 ioc.len = len; 308 ioc.set = FALSE; 309 ioc.driver = DHD_IOCTL_MAGIC; 310 ioc.used = 0; 311 ioc.needed = 0; 312 313 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1); 314 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; 315 316 ifr.ifr_data = (caddr_t) &ioc; 317 if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0) 318 if (cmd != WLC_GET_MAGIC && cmd != WLC_GET_BSSID) { 319 if ((cmd == WLC_GET_VAR) || (cmd == WLC_SET_VAR)) { 320 snprintf(buffer, sizeof(buffer), "%s: WLC_%s_VAR(%s)", name, 321 cmd == WLC_GET_VAR ? "GET" : "SET", (char *)buf); 322 } else { 323 snprintf(buffer, sizeof(buffer), "%s: cmd=%d", name, cmd); 324 } 325 perror(buffer); 326 } 327 /* cleanup */ 328 close(s); 329 return ret; 330} 331 332/* 333 * set named & bss indexed driver variable to buffer value 334 */ 335int 336dhd_bssiovar_setbuf(char *ifname, char *iovar, int bssidx, void *param, int paramlen, void *bufptr, 337 int buflen) 338{ 339 int err; 340 int iolen; 341 342 err = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &iolen); 343 if (err) 344 return err; 345 346 return dhd_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); 347} 348#endif /* __CONFIG_DHDAP__ */ 349 350/* 351 * get named & bss indexed driver variable buffer value 352 */ 353int 354wl_bssiovar_getbuf(char *ifname, char *iovar, int bssidx, void *param, int paramlen, void *bufptr, 355 int buflen) 356{ 357 int err; 358 int iolen; 359 360 err = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &iolen); 361 if (err) 362 return err; 363 364 return wl_ioctl(ifname, WLC_GET_VAR, bufptr, buflen); 365} 366 367/* 368 * set named & bss indexed driver variable to buffer value 369 */ 370int 371wl_bssiovar_set(char *ifname, char *iovar, int bssidx, void *param, int paramlen) 372{ 373 char smbuf[WLC_IOCTL_SMLEN]; 374 375 return wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, smbuf, sizeof(smbuf)); 376} 377 378#ifdef __CONFIG_DHDAP__ 379/* 380 * set named & bss indexed driver variable to buffer value 381 */ 382int 383dhd_bssiovar_set(char *ifname, char *iovar, int bssidx, void *param, int paramlen) 384{ 385 char smbuf[WLC_IOCTL_SMLEN]; 386 387 return dhd_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, smbuf, sizeof(smbuf)); 388} 389#endif 390 391/* 392 * get named & bss indexed driver variable buffer value 393 */ 394int 395wl_bssiovar_get(char *ifname, char *iovar, int bssidx, void *outbuf, int len) 396{ 397 char smbuf[WLC_IOCTL_SMLEN]; 398 int err; 399 400 /* use the return buffer if it is bigger than what we have on the stack */ 401 if (len > (int)sizeof(smbuf)) { 402 err = wl_bssiovar_getbuf(ifname, iovar, bssidx, NULL, 0, outbuf, len); 403 } else { 404 memset(smbuf, 0, sizeof(smbuf)); 405 err = wl_bssiovar_getbuf(ifname, iovar, bssidx, NULL, 0, smbuf, sizeof(smbuf)); 406 if (err == 0) 407 memcpy(outbuf, smbuf, len); 408 } 409 410 return err; 411} 412 413/* 414 * set named & bss indexed driver variable to int value 415 */ 416int 417wl_bssiovar_setint(char *ifname, char *iovar, int bssidx, int val) 418{ 419 return wl_bssiovar_set(ifname, iovar, bssidx, &val, sizeof(int)); 420} 421 422#ifdef __CONFIG_DHDAP__ 423/* 424 * set named & bss indexed driver variable to int value 425 */ 426int 427dhd_bssiovar_setint(char *ifname, char *iovar, int bssidx, int val) 428{ 429 return dhd_bssiovar_set(ifname, iovar, bssidx, &val, sizeof(int)); 430} 431#endif 432 433/* 434void 435wl_printlasterror(char *name) 436{ 437 char err_buf[WLC_IOCTL_SMLEN]; 438 strcpy(err_buf, "bcmerrstr"); 439 440 fprintf(stderr, "Error: "); 441 if ( wl_ioctl(name, WLC_GET_VAR, err_buf, sizeof (err_buf)) != 0) 442 fprintf(stderr, "Error getting the Errorstring from driver\n"); 443 else 444 fprintf(stderr, err_buf); 445} 446*/ 447