Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wifi;
     18 
     19 import android.net.wifi.BatchedScanSettings;
     20 import android.net.wifi.RttManager;
     21 import android.net.wifi.ScanResult;
     22 import android.net.wifi.WifiConfiguration;
     23 import android.net.wifi.WifiLinkLayerStats;
     24 import android.net.wifi.WifiManager;
     25 import android.net.wifi.WifiScanner;
     26 import android.net.wifi.RttManager;
     27 import android.net.wifi.WifiSsid;
     28 import android.net.wifi.WpsInfo;
     29 import android.net.wifi.p2p.WifiP2pConfig;
     30 import android.net.wifi.p2p.WifiP2pGroup;
     31 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
     32 import android.net.wifi.WifiEnterpriseConfig;
     33 import android.os.SystemClock;
     34 import android.text.TextUtils;
     35 import android.util.Base64;
     36 import android.util.LocalLog;
     37 import android.util.Log;
     38 
     39 import java.io.ByteArrayOutputStream;
     40 import java.io.IOException;
     41 import java.nio.ByteBuffer;
     42 import java.nio.CharBuffer;
     43 import java.nio.charset.CharacterCodingException;
     44 import java.nio.charset.CharsetDecoder;
     45 import java.nio.charset.StandardCharsets;
     46 import java.util.ArrayList;
     47 import java.util.List;
     48 import java.util.Locale;
     49 import java.util.zip.Deflater;
     50 import libcore.util.HexEncoding;
     51 /**
     52  * Native calls for bring up/shut down of the supplicant daemon and for
     53  * sending requests to the supplicant daemon
     54  *
     55  * waitForEvent() is called on the monitor thread for events. All other methods
     56  * must be serialized from the framework.
     57  *
     58  * {@hide}
     59  */
     60 public class WifiNative {
     61 
     62     private static boolean DBG = false;
     63     private final String mTAG;
     64     private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
     65 
     66     static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED     = 0;
     67     static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED    = 1;
     68     static final int BLUETOOTH_COEXISTENCE_MODE_SENSE       = 2;
     69 
     70     static final int SCAN_WITHOUT_CONNECTION_SETUP          = 1;
     71     static final int SCAN_WITH_CONNECTION_SETUP             = 2;
     72 
     73     // Hold this lock before calling supplicant - it is required to
     74     // mutually exclude access from Wifi and P2p state machines
     75     static final Object mLock = new Object();
     76 
     77     public final String mInterfaceName;
     78     public final String mInterfacePrefix;
     79 
     80     private boolean mSuspendOptEnabled = false;
     81 
     82     private static final int EID_HT_OPERATION = 61;
     83     private static final int EID_VHT_OPERATION = 192;
     84     private static final int EID_EXTENDED_CAPS = 127;
     85     private static final int RTT_RESP_ENABLE_BIT = 70;
     86     /* Register native functions */
     87 
     88     static {
     89         /* Native functions are defined in libwifi-service.so */
     90         System.loadLibrary("wifi-service");
     91         registerNatives();
     92     }
     93 
     94     private static native int registerNatives();
     95 
     96     public native static boolean loadDriver();
     97 
     98     public native static boolean isDriverLoaded();
     99 
    100     public native static boolean unloadDriver();
    101 
    102     public native static boolean startSupplicant(boolean p2pSupported);
    103 
    104     /* Sends a kill signal to supplicant. To be used when we have lost connection
    105        or when the supplicant is hung */
    106     public native static boolean killSupplicant(boolean p2pSupported);
    107 
    108     private native boolean connectToSupplicantNative();
    109 
    110     private native void closeSupplicantConnectionNative();
    111 
    112     /**
    113      * Wait for the supplicant to send an event, returning the event string.
    114      * @return the event string sent by the supplicant.
    115      */
    116     private native String waitForEventNative();
    117 
    118     private native boolean doBooleanCommandNative(String command);
    119 
    120     private native int doIntCommandNative(String command);
    121 
    122     private native String doStringCommandNative(String command);
    123 
    124     public WifiNative(String interfaceName) {
    125         mInterfaceName = interfaceName;
    126         mTAG = "WifiNative-" + interfaceName;
    127         if (!interfaceName.equals("p2p0")) {
    128             mInterfacePrefix = "IFNAME=" + interfaceName + " ";
    129         } else {
    130             // commands for p2p0 interface don't need prefix
    131             mInterfacePrefix = "";
    132         }
    133     }
    134 
    135     void enableVerboseLogging(int verbose) {
    136         if (verbose > 0) {
    137             DBG = true;
    138         } else {
    139             DBG = false;
    140         }
    141     }
    142 
    143     private static final LocalLog mLocalLog = new LocalLog(16384);
    144 
    145     // hold mLock before accessing mCmdIdLock
    146     private static int sCmdId;
    147 
    148     public static LocalLog getLocalLog() {
    149         return mLocalLog;
    150     }
    151 
    152     private static int getNewCmdIdLocked() {
    153         return sCmdId++;
    154     }
    155 
    156     private void localLog(String s) {
    157         if (mLocalLog != null)
    158             mLocalLog.log(mInterfaceName + ": " + s);
    159     }
    160 
    161     public boolean connectToSupplicant() {
    162         synchronized(mLock) {
    163             localLog(mInterfacePrefix + "connectToSupplicant");
    164             return connectToSupplicantNative();
    165         }
    166     }
    167 
    168     public void closeSupplicantConnection() {
    169         synchronized(mLock) {
    170             localLog(mInterfacePrefix + "closeSupplicantConnection");
    171             closeSupplicantConnectionNative();
    172         }
    173     }
    174 
    175     public String waitForEvent() {
    176         // No synchronization necessary .. it is implemented in WifiMonitor
    177         return waitForEventNative();
    178     }
    179 
    180     private boolean doBooleanCommand(String command) {
    181         if (DBG) Log.d(mTAG, "doBoolean: " + command);
    182         synchronized (mLock) {
    183             int cmdId = getNewCmdIdLocked();
    184             String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command;
    185             boolean result = doBooleanCommandNative(mInterfacePrefix + command);
    186             localLog(toLog + " -> " + result);
    187             if (DBG) Log.d(mTAG, command + ": returned " + result);
    188             return result;
    189         }
    190     }
    191 
    192     private boolean doBooleanCommandWithoutLogging(String command) {
    193         if (DBG) Log.d(mTAG, "doBooleanCommandWithoutLogging: " + command);
    194         synchronized (mLock) {
    195             int cmdId = getNewCmdIdLocked();
    196             boolean result = doBooleanCommandNative(mInterfacePrefix + command);
    197             if (DBG) Log.d(mTAG, command + ": returned " + result);
    198             return result;
    199         }
    200     }
    201 
    202     private int doIntCommand(String command) {
    203         if (DBG) Log.d(mTAG, "doInt: " + command);
    204         synchronized (mLock) {
    205             int cmdId = getNewCmdIdLocked();
    206             String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command;
    207             int result = doIntCommandNative(mInterfacePrefix + command);
    208             localLog(toLog + " -> " + result);
    209             if (DBG) Log.d(mTAG, "   returned " + result);
    210             return result;
    211         }
    212     }
    213 
    214     private String doStringCommand(String command) {
    215         if (DBG) {
    216             //GET_NETWORK commands flood the logs
    217             if (!command.startsWith("GET_NETWORK")) {
    218                 Log.d(mTAG, "doString: [" + command + "]");
    219             }
    220         }
    221         synchronized (mLock) {
    222             int cmdId = getNewCmdIdLocked();
    223             String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command;
    224             String result = doStringCommandNative(mInterfacePrefix + command);
    225             if (result == null) {
    226                 if (DBG) Log.d(mTAG, "doStringCommandNative no result");
    227             } else {
    228                 if (!command.startsWith("STATUS-")) {
    229                     localLog(toLog + " -> " + result);
    230                 }
    231                 if (DBG) Log.d(mTAG, "   returned " + result.replace("\n", " "));
    232             }
    233             return result;
    234         }
    235     }
    236 
    237     private String doStringCommandWithoutLogging(String command) {
    238         if (DBG) {
    239             //GET_NETWORK commands flood the logs
    240             if (!command.startsWith("GET_NETWORK")) {
    241                 Log.d(mTAG, "doString: [" + command + "]");
    242             }
    243         }
    244         synchronized (mLock) {
    245             return doStringCommandNative(mInterfacePrefix + command);
    246         }
    247     }
    248 
    249     public boolean ping() {
    250         String pong = doStringCommand("PING");
    251         return (pong != null && pong.equals("PONG"));
    252     }
    253 
    254     public void setSupplicantLogLevel(String level) {
    255         doStringCommand("LOG_LEVEL " + level);
    256     }
    257 
    258     public String getFreqCapability() {
    259         return doStringCommand("GET_CAPABILITY freq");
    260     }
    261 
    262     public boolean scan(int type, String freqList) {
    263         if (type == SCAN_WITHOUT_CONNECTION_SETUP) {
    264             if (freqList == null) return doBooleanCommand("SCAN TYPE=ONLY");
    265             else return doBooleanCommand("SCAN TYPE=ONLY freq=" + freqList);
    266         } else if (type == SCAN_WITH_CONNECTION_SETUP) {
    267             if (freqList == null) return doBooleanCommand("SCAN");
    268             else return doBooleanCommand("SCAN freq=" + freqList);
    269         } else {
    270             throw new IllegalArgumentException("Invalid scan type");
    271         }
    272     }
    273 
    274     /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta.
    275      *
    276      * Note that underneath we use a harsh-sounding "terminate" supplicant command
    277      * for a graceful stop and a mild-sounding "stop" interface
    278      * to kill the process
    279      */
    280     public boolean stopSupplicant() {
    281         return doBooleanCommand("TERMINATE");
    282     }
    283 
    284     public String listNetworks() {
    285         return doStringCommand("LIST_NETWORKS");
    286     }
    287 
    288     public String listNetworks(int last_id) {
    289         return doStringCommand("LIST_NETWORKS LAST_ID=" + last_id);
    290     }
    291 
    292     public int addNetwork() {
    293         return doIntCommand("ADD_NETWORK");
    294     }
    295 
    296     public boolean setNetworkVariable(int netId, String name, String value) {
    297         if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false;
    298         if (name.equals(WifiConfiguration.pskVarName)
    299                 || name.equals(WifiEnterpriseConfig.PASSWORD_KEY)) {
    300             return doBooleanCommandWithoutLogging("SET_NETWORK " + netId + " " + name + " " + value);
    301         } else {
    302             return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value);
    303         }
    304     }
    305 
    306     public String getNetworkVariable(int netId, String name) {
    307         if (TextUtils.isEmpty(name)) return null;
    308 
    309         // GET_NETWORK will likely flood the logs ...
    310         return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name);
    311     }
    312 
    313     public boolean removeNetwork(int netId) {
    314         return doBooleanCommand("REMOVE_NETWORK " + netId);
    315     }
    316 
    317 
    318     private void logDbg(String debug) {
    319         long now = SystemClock.elapsedRealtimeNanos();
    320         String ts = String.format("[%,d us] ", now/1000);
    321         Log.e("WifiNative: ", ts+debug+ " stack:"
    322                 + Thread.currentThread().getStackTrace()[2].getMethodName() +" - "
    323                 + Thread.currentThread().getStackTrace()[3].getMethodName() +" - "
    324                 + Thread.currentThread().getStackTrace()[4].getMethodName() +" - "
    325                 + Thread.currentThread().getStackTrace()[5].getMethodName()+" - "
    326                 + Thread.currentThread().getStackTrace()[6].getMethodName());
    327 
    328     }
    329     public boolean enableNetwork(int netId, boolean disableOthers) {
    330         if (DBG) logDbg("enableNetwork nid=" + Integer.toString(netId)
    331                 + " disableOthers=" + disableOthers);
    332         if (disableOthers) {
    333             return doBooleanCommand("SELECT_NETWORK " + netId);
    334         } else {
    335             return doBooleanCommand("ENABLE_NETWORK " + netId);
    336         }
    337     }
    338 
    339     public boolean disableNetwork(int netId) {
    340         if (DBG) logDbg("disableNetwork nid=" + Integer.toString(netId));
    341         return doBooleanCommand("DISABLE_NETWORK " + netId);
    342     }
    343 
    344     public boolean selectNetwork(int netId) {
    345         if (DBG) logDbg("selectNetwork nid=" + Integer.toString(netId));
    346         return doBooleanCommand("SELECT_NETWORK " + netId);
    347     }
    348 
    349     public boolean reconnect() {
    350         if (DBG) logDbg("RECONNECT ");
    351         return doBooleanCommand("RECONNECT");
    352     }
    353 
    354     public boolean reassociate() {
    355         if (DBG) logDbg("REASSOCIATE ");
    356         return doBooleanCommand("REASSOCIATE");
    357     }
    358 
    359     public boolean disconnect() {
    360         if (DBG) logDbg("DISCONNECT ");
    361         return doBooleanCommand("DISCONNECT");
    362     }
    363 
    364     public String status() {
    365         return status(false);
    366     }
    367 
    368     public String status(boolean noEvents) {
    369         if (noEvents) {
    370             return doStringCommand("STATUS-NO_EVENTS");
    371         } else {
    372             return doStringCommand("STATUS");
    373         }
    374     }
    375 
    376     public String getMacAddress() {
    377         //Macaddr = XX.XX.XX.XX.XX.XX
    378         String ret = doStringCommand("DRIVER MACADDR");
    379         if (!TextUtils.isEmpty(ret)) {
    380             String[] tokens = ret.split(" = ");
    381             if (tokens.length == 2) return tokens[1];
    382         }
    383         return null;
    384     }
    385 
    386 
    387 
    388     /**
    389      * Format of results:
    390      * =================
    391      * id=1
    392      * bssid=68:7f:74:d7:1b:6e
    393      * freq=2412
    394      * level=-43
    395      * tsf=1344621975160944
    396      * age=2623
    397      * flags=[WPA2-PSK-CCMP][WPS][ESS]
    398      * ssid=zubyb
    399      * ====
    400      *
    401      * RANGE=ALL gets all scan results
    402      * RANGE=ID- gets results from ID
    403      * MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details
    404      * 0                         0                        1                       0     2
    405      *                           WPA_BSS_MASK_MESH_SCAN | WPA_BSS_MASK_DELIM    | WPA_BSS_MASK_WIFI_DISPLAY
    406      * 0                         0                        0                       1     1   -> 9
    407      * WPA_BSS_MASK_INTERNETW  | WPA_BSS_MASK_P2P_SCAN  | WPA_BSS_MASK_WPS_SCAN | WPA_BSS_MASK_SSID
    408      * 1                         0                        0                       1     9   -> d
    409      * WPA_BSS_MASK_FLAGS      | WPA_BSS_MASK_IE        | WPA_BSS_MASK_AGE      | WPA_BSS_MASK_TSF
    410      * 1                         0                        0                       0     8
    411      * WPA_BSS_MASK_LEVEL      | WPA_BSS_MASK_NOISE     | WPA_BSS_MASK_QUAL     | WPA_BSS_MASK_CAPABILITIES
    412      * 0                         1                        1                       1     7
    413      * WPA_BSS_MASK_BEACON_INT | WPA_BSS_MASK_FREQ      | WPA_BSS_MASK_BSSID    | WPA_BSS_MASK_ID
    414      *
    415      * WPA_BSS_MASK_INTERNETW adds ANQP info (ctrl_iface:4151-4176)
    416      *
    417      * ctrl_iface.c:wpa_supplicant_ctrl_iface_process:7884
    418      *  wpa_supplicant_ctrl_iface_bss:4315
    419      *  print_bss_info
    420      */
    421     public String scanResults(int sid) {
    422         return doStringCommandWithoutLogging("BSS RANGE=" + sid + "- MASK=0x29d87");
    423     }
    424 
    425     public String doCustomCommand(String command) {
    426         return doStringCommand(command);
    427     }
    428 
    429     /**
    430      * Format of result:
    431      * id=1016
    432      * bssid=00:03:7f:40:84:10
    433      * freq=2462
    434      * beacon_int=200
    435      * capabilities=0x0431
    436      * qual=0
    437      * noise=0
    438      * level=-46
    439      * tsf=0000002669008476
    440      * age=5
    441      * ie=00105143412d485332302d52322d54455354010882848b960c12182403010b0706555...
    442      * flags=[WPA2-EAP-CCMP][ESS][P2P][HS20]
    443      * ssid=QCA-HS20-R2-TEST
    444      * p2p_device_name=
    445      * p2p_config_methods=0x0SET_NE
    446      * anqp_venue_name=02083d656e6757692d466920416c6c69616e63650a3239383920436f...
    447      * anqp_network_auth_type=010000
    448      * anqp_roaming_consortium=03506f9a05001bc504bd
    449      * anqp_ip_addr_type_availability=0c
    450      * anqp_nai_realm=0200300000246d61696c2e6578616d706c652e636f6d3b636973636f2...
    451      * anqp_3gpp=000600040132f465
    452      * anqp_domain_name=0b65786d61706c652e636f6d
    453      * hs20_operator_friendly_name=11656e6757692d466920416c6c69616e63650e636869...
    454      * hs20_wan_metrics=01c40900008001000000000a00
    455      * hs20_connection_capability=0100000006140001061600000650000106bb010106bb0...
    456      * hs20_osu_providers_list=0b5143412d4f53552d425353010901310015656e6757692d...
    457      */
    458     public String scanResult(String bssid) {
    459         return doStringCommand("BSS " + bssid);
    460     }
    461 
    462     /**
    463      * Format of command
    464      * DRIVER WLS_BATCHING SET SCANFREQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s
    465      * where x is an ascii representation of an integer number of seconds between scans
    466      *       r is an ascii representation of an integer number of scans per batch
    467      *       y is an ascii representation of an integer number of the max AP to remember per scan
    468      *       z, w, t represent a 1..n size list of channel numbers and/or 'A', 'B' values
    469      *           indicating entire ranges of channels
    470      *       s is an ascii representation of an integer number of highest-strength AP
    471      *           for which we'd like approximate distance reported
    472      *
    473      * The return value is an ascii integer representing a guess of the number of scans
    474      * the firmware can remember before it runs out of buffer space or -1 on error
    475      */
    476     public String setBatchedScanSettings(BatchedScanSettings settings) {
    477         if (settings == null) {
    478             return doStringCommand("DRIVER WLS_BATCHING STOP");
    479         }
    480         String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec;
    481         cmd += " MSCAN=" + settings.maxScansPerBatch;
    482         if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
    483             cmd += " BESTN=" + settings.maxApPerScan;
    484         }
    485         if (settings.channelSet != null && !settings.channelSet.isEmpty()) {
    486             cmd += " CHANNEL=<";
    487             int i = 0;
    488             for (String channel : settings.channelSet) {
    489                 cmd += (i > 0 ? "," : "") + channel;
    490                 ++i;
    491             }
    492             cmd += ">";
    493         }
    494         if (settings.maxApForDistance != BatchedScanSettings.UNSPECIFIED) {
    495             cmd += " RTT=" + settings.maxApForDistance;
    496         }
    497         return doStringCommand(cmd);
    498     }
    499 
    500     public String getBatchedScanResults() {
    501         return doStringCommand("DRIVER WLS_BATCHING GET");
    502     }
    503 
    504     public boolean startDriver() {
    505         return doBooleanCommand("DRIVER START");
    506     }
    507 
    508     public boolean stopDriver() {
    509         return doBooleanCommand("DRIVER STOP");
    510     }
    511 
    512 
    513     /**
    514      * Start filtering out Multicast V4 packets
    515      * @return {@code true} if the operation succeeded, {@code false} otherwise
    516      *
    517      * Multicast filtering rules work as follows:
    518      *
    519      * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
    520      * a power optimized mode (typically when screen goes off).
    521      *
    522      * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
    523      * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
    524      *
    525      * DRIVER RXFILTER-ADD Num
    526      *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
    527      *
    528      * and DRIVER RXFILTER-START
    529      * In order to stop the usage of these rules, we do
    530      *
    531      * DRIVER RXFILTER-STOP
    532      * DRIVER RXFILTER-REMOVE Num
    533      *   where Num is as described for RXFILTER-ADD
    534      *
    535      * The  SETSUSPENDOPT driver command overrides the filtering rules
    536      */
    537     public boolean startFilteringMulticastV4Packets() {
    538         return doBooleanCommand("DRIVER RXFILTER-STOP")
    539             && doBooleanCommand("DRIVER RXFILTER-REMOVE 2")
    540             && doBooleanCommand("DRIVER RXFILTER-START");
    541     }
    542 
    543     /**
    544      * Stop filtering out Multicast V4 packets.
    545      * @return {@code true} if the operation succeeded, {@code false} otherwise
    546      */
    547     public boolean stopFilteringMulticastV4Packets() {
    548         return doBooleanCommand("DRIVER RXFILTER-STOP")
    549             && doBooleanCommand("DRIVER RXFILTER-ADD 2")
    550             && doBooleanCommand("DRIVER RXFILTER-START");
    551     }
    552 
    553     /**
    554      * Start filtering out Multicast V6 packets
    555      * @return {@code true} if the operation succeeded, {@code false} otherwise
    556      */
    557     public boolean startFilteringMulticastV6Packets() {
    558         return doBooleanCommand("DRIVER RXFILTER-STOP")
    559             && doBooleanCommand("DRIVER RXFILTER-REMOVE 3")
    560             && doBooleanCommand("DRIVER RXFILTER-START");
    561     }
    562 
    563     /**
    564      * Stop filtering out Multicast V6 packets.
    565      * @return {@code true} if the operation succeeded, {@code false} otherwise
    566      */
    567     public boolean stopFilteringMulticastV6Packets() {
    568         return doBooleanCommand("DRIVER RXFILTER-STOP")
    569             && doBooleanCommand("DRIVER RXFILTER-ADD 3")
    570             && doBooleanCommand("DRIVER RXFILTER-START");
    571     }
    572 
    573     /**
    574      * Set the operational frequency band
    575      * @param band One of
    576      *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
    577      *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
    578      *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
    579      * @return {@code true} if the operation succeeded, {@code false} otherwise
    580      */
    581     public boolean setBand(int band) {
    582         String bandstr;
    583 
    584         if (band == WifiManager.WIFI_FREQUENCY_BAND_5GHZ)
    585             bandstr = "5G";
    586         else if (band == WifiManager.WIFI_FREQUENCY_BAND_2GHZ)
    587             bandstr = "2G";
    588         else
    589             bandstr = "AUTO";
    590         return doBooleanCommand("SET SETBAND " + bandstr);
    591     }
    592 
    593     /**
    594       * Sets the bluetooth coexistence mode.
    595       *
    596       * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
    597       *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
    598       *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
    599       * @return Whether the mode was successfully set.
    600       */
    601     public boolean setBluetoothCoexistenceMode(int mode) {
    602         return doBooleanCommand("DRIVER BTCOEXMODE " + mode);
    603     }
    604 
    605     /**
    606      * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
    607      * some of the low-level scan parameters used by the driver are changed to
    608      * reduce interference with A2DP streaming.
    609      *
    610      * @param isSet whether to enable or disable this mode
    611      * @return {@code true} if the command succeeded, {@code false} otherwise.
    612      */
    613     public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) {
    614         if (setCoexScanMode) {
    615             return doBooleanCommand("DRIVER BTCOEXSCAN-START");
    616         } else {
    617             return doBooleanCommand("DRIVER BTCOEXSCAN-STOP");
    618         }
    619     }
    620 
    621     public void enableSaveConfig() {
    622         doBooleanCommand("SET update_config 1");
    623     }
    624 
    625     public boolean saveConfig() {
    626         return doBooleanCommand("SAVE_CONFIG");
    627     }
    628 
    629     public boolean addToBlacklist(String bssid) {
    630         if (TextUtils.isEmpty(bssid)) return false;
    631         return doBooleanCommand("BLACKLIST " + bssid);
    632     }
    633 
    634     public boolean clearBlacklist() {
    635         return doBooleanCommand("BLACKLIST clear");
    636     }
    637 
    638     public boolean setSuspendOptimizations(boolean enabled) {
    639        // if (mSuspendOptEnabled == enabled) return true;
    640         mSuspendOptEnabled = enabled;
    641 
    642         Log.e("native", "do suspend " + enabled);
    643         if (enabled) {
    644             return doBooleanCommand("DRIVER SETSUSPENDMODE 1");
    645         } else {
    646             return doBooleanCommand("DRIVER SETSUSPENDMODE 0");
    647         }
    648     }
    649 
    650     public boolean setCountryCode(String countryCode) {
    651         if (countryCode != null)
    652             return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
    653         else
    654             return doBooleanCommand("DRIVER COUNTRY");
    655     }
    656 
    657     public boolean enableBackgroundScan(boolean enable) {
    658         boolean ret;
    659         if (enable) {
    660             ret = doBooleanCommand("SET pno 1");
    661         } else {
    662             ret = doBooleanCommand("SET pno 0");
    663         }
    664         return ret;
    665     }
    666 
    667     public void enableAutoConnect(boolean enable) {
    668         if (enable) {
    669             doBooleanCommand("STA_AUTOCONNECT 1");
    670         } else {
    671             doBooleanCommand("STA_AUTOCONNECT 0");
    672         }
    673     }
    674 
    675     public void setScanInterval(int scanInterval) {
    676         doBooleanCommand("SCAN_INTERVAL " + scanInterval);
    677     }
    678 
    679     public void startTdls(String macAddr, boolean enable) {
    680         if (enable) {
    681             doBooleanCommand("TDLS_DISCOVER " + macAddr);
    682             doBooleanCommand("TDLS_SETUP " + macAddr);
    683         } else {
    684             doBooleanCommand("TDLS_TEARDOWN " + macAddr);
    685         }
    686     }
    687 
    688     /** Example output:
    689      * RSSI=-65
    690      * LINKSPEED=48
    691      * NOISE=9999
    692      * FREQUENCY=0
    693      */
    694     public String signalPoll() {
    695         return doStringCommandWithoutLogging("SIGNAL_POLL");
    696     }
    697 
    698     /** Example outout:
    699      * TXGOOD=396
    700      * TXBAD=1
    701      */
    702     public String pktcntPoll() {
    703         return doStringCommand("PKTCNT_POLL");
    704     }
    705 
    706     public void bssFlush() {
    707         doBooleanCommand("BSS_FLUSH 0");
    708     }
    709 
    710     public boolean startWpsPbc(String bssid) {
    711         if (TextUtils.isEmpty(bssid)) {
    712             return doBooleanCommand("WPS_PBC");
    713         } else {
    714             return doBooleanCommand("WPS_PBC " + bssid);
    715         }
    716     }
    717 
    718     public boolean startWpsPbc(String iface, String bssid) {
    719         synchronized (mLock) {
    720             if (TextUtils.isEmpty(bssid)) {
    721                 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
    722             } else {
    723                 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
    724             }
    725         }
    726     }
    727 
    728     public boolean startWpsPinKeypad(String pin) {
    729         if (TextUtils.isEmpty(pin)) return false;
    730         return doBooleanCommand("WPS_PIN any " + pin);
    731     }
    732 
    733     public boolean startWpsPinKeypad(String iface, String pin) {
    734         if (TextUtils.isEmpty(pin)) return false;
    735         synchronized (mLock) {
    736             return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
    737         }
    738     }
    739 
    740 
    741     public String startWpsPinDisplay(String bssid) {
    742         if (TextUtils.isEmpty(bssid)) {
    743             return doStringCommand("WPS_PIN any");
    744         } else {
    745             return doStringCommand("WPS_PIN " + bssid);
    746         }
    747     }
    748 
    749     public String startWpsPinDisplay(String iface, String bssid) {
    750         synchronized (mLock) {
    751             if (TextUtils.isEmpty(bssid)) {
    752                 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
    753             } else {
    754                 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
    755             }
    756         }
    757     }
    758 
    759     public boolean setExternalSim(boolean external) {
    760         synchronized (mLock) {
    761             String value = external ? "1" : "0";
    762             Log.d(TAG, "Setting external_sim to " + value);
    763             return doBooleanCommand("SET external_sim " + value);
    764         }
    765     }
    766 
    767     public boolean simAuthResponse(int id, String type, String response) {
    768         // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS
    769         synchronized (mLock) {
    770             return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response);
    771         }
    772     }
    773 
    774     public boolean simIdentityResponse(int id, String response) {
    775         synchronized (mLock) {
    776             return doBooleanCommand("CTRL-RSP-IDENTITY-" + id + ":" + response);
    777         }
    778     }
    779 
    780     /* Configures an access point connection */
    781     public boolean startWpsRegistrar(String bssid, String pin) {
    782         if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false;
    783         return doBooleanCommand("WPS_REG " + bssid + " " + pin);
    784     }
    785 
    786     public boolean cancelWps() {
    787         return doBooleanCommand("WPS_CANCEL");
    788     }
    789 
    790     public boolean setPersistentReconnect(boolean enabled) {
    791         int value = (enabled == true) ? 1 : 0;
    792         return doBooleanCommand("SET persistent_reconnect " + value);
    793     }
    794 
    795     public boolean setDeviceName(String name) {
    796         return doBooleanCommand("SET device_name " + name);
    797     }
    798 
    799     public boolean setDeviceType(String type) {
    800         return doBooleanCommand("SET device_type " + type);
    801     }
    802 
    803     public boolean setConfigMethods(String cfg) {
    804         return doBooleanCommand("SET config_methods " + cfg);
    805     }
    806 
    807     public boolean setManufacturer(String value) {
    808         return doBooleanCommand("SET manufacturer " + value);
    809     }
    810 
    811     public boolean setModelName(String value) {
    812         return doBooleanCommand("SET model_name " + value);
    813     }
    814 
    815     public boolean setModelNumber(String value) {
    816         return doBooleanCommand("SET model_number " + value);
    817     }
    818 
    819     public boolean setSerialNumber(String value) {
    820         return doBooleanCommand("SET serial_number " + value);
    821     }
    822 
    823     public boolean setP2pSsidPostfix(String postfix) {
    824         return doBooleanCommand("SET p2p_ssid_postfix " + postfix);
    825     }
    826 
    827     public boolean setP2pGroupIdle(String iface, int time) {
    828         synchronized (mLock) {
    829             return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
    830         }
    831     }
    832 
    833     public void setPowerSave(boolean enabled) {
    834         if (enabled) {
    835             doBooleanCommand("SET ps 1");
    836         } else {
    837             doBooleanCommand("SET ps 0");
    838         }
    839     }
    840 
    841     public boolean setP2pPowerSave(String iface, boolean enabled) {
    842         synchronized (mLock) {
    843             if (enabled) {
    844                 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
    845             } else {
    846                 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
    847             }
    848         }
    849     }
    850 
    851     public boolean setWfdEnable(boolean enable) {
    852         return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0"));
    853     }
    854 
    855     public boolean setWfdDeviceInfo(String hex) {
    856         return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex);
    857     }
    858 
    859     /**
    860      * "sta" prioritizes STA connection over P2P and "p2p" prioritizes
    861      * P2P connection over STA
    862      */
    863     public boolean setConcurrencyPriority(String s) {
    864         return doBooleanCommand("P2P_SET conc_pref " + s);
    865     }
    866 
    867     public boolean p2pFind() {
    868         return doBooleanCommand("P2P_FIND");
    869     }
    870 
    871     public boolean p2pFind(int timeout) {
    872         if (timeout <= 0) {
    873             return p2pFind();
    874         }
    875         return doBooleanCommand("P2P_FIND " + timeout);
    876     }
    877 
    878     public boolean p2pStopFind() {
    879        return doBooleanCommand("P2P_STOP_FIND");
    880     }
    881 
    882     public boolean p2pListen() {
    883         return doBooleanCommand("P2P_LISTEN");
    884     }
    885 
    886     public boolean p2pListen(int timeout) {
    887         if (timeout <= 0) {
    888             return p2pListen();
    889         }
    890         return doBooleanCommand("P2P_LISTEN " + timeout);
    891     }
    892 
    893     public boolean p2pExtListen(boolean enable, int period, int interval) {
    894         if (enable && interval < period) {
    895             return false;
    896         }
    897         return doBooleanCommand("P2P_EXT_LISTEN"
    898                     + (enable ? (" " + period + " " + interval) : ""));
    899     }
    900 
    901     public boolean p2pSetChannel(int lc, int oc) {
    902         if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc);
    903 
    904         if (lc >=1 && lc <= 11) {
    905             if (!doBooleanCommand("P2P_SET listen_channel " + lc)) {
    906                 return false;
    907             }
    908         } else if (lc != 0) {
    909             return false;
    910         }
    911 
    912         if (oc >= 1 && oc <= 165 ) {
    913             int freq = (oc <= 14 ? 2407 : 5000) + oc * 5;
    914             return doBooleanCommand("P2P_SET disallow_freq 1000-"
    915                     + (freq - 5) + "," + (freq + 5) + "-6000");
    916         } else if (oc == 0) {
    917             /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */
    918             return doBooleanCommand("P2P_SET disallow_freq \"\"");
    919         }
    920 
    921         return false;
    922     }
    923 
    924     public boolean p2pFlush() {
    925         return doBooleanCommand("P2P_FLUSH");
    926     }
    927 
    928     /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad]
    929         [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */
    930     public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) {
    931         if (config == null) return null;
    932         List<String> args = new ArrayList<String>();
    933         WpsInfo wps = config.wps;
    934         args.add(config.deviceAddress);
    935 
    936         switch (wps.setup) {
    937             case WpsInfo.PBC:
    938                 args.add("pbc");
    939                 break;
    940             case WpsInfo.DISPLAY:
    941                 if (TextUtils.isEmpty(wps.pin)) {
    942                     args.add("pin");
    943                 } else {
    944                     args.add(wps.pin);
    945                 }
    946                 args.add("display");
    947                 break;
    948             case WpsInfo.KEYPAD:
    949                 args.add(wps.pin);
    950                 args.add("keypad");
    951                 break;
    952             case WpsInfo.LABEL:
    953                 args.add(wps.pin);
    954                 args.add("label");
    955             default:
    956                 break;
    957         }
    958 
    959         if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) {
    960             args.add("persistent");
    961         }
    962 
    963         if (joinExistingGroup) {
    964             args.add("join");
    965         } else {
    966             //TODO: This can be adapted based on device plugged in state and
    967             //device battery state
    968             int groupOwnerIntent = config.groupOwnerIntent;
    969             if (groupOwnerIntent < 0 || groupOwnerIntent > 15) {
    970                 groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT;
    971             }
    972             args.add("go_intent=" + groupOwnerIntent);
    973         }
    974 
    975         String command = "P2P_CONNECT ";
    976         for (String s : args) command += s + " ";
    977 
    978         return doStringCommand(command);
    979     }
    980 
    981     public boolean p2pCancelConnect() {
    982         return doBooleanCommand("P2P_CANCEL");
    983     }
    984 
    985     public boolean p2pProvisionDiscovery(WifiP2pConfig config) {
    986         if (config == null) return false;
    987 
    988         switch (config.wps.setup) {
    989             case WpsInfo.PBC:
    990                 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc");
    991             case WpsInfo.DISPLAY:
    992                 //We are doing display, so provision discovery is keypad
    993                 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad");
    994             case WpsInfo.KEYPAD:
    995                 //We are doing keypad, so provision discovery is display
    996                 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display");
    997             default:
    998                 break;
    999         }
   1000         return false;
   1001     }
   1002 
   1003     public boolean p2pGroupAdd(boolean persistent) {
   1004         if (persistent) {
   1005             return doBooleanCommand("P2P_GROUP_ADD persistent");
   1006         }
   1007         return doBooleanCommand("P2P_GROUP_ADD");
   1008     }
   1009 
   1010     public boolean p2pGroupAdd(int netId) {
   1011         return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId);
   1012     }
   1013 
   1014     public boolean p2pGroupRemove(String iface) {
   1015         if (TextUtils.isEmpty(iface)) return false;
   1016         synchronized (mLock) {
   1017             return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
   1018         }
   1019     }
   1020 
   1021     public boolean p2pReject(String deviceAddress) {
   1022         return doBooleanCommand("P2P_REJECT " + deviceAddress);
   1023     }
   1024 
   1025     /* Invite a peer to a group */
   1026     public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) {
   1027         if (TextUtils.isEmpty(deviceAddress)) return false;
   1028 
   1029         if (group == null) {
   1030             return doBooleanCommand("P2P_INVITE peer=" + deviceAddress);
   1031         } else {
   1032             return doBooleanCommand("P2P_INVITE group=" + group.getInterface()
   1033                     + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress);
   1034         }
   1035     }
   1036 
   1037     /* Reinvoke a persistent connection */
   1038     public boolean p2pReinvoke(int netId, String deviceAddress) {
   1039         if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false;
   1040 
   1041         return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress);
   1042     }
   1043 
   1044     public String p2pGetSsid(String deviceAddress) {
   1045         return p2pGetParam(deviceAddress, "oper_ssid");
   1046     }
   1047 
   1048     public String p2pGetDeviceAddress() {
   1049 
   1050         Log.d(TAG, "p2pGetDeviceAddress");
   1051 
   1052         String status = null;
   1053 
   1054         /* Explicitly calling the API without IFNAME= prefix to take care of the devices that
   1055         don't have p2p0 interface. Supplicant seems to be returning the correct address anyway. */
   1056 
   1057         synchronized (mLock) {
   1058             status = doStringCommandNative("STATUS");
   1059         }
   1060 
   1061         String result = "";
   1062         if (status != null) {
   1063             String[] tokens = status.split("\n");
   1064             for (String token : tokens) {
   1065                 if (token.startsWith("p2p_device_address=")) {
   1066                     String[] nameValue = token.split("=");
   1067                     if (nameValue.length != 2)
   1068                         break;
   1069                     result = nameValue[1];
   1070                 }
   1071             }
   1072         }
   1073 
   1074         Log.d(TAG, "p2pGetDeviceAddress returning " + result);
   1075         return result;
   1076     }
   1077 
   1078     public int getGroupCapability(String deviceAddress) {
   1079         int gc = 0;
   1080         if (TextUtils.isEmpty(deviceAddress)) return gc;
   1081         String peerInfo = p2pPeer(deviceAddress);
   1082         if (TextUtils.isEmpty(peerInfo)) return gc;
   1083 
   1084         String[] tokens = peerInfo.split("\n");
   1085         for (String token : tokens) {
   1086             if (token.startsWith("group_capab=")) {
   1087                 String[] nameValue = token.split("=");
   1088                 if (nameValue.length != 2) break;
   1089                 try {
   1090                     return Integer.decode(nameValue[1]);
   1091                 } catch(NumberFormatException e) {
   1092                     return gc;
   1093                 }
   1094             }
   1095         }
   1096         return gc;
   1097     }
   1098 
   1099     public String p2pPeer(String deviceAddress) {
   1100         return doStringCommand("P2P_PEER " + deviceAddress);
   1101     }
   1102 
   1103     private String p2pGetParam(String deviceAddress, String key) {
   1104         if (deviceAddress == null) return null;
   1105 
   1106         String peerInfo = p2pPeer(deviceAddress);
   1107         if (peerInfo == null) return null;
   1108         String[] tokens= peerInfo.split("\n");
   1109 
   1110         key += "=";
   1111         for (String token : tokens) {
   1112             if (token.startsWith(key)) {
   1113                 String[] nameValue = token.split("=");
   1114                 if (nameValue.length != 2) break;
   1115                 return nameValue[1];
   1116             }
   1117         }
   1118         return null;
   1119     }
   1120 
   1121     public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) {
   1122         /*
   1123          * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump>
   1124          * P2P_SERVICE_ADD upnp <version hex> <service>
   1125          *
   1126          * e.g)
   1127          * [Bonjour]
   1128          * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.)
   1129          * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027
   1130          * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript)
   1131          * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001
   1132          *  09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074
   1133          *
   1134          * [UPnP]
   1135          * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
   1136          * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice
   1137          * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp
   1138          * -org:device:InternetGatewayDevice:1
   1139          * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp
   1140          * -org:service:ContentDirectory:2
   1141          */
   1142         for (String s : servInfo.getSupplicantQueryList()) {
   1143             String command = "P2P_SERVICE_ADD";
   1144             command += (" " + s);
   1145             if (!doBooleanCommand(command)) {
   1146                 return false;
   1147             }
   1148         }
   1149         return true;
   1150     }
   1151 
   1152     public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) {
   1153         /*
   1154          * P2P_SERVICE_DEL bonjour <query hexdump>
   1155          * P2P_SERVICE_DEL upnp <version hex> <service>
   1156          */
   1157         for (String s : servInfo.getSupplicantQueryList()) {
   1158             String command = "P2P_SERVICE_DEL ";
   1159 
   1160             String[] data = s.split(" ");
   1161             if (data.length < 2) {
   1162                 return false;
   1163             }
   1164             if ("upnp".equals(data[0])) {
   1165                 command += s;
   1166             } else if ("bonjour".equals(data[0])) {
   1167                 command += data[0];
   1168                 command += (" " + data[1]);
   1169             } else {
   1170                 return false;
   1171             }
   1172             if (!doBooleanCommand(command)) {
   1173                 return false;
   1174             }
   1175         }
   1176         return true;
   1177     }
   1178 
   1179     public boolean p2pServiceFlush() {
   1180         return doBooleanCommand("P2P_SERVICE_FLUSH");
   1181     }
   1182 
   1183     public String p2pServDiscReq(String addr, String query) {
   1184         String command = "P2P_SERV_DISC_REQ";
   1185         command += (" " + addr);
   1186         command += (" " + query);
   1187 
   1188         return doStringCommand(command);
   1189     }
   1190 
   1191     public boolean p2pServDiscCancelReq(String id) {
   1192         return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id);
   1193     }
   1194 
   1195     /* Set the current mode of miracast operation.
   1196      *  0 = disabled
   1197      *  1 = operating as source
   1198      *  2 = operating as sink
   1199      */
   1200     public void setMiracastMode(int mode) {
   1201         // Note: optional feature on the driver. It is ok for this to fail.
   1202         doBooleanCommand("DRIVER MIRACAST " + mode);
   1203     }
   1204 
   1205     public boolean fetchAnqp(String bssid, String subtypes) {
   1206         return doBooleanCommand("ANQP_GET " + bssid + " " + subtypes);
   1207     }
   1208 
   1209     /*
   1210      * NFC-related calls
   1211      */
   1212     public String getNfcWpsConfigurationToken(int netId) {
   1213         return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId);
   1214     }
   1215 
   1216     public String getNfcHandoverRequest() {
   1217         return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR");
   1218     }
   1219 
   1220     public String getNfcHandoverSelect() {
   1221         return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR");
   1222     }
   1223 
   1224     public boolean initiatorReportNfcHandover(String selectMessage) {
   1225         return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage);
   1226     }
   1227 
   1228     public boolean responderReportNfcHandover(String requestMessage) {
   1229         return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00");
   1230     }
   1231 
   1232     /* WIFI HAL support */
   1233 
   1234     private static final String TAG = "WifiNative-HAL";
   1235     private static long sWifiHalHandle = 0;             /* used by JNI to save wifi_handle */
   1236     private static long[] sWifiIfaceHandles = null;     /* used by JNI to save interface handles */
   1237     private static int sWlan0Index = -1;
   1238     private static int sP2p0Index = -1;
   1239     private static MonitorThread sThread;
   1240     private static final int STOP_HAL_TIMEOUT_MS = 1000;
   1241 
   1242     private static native boolean startHalNative();
   1243     private static native void stopHalNative();
   1244     private static native void waitForHalEventNative();
   1245 
   1246     private static class MonitorThread extends Thread {
   1247         public void run() {
   1248             Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle));
   1249             waitForHalEventNative();
   1250         }
   1251     }
   1252 
   1253     synchronized public static boolean startHal() {
   1254 
   1255         String debugLog = "startHal stack: ";
   1256         java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace();
   1257         for (int i = 2; i < elements.length && i <= 7; i++ ) {
   1258             debugLog = debugLog + " - " + elements[i].getMethodName();
   1259         }
   1260 
   1261         mLocalLog.log(debugLog);
   1262 
   1263         synchronized (mLock) {
   1264             if (startHalNative() && (getInterfaces() != 0) && (sWlan0Index != -1)) {
   1265                 sThread = new MonitorThread();
   1266                 sThread.start();
   1267                 return true;
   1268             } else {
   1269                 if (DBG) mLocalLog.log("Could not start hal");
   1270                 Log.e(TAG, "Could not start hal");
   1271                 return false;
   1272             }
   1273         }
   1274     }
   1275 
   1276     synchronized public static void stopHal() {
   1277         synchronized (mLock) {
   1278             if (isHalStarted()) {
   1279                 stopHalNative();
   1280                 try {
   1281                     sThread.join(STOP_HAL_TIMEOUT_MS);
   1282                     Log.d(TAG, "HAL event thread stopped successfully");
   1283                 } catch (InterruptedException e) {
   1284                     Log.e(TAG, "Could not stop HAL cleanly");
   1285                 }
   1286                 sThread = null;
   1287                 sWifiHalHandle = 0;
   1288                 sWifiIfaceHandles = null;
   1289                 sWlan0Index = -1;
   1290                 sP2p0Index = -1;
   1291             }
   1292         }
   1293     }
   1294 
   1295     public static boolean isHalStarted() {
   1296         return (sWifiHalHandle != 0);
   1297     }
   1298     private static native int getInterfacesNative();
   1299 
   1300     synchronized public static int getInterfaces() {
   1301         synchronized (mLock) {
   1302             if (isHalStarted()) {
   1303                 if (sWifiIfaceHandles == null) {
   1304                     int num = getInterfacesNative();
   1305                     int wifi_num = 0;
   1306                     for (int i = 0; i < num; i++) {
   1307                         String name = getInterfaceNameNative(i);
   1308                         Log.i(TAG, "interface[" + i + "] = " + name);
   1309                         if (name.equals("wlan0")) {
   1310                             sWlan0Index = i;
   1311                             wifi_num++;
   1312                         } else if (name.equals("p2p0")) {
   1313                             sP2p0Index = i;
   1314                             wifi_num++;
   1315                         }
   1316                     }
   1317                     return wifi_num;
   1318                 } else {
   1319                     return sWifiIfaceHandles.length;
   1320                 }
   1321             } else {
   1322                 return 0;
   1323             }
   1324         }
   1325     }
   1326 
   1327     private static native String getInterfaceNameNative(int index);
   1328     synchronized public static String getInterfaceName(int index) {
   1329         return getInterfaceNameNative(index);
   1330     }
   1331 
   1332     public static class ScanCapabilities {
   1333         public int  max_scan_cache_size;                 // in number of scan results??
   1334         public int  max_scan_buckets;
   1335         public int  max_ap_cache_per_scan;
   1336         public int  max_rssi_sample_size;
   1337         public int  max_scan_reporting_threshold;        // in number of scan results??
   1338         public int  max_hotlist_bssids;
   1339         public int  max_significant_wifi_change_aps;
   1340     }
   1341 
   1342     synchronized public static boolean getScanCapabilities(ScanCapabilities capabilities) {
   1343         synchronized (mLock) {
   1344             return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities);
   1345         }
   1346     }
   1347 
   1348     private static native boolean getScanCapabilitiesNative(
   1349             int iface, ScanCapabilities capabilities);
   1350 
   1351     private static native boolean startScanNative(int iface, int id, ScanSettings settings);
   1352     private static native boolean stopScanNative(int iface, int id);
   1353     private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush);
   1354     private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface);
   1355     private static native void setWifiLinkLayerStatsNative(int iface, int enable);
   1356 
   1357     public static class ChannelSettings {
   1358         int frequency;
   1359         int dwell_time_ms;
   1360         boolean passive;
   1361     }
   1362 
   1363     public static class BucketSettings {
   1364         int bucket;
   1365         int band;
   1366         int period_ms;
   1367         int report_events;
   1368         int num_channels;
   1369         ChannelSettings channels[];
   1370     }
   1371 
   1372     public static class ScanSettings {
   1373         int base_period_ms;
   1374         int max_ap_per_scan;
   1375         int report_threshold_percent;
   1376         int report_threshold_num_scans;
   1377         int num_buckets;
   1378         BucketSettings buckets[];
   1379     }
   1380 
   1381     public static interface ScanEventHandler {
   1382         void onScanResultsAvailable();
   1383         void onFullScanResult(ScanResult fullScanResult);
   1384         void onScanStatus();
   1385         void onScanPaused(WifiScanner.ScanData[] data);
   1386         void onScanRestarted();
   1387     }
   1388 
   1389     synchronized static void onScanResultsAvailable(int id) {
   1390         if (sScanEventHandler  != null) {
   1391             sScanEventHandler.onScanResultsAvailable();
   1392         }
   1393     }
   1394 
   1395     /* scan status, keep these values in sync with gscan.h */
   1396     private static int WIFI_SCAN_BUFFER_FULL = 0;
   1397     private static int WIFI_SCAN_COMPLETE = 1;
   1398 
   1399     synchronized static void onScanStatus(int status) {
   1400         if (status == WIFI_SCAN_BUFFER_FULL) {
   1401             /* we have a separate event to take care of this */
   1402         } else if (status == WIFI_SCAN_COMPLETE) {
   1403             if (sScanEventHandler  != null) {
   1404                 sScanEventHandler.onScanStatus();
   1405             }
   1406         }
   1407     }
   1408 
   1409     public static  WifiSsid createWifiSsid (byte[] rawSsid) {
   1410         String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid));
   1411 
   1412         if (ssidHexString == null) {
   1413             return null;
   1414         }
   1415 
   1416         WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString);
   1417 
   1418         return wifiSsid;
   1419     }
   1420 
   1421     public static String ssidConvert(byte[] rawSsid) {
   1422         String ssid;
   1423 
   1424         CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
   1425         try {
   1426             CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid));
   1427             ssid = decoded.toString();
   1428         } catch (CharacterCodingException cce) {
   1429             ssid = null;
   1430         }
   1431 
   1432         if (ssid == null) {
   1433             ssid = new String(rawSsid, StandardCharsets.ISO_8859_1);
   1434         }
   1435 
   1436         return ssid;
   1437     }
   1438 
   1439     public static boolean setSsid(byte[] rawSsid, ScanResult result) {
   1440         if (rawSsid == null || rawSsid.length == 0 || result == null) {
   1441             return false;
   1442         }
   1443 
   1444         result.SSID = ssidConvert(rawSsid);
   1445         result.wifiSsid = createWifiSsid(rawSsid);
   1446         return true;
   1447     }
   1448 
   1449     static void populateScanResult(ScanResult result, byte bytes[], String dbg) {
   1450         int num = 0;
   1451         if (bytes == null) return;
   1452         if (dbg == null) dbg = "";
   1453         for (int i = 0; i < bytes.length - 1; ) {
   1454             int type  = bytes[i] & 0xFF;
   1455             int len = bytes[i + 1] & 0xFF;
   1456             if (i + len + 2 > bytes.length) {
   1457                 Log.w(TAG, dbg + "bad length " + len + " of IE " + type + " from " + result.BSSID);
   1458                 Log.w(TAG, dbg + "ignoring the rest of the IEs");
   1459                 break;
   1460             }
   1461             num++;
   1462             if (DBG) Log.i(TAG, dbg + "bytes[" + i + "] = [" + type + ", " + len + "]" + ", " +
   1463                     "next = " + (i + len + 2));
   1464             i += len + 2;
   1465         }
   1466 
   1467         int secondChanelOffset = 0;
   1468         byte channelMode = 0;
   1469         byte centerFreqIndex1 = 0;
   1470         byte centerFreqIndex2 = 0;
   1471 
   1472         boolean is80211McRTTResponder = false;
   1473 
   1474         ScanResult.InformationElement elements[] = new ScanResult.InformationElement[num];
   1475         for (int i = 0, index = 0; i < num; i++) {
   1476             int type  = bytes[index] & 0xFF;
   1477             int len = bytes[index + 1] & 0xFF;
   1478             if (DBG) Log.i(TAG, dbg + "index = " + index + ", type = " + type + ", len = " + len);
   1479             ScanResult.InformationElement elem = new ScanResult.InformationElement();
   1480             elem.id = type;
   1481             elem.bytes = new byte[len];
   1482             for (int j = 0; j < len; j++) {
   1483                 elem.bytes[j] = bytes[index + j + 2];
   1484             }
   1485             elements[i] = elem;
   1486             int inforStart = index + 2;
   1487             index += (len + 2);
   1488 
   1489             if(type == EID_HT_OPERATION) {
   1490                 secondChanelOffset = bytes[inforStart + 1] & 0x3;
   1491             } else if(type == EID_VHT_OPERATION) {
   1492                 channelMode = bytes[inforStart];
   1493                 centerFreqIndex1 = bytes[inforStart + 1];
   1494                 centerFreqIndex2 = bytes[inforStart + 2];
   1495             } else if (type == EID_EXTENDED_CAPS) {
   1496                 int tempIndex = RTT_RESP_ENABLE_BIT / 8;
   1497                 byte offset = RTT_RESP_ENABLE_BIT % 8;
   1498 
   1499                 if(len < tempIndex + 1) {
   1500                     is80211McRTTResponder = false;
   1501                 } else {
   1502                     if ((bytes[inforStart + tempIndex] & ((byte)0x1 << offset)) != 0) {
   1503                         is80211McRTTResponder = true;
   1504                     } else {
   1505                         is80211McRTTResponder = false;
   1506                     }
   1507                 }
   1508             }
   1509         }
   1510 
   1511         if (is80211McRTTResponder) {
   1512             result.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
   1513         } else {
   1514             result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER);
   1515         }
   1516 
   1517         //handle RTT related information
   1518         if (channelMode != 0) {
   1519             // 80 or 160 MHz
   1520             result.channelWidth = channelMode + 1;
   1521 
   1522             //convert channel index to frequency in MHz, channel 36 is 5180MHz
   1523             result.centerFreq0 = (centerFreqIndex1 - 36) * 5 + 5180;
   1524 
   1525             if(channelMode > 1) { //160MHz
   1526                 result.centerFreq1 = (centerFreqIndex2 - 36) * 5 + 5180;
   1527             } else {
   1528                 result.centerFreq1 = 0;
   1529             }
   1530         } else {
   1531             //20 or 40 MHz
   1532             if (secondChanelOffset != 0) {//40MHz
   1533                 result.channelWidth = 1;
   1534                 if (secondChanelOffset == 1) {
   1535                     result.centerFreq0 = result.frequency + 20;
   1536                 } else if (secondChanelOffset == 3) {
   1537                     result.centerFreq0 = result.frequency - 20;
   1538                 } else {
   1539                     result.centerFreq0 = 0;
   1540                     Log.e(TAG, dbg + ": Error on secondChanelOffset");
   1541                 }
   1542             } else {
   1543                 result.centerFreq0  = 0;
   1544                 result.centerFreq1  = 0;
   1545             }
   1546             result.centerFreq1  = 0;
   1547         }
   1548         if(DBG) {
   1549             Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth +
   1550                     " PrimaryFreq: " + result.frequency +" mCenterfreq0: " + result.centerFreq0 +
   1551                     " mCenterfreq1: " + result.centerFreq1 + (is80211McRTTResponder ?
   1552                     "Support RTT reponder: " : "Do not support RTT responder"));
   1553         }
   1554 
   1555         result.informationElements = elements;
   1556     }
   1557 
   1558     synchronized static void onFullScanResult(int id, ScanResult result, byte bytes[]) {
   1559         if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID + ", " +
   1560                 "num = " + bytes.length);
   1561 
   1562         if (sScanEventHandler == null) {
   1563             return;
   1564         }
   1565         populateScanResult(result, bytes, " onFullScanResult ");
   1566 
   1567         sScanEventHandler.onFullScanResult(result);
   1568     }
   1569 
   1570     private static int sScanCmdId = 0;
   1571     private static ScanEventHandler sScanEventHandler;
   1572     private static ScanSettings sScanSettings;
   1573 
   1574     synchronized public static boolean startScan(
   1575             ScanSettings settings, ScanEventHandler eventHandler) {
   1576         synchronized (mLock) {
   1577             if (isHalStarted()) {
   1578 
   1579                 if (sScanCmdId != 0) {
   1580                     stopScan();
   1581                 } else if (sScanSettings != null || sScanEventHandler != null) {
   1582                 /* current scan is paused; no need to stop it */
   1583                 }
   1584 
   1585                 sScanCmdId = getNewCmdIdLocked();
   1586 
   1587                 sScanSettings = settings;
   1588                 sScanEventHandler = eventHandler;
   1589 
   1590                 if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) {
   1591                     sScanEventHandler = null;
   1592                     sScanSettings = null;
   1593                     sScanCmdId = 0;
   1594                     return false;
   1595                 }
   1596 
   1597                 return true;
   1598             } else {
   1599                 return false;
   1600             }
   1601         }
   1602     }
   1603 
   1604     synchronized public static void stopScan() {
   1605         synchronized (mLock) {
   1606             if (isHalStarted()) {
   1607                 stopScanNative(sWlan0Index, sScanCmdId);
   1608                 sScanSettings = null;
   1609                 sScanEventHandler = null;
   1610                 sScanCmdId = 0;
   1611             }
   1612         }
   1613     }
   1614 
   1615     synchronized public static void pauseScan() {
   1616         synchronized (mLock) {
   1617             if (isHalStarted()) {
   1618                 if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) {
   1619                     Log.d(TAG, "Pausing scan");
   1620                     WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true);
   1621                     stopScanNative(sWlan0Index, sScanCmdId);
   1622                     sScanCmdId = 0;
   1623                     sScanEventHandler.onScanPaused(scanData);
   1624                 }
   1625             }
   1626         }
   1627     }
   1628 
   1629     synchronized public static void restartScan() {
   1630         synchronized (mLock) {
   1631             if (isHalStarted()) {
   1632                 if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) {
   1633                     Log.d(TAG, "Restarting scan");
   1634                     ScanEventHandler handler = sScanEventHandler;
   1635                     ScanSettings settings = sScanSettings;
   1636                     if (startScan(sScanSettings, sScanEventHandler)) {
   1637                         sScanEventHandler.onScanRestarted();
   1638                     } else {
   1639                     /* we are still paused; don't change state */
   1640                         sScanEventHandler = handler;
   1641                         sScanSettings = settings;
   1642                     }
   1643                 }
   1644             }
   1645         }
   1646     }
   1647 
   1648     synchronized public static WifiScanner.ScanData[] getScanResults(boolean flush) {
   1649         synchronized (mLock) {
   1650             if (isHalStarted()) {
   1651                 return getScanResultsNative(sWlan0Index, flush);
   1652             } else {
   1653                 return null;
   1654             }
   1655         }
   1656     }
   1657 
   1658     public static interface HotlistEventHandler {
   1659         void onHotlistApFound (ScanResult[] result);
   1660         void onHotlistApLost  (ScanResult[] result);
   1661     }
   1662 
   1663     private static int sHotlistCmdId = 0;
   1664     private static HotlistEventHandler sHotlistEventHandler;
   1665 
   1666     private native static boolean setHotlistNative(int iface, int id,
   1667             WifiScanner.HotlistSettings settings);
   1668     private native static boolean resetHotlistNative(int iface, int id);
   1669 
   1670     synchronized public static boolean setHotlist(WifiScanner.HotlistSettings settings,
   1671                                     HotlistEventHandler eventHandler) {
   1672         synchronized (mLock) {
   1673             if (isHalStarted()) {
   1674                 if (sHotlistCmdId != 0) {
   1675                     return false;
   1676                 } else {
   1677                     sHotlistCmdId = getNewCmdIdLocked();
   1678                 }
   1679 
   1680                 sHotlistEventHandler = eventHandler;
   1681                 if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) {
   1682                     sHotlistEventHandler = null;
   1683                     return false;
   1684                 }
   1685 
   1686                 return true;
   1687             } else {
   1688                 return false;
   1689             }
   1690         }
   1691     }
   1692 
   1693     synchronized public static void resetHotlist() {
   1694         synchronized (mLock) {
   1695             if (isHalStarted()) {
   1696                 if (sHotlistCmdId != 0) {
   1697                     resetHotlistNative(sWlan0Index, sHotlistCmdId);
   1698                     sHotlistCmdId = 0;
   1699                     sHotlistEventHandler = null;
   1700                 }
   1701             }
   1702         }
   1703     }
   1704 
   1705     synchronized public static void onHotlistApFound(int id, ScanResult[] results) {
   1706         synchronized (mLock) {
   1707             if (isHalStarted()) {
   1708                 if (sHotlistCmdId != 0) {
   1709                     sHotlistEventHandler.onHotlistApFound(results);
   1710                 } else {
   1711                 /* this can happen because of race conditions */
   1712                     Log.d(TAG, "Ignoring hotlist AP found event");
   1713                 }
   1714             }
   1715         }
   1716     }
   1717 
   1718     synchronized public static void onHotlistApLost(int id, ScanResult[] results) {
   1719         synchronized (mLock) {
   1720             if (isHalStarted()) {
   1721                 if (sHotlistCmdId != 0) {
   1722                     sHotlistEventHandler.onHotlistApLost(results);
   1723                 } else {
   1724                 /* this can happen because of race conditions */
   1725                     Log.d(TAG, "Ignoring hotlist AP lost event");
   1726                 }
   1727             }
   1728         }
   1729     }
   1730 
   1731     public static interface SignificantWifiChangeEventHandler {
   1732         void onChangesFound(ScanResult[] result);
   1733     }
   1734 
   1735     private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler;
   1736     private static int sSignificantWifiChangeCmdId;
   1737 
   1738     private static native boolean trackSignificantWifiChangeNative(
   1739             int iface, int id, WifiScanner.WifiChangeSettings settings);
   1740     private static native boolean untrackSignificantWifiChangeNative(int iface, int id);
   1741 
   1742     synchronized public static boolean trackSignificantWifiChange(
   1743             WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
   1744         synchronized (mLock) {
   1745             if (isHalStarted()) {
   1746                 if (sSignificantWifiChangeCmdId != 0) {
   1747                     return false;
   1748                 } else {
   1749                     sSignificantWifiChangeCmdId = getNewCmdIdLocked();
   1750                 }
   1751 
   1752                 sSignificantWifiChangeHandler = handler;
   1753                 if (trackSignificantWifiChangeNative(sWlan0Index, sScanCmdId, settings) == false) {
   1754                     sSignificantWifiChangeHandler = null;
   1755                     return false;
   1756                 }
   1757 
   1758                 return true;
   1759             } else {
   1760                 return false;
   1761             }
   1762 
   1763         }
   1764     }
   1765 
   1766     synchronized static void untrackSignificantWifiChange() {
   1767         synchronized (mLock) {
   1768             if (isHalStarted()) {
   1769                 if (sSignificantWifiChangeCmdId != 0) {
   1770                     untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId);
   1771                     sSignificantWifiChangeCmdId = 0;
   1772                     sSignificantWifiChangeHandler = null;
   1773                 }
   1774             }
   1775         }
   1776     }
   1777 
   1778     synchronized static void onSignificantWifiChange(int id, ScanResult[] results) {
   1779         synchronized (mLock) {
   1780             if (sSignificantWifiChangeCmdId != 0) {
   1781                 sSignificantWifiChangeHandler.onChangesFound(results);
   1782             } else {
   1783             /* this can happen because of race conditions */
   1784                 Log.d(TAG, "Ignoring significant wifi change");
   1785             }
   1786         }
   1787     }
   1788 
   1789     synchronized public static WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
   1790         // TODO: use correct iface name to Index translation
   1791         if (iface == null) return null;
   1792         synchronized (mLock) {
   1793             if (isHalStarted()) {
   1794                 return getWifiLinkLayerStatsNative(sWlan0Index);
   1795             } else {
   1796                 return null;
   1797             }
   1798         }
   1799     }
   1800 
   1801     synchronized public static void setWifiLinkLayerStats(String iface, int enable) {
   1802         if (iface == null) return;
   1803         synchronized (mLock) {
   1804             if (isHalStarted()) {
   1805                 setWifiLinkLayerStatsNative(sWlan0Index, enable);
   1806             }
   1807         }
   1808     }
   1809 
   1810     public static native int getSupportedFeatureSetNative(int iface);
   1811     synchronized public static int getSupportedFeatureSet() {
   1812         synchronized (mLock) {
   1813             if (isHalStarted()) {
   1814                 return getSupportedFeatureSetNative(sWlan0Index);
   1815             } else {
   1816                 Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started");
   1817                 return 0;
   1818             }
   1819         }
   1820     }
   1821 
   1822     /* Rtt related commands/events */
   1823     public static interface RttEventHandler {
   1824         void onRttResults(RttManager.RttResult[] result);
   1825     }
   1826 
   1827     private static RttEventHandler sRttEventHandler;
   1828     private static int sRttCmdId;
   1829 
   1830     synchronized private static void onRttResults(int id, RttManager.RttResult[] results) {
   1831         if (id == sRttCmdId) {
   1832             Log.d(TAG, "Received " + results.length + " rtt results");
   1833             sRttEventHandler.onRttResults(results);
   1834             sRttCmdId = 0;
   1835         } else {
   1836             Log.d(TAG, "RTT Received event for unknown cmd = " + id + ", current id = " + sRttCmdId);
   1837         }
   1838     }
   1839 
   1840     private static native boolean requestRangeNative(
   1841             int iface, int id, RttManager.RttParams[] params);
   1842     private static native boolean cancelRangeRequestNative(
   1843             int iface, int id, RttManager.RttParams[] params);
   1844 
   1845     synchronized public static boolean requestRtt(
   1846             RttManager.RttParams[] params, RttEventHandler handler) {
   1847         synchronized (mLock) {
   1848             if (isHalStarted()) {
   1849                 if (sRttCmdId != 0) {
   1850                     Log.v("TAG", "Last one is still under measurement!");
   1851                     return false;
   1852                 } else {
   1853                     sRttCmdId = getNewCmdIdLocked();
   1854                 }
   1855                 sRttEventHandler = handler;
   1856                 Log.v(TAG, "native issue RTT request");
   1857                 return requestRangeNative(sWlan0Index, sRttCmdId, params);
   1858             } else {
   1859                 return false;
   1860             }
   1861         }
   1862     }
   1863 
   1864     synchronized public static boolean cancelRtt(RttManager.RttParams[] params) {
   1865         synchronized(mLock) {
   1866             if (isHalStarted()) {
   1867                 if (sRttCmdId == 0) {
   1868                     return false;
   1869                 }
   1870 
   1871                 sRttCmdId = 0;
   1872 
   1873                 if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) {
   1874                     sRttEventHandler = null;
   1875                     Log.v(TAG, "RTT cancel Request Successfully");
   1876                     return true;
   1877                 } else {
   1878                     Log.e(TAG, "RTT cancel Request failed");
   1879                     return false;
   1880                 }
   1881             } else {
   1882                 return false;
   1883             }
   1884         }
   1885     }
   1886 
   1887     private static native boolean setScanningMacOuiNative(int iface, byte[] oui);
   1888 
   1889     synchronized public static boolean setScanningMacOui(byte[] oui) {
   1890         synchronized (mLock) {
   1891             if (isHalStarted()) {
   1892                 return setScanningMacOuiNative(sWlan0Index, oui);
   1893             } else {
   1894                 return false;
   1895             }
   1896         }
   1897     }
   1898 
   1899     private static native int[] getChannelsForBandNative(
   1900             int iface, int band);
   1901 
   1902     synchronized public static int [] getChannelsForBand(int band) {
   1903         synchronized (mLock) {
   1904             if (isHalStarted()) {
   1905                 return getChannelsForBandNative(sWlan0Index, band);
   1906 	    } else {
   1907                 return null;
   1908             }
   1909         }
   1910     }
   1911 
   1912     private static native boolean isGetChannelsForBandSupportedNative();
   1913     synchronized public static boolean isGetChannelsForBandSupported(){
   1914         synchronized (mLock) {
   1915             if (isHalStarted()) {
   1916                 return isGetChannelsForBandSupportedNative();
   1917 	    } else {
   1918                 return false;
   1919             }
   1920         }
   1921     }
   1922 
   1923     private static native boolean setDfsFlagNative(int iface, boolean dfsOn);
   1924     synchronized public static boolean setDfsFlag(boolean dfsOn) {
   1925         synchronized (mLock) {
   1926             if (isHalStarted()) {
   1927                 return setDfsFlagNative(sWlan0Index, dfsOn);
   1928             } else {
   1929                 return false;
   1930             }
   1931         }
   1932     }
   1933 
   1934     private static native boolean toggleInterfaceNative(int on);
   1935     synchronized public static boolean toggleInterface(int on) {
   1936         synchronized (mLock) {
   1937             if (isHalStarted()) {
   1938                 return toggleInterfaceNative(0);
   1939             } else {
   1940                 return false;
   1941             }
   1942         }
   1943     }
   1944 
   1945     private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface);
   1946     synchronized public static RttManager.RttCapabilities getRttCapabilities() {
   1947         synchronized (mLock) {
   1948             if (isHalStarted()) {
   1949                 return getRttCapabilitiesNative(sWlan0Index);
   1950             }else {
   1951                 return null;
   1952             }
   1953         }
   1954     }
   1955 
   1956     private static native boolean setCountryCodeHalNative(int iface, String CountryCode);
   1957     synchronized public static boolean setCountryCodeHal( String CountryCode) {
   1958         synchronized (mLock) {
   1959             if (isHalStarted()) {
   1960                 return setCountryCodeHalNative(sWlan0Index, CountryCode);
   1961             } else {
   1962                 return false;
   1963             }
   1964         }
   1965     }
   1966 
   1967     /* Rtt related commands/events */
   1968     public abstract class TdlsEventHandler {
   1969         abstract public void onTdlsStatus(String macAddr, int status, int reason);
   1970     }
   1971 
   1972     private static TdlsEventHandler sTdlsEventHandler;
   1973 
   1974     private static native boolean enableDisableTdlsNative(int iface, boolean enable,
   1975             String macAddr);
   1976     synchronized public static boolean enableDisableTdls(boolean enable, String macAdd,
   1977             TdlsEventHandler tdlsCallBack) {
   1978         synchronized (mLock) {
   1979             sTdlsEventHandler = tdlsCallBack;
   1980             return enableDisableTdlsNative(sWlan0Index, enable, macAdd);
   1981         }
   1982     }
   1983 
   1984     // Once TDLS per mac and event feature is implemented, this class definition should be
   1985     // moved to the right place, like WifiManager etc
   1986     public static class TdlsStatus {
   1987         int channel;
   1988         int global_operating_class;
   1989         int state;
   1990         int reason;
   1991     }
   1992     private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr);
   1993     synchronized public static TdlsStatus getTdlsStatus (String macAdd) {
   1994         synchronized (mLock) {
   1995             if (isHalStarted()) {
   1996                 return getTdlsStatusNative(sWlan0Index, macAdd);
   1997             } else {
   1998                 return null;
   1999             }
   2000         }
   2001     }
   2002 
   2003     //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be
   2004     // moved to the right place, like WifiStateMachine etc
   2005     public static class TdlsCapabilities {
   2006         /* Maximum TDLS session number can be supported by the Firmware and hardware */
   2007         int maxConcurrentTdlsSessionNumber;
   2008         boolean isGlobalTdlsSupported;
   2009         boolean isPerMacTdlsSupported;
   2010         boolean isOffChannelTdlsSupported;
   2011     }
   2012 
   2013 
   2014 
   2015     private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface);
   2016     synchronized public static TdlsCapabilities getTdlsCapabilities () {
   2017         synchronized (mLock) {
   2018             if (isHalStarted()) {
   2019                 return getTdlsCapabilitiesNative(sWlan0Index);
   2020             } else {
   2021                 return null;
   2022             }
   2023         }
   2024     }
   2025 
   2026     synchronized private static boolean onTdlsStatus(String macAddr, int status, int reason) {
   2027          if (sTdlsEventHandler == null) {
   2028              return false;
   2029          } else {
   2030              sTdlsEventHandler.onTdlsStatus(macAddr, status, reason);
   2031              return true;
   2032          }
   2033     }
   2034 
   2035     //---------------------------------------------------------------------------------
   2036 
   2037     /* Wifi Logger commands/events */
   2038 
   2039     public static native boolean startLogging(int iface);
   2040 
   2041     public static interface WifiLoggerEventHandler {
   2042         void onRingBufferData(RingBufferStatus status, byte[] buffer);
   2043         void onWifiAlert(int errorCode, byte[] buffer);
   2044     }
   2045 
   2046     private static WifiLoggerEventHandler sWifiLoggerEventHandler = null;
   2047 
   2048     private static void onRingBufferData(RingBufferStatus status, byte[] buffer) {
   2049         if (sWifiLoggerEventHandler != null)
   2050             sWifiLoggerEventHandler.onRingBufferData(status, buffer);
   2051     }
   2052 
   2053     private static void onWifiAlert(byte[] buffer, int errorCode) {
   2054         if (sWifiLoggerEventHandler != null)
   2055             sWifiLoggerEventHandler.onWifiAlert(errorCode, buffer);
   2056     }
   2057 
   2058     private static int sLogCmdId = -1;
   2059     private static native boolean setLoggingEventHandlerNative(int iface, int id);
   2060     synchronized public static boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
   2061         synchronized (mLock) {
   2062             if (isHalStarted()) {
   2063                 int oldId =  sLogCmdId;
   2064                 sLogCmdId = getNewCmdIdLocked();
   2065                 if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) {
   2066                     sLogCmdId = oldId;
   2067                     return false;
   2068                 }
   2069                 sWifiLoggerEventHandler = handler;
   2070                 return true;
   2071             } else {
   2072                 return false;
   2073             }
   2074         }
   2075     }
   2076 
   2077     private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel,
   2078             int flags, int minIntervalSec ,int minDataSize, String ringName);
   2079     synchronized public static boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
   2080             int minDataSize, String ringName){
   2081         synchronized (mLock) {
   2082             if (isHalStarted()) {
   2083                 return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval,
   2084                         minDataSize, ringName);
   2085             } else {
   2086                 return false;
   2087             }
   2088         }
   2089     }
   2090 
   2091     private static native int getSupportedLoggerFeatureSetNative(int iface);
   2092     synchronized public static int getSupportedLoggerFeatureSet() {
   2093         synchronized (mLock) {
   2094             if (isHalStarted()) {
   2095                 return getSupportedLoggerFeatureSetNative(sWlan0Index);
   2096             } else {
   2097                 return 0;
   2098             }
   2099         }
   2100     }
   2101 
   2102     private static native boolean resetLogHandlerNative(int iface, int id);
   2103     synchronized public static boolean resetLogHandler() {
   2104         synchronized (mLock) {
   2105             if (isHalStarted()) {
   2106                 if (sLogCmdId == -1) {
   2107                     Log.e(TAG,"Can not reset handler Before set any handler");
   2108                     return false;
   2109                 }
   2110                 sWifiLoggerEventHandler = null;
   2111                 if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) {
   2112                     sLogCmdId = -1;
   2113                     return true;
   2114                 } else {
   2115                     return false;
   2116                 }
   2117             } else {
   2118                 return false;
   2119             }
   2120         }
   2121     }
   2122 
   2123     private static native String getDriverVersionNative(int iface);
   2124     synchronized public static String getDriverVersion() {
   2125         synchronized (mLock) {
   2126             if (isHalStarted()) {
   2127                 return getDriverVersionNative(sWlan0Index);
   2128             } else {
   2129                 return "";
   2130             }
   2131         }
   2132     }
   2133 
   2134 
   2135     private static native String getFirmwareVersionNative(int iface);
   2136     synchronized public static String getFirmwareVersion() {
   2137         synchronized (mLock) {
   2138             if (isHalStarted()) {
   2139                 return getFirmwareVersionNative(sWlan0Index);
   2140             } else {
   2141                 return "";
   2142             }
   2143         }
   2144     }
   2145 
   2146     public static class RingBufferStatus{
   2147         String name;
   2148         int flag;
   2149         int ringBufferId;
   2150         int ringBufferByteSize;
   2151         int verboseLevel;
   2152         int writtenBytes;
   2153         int readBytes;
   2154         int writtenRecords;
   2155 
   2156         @Override
   2157         public String toString() {
   2158             return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
   2159                     " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
   2160                     " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
   2161                     " writtenRecords: " + writtenRecords;
   2162         }
   2163     }
   2164 
   2165     private static native RingBufferStatus[] getRingBufferStatusNative(int iface);
   2166     synchronized public static RingBufferStatus[] getRingBufferStatus() {
   2167         synchronized (mLock) {
   2168             if (isHalStarted()) {
   2169                 return getRingBufferStatusNative(sWlan0Index);
   2170             } else {
   2171                 return null;
   2172             }
   2173         }
   2174     }
   2175 
   2176     private static native boolean getRingBufferDataNative(int iface, String ringName);
   2177     synchronized public static boolean getRingBufferData(String ringName) {
   2178         synchronized (mLock) {
   2179             if (isHalStarted()) {
   2180                 return getRingBufferDataNative(sWlan0Index, ringName);
   2181             } else {
   2182                 return false;
   2183             }
   2184         }
   2185     }
   2186 
   2187     static private byte[] mFwMemoryDump;
   2188     private static void onWifiFwMemoryAvailable(byte[] buffer) {
   2189         mFwMemoryDump = buffer;
   2190         if (DBG) {
   2191             Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " +
   2192                     (buffer == null ? 0 :  buffer.length));
   2193         }
   2194     }
   2195 
   2196     private static native boolean getFwMemoryDumpNative(int iface);
   2197     synchronized public static byte[] getFwMemoryDump() {
   2198         synchronized (mLock) {
   2199             if (isHalStarted()) {
   2200                 if(getFwMemoryDumpNative(sWlan0Index)) {
   2201                     byte[] fwMemoryDump = mFwMemoryDump;
   2202                     mFwMemoryDump = null;
   2203                     return fwMemoryDump;
   2204                 } else {
   2205                     return null;
   2206                 }
   2207             }
   2208 
   2209             return null;
   2210         }
   2211     }
   2212 
   2213     //---------------------------------------------------------------------------------
   2214     /* Configure ePNO */
   2215 
   2216     public class WifiPnoNetwork {
   2217         String SSID;
   2218         int rssi_threshold;
   2219         int flags;
   2220         int auth;
   2221         String configKey; // kept for reference
   2222 
   2223         WifiPnoNetwork(WifiConfiguration config, int threshold) {
   2224             if (config.SSID == null) {
   2225                 this.SSID = "";
   2226                 this.flags = 1;
   2227             } else {
   2228                 this.SSID = config.SSID;
   2229             }
   2230             this.rssi_threshold = threshold;
   2231             if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
   2232                 auth |= 2;
   2233             } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) ||
   2234                     config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) {
   2235                 auth |= 4;
   2236             } else if (config.wepKeys[0] != null) {
   2237                 auth |= 1;
   2238             } else {
   2239                 auth |= 1;
   2240             }
   2241 //            auth = 0;
   2242             flags |= 6; //A and G
   2243             configKey = config.configKey();
   2244         }
   2245 
   2246         @Override
   2247         public String toString() {
   2248             StringBuilder sbuf = new StringBuilder();
   2249             sbuf.append(this.SSID);
   2250             sbuf.append(" flags=").append(this.flags);
   2251             sbuf.append(" rssi=").append(this.rssi_threshold);
   2252             sbuf.append(" auth=").append(this.auth);
   2253             return sbuf.toString();
   2254         }
   2255     }
   2256 
   2257     public static interface WifiPnoEventHandler {
   2258         void onPnoNetworkFound(ScanResult results[]);
   2259     }
   2260 
   2261     private static WifiPnoEventHandler sWifiPnoEventHandler;
   2262 
   2263     private static int sPnoCmdId = 0;
   2264 
   2265     private native static boolean setPnoListNative(int iface, int id, WifiPnoNetwork list[]);
   2266 
   2267     synchronized public static boolean setPnoList(WifiPnoNetwork list[],
   2268                                                   WifiPnoEventHandler eventHandler) {
   2269         Log.e(TAG, "setPnoList cmd " + sPnoCmdId);
   2270 
   2271         synchronized (mLock) {
   2272             if (isHalStarted()) {
   2273 
   2274                 sPnoCmdId = getNewCmdIdLocked();
   2275 
   2276                 sWifiPnoEventHandler = eventHandler;
   2277                 if (setPnoListNative(sWlan0Index, sPnoCmdId, list)) {
   2278                     return true;
   2279                 }
   2280             }
   2281 
   2282             sWifiPnoEventHandler = null;
   2283             return false;
   2284         }
   2285     }
   2286 
   2287     synchronized public static void onPnoNetworkFound(int id, ScanResult[] results) {
   2288 
   2289         if (results == null) {
   2290             Log.e(TAG, "onPnoNetworkFound null results");
   2291             return;
   2292 
   2293         }
   2294         Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length);
   2295 
   2296         //Log.e(TAG, "onPnoNetworkFound length " + results.length);
   2297         //return;
   2298         for (int i=0; i<results.length; i++) {
   2299             Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID
   2300                     + " " + results[i].level + " " + results[i].frequency);
   2301 
   2302             populateScanResult(results[i], results[i].bytes, "onPnoNetworkFound ");
   2303             results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID);
   2304         }
   2305         synchronized (mLock) {
   2306             if (sPnoCmdId != 0 && sWifiPnoEventHandler != null) {
   2307                 sWifiPnoEventHandler.onPnoNetworkFound(results);
   2308             } else {
   2309                 /* this can happen because of race conditions */
   2310                 Log.d(TAG, "Ignoring Pno Network found event");
   2311             }
   2312         }
   2313     }
   2314 
   2315     public class WifiLazyRoamParams {
   2316         int A_band_boost_threshold;
   2317         int A_band_penalty_threshold;
   2318         int A_band_boost_factor;
   2319         int A_band_penalty_factor;
   2320         int A_band_max_boost;
   2321         int lazy_roam_hysteresis;
   2322         int alert_roam_rssi_trigger;
   2323 
   2324         WifiLazyRoamParams() {
   2325         }
   2326 
   2327         @Override
   2328         public String toString() {
   2329             StringBuilder sbuf = new StringBuilder();
   2330             sbuf.append(" A_band_boost_threshold=").append(this.A_band_boost_threshold);
   2331             sbuf.append(" A_band_penalty_threshold=").append(this.A_band_penalty_threshold);
   2332             sbuf.append(" A_band_boost_factor=").append(this.A_band_boost_factor);
   2333             sbuf.append(" A_band_penalty_factor=").append(this.A_band_penalty_factor);
   2334             sbuf.append(" A_band_max_boost=").append(this.A_band_max_boost);
   2335             sbuf.append(" lazy_roam_hysteresis=").append(this.lazy_roam_hysteresis);
   2336             sbuf.append(" alert_roam_rssi_trigger=").append(this.alert_roam_rssi_trigger);
   2337             return sbuf.toString();
   2338         }
   2339     }
   2340 
   2341     private native static boolean setLazyRoamNative(int iface, int id,
   2342                                               boolean enabled, WifiLazyRoamParams param);
   2343 
   2344     synchronized public static boolean setLazyRoam(boolean enabled, WifiLazyRoamParams params) {
   2345         synchronized (mLock) {
   2346             if (isHalStarted()) {
   2347                 sPnoCmdId = getNewCmdIdLocked();
   2348                 return setLazyRoamNative(sWlan0Index, sPnoCmdId, enabled, params);
   2349             } else {
   2350                 return false;
   2351             }
   2352         }
   2353     }
   2354 
   2355     private native static boolean setBssidBlacklistNative(int iface, int id,
   2356                                               String list[]);
   2357 
   2358     synchronized public static boolean setBssidBlacklist(String list[]) {
   2359         int size = 0;
   2360         if (list != null) {
   2361             size = list.length;
   2362         }
   2363         Log.e(TAG, "setBssidBlacklist cmd " + sPnoCmdId + " size " + size);
   2364 
   2365         synchronized (mLock) {
   2366             if (isHalStarted()) {
   2367                 sPnoCmdId = getNewCmdIdLocked();
   2368                 return setBssidBlacklistNative(sWlan0Index, sPnoCmdId, list);
   2369             } else {
   2370                 return false;
   2371             }
   2372         }
   2373     }
   2374 
   2375     private native static boolean setSsidWhitelistNative(int iface, int id, String list[]);
   2376 
   2377     synchronized public static boolean setSsidWhitelist(String list[]) {
   2378         int size = 0;
   2379         if (list != null) {
   2380             size = list.length;
   2381         }
   2382         Log.e(TAG, "setSsidWhitelist cmd " + sPnoCmdId + " size " + size);
   2383 
   2384         synchronized (mLock) {
   2385             if (isHalStarted()) {
   2386                 sPnoCmdId = getNewCmdIdLocked();
   2387 
   2388                 return setSsidWhitelistNative(sWlan0Index, sPnoCmdId, list);
   2389             } else {
   2390                 return false;
   2391             }
   2392         }
   2393     }
   2394 }
   2395