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) &range;
            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;
}
Esempio n. 2
0
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 *) &range;
            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;
}
Esempio n. 3
0
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 *) &range;
            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;
}