/* * Wireless network adapter utilities * * Copyright 2006, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * */ #include #include #include #include #include #include #include typedef u_int64_t u64; typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; #include #include #include #include #include #include int wl_ioctl(char *name, int cmd, void *buf, int len) { struct ifreq ifr; wl_ioctl_t ioc; int ret = 0; int s; /* open socket to kernel */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return errno; } /* do it */ ioc.cmd = cmd; ioc.buf = buf; ioc.len = len; strncpy(ifr.ifr_name, name, IFNAMSIZ); ifr.ifr_data = (caddr_t) &ioc; if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0) /* cleanup */ close(s); return ret; } static inline int wl_get_dev_type(char *name, void *buf, int len) { int s; int ret; struct ifreq ifr; struct ethtool_drvinfo info; /* open socket to kernel */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return -1; } /* get device type */ memset(&info, 0, sizeof(info)); info.cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (caddr_t)&info; strncpy(ifr.ifr_name, name, IFNAMSIZ); if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) { *(char *)buf = '\0'; } else strncpy(buf, info.driver, len); close(s); return ret; } int wl_probe(char *name) { int ret, val; char buf[3]; if ((ret = wl_get_dev_type(name, buf, 3)) < 0) return ret; /* Check interface */ if (strncmp(buf, "wl", 2)) return -1; if ((ret = wl_ioctl(name, WLC_GET_VERSION, &val, sizeof(val)))) return ret; if (val > WLC_IOCTL_VERSION) return -1; return ret; } static 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); } static 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); } 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; } /* * 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 */ static 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); } /* * get named & bss indexed driver variable buffer value */ static 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)); } /* * 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; } 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); }