int android_ioctl_siwpriv(struct net_device *dev, struct iw_request_info *__info, struct iw_point *data, char *__extra) { char *cmd = data->pointer; char *buf = data->pointer; AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); if (!cmd || !buf) { return -EOPNOTSUPP; } if (strcasecmp(cmd, "RSSI")==0 || strcasecmp(cmd, "RSSI-APPROX") == 0) { int rssi = 255; struct iw_statistics *iwStats; struct iw_statistics* (*get_iwstats)(struct net_device *); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) get_iwstats = dev->get_wireless_stats; #else get_iwstats = dev->wireless_handlers->get_wireless_stats; #endif iwStats = get_iwstats(dev); if (iwStats) { rssi = iwStats->qual.qual; if (rssi == 255) rssi = -200; else rssi += (161 - 256); } return snprintf(buf, data->length, "SSID rssi %d\n", rssi); } else if (strcasecmp(cmd, "LINKSPEED")==0) { int iocmd = SIOCGIWRATE - SIOCSIWCOMMIT; const iw_handler getRate = dev->wireless_handlers->standard[iocmd]; if (getRate) { union iwreq_data miwr; struct iw_request_info minfo; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); minfo.cmd = SIOCGIWRATE; if (getRate(dev, &minfo, &miwr, NULL) == 0) { unsigned int speed_kbps = miwr.param.value / 1000000; if ((!miwr.param.fixed)) { return snprintf(buf, data->length, "LinkSpeed %u\n", speed_kbps); } } } return -1; } else if (strcasecmp(cmd, "MACADDR")==0) { /* reply comes back in the form "Macaddr = XX.XX.XX.XX.XX.XX" where XX */ A_UCHAR *mac = dev->dev_addr; return snprintf(buf, data->length, "Macaddr = %02X.%02X.%02X.%02X.%02X.%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } else if (strcasecmp(cmd, "SCAN-ACTIVE")==0) { return 0; /* unsupport function. Suppress the error */ } else if (strcasecmp(cmd, "SCAN-PASSIVE")==0) { return 0; /* unsupport function. Suppress the error */ } else if (strcasecmp(cmd, "START")==0 || strcasecmp(cmd, "STOP")==0) { struct ifreq ifr; char userBuf[16]; int ex_arg = (strcasecmp(cmd, "START")==0) ? WLAN_ENABLED : WLAN_DISABLED; A_MEMZERO(userBuf, sizeof(userBuf)); ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_SET_WLAN_STATE; ((int *)userBuf)[1] = ex_arg; return android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf); } else if (strncasecmp(cmd, "POWERMODE ", 10)==0) { int mode; if (sscanf(cmd, "%*s %d", &mode) == 1) { int iocmd = SIOCSIWPOWER - SIOCSIWCOMMIT; iw_handler setPower = dev->wireless_handlers->standard[iocmd]; if (setPower) { union iwreq_data miwr; struct iw_request_info minfo; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); minfo.cmd = SIOCSIWPOWER; if (mode == 0 /* auto */) miwr.power.disabled = 0; else if (mode == 1 /* active */) miwr.power.disabled = 1; else return -1; return setPower(dev, &minfo, &miwr, NULL); } } return -1; } else if (strcasecmp(cmd, "SCAN-CHANNELS")==0) { /* reply comes back in the form "Scan-Channels = X" where X is the number of channels */ int iocmd = SIOCGIWRANGE - SIOCSIWCOMMIT; iw_handler getRange = dev->wireless_handlers->standard[iocmd]; if (getRange) { union iwreq_data miwr; struct iw_request_info minfo; struct iw_range range; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); A_MEMZERO(&range, sizeof(range)); minfo.cmd = SIOCGIWRANGE; miwr.data.pointer = (caddr_t) ⦥ miwr.data.length = sizeof(range); getRange(dev, &minfo, &miwr, (char*)&range); } if (ar->arNumChannels!=-1) { return snprintf(buf, data->length, "Scan-Channels = %d\n", ar->arNumChannels); } return -1; } else if (strncasecmp(cmd, "SCAN-CHANNELS ", 14)==0 || strncasecmp(cmd, "COUNTRY ", 8)==0) { /* * Set the available channels with WMI_SET_CHANNELPARAMS cmd * However, the channels will be limited by the eeprom regulator domain * Try to use a regulator domain which will not limited the channels range. */ int i; int chan = 0; A_UINT16 *clist; struct ifreq ifr; char ioBuf[256]; WMI_CHANNEL_PARAMS_CMD *chParamCmd = (WMI_CHANNEL_PARAMS_CMD *)ioBuf; if (strncasecmp(cmd, "COUNTRY ", 8)==0) { char *country = cmd + 8; if (strcasecmp(country, "US")==0) { chan = 11; } else if (strcasecmp(country, "JP")==0) { chan = 14; } else if (strcasecmp(country, "EU")==0) { chan = 13; } } else if (sscanf(cmd, "%*s %d", &chan) != 1) { return -1; } if ( (chan != 11) && (chan != 13) && (chan != 14)) { return -1; } if (ar->arNextMode == AP_NETWORK) { return -1; } A_MEMZERO(&ifr, sizeof(ifr)); A_MEMZERO(ioBuf, sizeof(ioBuf)); chParamCmd->phyMode = WMI_11G_MODE; clist = chParamCmd->channelList; chParamCmd->numChannels = chan; chParamCmd->scanParam = 1; for (i = 0; i < chan; i++) { clist[i] = wlan_ieee2freq(i + 1); } return android_do_ioctl_direct(dev, AR6000_IOCTL_WMI_SET_CHANNELPARAMS, &ifr, ioBuf); } else if (strncasecmp(cmd, "BTCOEXMODE ", 11)==0) { int mode; if (sscanf(cmd, "%*s %d", &mode)==1) { /* * Android disable BT-COEX when obtaining dhcp packet except there is headset is connected * It enable the BT-COEX after dhcp process is finished * We ignore since we have our way to do bt-coex during dhcp obtaining. */ switch (mode) { case 1: /* Disable*/ break; case 0: /* Enable */ /* fall through */ case 2: /* Sense*/ /* fall through */ default: break; } return 0; /* ignore it */ } return -1; } else if (strcasecmp(cmd, "BTCOEXSCAN-START")==0) { /* Android enable or disable Bluetooth coexistence scan mode. When this mode is on, * some of the low-level scan parameters used by the driver are changed to * reduce interference with A2DP streaming. */ return 0; /* ignore it since we have btfilter */ } else if (strcasecmp(cmd, "BTCOEXSCAN-STOP")==0) { return 0; /* ignore it since we have btfilter */ } else if (strncasecmp(cmd, "RXFILTER-ADD ", 13)==0) { return 0; /* ignore it */ } else if (strncasecmp(cmd, "RXFILTER-REMOVE ", 16)==0) { return 0; /* ignoret it */ } else if (strcasecmp(cmd, "RXFILTER-START")==0 || strcasecmp(cmd, "RXFILTER-STOP")==0) { unsigned int flags = dev->flags; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) int mc_count = dev->mc_count; #else int mc_count = netdev_mc_count(dev); #endif if (!(flags & IFF_UP)) { return -1; } if (strcasecmp(cmd, "RXFILTER-START")==0) { if (mc_count > 0 || (flags & IFF_MULTICAST) ) { flags &= ~IFF_MULTICAST; } } else { flags |= IFF_MULTICAST; } if (flags != dev->flags) { dev_change_flags(dev, flags); } return 0; } return -EOPNOTSUPP; }
int android_ioctl_siwpriv(struct net_device *dev, struct iw_request_info *__info, struct iw_point *data, char *__extra) { char cmd[384]; /* assume that android command will not excess 384 */ char buf[512]; int len = sizeof(cmd)-1; AR_SOFTC_DEV_T *arPriv = (AR_SOFTC_DEV_T *)ar6k_priv(dev); AR_SOFTC_STA_T *arSta = &arPriv->arSta; if (!data->pointer) { return -EOPNOTSUPP; } if (data->length < len) { len = data->length; } if (copy_from_user(cmd, data->pointer, len)) { return -EIO; } cmd[len] = 0; if (strcasecmp(cmd, "RSSI")==0 || strcasecmp(cmd, "RSSI-APPROX") == 0) { int rssi = -200; struct iw_statistics *iwStats; struct iw_statistics* (*get_iwstats)(struct net_device *); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) get_iwstats = dev->get_wireless_stats; #else get_iwstats = dev->wireless_handlers->get_wireless_stats; #endif if (get_iwstats && arPriv->arConnected) { iwStats = get_iwstats(dev); if (iwStats) { rssi = iwStats->qual.qual; if (rssi == 255) rssi = -200; else rssi += (161 - 256); } } len = snprintf(buf, data->length, "SSID rssi %d\n", rssi) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (strcasecmp(cmd, "LINKSPEED")==0) { /* We skip to use SIOCGIWRATE since Android always asked LINKSPEED just after RSSI*/ unsigned int speed_mbps; if (arPriv->arConnected) { speed_mbps = arPriv->arTargetStats.tx_unicast_rate / 1000; } else { speed_mbps = 1; } len = snprintf(buf, data->length, "LinkSpeed %u\n", speed_mbps) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (memcmp(cmd, "CSCAN S\x01\x00\x00S\x00", 12)==0) { int iocmd = SIOCSIWSCAN - SIOCSIWCOMMIT; const iw_handler setScan = dev->wireless_handlers->standard[iocmd]; A_INT32 home_dwell=0, pas_dwell=0, act_dwell=0; A_UCHAR ssid[IW_ESSID_MAX_SIZE+1] = { 0 }; A_INT32 ssid_len = 0, ie_len; A_UINT8 index = 1; /* reserve index 0 for wext */ A_INT32 ch = 0; A_CHAR nprobe, scantype; struct iw_freq chList[IW_MAX_FREQUENCIES]; A_UCHAR *scanBuf = (A_UCHAR*)(cmd + 12); A_UCHAR *scanEnd = (A_UCHAR*)(cmd + len); A_BOOL broadcastSsid = FALSE; while ( scanBuf < scanEnd ) { A_UCHAR *sp = scanBuf; switch (*scanBuf) { case 'S': /* SSID section */ if (ssid_len > 0 && index < MAX_PROBED_SSID_INDEX) { /* setup the last parsed ssid, reserve index 0 for wext */ if (wmi_probedSsid_cmd(arPriv->arWmi, index, SPECIFIC_SSID_FLAG, ssid_len, ssid) == A_OK) { ++index; if (arSta->scanSpecificSsid<index) { arSta->scanSpecificSsid = index; } } } ie_len = ((scanBuf + 1) < scanEnd) ? ((A_INT32)*(scanBuf+1) + 1) : 0; if ((scanBuf+ie_len) < scanEnd ) { ssid_len = *(scanBuf+1); if (ssid_len == 0) { broadcastSsid = TRUE; } else { A_MEMCPY(ssid, scanBuf+2, ssid_len); ssid[ssid_len] = '\0'; } } scanBuf += 1 + ie_len; break; case 'C': /* Channel section */ if (scanBuf+1 < scanEnd) { int value = *(scanBuf+1); if (value == 0) { ch = 0; /* scan for all channels */ } else if (ch < IW_MAX_FREQUENCIES) { if (value>1000) { chList[ch].e = 1; chList[ch].m = value * 100000; } else { chList[ch].e = 0; chList[ch].m = value; } ++ch; } } scanBuf += 2; break; case 'P': /* Passive dwell section */ if (scanBuf+2 < scanEnd) { pas_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8); } scanBuf += 3; break; case 'H': /* Home dwell section */ if (scanBuf+2 < scanEnd) { home_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8); } scanBuf += 3; break; case 'N': /* Number of probe section */ if (scanBuf+1 < scanEnd) { nprobe = *(scanBuf+1); } scanBuf += 2; break; case 'A': /* Active dwell section */ if (scanBuf+2 < scanEnd) { act_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8); } scanBuf += 3; break; case 'T': /* Scan active type section */ if (scanBuf+1 < scanEnd) { scantype = *(scanBuf+1); } scanBuf += 2; break; default: break; } if (sp == scanBuf) { return -1; /* parsing error */ } } if (ssid_len>0) { A_UINT8 idx; /* Clean up the last specific scan items */ for (idx=index; idx<arSta->scanSpecificSsid; ++idx) { wmi_probedSsid_cmd(arPriv->arWmi, idx, DISABLE_SSID_FLAG, 0, NULL); } arSta->scanSpecificSsid = index; /* * There is no way to know when we need to send broadcast probe in current Android wpa_supplicant_6 * combo scan implemenation. Always force to sent it here uniti future Android version will set * the broadcast flags for combo scan. */ #if 0 if (broadcastSsid) #endif { /* setup the last index as broadcast SSID for combo scan */ ++arSta->scanSpecificSsid; wmi_probedSsid_cmd(arPriv->arWmi, index, ANY_SSID_FLAG, 0, NULL); } } if (pas_dwell>0) { /* TODO: Should we change our passive dwell? There may be some impact for bt-coex */ } if (home_dwell>0) { /* TODO: Should we adjust home_dwell? How to pass it to wext handler? */ } if (setScan) { union iwreq_data miwr; struct iw_request_info minfo; struct iw_scan_req scanreq, *pScanReq = NULL; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); A_MEMZERO(&scanreq, sizeof(scanreq)); if (ssid_len > 0) { pScanReq = &scanreq; memcpy(scanreq.essid, ssid, ssid_len); scanreq.essid_len = ssid_len; miwr.data.flags |= IW_SCAN_THIS_ESSID; } if (ch > 0) { pScanReq = &scanreq; scanreq.num_channels = ch; memcpy(scanreq.channel_list, chList, ch * sizeof(chList[0])); miwr.data.flags |= IW_SCAN_THIS_FREQ; } if (pScanReq) { miwr.data.pointer = (__force void __user *)&scanreq; miwr.data.length = sizeof(scanreq); } minfo.cmd = SIOCSIWSCAN; return setScan(dev, &minfo, &miwr, (char*)pScanReq); } return -1; } else if (strcasecmp(cmd, "MACADDR")==0) { /* reply comes back in the form "Macaddr = XX:XX:XX:XX:XX:XX" where XX */ A_UCHAR *mac = dev->dev_addr; len = snprintf(buf, data->length, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (strcasecmp(cmd, "SCAN-ACTIVE")==0) { return 0; /* unsupport function. Suppress the error */ } else if (strcasecmp(cmd, "SCAN-PASSIVE")==0) { return 0; /* unsupport function. Suppress the error */ } else if (strcasecmp(cmd, "START")==0 || strcasecmp(cmd, "STOP")==0) { struct ifreq ifr; char userBuf[16]; int ex_arg = (strcasecmp(cmd, "START")==0) ? WLAN_ENABLED : WLAN_DISABLED; int ret; A_MEMZERO(userBuf, sizeof(userBuf)); ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_SET_WLAN_STATE; ((int *)userBuf)[1] = ex_arg; ret = android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf); if (ret==0) { /* Send wireless event which need by android supplicant */ union iwreq_data wrqu; A_MEMZERO(&wrqu, sizeof(wrqu)); wrqu.data.length = strlen(cmd); wireless_send_event(dev, IWEVCUSTOM, &wrqu, cmd); } return ret; } else if (strncasecmp(cmd, "POWERMODE ", 10)==0) { int mode; if (sscanf(cmd, "%*s %d", &mode) == 1) { int iocmd = SIOCSIWPOWER - SIOCSIWCOMMIT; iw_handler setPower = dev->wireless_handlers->standard[iocmd]; if (setPower) { union iwreq_data miwr; struct iw_request_info minfo; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); minfo.cmd = SIOCSIWPOWER; if (mode == 0 /* auto */) miwr.power.disabled = 0; else if (mode == 1 /* active */) miwr.power.disabled = 1; else return -1; return setPower(dev, &minfo, &miwr, NULL); } } return -1; } else if (strcasecmp(cmd, "GETPOWER")==0) { struct ifreq ifr; int userBuf[2]; A_MEMZERO(userBuf, sizeof(userBuf)); ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_GET_POWER_MODE; if (android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf)>=0) { WMI_POWER_MODE_CMD *getPowerMode = (WMI_POWER_MODE_CMD *)userBuf; len = snprintf(buf, data->length, "powermode = %u\n", (getPowerMode->powerMode==MAX_PERF_POWER) ? 1/*active*/ : 0/*auto*/) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } return -1; } else if (strncasecmp(cmd, "SETSUSPENDOPT ", 14)==0) { int enable; if (sscanf(cmd, "%*s %d", &enable)==1) { /* * We set our suspend mode by wlan_config.h now. * Should we follow Android command?? TODO */ return 0; } return -1; } else if (strcasecmp(cmd, "SCAN-CHANNELS")==0) { // reply comes back in the form "Scan-Channels = X" where X is the number of channels int iocmd = SIOCGIWRANGE - SIOCSIWCOMMIT; iw_handler getRange = dev->wireless_handlers->standard[iocmd]; if (getRange) { union iwreq_data miwr; struct iw_request_info minfo; struct iw_range range; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); A_MEMZERO(&range, sizeof(range)); minfo.cmd = SIOCGIWRANGE; miwr.data.pointer = (__force void __user *) ⦥ miwr.data.length = sizeof(range); getRange(dev, &minfo, &miwr, (char*)&range); } if (arSta->arNumChannels!=-1) { len = snprintf(buf, data->length, "Scan-Channels = %d\n", arSta->arNumChannels) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } return -1; } else if (strncasecmp(cmd, "SCAN-CHANNELS ", 14)==0 || strncasecmp(cmd, "COUNTRY ", 8)==0) { /* * Set the available channels with WMI_SET_CHANNELPARAMS cmd * However, the channels will be limited by the eeprom regulator domain * Try to use a regulator domain which will not limited the channels range. */ int i; int chan = 0; A_UINT16 *clist; struct ifreq ifr; char ioBuf[256]; WMI_CHANNEL_PARAMS_CMD *chParamCmd = (WMI_CHANNEL_PARAMS_CMD *)ioBuf; if (strncasecmp(cmd, "COUNTRY ", 8)==0) { char *country = cmd + 8; if (strcasecmp(country, "US")==0) { chan = 11; } else if (strcasecmp(country, "JP")==0) { chan = 14; } else if (strcasecmp(country, "EU")==0) { chan = 13; } } else if (sscanf(cmd, "%*s %d", &chan) != 1) { return -1; } if ( (chan != 11) && (chan != 13) && (chan != 14)) { return -1; } if (arPriv->arNextMode == AP_NETWORK) { return -1; } A_MEMZERO(&ifr, sizeof(ifr)); A_MEMZERO(ioBuf, sizeof(ioBuf)); chParamCmd->phyMode = WMI_11G_MODE; clist = chParamCmd->channelList; chParamCmd->numChannels = chan; chParamCmd->scanParam = 1; for (i = 0; i < chan; i++) { clist[i] = wlan_ieee2freq(i + 1); } return android_do_ioctl_direct(dev, AR6000_IOCTL_WMI_SET_CHANNELPARAMS, &ifr, ioBuf); } else if (strncasecmp(cmd, "BTCOEXMODE ", 11)==0) { int mode; if (sscanf(cmd, "%*s %d", &mode)==1) { /* * Android disable BT-COEX when obtaining dhcp packet except there is headset is connected * It enable the BT-COEX after dhcp process is finished * We ignore since we have our way to do bt-coex during dhcp obtaining. */ switch (mode) { case 1: /* Disable*/ break; case 0: /* Enable */ /* fall through */ case 2: /* Sense*/ /* fall through */ default: break; } return 0; /* ignore it */ } return -1; } else if (strcasecmp(cmd, "BTCOEXSCAN-START")==0) { /* Android enable or disable Bluetooth coexistence scan mode. When this mode is on, * some of the low-level scan parameters used by the driver are changed to * reduce interference with A2DP streaming. */ return 0; /* ignore it since we have btfilter */ } else if (strcasecmp(cmd, "BTCOEXSCAN-STOP")==0) { return 0; /* ignore it since we have btfilter */ } else if (strncasecmp(cmd, "RXFILTER-ADD ", 13)==0) { return 0; /* ignore it */ } else if (strncasecmp(cmd, "RXFILTER-REMOVE ", 16)==0) { return 0; /* ignoret it */ } else if (strcasecmp(cmd, "RXFILTER-START")==0 || strcasecmp(cmd, "RXFILTER-STOP")==0) { unsigned int flags = dev->flags; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) int mc_count = dev->mc_count; #else int mc_count = netdev_mc_count(dev); #endif if (strcasecmp(cmd, "RXFILTER-START")==0) { if (mc_count > 0 || (flags & IFF_MULTICAST) ) { flags &= ~IFF_MULTICAST; } } else { flags |= IFF_MULTICAST; } if (flags != dev->flags) { dev_change_flags(dev, flags); } return 0; } return -EOPNOTSUPP; }
int android_ioctl_siwpriv(struct net_device *dev, struct iw_request_info *__info, struct iw_point *data, char *__extra) { char cmd[32]; /* assume that android command will not excess 32 */ char buf[32]; char *cmdbuf; int len = sizeof(cmd)-1; AR_SOFTC_DEV_T *arPriv = (AR_SOFTC_DEV_T *)ar6k_priv(dev); AR_SOFTC_STA_T *arSta = &arPriv->arSta; if (!data->pointer) { return -EOPNOTSUPP; } if (data->length < len) { len = data->length; } if (copy_from_user(cmd, data->pointer, len)) { return -EIO; } cmd[len] = 0; if (strcasecmp(cmd, "RSSI")==0 || strcasecmp(cmd, "RSSI-APPROX") == 0) { int rssi = -200; struct iw_statistics *iwStats; struct iw_statistics* (*get_iwstats)(struct net_device *); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) get_iwstats = dev->get_wireless_stats; #else get_iwstats = dev->wireless_handlers->get_wireless_stats; #endif if (get_iwstats && arPriv->arConnected) { iwStats = get_iwstats(dev); if (iwStats) { rssi = iwStats->qual.qual; if (rssi == 255) rssi = -200; else rssi += (161 - 256); } } len = snprintf(buf, data->length, "SSID rssi %d\n", rssi) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (strcasecmp(cmd, "LINKSPEED")==0) { /* We skip to use SIOCGIWRATE since Android always asked LINKSPEED just after RSSI*/ unsigned int speed_mbps; if (arPriv->arConnected) { speed_mbps = arPriv->arTargetStats.tx_unicast_rate / 1000; } else { speed_mbps = 1; } len = snprintf(buf, data->length, "LinkSpeed %u\n", speed_mbps) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (memcmp(cmd, "CSCAN S\x01\x00\x00S\x00", 12)==0) { int ret=0; if (!(cmdbuf = A_MALLOC(data->length))) return -ENOMEM; if (copy_from_user(cmdbuf, data->pointer, data->length)) { A_FREE(cmdbuf); return -EFAULT; } ret = ar6000_cscan(dev,data, cmdbuf); A_FREE(cmdbuf); return ret; } else if (strcasecmp(cmd, "MACADDR")==0) { /* reply comes back in the form "Macaddr = XX:XX:XX:XX:XX:XX" where XX */ A_UCHAR *mac = dev->dev_addr; len = snprintf(buf, data->length, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (strcasecmp(cmd, "SCAN-ACTIVE")==0) { return 0; /* unsupport function. Suppress the error */ } else if (strcasecmp(cmd, "SCAN-PASSIVE")==0) { return 0; /* unsupport function. Suppress the error */ } else if (strcasecmp(cmd, "START")==0 || strcasecmp(cmd, "STOP")==0) { struct ifreq ifr; char userBuf[16]; int ex_arg = (strcasecmp(cmd, "START")==0) ? WLAN_ENABLED : WLAN_DISABLED; int ret; A_MEMZERO(userBuf, sizeof(userBuf)); ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_SET_WLAN_STATE; ((int *)userBuf)[1] = ex_arg; ret = android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf); if (ret==0) { /* Send wireless event which need by android supplicant */ union iwreq_data wrqu; A_MEMZERO(&wrqu, sizeof(wrqu)); wrqu.data.length = strlen(cmd); wireless_send_event(dev, IWEVCUSTOM, &wrqu, cmd); } return ret; } else if (strncasecmp(cmd, "POWERMODE ", 10)==0) { int mode; if (sscanf(cmd, "%*s %d", &mode) == 1) { int iocmd = SIOCSIWPOWER - SIOCSIWCOMMIT; iw_handler setPower = dev->wireless_handlers->standard[iocmd]; if (setPower) { union iwreq_data miwr; struct iw_request_info minfo; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); minfo.cmd = SIOCSIWPOWER; if (mode == 0 /* auto */) miwr.power.disabled = 0; else if (mode == 1 /* active */) miwr.power.disabled = 1; else return -1; return setPower(dev, &minfo, &miwr, NULL); } } return -1; } else if (strcasecmp(cmd, "GETPOWER")==0) { struct ifreq ifr; int userBuf[2]; A_MEMZERO(userBuf, sizeof(userBuf)); ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_GET_POWER_MODE; if (android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf)>=0) { WMI_POWER_MODE_CMD *getPowerMode = (WMI_POWER_MODE_CMD *)userBuf; len = snprintf(buf, data->length, "powermode = %u\n", (getPowerMode->powerMode==MAX_PERF_POWER) ? 1/*active*/ : 0/*auto*/) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } return -1; } else if (strcasecmp(cmd, "GETBAND")==0) { int band; /*0: auto, 1: 5GHz only, 2: 2.4GHz Only*/ switch (arPriv->arPhyCapability) { case WMI_11A_CAPABILITY: case WMI_11NA_CAPABILITY: band = 1; break; case WMI_11NG_CAPABILITY: case WMI_11G_CAPABILITY: band = 2; break; case WMI_11AG_CAPABILITY: case WMI_11NAG_CAPABILITY: default: band = 0; break; } len = snprintf(buf, data->length, "Band %d\n", band) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (strncasecmp(cmd, "SETBAND ", 8)==0) { int band; if (sscanf(cmd, "%*s %d", &band) == 1) { switch (band) { case 1: /* 5GHz Only*/ /* TODO: Using WMI_CHANNEL_PARAMS_CMD to disable all 5GHz channels? */ break; case 2: /* 5GHz Only*/ /* TODO: Using WMI_CHANNEL_PARAMS_CMD to disable all 2.4GHz channels? */ break; case 0: /* auto */ default: break; } return 0; } return -1; } else if (strncasecmp(cmd, "SETSUSPENDOPT ", 14)==0) { int enable; if (sscanf(cmd, "%*s %d", &enable)==1) { /* * We set our suspend mode by wlan_config.h now. * Should we follow Android command?? TODO */ return 0; } return -1; } else if (strcasecmp(cmd, "SCAN-CHANNELS")==0) { // reply comes back in the form "Scan-Channels = X" where X is the number of channels int iocmd = SIOCGIWRANGE - SIOCSIWCOMMIT; iw_handler getRange = dev->wireless_handlers->standard[iocmd]; if (getRange) { union iwreq_data miwr; struct iw_request_info minfo; struct iw_range range; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); A_MEMZERO(&range, sizeof(range)); minfo.cmd = SIOCGIWRANGE; miwr.data.pointer = (__force void __user *) ⦥ miwr.data.length = sizeof(range); getRange(dev, &minfo, &miwr, (char*)&range); } if (arSta->arNumChannels!=-1) { len = snprintf(buf, data->length, "Scan-Channels = %d\n", arSta->arNumChannels) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } return -1; } else if (strncasecmp(cmd, "SCAN-CHANNELS ", 14)==0 || strncasecmp(cmd, "COUNTRY ", 8)==0) { /* * Set the available channels with WMI_SET_CHANNELPARAMS cmd * However, the channels will be limited by the eeprom regulator domain * Try to use a regulator domain which will not limited the channels range. */ int i; int chan = 0; A_UINT16 *clist; struct ifreq ifr; char ioBuf[256]; WMI_CHANNEL_PARAMS_CMD *chParamCmd = (WMI_CHANNEL_PARAMS_CMD *)ioBuf; if (strncasecmp(cmd, "COUNTRY ", 8)==0) { char *country = cmd + 8; if (strcasecmp(country, "US")==0) { chan = 11; } else if (strcasecmp(country, "JP")==0) { chan = 14; } else if (strcasecmp(country, "EU")==0) { chan = 13; } } else if (sscanf(cmd, "%*s %d", &chan) != 1) { return -1; } if ( (chan != 11) && (chan != 13) && (chan != 14)) { return -1; } if (arPriv->arNextMode == AP_NETWORK) { return -1; } A_MEMZERO(&ifr, sizeof(ifr)); A_MEMZERO(ioBuf, sizeof(ioBuf)); chParamCmd->phyMode = WMI_11G_MODE; clist = chParamCmd->channelList; chParamCmd->numChannels = chan; chParamCmd->scanParam = 1; for (i = 0; i < chan; i++) { clist[i] = wlan_ieee2freq(i + 1); } return android_do_ioctl_direct(dev, AR6000_IOCTL_WMI_SET_CHANNELPARAMS, &ifr, ioBuf); } else if (strncasecmp(cmd, "BTCOEXMODE ", 11)==0) { int mode; if (sscanf(cmd, "%*s %d", &mode)==1) { /* * Android disable BT-COEX when obtaining dhcp packet except there is headset is connected * It enable the BT-COEX after dhcp process is finished * We ignore since we have our way to do bt-coex during dhcp obtaining. */ switch (mode) { case 1: /* Disable*/ break; case 0: /* Enable */ /* fall through */ case 2: /* Sense*/ /* fall through */ default: break; } return 0; /* ignore it */ } return -1; } else if (strcasecmp(cmd, "BTCOEXSCAN-START")==0) { /* Android enable or disable Bluetooth coexistence scan mode. When this mode is on, * some of the low-level scan parameters used by the driver are changed to * reduce interference with A2DP streaming. */ return 0; /* ignore it since we have btfilter */ } else if (strcasecmp(cmd, "BTCOEXSCAN-STOP")==0) { return 0; /* ignore it since we have btfilter */ } else if (strncasecmp(cmd, "RXFILTER-ADD ", 13)==0) { return 0; /* ignore it */ } else if (strncasecmp(cmd, "RXFILTER-REMOVE ", 16)==0) { return 0; /* ignoret it */ } else if (strcasecmp(cmd, "RXFILTER-START")==0 || strcasecmp(cmd, "RXFILTER-STOP")==0) { unsigned int flags = dev->flags; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) int mc_count = dev->mc_count; #else int mc_count = netdev_mc_count(dev); #endif if (strcasecmp(cmd, "RXFILTER-START")==0) { if (mc_count > 0 || (flags & IFF_MULTICAST) ) { //flags &= ~IFF_MULTICAST; //to always enable multicast flags |= IFF_MULTICAST; } } else { flags |= IFF_MULTICAST; } if (flags != dev->flags) { dev_change_flags(dev, flags); } return 0; } return -EOPNOTSUPP; }