/* * Wireless network adapter utilities * * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: wl.c 470880 2014-04-16 22:00:58Z $ */ #include #include #include #include #include #include #if defined(__ECOS) #include #endif #include #include #include #include int wl_probe(char *name) { int ret, val; #if defined(linux) || defined(__ECOS) char buf[DEV_TYPE_LEN]; if ((ret = wl_get_dev_type(name, buf, DEV_TYPE_LEN)) < 0) return ret; /* Check interface */ if (strncmp(buf, "wl", 2)) return -1; #else /* Check interface */ if ((ret = wl_ioctl(name, WLC_GET_MAGIC, &val, sizeof(val)))) return ret; #endif if ((ret = wl_ioctl(name, WLC_GET_VERSION, &val, sizeof(val)))) return ret; if (val > WLC_IOCTL_VERSION) return -1; return ret; } #ifdef __CONFIG_DHDAP__ #include /* * Probe the specified interface. * @param name interface name * @return 0 if using dhd driver * <0 otherwise */ int dhd_probe(char *name) { int ret, val; val = 0; /* Check interface */ ret = dhd_ioctl(name, DHD_GET_MAGIC, &val, sizeof(val)); if (val == WLC_IOCTL_MAGIC) { ret = 1; /* is_dhd = !dhd_probe(), so ret 1 for WL */ } else if (val == DHD_IOCTL_MAGIC) { ret = 0; } else { if (ret < 0) { perror("dhd_ioctl"); } ret = 1; /* default: WL mode */ } return ret; } #endif /* __CONFIG_DHDAP__ */ int wl_iovar_getbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen) { int err; uint namelen; uint iolen; namelen = strlen(iovar) + 1; /* length of iovar name plus null */ iolen = namelen + paramlen; /* check for overflow */ if (iolen > buflen) return (BCME_BUFTOOSHORT); memcpy(bufptr, iovar, namelen); /* copy iovar name including null */ memcpy((int8*)bufptr + namelen, param, paramlen); err = wl_ioctl(ifname, WLC_GET_VAR, bufptr, buflen); return (err); } #ifdef __CONFIG_DHDAP__ int dhd_iovar_setbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen) { uint namelen; uint iolen; namelen = strlen(iovar) + 1; /* length of iovar name plus null */ iolen = namelen + paramlen; /* check for overflow */ if (iolen > buflen) return (BCME_BUFTOOSHORT); memcpy(bufptr, iovar, namelen); /* copy iovar name including null */ memcpy((int8*)bufptr + namelen, param, paramlen); return dhd_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); } #endif /* __CONFIG_DHDAP__ */ int wl_iovar_setbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen) { uint namelen; uint iolen; namelen = strlen(iovar) + 1; /* length of iovar name plus null */ iolen = namelen + paramlen; /* check for overflow */ if (iolen > buflen) return (BCME_BUFTOOSHORT); memcpy(bufptr, iovar, namelen); /* copy iovar name including null */ memcpy((int8*)bufptr + namelen, param, paramlen); return wl_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); } #ifdef __CONFIG_DHDAP__ int dhd_iovar_set(char *ifname, char *iovar, void *param, int paramlen) { char smbuf[WLC_IOCTL_SMLEN]; return dhd_iovar_setbuf(ifname, iovar, param, paramlen, smbuf, sizeof(smbuf)); } #endif /* __CONFIG_DHDAP__ */ int wl_iovar_set(char *ifname, char *iovar, void *param, int paramlen) { char smbuf[WLC_IOCTL_SMLEN]; return wl_iovar_setbuf(ifname, iovar, param, paramlen, smbuf, sizeof(smbuf)); } int wl_iovar_get(char *ifname, char *iovar, void *bufptr, int buflen) { char smbuf[WLC_IOCTL_SMLEN]; int ret; /* use the return buffer if it is bigger than what we have on the stack */ if (buflen > sizeof(smbuf)) { ret = wl_iovar_getbuf(ifname, iovar, NULL, 0, bufptr, buflen); } else { ret = wl_iovar_getbuf(ifname, iovar, NULL, 0, smbuf, sizeof(smbuf)); if (ret == 0) memcpy(bufptr, smbuf, buflen); } return ret; } #ifdef __CONFIG_DHDAP__ /* * set named driver variable to int value * calling example: dhd_iovar_setint(ifname, "arate", rate) */ int dhd_iovar_setint(char *ifname, char *iovar, int val) { return dhd_iovar_set(ifname, iovar, &val, sizeof(val)); } #endif /* __CONFIG_DHDAP__ */ /* * set named driver variable to int value * calling example: wl_iovar_setint(ifname, "arate", rate) */ int wl_iovar_setint(char *ifname, char *iovar, int val) { return wl_iovar_set(ifname, iovar, &val, sizeof(val)); } /* * get named driver variable to int value and return error indication * calling example: wl_iovar_getint(ifname, "arate", &rate) */ int wl_iovar_getint(char *ifname, char *iovar, int *val) { return wl_iovar_get(ifname, iovar, val, sizeof(int)); } /* * format a bsscfg indexed iovar buffer */ static int wl_bssiovar_mkbuf(char *iovar, int bssidx, void *param, int paramlen, void *bufptr, int buflen, int *plen) { char *prefix = "bsscfg:"; int8* p; uint prefixlen; uint namelen; uint iolen; prefixlen = strlen(prefix); /* length of bsscfg prefix */ namelen = strlen(iovar) + 1; /* length of iovar name + null */ iolen = prefixlen + namelen + sizeof(int) + paramlen; /* check for overflow */ if (buflen < 0 || iolen > (uint)buflen) { *plen = 0; return BCME_BUFTOOSHORT; } p = (int8*)bufptr; /* copy prefix, no null */ memcpy(p, prefix, prefixlen); p += prefixlen; /* copy iovar name including null */ memcpy(p, iovar, namelen); p += namelen; /* bss config index as first param */ memcpy(p, &bssidx, sizeof(int32)); p += sizeof(int32); /* parameter buffer follows */ if (paramlen) memcpy(p, param, paramlen); *plen = iolen; return 0; } /* * set named & bss indexed driver variable to buffer value */ int wl_bssiovar_setbuf(char *ifname, char *iovar, int bssidx, void *param, int paramlen, void *bufptr, int buflen) { int err; int iolen; err = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &iolen); if (err) return err; return wl_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); } #ifdef __CONFIG_DHDAP__ int dhd_ioctl(char *name, int cmd, void *buf, int len) { struct ifreq ifr; dhd_ioctl_t ioc; int ret = 0; int s; char buffer[WLC_IOCTL_SMLEN]; /* open socket to kernel */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return -1; } /* do it */ if (cmd == WLC_SET_VAR) { cmd = DHD_SET_VAR; } else if (cmd == WLC_GET_VAR) { cmd = DHD_GET_VAR; } ioc.cmd = cmd; ioc.buf = buf; ioc.len = len; ioc.set = FALSE; ioc.driver = DHD_IOCTL_MAGIC; ioc.used = 0; ioc.needed = 0; strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1); ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; ifr.ifr_data = (caddr_t) &ioc; if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0) if (cmd != WLC_GET_MAGIC && cmd != WLC_GET_BSSID) { if ((cmd == WLC_GET_VAR) || (cmd == WLC_SET_VAR)) { snprintf(buffer, sizeof(buffer), "%s: WLC_%s_VAR(%s)", name, cmd == WLC_GET_VAR ? "GET" : "SET", (char *)buf); } else { snprintf(buffer, sizeof(buffer), "%s: cmd=%d", name, cmd); } perror(buffer); } /* cleanup */ close(s); return ret; } /* * set named & bss indexed driver variable to buffer value */ int dhd_bssiovar_setbuf(char *ifname, char *iovar, int bssidx, void *param, int paramlen, void *bufptr, int buflen) { int err; int iolen; err = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &iolen); if (err) return err; return dhd_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); } #endif /* __CONFIG_DHDAP__ */ /* * get named & bss indexed driver variable buffer value */ int wl_bssiovar_getbuf(char *ifname, char *iovar, int bssidx, void *param, int paramlen, void *bufptr, int buflen) { int err; int iolen; err = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &iolen); if (err) return err; return wl_ioctl(ifname, WLC_GET_VAR, bufptr, buflen); } /* * set named & bss indexed driver variable to buffer value */ int wl_bssiovar_set(char *ifname, char *iovar, int bssidx, void *param, int paramlen) { char smbuf[WLC_IOCTL_SMLEN]; return wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, smbuf, sizeof(smbuf)); } #ifdef __CONFIG_DHDAP__ /* * set named & bss indexed driver variable to buffer value */ int dhd_bssiovar_set(char *ifname, char *iovar, int bssidx, void *param, int paramlen) { char smbuf[WLC_IOCTL_SMLEN]; return dhd_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, smbuf, sizeof(smbuf)); } #endif /* * get named & bss indexed driver variable buffer value */ int wl_bssiovar_get(char *ifname, char *iovar, int bssidx, void *outbuf, int len) { char smbuf[WLC_IOCTL_SMLEN]; int err; /* use the return buffer if it is bigger than what we have on the stack */ if (len > (int)sizeof(smbuf)) { err = wl_bssiovar_getbuf(ifname, iovar, bssidx, NULL, 0, outbuf, len); } else { memset(smbuf, 0, sizeof(smbuf)); err = wl_bssiovar_getbuf(ifname, iovar, bssidx, NULL, 0, smbuf, sizeof(smbuf)); if (err == 0) memcpy(outbuf, smbuf, len); } return err; } /* * set named & bss indexed driver variable to int value */ int wl_bssiovar_setint(char *ifname, char *iovar, int bssidx, int val) { return wl_bssiovar_set(ifname, iovar, bssidx, &val, sizeof(int)); } #ifdef __CONFIG_DHDAP__ /* * set named & bss indexed driver variable to int value */ int dhd_bssiovar_setint(char *ifname, char *iovar, int bssidx, int val) { return dhd_bssiovar_set(ifname, iovar, bssidx, &val, sizeof(int)); } #endif /* void wl_printlasterror(char *name) { char err_buf[WLC_IOCTL_SMLEN]; strcpy(err_buf, "bcmerrstr"); fprintf(stderr, "Error: "); if ( wl_ioctl(name, WLC_GET_VAR, err_buf, sizeof (err_buf)) != 0) fprintf(stderr, "Error getting the Errorstring from driver\n"); else fprintf(stderr, err_buf); } */