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.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.app.AlarmManager;
     22 import android.app.PendingIntent;
     23 import android.content.BroadcastReceiver;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.IntentFilter;
     27 import android.net.apf.ApfCapabilities;
     28 import android.net.wifi.RttManager;
     29 import android.net.wifi.RttManager.ResponderConfig;
     30 import android.net.wifi.ScanResult;
     31 import android.net.wifi.WifiConfiguration;
     32 import android.net.wifi.WifiEnterpriseConfig;
     33 import android.net.wifi.WifiLinkLayerStats;
     34 import android.net.wifi.WifiManager;
     35 import android.net.wifi.WifiScanner;
     36 import android.net.wifi.WifiSsid;
     37 import android.net.wifi.WifiWakeReasonAndCounts;
     38 import android.net.wifi.WpsInfo;
     39 import android.net.wifi.p2p.WifiP2pConfig;
     40 import android.net.wifi.p2p.WifiP2pGroup;
     41 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
     42 import android.os.SystemClock;
     43 import android.os.SystemProperties;
     44 import android.text.TextUtils;
     45 import android.util.LocalLog;
     46 import android.util.Log;
     47 
     48 import com.android.internal.annotations.Immutable;
     49 import com.android.internal.util.HexDump;
     50 import com.android.server.connectivity.KeepalivePacketData;
     51 import com.android.server.wifi.hotspot2.NetworkDetail;
     52 import com.android.server.wifi.hotspot2.SupplicantBridge;
     53 import com.android.server.wifi.hotspot2.Utils;
     54 import com.android.server.wifi.util.FrameParser;
     55 import com.android.server.wifi.util.InformationElementUtil;
     56 
     57 import libcore.util.HexEncoding;
     58 
     59 import org.json.JSONException;
     60 import org.json.JSONObject;
     61 
     62 import java.io.PrintWriter;
     63 import java.io.StringWriter;
     64 import java.io.UnsupportedEncodingException;
     65 import java.net.URLDecoder;
     66 import java.net.URLEncoder;
     67 import java.nio.ByteBuffer;
     68 import java.nio.CharBuffer;
     69 import java.nio.charset.CharacterCodingException;
     70 import java.nio.charset.CharsetDecoder;
     71 import java.nio.charset.StandardCharsets;
     72 import java.text.SimpleDateFormat;
     73 import java.util.ArrayList;
     74 import java.util.BitSet;
     75 import java.util.Date;
     76 import java.util.HashMap;
     77 import java.util.Iterator;
     78 import java.util.List;
     79 import java.util.Locale;
     80 import java.util.Map;
     81 import java.util.Objects;
     82 import java.util.Set;
     83 import java.util.TimeZone;
     84 
     85 
     86 /**
     87  * Native calls for bring up/shut down of the supplicant daemon and for
     88  * sending requests to the supplicant daemon
     89  *
     90  * waitForEvent() is called on the monitor thread for events. All other methods
     91  * must be serialized from the framework.
     92  *
     93  * {@hide}
     94  */
     95 public class WifiNative {
     96     private static boolean DBG = false;
     97 
     98     // Must match wifi_hal.h
     99     public static final int WIFI_SUCCESS = 0;
    100 
    101     /**
    102      * Hold this lock before calling supplicant or HAL methods
    103      * it is required to mutually exclude access to the driver
    104      */
    105     public static final Object sLock = new Object();
    106 
    107     private static final LocalLog sLocalLog = new LocalLog(8192);
    108 
    109     public @NonNull LocalLog getLocalLog() {
    110         return sLocalLog;
    111     }
    112 
    113     /* Register native functions */
    114     static {
    115         /* Native functions are defined in libwifi-service.so */
    116         System.loadLibrary("wifi-service");
    117         registerNatives();
    118     }
    119 
    120     private static native int registerNatives();
    121 
    122     /*
    123      * Singleton WifiNative instances
    124      */
    125     private static WifiNative wlanNativeInterface =
    126             new WifiNative(SystemProperties.get("wifi.interface", "wlan0"), true);
    127     public static WifiNative getWlanNativeInterface() {
    128         return wlanNativeInterface;
    129     }
    130 
    131     private static WifiNative p2pNativeInterface =
    132             // commands for p2p0 interface don't need prefix
    133             new WifiNative(SystemProperties.get("wifi.direct.interface", "p2p0"), false);
    134     public static WifiNative getP2pNativeInterface() {
    135         return p2pNativeInterface;
    136     }
    137 
    138 
    139     private final String mTAG;
    140     private final String mInterfaceName;
    141     private final String mInterfacePrefix;
    142 
    143     private Context mContext = null;
    144     public void initContext(Context context) {
    145         if (mContext == null && context != null) {
    146             mContext = context;
    147         }
    148     }
    149 
    150     private WifiNative(String interfaceName,
    151                        boolean requiresPrefix) {
    152         mInterfaceName = interfaceName;
    153         mTAG = "WifiNative-" + interfaceName;
    154 
    155         if (requiresPrefix) {
    156             mInterfacePrefix = "IFNAME=" + interfaceName + " ";
    157         } else {
    158             mInterfacePrefix = "";
    159         }
    160     }
    161 
    162     public String getInterfaceName() {
    163         return mInterfaceName;
    164     }
    165 
    166     // Note this affects logging on for all interfaces
    167     void enableVerboseLogging(int verbose) {
    168         if (verbose > 0) {
    169             DBG = true;
    170         } else {
    171             DBG = false;
    172         }
    173     }
    174 
    175     private void localLog(String s) {
    176         if (sLocalLog != null) sLocalLog.log(mInterfaceName + ": " + s);
    177     }
    178 
    179 
    180 
    181     /*
    182      * Driver and Supplicant management
    183      */
    184     private native static boolean loadDriverNative();
    185     public boolean loadDriver() {
    186         synchronized (sLock) {
    187             return loadDriverNative();
    188         }
    189     }
    190 
    191     private native static boolean isDriverLoadedNative();
    192     public boolean isDriverLoaded() {
    193         synchronized (sLock) {
    194             return isDriverLoadedNative();
    195         }
    196     }
    197 
    198     private native static boolean unloadDriverNative();
    199     public boolean unloadDriver() {
    200         synchronized (sLock) {
    201             return unloadDriverNative();
    202         }
    203     }
    204 
    205     private native static boolean startSupplicantNative(boolean p2pSupported);
    206     public boolean startSupplicant(boolean p2pSupported) {
    207         synchronized (sLock) {
    208             return startSupplicantNative(p2pSupported);
    209         }
    210     }
    211 
    212     /* Sends a kill signal to supplicant. To be used when we have lost connection
    213        or when the supplicant is hung */
    214     private native static boolean killSupplicantNative(boolean p2pSupported);
    215     public boolean killSupplicant(boolean p2pSupported) {
    216         synchronized (sLock) {
    217             return killSupplicantNative(p2pSupported);
    218         }
    219     }
    220 
    221     private native static boolean connectToSupplicantNative();
    222     public boolean connectToSupplicant() {
    223         synchronized (sLock) {
    224             localLog(mInterfacePrefix + "connectToSupplicant");
    225             return connectToSupplicantNative();
    226         }
    227     }
    228 
    229     private native static void closeSupplicantConnectionNative();
    230     public void closeSupplicantConnection() {
    231         synchronized (sLock) {
    232             localLog(mInterfacePrefix + "closeSupplicantConnection");
    233             closeSupplicantConnectionNative();
    234         }
    235     }
    236 
    237     /**
    238      * Wait for the supplicant to send an event, returning the event string.
    239      * @return the event string sent by the supplicant.
    240      */
    241     private native static String waitForEventNative();
    242     public String waitForEvent() {
    243         // No synchronization necessary .. it is implemented in WifiMonitor
    244         return waitForEventNative();
    245     }
    246 
    247 
    248     /*
    249      * Supplicant Command Primitives
    250      */
    251     private native boolean doBooleanCommandNative(String command);
    252 
    253     private native int doIntCommandNative(String command);
    254 
    255     private native String doStringCommandNative(String command);
    256 
    257     private boolean doBooleanCommand(String command) {
    258         if (DBG) Log.d(mTAG, "doBoolean: " + command);
    259         synchronized (sLock) {
    260             String toLog = mInterfacePrefix + command;
    261             boolean result = doBooleanCommandNative(mInterfacePrefix + command);
    262             localLog(toLog + " -> " + result);
    263             if (DBG) Log.d(mTAG, command + ": returned " + result);
    264             return result;
    265         }
    266     }
    267 
    268     private boolean doBooleanCommandWithoutLogging(String command) {
    269         if (DBG) Log.d(mTAG, "doBooleanCommandWithoutLogging: " + command);
    270         synchronized (sLock) {
    271             boolean result = doBooleanCommandNative(mInterfacePrefix + command);
    272             if (DBG) Log.d(mTAG, command + ": returned " + result);
    273             return result;
    274         }
    275     }
    276 
    277     private int doIntCommand(String command) {
    278         if (DBG) Log.d(mTAG, "doInt: " + command);
    279         synchronized (sLock) {
    280             String toLog = mInterfacePrefix + command;
    281             int result = doIntCommandNative(mInterfacePrefix + command);
    282             localLog(toLog + " -> " + result);
    283             if (DBG) Log.d(mTAG, "   returned " + result);
    284             return result;
    285         }
    286     }
    287 
    288     private String doStringCommand(String command) {
    289         if (DBG) {
    290             //GET_NETWORK commands flood the logs
    291             if (!command.startsWith("GET_NETWORK")) {
    292                 Log.d(mTAG, "doString: [" + command + "]");
    293             }
    294         }
    295         synchronized (sLock) {
    296             String toLog = mInterfacePrefix + command;
    297             String result = doStringCommandNative(mInterfacePrefix + command);
    298             if (result == null) {
    299                 if (DBG) Log.d(mTAG, "doStringCommandNative no result");
    300             } else {
    301                 if (!command.startsWith("STATUS-")) {
    302                     localLog(toLog + " -> " + result);
    303                 }
    304                 if (DBG) Log.d(mTAG, "   returned " + result.replace("\n", " "));
    305             }
    306             return result;
    307         }
    308     }
    309 
    310     private String doStringCommandWithoutLogging(String command) {
    311         if (DBG) {
    312             //GET_NETWORK commands flood the logs
    313             if (!command.startsWith("GET_NETWORK")) {
    314                 Log.d(mTAG, "doString: [" + command + "]");
    315             }
    316         }
    317         synchronized (sLock) {
    318             return doStringCommandNative(mInterfacePrefix + command);
    319         }
    320     }
    321 
    322     public String doCustomSupplicantCommand(String command) {
    323         return doStringCommand(command);
    324     }
    325 
    326     /*
    327      * Wrappers for supplicant commands
    328      */
    329     public boolean ping() {
    330         String pong = doStringCommand("PING");
    331         return (pong != null && pong.equals("PONG"));
    332     }
    333 
    334     public void setSupplicantLogLevel(String level) {
    335         doStringCommand("LOG_LEVEL " + level);
    336     }
    337 
    338     public String getFreqCapability() {
    339         return doStringCommand("GET_CAPABILITY freq");
    340     }
    341 
    342     /**
    343      * Create a comma separate string from integer set.
    344      * @param values List of integers.
    345      * @return comma separated string.
    346      */
    347     private static String createCSVStringFromIntegerSet(Set<Integer> values) {
    348         StringBuilder list = new StringBuilder();
    349         boolean first = true;
    350         for (Integer value : values) {
    351             if (!first) {
    352                 list.append(",");
    353             }
    354             list.append(value);
    355             first = false;
    356         }
    357         return list.toString();
    358     }
    359 
    360     /**
    361      * Start a scan using wpa_supplicant for the given frequencies.
    362      * @param freqs list of frequencies to scan for, if null scan all supported channels.
    363      * @param hiddenNetworkIds List of hidden networks to be scanned for.
    364      */
    365     public boolean scan(Set<Integer> freqs, Set<Integer> hiddenNetworkIds) {
    366         String freqList = null;
    367         String hiddenNetworkIdList = null;
    368         if (freqs != null && freqs.size() != 0) {
    369             freqList = createCSVStringFromIntegerSet(freqs);
    370         }
    371         if (hiddenNetworkIds != null && hiddenNetworkIds.size() != 0) {
    372             hiddenNetworkIdList = createCSVStringFromIntegerSet(hiddenNetworkIds);
    373         }
    374         return scanWithParams(freqList, hiddenNetworkIdList);
    375     }
    376 
    377     private boolean scanWithParams(String freqList, String hiddenNetworkIdList) {
    378         StringBuilder scanCommand = new StringBuilder();
    379         scanCommand.append("SCAN TYPE=ONLY");
    380         if (freqList != null) {
    381             scanCommand.append(" freq=" + freqList);
    382         }
    383         if (hiddenNetworkIdList != null) {
    384             scanCommand.append(" scan_id=" + hiddenNetworkIdList);
    385         }
    386         return doBooleanCommand(scanCommand.toString());
    387     }
    388 
    389     /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta.
    390      *
    391      * Note that underneath we use a harsh-sounding "terminate" supplicant command
    392      * for a graceful stop and a mild-sounding "stop" interface
    393      * to kill the process
    394      */
    395     public boolean stopSupplicant() {
    396         return doBooleanCommand("TERMINATE");
    397     }
    398 
    399     public String listNetworks() {
    400         return doStringCommand("LIST_NETWORKS");
    401     }
    402 
    403     public String listNetworks(int last_id) {
    404         return doStringCommand("LIST_NETWORKS LAST_ID=" + last_id);
    405     }
    406 
    407     public int addNetwork() {
    408         return doIntCommand("ADD_NETWORK");
    409     }
    410 
    411     public boolean setNetworkExtra(int netId, String name, Map<String, String> values) {
    412         final String encoded;
    413         try {
    414             encoded = URLEncoder.encode(new JSONObject(values).toString(), "UTF-8");
    415         } catch (NullPointerException e) {
    416             Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
    417             return false;
    418         } catch (UnsupportedEncodingException e) {
    419             Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
    420             return false;
    421         }
    422         return setNetworkVariable(netId, name, "\"" + encoded + "\"");
    423     }
    424 
    425     public boolean setNetworkVariable(int netId, String name, String value) {
    426         if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false;
    427         if (name.equals(WifiConfiguration.pskVarName)
    428                 || name.equals(WifiEnterpriseConfig.PASSWORD_KEY)) {
    429             return doBooleanCommandWithoutLogging("SET_NETWORK " + netId + " " + name + " " + value);
    430         } else {
    431             return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value);
    432         }
    433     }
    434 
    435     public Map<String, String> getNetworkExtra(int netId, String name) {
    436         final String wrapped = getNetworkVariable(netId, name);
    437         if (wrapped == null || !wrapped.startsWith("\"") || !wrapped.endsWith("\"")) {
    438             return null;
    439         }
    440         try {
    441             final String encoded = wrapped.substring(1, wrapped.length() - 1);
    442             // This method reads a JSON dictionary that was written by setNetworkExtra(). However,
    443             // on devices that upgraded from Marshmallow, it may encounter a legacy value instead -
    444             // an FQDN stored as a plain string. If such a value is encountered, the JSONObject
    445             // constructor will thrown a JSONException and the method will return null.
    446             final JSONObject json = new JSONObject(URLDecoder.decode(encoded, "UTF-8"));
    447             final Map<String, String> values = new HashMap<String, String>();
    448             final Iterator<?> it = json.keys();
    449             while (it.hasNext()) {
    450                 final String key = (String) it.next();
    451                 final Object value = json.get(key);
    452                 if (value instanceof String) {
    453                     values.put(key, (String) value);
    454                 }
    455             }
    456             return values;
    457         } catch (UnsupportedEncodingException e) {
    458             Log.e(TAG, "Unable to deserialize networkExtra: " + e.toString());
    459             return null;
    460         } catch (JSONException e) {
    461             // This is not necessarily an error. This exception will also occur if we encounter a
    462             // legacy FQDN stored as a plain string. We want to return null in this case as no JSON
    463             // dictionary of extras was found.
    464             return null;
    465         }
    466     }
    467 
    468     public String getNetworkVariable(int netId, String name) {
    469         if (TextUtils.isEmpty(name)) return null;
    470 
    471         // GET_NETWORK will likely flood the logs ...
    472         return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name);
    473     }
    474 
    475     public boolean removeNetwork(int netId) {
    476         return doBooleanCommand("REMOVE_NETWORK " + netId);
    477     }
    478 
    479 
    480     private void logDbg(String debug) {
    481         long now = SystemClock.elapsedRealtimeNanos();
    482         String ts = String.format("[%,d us] ", now/1000);
    483         Log.e("WifiNative: ", ts+debug+ " stack:"
    484                 + Thread.currentThread().getStackTrace()[2].getMethodName() +" - "
    485                 + Thread.currentThread().getStackTrace()[3].getMethodName() +" - "
    486                 + Thread.currentThread().getStackTrace()[4].getMethodName() +" - "
    487                 + Thread.currentThread().getStackTrace()[5].getMethodName()+" - "
    488                 + Thread.currentThread().getStackTrace()[6].getMethodName());
    489 
    490     }
    491 
    492     /**
    493      * Enables a network in wpa_supplicant.
    494      * @param netId - Network ID of the network to be enabled.
    495      * @return true if command succeeded, false otherwise.
    496      */
    497     public boolean enableNetwork(int netId) {
    498         if (DBG) logDbg("enableNetwork nid=" + Integer.toString(netId));
    499         return doBooleanCommand("ENABLE_NETWORK " + netId);
    500     }
    501 
    502     /**
    503      * Enable a network in wpa_supplicant, do not connect.
    504      * @param netId - Network ID of the network to be enabled.
    505      * @return true if command succeeded, false otherwise.
    506      */
    507     public boolean enableNetworkWithoutConnect(int netId) {
    508         if (DBG) logDbg("enableNetworkWithoutConnect nid=" + Integer.toString(netId));
    509         return doBooleanCommand("ENABLE_NETWORK " + netId + " " + "no-connect");
    510     }
    511 
    512     /**
    513      * Disables a network in wpa_supplicant.
    514      * @param netId - Network ID of the network to be disabled.
    515      * @return true if command succeeded, false otherwise.
    516      */
    517     public boolean disableNetwork(int netId) {
    518         if (DBG) logDbg("disableNetwork nid=" + Integer.toString(netId));
    519         return doBooleanCommand("DISABLE_NETWORK " + netId);
    520     }
    521 
    522     /**
    523      * Select a network in wpa_supplicant (Disables all others).
    524      * @param netId - Network ID of the network to be selected.
    525      * @return true if command succeeded, false otherwise.
    526      */
    527     public boolean selectNetwork(int netId) {
    528         if (DBG) logDbg("selectNetwork nid=" + Integer.toString(netId));
    529         return doBooleanCommand("SELECT_NETWORK " + netId);
    530     }
    531 
    532     public boolean reconnect() {
    533         if (DBG) logDbg("RECONNECT ");
    534         return doBooleanCommand("RECONNECT");
    535     }
    536 
    537     public boolean reassociate() {
    538         if (DBG) logDbg("REASSOCIATE ");
    539         return doBooleanCommand("REASSOCIATE");
    540     }
    541 
    542     public boolean disconnect() {
    543         if (DBG) logDbg("DISCONNECT ");
    544         return doBooleanCommand("DISCONNECT");
    545     }
    546 
    547     public String status() {
    548         return status(false);
    549     }
    550 
    551     public String status(boolean noEvents) {
    552         if (noEvents) {
    553             return doStringCommand("STATUS-NO_EVENTS");
    554         } else {
    555             return doStringCommand("STATUS");
    556         }
    557     }
    558 
    559     public String getMacAddress() {
    560         //Macaddr = XX.XX.XX.XX.XX.XX
    561         String ret = doStringCommand("DRIVER MACADDR");
    562         if (!TextUtils.isEmpty(ret)) {
    563             String[] tokens = ret.split(" = ");
    564             if (tokens.length == 2) return tokens[1];
    565         }
    566         return null;
    567     }
    568 
    569 
    570 
    571     /**
    572      * Format of results:
    573      * =================
    574      * id=1
    575      * bssid=68:7f:76:d7:1a:6e
    576      * freq=2412
    577      * level=-44
    578      * tsf=1344626243700342
    579      * flags=[WPA2-PSK-CCMP][WPS][ESS]
    580      * ssid=zfdy
    581      * ====
    582      * id=2
    583      * bssid=68:5f:74:d7:1a:6f
    584      * freq=5180
    585      * level=-73
    586      * tsf=1344626243700373
    587      * flags=[WPA2-PSK-CCMP][WPS][ESS]
    588      * ssid=zuby
    589      * ====
    590      *
    591      * RANGE=ALL gets all scan results
    592      * RANGE=ID- gets results from ID
    593      * MASK=<N> BSS command information mask.
    594      *
    595      * The mask used in this method, 0x29d87, gets the following fields:
    596      *
    597      *     WPA_BSS_MASK_ID         (Bit 0)
    598      *     WPA_BSS_MASK_BSSID      (Bit 1)
    599      *     WPA_BSS_MASK_FREQ       (Bit 2)
    600      *     WPA_BSS_MASK_LEVEL      (Bit 7)
    601      *     WPA_BSS_MASK_TSF        (Bit 8)
    602      *     WPA_BSS_MASK_IE         (Bit 10)
    603      *     WPA_BSS_MASK_FLAGS      (Bit 11)
    604      *     WPA_BSS_MASK_SSID       (Bit 12)
    605      *     WPA_BSS_MASK_INTERNETW  (Bit 15) (adds ANQP info)
    606      *     WPA_BSS_MASK_DELIM      (Bit 17)
    607      *
    608      * See wpa_supplicant/src/common/wpa_ctrl.h for details.
    609      */
    610     private String getRawScanResults(String range) {
    611         return doStringCommandWithoutLogging("BSS RANGE=" + range + " MASK=0x29d87");
    612     }
    613 
    614     private static final String BSS_IE_STR = "ie=";
    615     private static final String BSS_ID_STR = "id=";
    616     private static final String BSS_BSSID_STR = "bssid=";
    617     private static final String BSS_FREQ_STR = "freq=";
    618     private static final String BSS_LEVEL_STR = "level=";
    619     private static final String BSS_TSF_STR = "tsf=";
    620     private static final String BSS_FLAGS_STR = "flags=";
    621     private static final String BSS_SSID_STR = "ssid=";
    622     private static final String BSS_DELIMITER_STR = "====";
    623     private static final String BSS_END_STR = "####";
    624 
    625     public ArrayList<ScanDetail> getScanResults() {
    626         int next_sid = 0;
    627         ArrayList<ScanDetail> results = new ArrayList<>();
    628         while(next_sid >= 0) {
    629             String rawResult = getRawScanResults(next_sid+"-");
    630             next_sid = -1;
    631 
    632             if (TextUtils.isEmpty(rawResult))
    633                 break;
    634 
    635             String[] lines = rawResult.split("\n");
    636 
    637 
    638             // note that all these splits and substrings keep references to the original
    639             // huge string buffer while the amount we really want is generally pretty small
    640             // so make copies instead (one example b/11087956 wasted 400k of heap here).
    641             final int bssidStrLen = BSS_BSSID_STR.length();
    642             final int flagLen = BSS_FLAGS_STR.length();
    643 
    644             String bssid = "";
    645             int level = 0;
    646             int freq = 0;
    647             long tsf = 0;
    648             String flags = "";
    649             WifiSsid wifiSsid = null;
    650             String infoElementsStr = null;
    651             List<String> anqpLines = null;
    652 
    653             for (String line : lines) {
    654                 if (line.startsWith(BSS_ID_STR)) { // Will find the last id line
    655                     try {
    656                         next_sid = Integer.parseInt(line.substring(BSS_ID_STR.length())) + 1;
    657                     } catch (NumberFormatException e) {
    658                         // Nothing to do
    659                     }
    660                 } else if (line.startsWith(BSS_BSSID_STR)) {
    661                     bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen);
    662                 } else if (line.startsWith(BSS_FREQ_STR)) {
    663                     try {
    664                         freq = Integer.parseInt(line.substring(BSS_FREQ_STR.length()));
    665                     } catch (NumberFormatException e) {
    666                         freq = 0;
    667                     }
    668                 } else if (line.startsWith(BSS_LEVEL_STR)) {
    669                     try {
    670                         level = Integer.parseInt(line.substring(BSS_LEVEL_STR.length()));
    671                         /* some implementations avoid negative values by adding 256
    672                          * so we need to adjust for that here.
    673                          */
    674                         if (level > 0) level -= 256;
    675                     } catch (NumberFormatException e) {
    676                         level = 0;
    677                     }
    678                 } else if (line.startsWith(BSS_TSF_STR)) {
    679                     try {
    680                         tsf = Long.parseLong(line.substring(BSS_TSF_STR.length()));
    681                     } catch (NumberFormatException e) {
    682                         tsf = 0;
    683                     }
    684                 } else if (line.startsWith(BSS_FLAGS_STR)) {
    685                     flags = new String(line.getBytes(), flagLen, line.length() - flagLen);
    686                 } else if (line.startsWith(BSS_SSID_STR)) {
    687                     wifiSsid = WifiSsid.createFromAsciiEncoded(
    688                             line.substring(BSS_SSID_STR.length()));
    689                 } else if (line.startsWith(BSS_IE_STR)) {
    690                     infoElementsStr = line;
    691                 } else if (SupplicantBridge.isAnqpAttribute(line)) {
    692                     if (anqpLines == null) {
    693                         anqpLines = new ArrayList<>();
    694                     }
    695                     anqpLines.add(line);
    696                 } else if (line.startsWith(BSS_DELIMITER_STR) || line.startsWith(BSS_END_STR)) {
    697                     if (bssid != null) {
    698                         try {
    699                             if (infoElementsStr == null) {
    700                                 throw new IllegalArgumentException("Null information element data");
    701                             }
    702                             int seperator = infoElementsStr.indexOf('=');
    703                             if (seperator < 0) {
    704                                 throw new IllegalArgumentException("No element separator");
    705                             }
    706 
    707                             ScanResult.InformationElement[] infoElements =
    708                                         InformationElementUtil.parseInformationElements(
    709                                         Utils.hexToBytes(infoElementsStr.substring(seperator + 1)));
    710 
    711                             NetworkDetail networkDetail = new NetworkDetail(bssid,
    712                                     infoElements, anqpLines, freq);
    713                             String xssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
    714                             if (!xssid.equals(networkDetail.getTrimmedSSID())) {
    715                                 Log.d(TAG, String.format(
    716                                         "Inconsistent SSID on BSSID '%s': '%s' vs '%s': %s",
    717                                         bssid, xssid, networkDetail.getSSID(), infoElementsStr));
    718                             }
    719 
    720                             if (networkDetail.hasInterworking()) {
    721                                 if (DBG) Log.d(TAG, "HSNwk: '" + networkDetail);
    722                             }
    723                             ScanDetail scan = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
    724                                     level, freq, tsf, infoElements, anqpLines);
    725                             results.add(scan);
    726                         } catch (IllegalArgumentException iae) {
    727                             Log.d(TAG, "Failed to parse information elements: " + iae);
    728                         }
    729                     }
    730                     bssid = null;
    731                     level = 0;
    732                     freq = 0;
    733                     tsf = 0;
    734                     flags = "";
    735                     wifiSsid = null;
    736                     infoElementsStr = null;
    737                     anqpLines = null;
    738                 }
    739             }
    740         }
    741         return results;
    742     }
    743 
    744     /**
    745      * Format of result:
    746      * id=1016
    747      * bssid=00:03:7f:40:84:10
    748      * freq=2462
    749      * beacon_int=200
    750      * capabilities=0x0431
    751      * qual=0
    752      * noise=0
    753      * level=-46
    754      * tsf=0000002669008476
    755      * age=5
    756      * ie=00105143412d485332302d52322d54455354010882848b960c12182403010b0706555...
    757      * flags=[WPA2-EAP-CCMP][ESS][P2P][HS20]
    758      * ssid=QCA-HS20-R2-TEST
    759      * p2p_device_name=
    760      * p2p_config_methods=0x0SET_NE
    761      * anqp_venue_name=02083d656e6757692d466920416c6c69616e63650a3239383920436f...
    762      * anqp_network_auth_type=010000
    763      * anqp_roaming_consortium=03506f9a05001bc504bd
    764      * anqp_ip_addr_type_availability=0c
    765      * anqp_nai_realm=0200300000246d61696c2e6578616d706c652e636f6d3b636973636f2...
    766      * anqp_3gpp=000600040132f465
    767      * anqp_domain_name=0b65786d61706c652e636f6d
    768      * hs20_operator_friendly_name=11656e6757692d466920416c6c69616e63650e636869...
    769      * hs20_wan_metrics=01c40900008001000000000a00
    770      * hs20_connection_capability=0100000006140001061600000650000106bb010106bb0...
    771      * hs20_osu_providers_list=0b5143412d4f53552d425353010901310015656e6757692d...
    772      */
    773     public String scanResult(String bssid) {
    774         return doStringCommand("BSS " + bssid);
    775     }
    776 
    777     public boolean startDriver() {
    778         return doBooleanCommand("DRIVER START");
    779     }
    780 
    781     public boolean stopDriver() {
    782         return doBooleanCommand("DRIVER STOP");
    783     }
    784 
    785 
    786     /**
    787      * Start filtering out Multicast V4 packets
    788      * @return {@code true} if the operation succeeded, {@code false} otherwise
    789      *
    790      * Multicast filtering rules work as follows:
    791      *
    792      * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
    793      * a power optimized mode (typically when screen goes off).
    794      *
    795      * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
    796      * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
    797      *
    798      * DRIVER RXFILTER-ADD Num
    799      *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
    800      *
    801      * and DRIVER RXFILTER-START
    802      * In order to stop the usage of these rules, we do
    803      *
    804      * DRIVER RXFILTER-STOP
    805      * DRIVER RXFILTER-REMOVE Num
    806      *   where Num is as described for RXFILTER-ADD
    807      *
    808      * The  SETSUSPENDOPT driver command overrides the filtering rules
    809      */
    810     public boolean startFilteringMulticastV4Packets() {
    811         return doBooleanCommand("DRIVER RXFILTER-STOP")
    812             && doBooleanCommand("DRIVER RXFILTER-REMOVE 2")
    813             && doBooleanCommand("DRIVER RXFILTER-START");
    814     }
    815 
    816     /**
    817      * Stop filtering out Multicast V4 packets.
    818      * @return {@code true} if the operation succeeded, {@code false} otherwise
    819      */
    820     public boolean stopFilteringMulticastV4Packets() {
    821         return doBooleanCommand("DRIVER RXFILTER-STOP")
    822             && doBooleanCommand("DRIVER RXFILTER-ADD 2")
    823             && doBooleanCommand("DRIVER RXFILTER-START");
    824     }
    825 
    826     /**
    827      * Start filtering out Multicast V6 packets
    828      * @return {@code true} if the operation succeeded, {@code false} otherwise
    829      */
    830     public boolean startFilteringMulticastV6Packets() {
    831         return doBooleanCommand("DRIVER RXFILTER-STOP")
    832             && doBooleanCommand("DRIVER RXFILTER-REMOVE 3")
    833             && doBooleanCommand("DRIVER RXFILTER-START");
    834     }
    835 
    836     /**
    837      * Stop filtering out Multicast V6 packets.
    838      * @return {@code true} if the operation succeeded, {@code false} otherwise
    839      */
    840     public boolean stopFilteringMulticastV6Packets() {
    841         return doBooleanCommand("DRIVER RXFILTER-STOP")
    842             && doBooleanCommand("DRIVER RXFILTER-ADD 3")
    843             && doBooleanCommand("DRIVER RXFILTER-START");
    844     }
    845 
    846     /**
    847      * Set the operational frequency band
    848      * @param band One of
    849      *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
    850      *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
    851      *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
    852      * @return {@code true} if the operation succeeded, {@code false} otherwise
    853      */
    854     public boolean setBand(int band) {
    855         String bandstr;
    856 
    857         if (band == WifiManager.WIFI_FREQUENCY_BAND_5GHZ)
    858             bandstr = "5G";
    859         else if (band == WifiManager.WIFI_FREQUENCY_BAND_2GHZ)
    860             bandstr = "2G";
    861         else
    862             bandstr = "AUTO";
    863         return doBooleanCommand("SET SETBAND " + bandstr);
    864     }
    865 
    866     public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED     = 0;
    867     public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED    = 1;
    868     public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE       = 2;
    869     /**
    870       * Sets the bluetooth coexistence mode.
    871       *
    872       * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
    873       *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
    874       *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
    875       * @return Whether the mode was successfully set.
    876       */
    877     public boolean setBluetoothCoexistenceMode(int mode) {
    878         return doBooleanCommand("DRIVER BTCOEXMODE " + mode);
    879     }
    880 
    881     /**
    882      * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
    883      * some of the low-level scan parameters used by the driver are changed to
    884      * reduce interference with A2DP streaming.
    885      *
    886      * @param isSet whether to enable or disable this mode
    887      * @return {@code true} if the command succeeded, {@code false} otherwise.
    888      */
    889     public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) {
    890         if (setCoexScanMode) {
    891             return doBooleanCommand("DRIVER BTCOEXSCAN-START");
    892         } else {
    893             return doBooleanCommand("DRIVER BTCOEXSCAN-STOP");
    894         }
    895     }
    896 
    897     public void enableSaveConfig() {
    898         doBooleanCommand("SET update_config 1");
    899     }
    900 
    901     public boolean saveConfig() {
    902         return doBooleanCommand("SAVE_CONFIG");
    903     }
    904 
    905     public boolean addToBlacklist(String bssid) {
    906         if (TextUtils.isEmpty(bssid)) return false;
    907         return doBooleanCommand("BLACKLIST " + bssid);
    908     }
    909 
    910     public boolean clearBlacklist() {
    911         return doBooleanCommand("BLACKLIST clear");
    912     }
    913 
    914     public boolean setSuspendOptimizations(boolean enabled) {
    915         if (enabled) {
    916             return doBooleanCommand("DRIVER SETSUSPENDMODE 1");
    917         } else {
    918             return doBooleanCommand("DRIVER SETSUSPENDMODE 0");
    919         }
    920     }
    921 
    922     public boolean setCountryCode(String countryCode) {
    923         if (countryCode != null)
    924             return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
    925         else
    926             return doBooleanCommand("DRIVER COUNTRY");
    927     }
    928 
    929     /**
    930      * Start/Stop PNO scan.
    931      * @param enable boolean indicating whether PNO is being enabled or disabled.
    932      */
    933     public boolean setPnoScan(boolean enable) {
    934         String cmd = enable ? "SET pno 1" : "SET pno 0";
    935         return doBooleanCommand(cmd);
    936     }
    937 
    938     public void enableAutoConnect(boolean enable) {
    939         if (enable) {
    940             doBooleanCommand("STA_AUTOCONNECT 1");
    941         } else {
    942             doBooleanCommand("STA_AUTOCONNECT 0");
    943         }
    944     }
    945 
    946     public void setScanInterval(int scanInterval) {
    947         doBooleanCommand("SCAN_INTERVAL " + scanInterval);
    948     }
    949 
    950     public void setHs20(boolean hs20) {
    951         if (hs20) {
    952             doBooleanCommand("SET HS20 1");
    953         } else {
    954             doBooleanCommand("SET HS20 0");
    955         }
    956     }
    957 
    958     public void startTdls(String macAddr, boolean enable) {
    959         if (enable) {
    960             synchronized (sLock) {
    961                 doBooleanCommand("TDLS_DISCOVER " + macAddr);
    962                 doBooleanCommand("TDLS_SETUP " + macAddr);
    963             }
    964         } else {
    965             doBooleanCommand("TDLS_TEARDOWN " + macAddr);
    966         }
    967     }
    968 
    969     /** Example output:
    970      * RSSI=-65
    971      * LINKSPEED=48
    972      * NOISE=9999
    973      * FREQUENCY=0
    974      */
    975     public String signalPoll() {
    976         return doStringCommandWithoutLogging("SIGNAL_POLL");
    977     }
    978 
    979     /** Example outout:
    980      * TXGOOD=396
    981      * TXBAD=1
    982      */
    983     public String pktcntPoll() {
    984         return doStringCommand("PKTCNT_POLL");
    985     }
    986 
    987     public void bssFlush() {
    988         doBooleanCommand("BSS_FLUSH 0");
    989     }
    990 
    991     public boolean startWpsPbc(String bssid) {
    992         if (TextUtils.isEmpty(bssid)) {
    993             return doBooleanCommand("WPS_PBC");
    994         } else {
    995             return doBooleanCommand("WPS_PBC " + bssid);
    996         }
    997     }
    998 
    999     public boolean startWpsPbc(String iface, String bssid) {
   1000         synchronized (sLock) {
   1001             if (TextUtils.isEmpty(bssid)) {
   1002                 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
   1003             } else {
   1004                 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
   1005             }
   1006         }
   1007     }
   1008 
   1009     public boolean startWpsPinKeypad(String pin) {
   1010         if (TextUtils.isEmpty(pin)) return false;
   1011         return doBooleanCommand("WPS_PIN any " + pin);
   1012     }
   1013 
   1014     public boolean startWpsPinKeypad(String iface, String pin) {
   1015         if (TextUtils.isEmpty(pin)) return false;
   1016         synchronized (sLock) {
   1017             return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
   1018         }
   1019     }
   1020 
   1021 
   1022     public String startWpsPinDisplay(String bssid) {
   1023         if (TextUtils.isEmpty(bssid)) {
   1024             return doStringCommand("WPS_PIN any");
   1025         } else {
   1026             return doStringCommand("WPS_PIN " + bssid);
   1027         }
   1028     }
   1029 
   1030     public String startWpsPinDisplay(String iface, String bssid) {
   1031         synchronized (sLock) {
   1032             if (TextUtils.isEmpty(bssid)) {
   1033                 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
   1034             } else {
   1035                 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
   1036             }
   1037         }
   1038     }
   1039 
   1040     public boolean setExternalSim(boolean external) {
   1041         String value = external ? "1" : "0";
   1042         Log.d(TAG, "Setting external_sim to " + value);
   1043         return doBooleanCommand("SET external_sim " + value);
   1044     }
   1045 
   1046     public boolean simAuthResponse(int id, String type, String response) {
   1047         // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS
   1048         return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response);
   1049     }
   1050 
   1051     public boolean simAuthFailedResponse(int id) {
   1052         // should be used with type GSM-AUTH
   1053         return doBooleanCommand("CTRL-RSP-SIM-" + id + ":GSM-FAIL");
   1054     }
   1055 
   1056     public boolean umtsAuthFailedResponse(int id) {
   1057         // should be used with type UMTS-AUTH
   1058         return doBooleanCommand("CTRL-RSP-SIM-" + id + ":UMTS-FAIL");
   1059     }
   1060 
   1061     public boolean simIdentityResponse(int id, String response) {
   1062         return doBooleanCommand("CTRL-RSP-IDENTITY-" + id + ":" + response);
   1063     }
   1064 
   1065     /* Configures an access point connection */
   1066     public boolean startWpsRegistrar(String bssid, String pin) {
   1067         if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false;
   1068         return doBooleanCommand("WPS_REG " + bssid + " " + pin);
   1069     }
   1070 
   1071     public boolean cancelWps() {
   1072         return doBooleanCommand("WPS_CANCEL");
   1073     }
   1074 
   1075     public boolean setPersistentReconnect(boolean enabled) {
   1076         int value = (enabled == true) ? 1 : 0;
   1077         return doBooleanCommand("SET persistent_reconnect " + value);
   1078     }
   1079 
   1080     public boolean setDeviceName(String name) {
   1081         return doBooleanCommand("SET device_name " + name);
   1082     }
   1083 
   1084     public boolean setDeviceType(String type) {
   1085         return doBooleanCommand("SET device_type " + type);
   1086     }
   1087 
   1088     public boolean setConfigMethods(String cfg) {
   1089         return doBooleanCommand("SET config_methods " + cfg);
   1090     }
   1091 
   1092     public boolean setManufacturer(String value) {
   1093         return doBooleanCommand("SET manufacturer " + value);
   1094     }
   1095 
   1096     public boolean setModelName(String value) {
   1097         return doBooleanCommand("SET model_name " + value);
   1098     }
   1099 
   1100     public boolean setModelNumber(String value) {
   1101         return doBooleanCommand("SET model_number " + value);
   1102     }
   1103 
   1104     public boolean setSerialNumber(String value) {
   1105         return doBooleanCommand("SET serial_number " + value);
   1106     }
   1107 
   1108     public boolean setP2pSsidPostfix(String postfix) {
   1109         return doBooleanCommand("SET p2p_ssid_postfix " + postfix);
   1110     }
   1111 
   1112     public boolean setP2pGroupIdle(String iface, int time) {
   1113         synchronized (sLock) {
   1114             return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
   1115         }
   1116     }
   1117 
   1118     public void setPowerSave(boolean enabled) {
   1119         if (enabled) {
   1120             doBooleanCommand("SET ps 1");
   1121         } else {
   1122             doBooleanCommand("SET ps 0");
   1123         }
   1124     }
   1125 
   1126     public boolean setP2pPowerSave(String iface, boolean enabled) {
   1127         synchronized (sLock) {
   1128             if (enabled) {
   1129                 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
   1130             } else {
   1131                 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
   1132             }
   1133         }
   1134     }
   1135 
   1136     public boolean setWfdEnable(boolean enable) {
   1137         return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0"));
   1138     }
   1139 
   1140     public boolean setWfdDeviceInfo(String hex) {
   1141         return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex);
   1142     }
   1143 
   1144     /**
   1145      * "sta" prioritizes STA connection over P2P and "p2p" prioritizes
   1146      * P2P connection over STA
   1147      */
   1148     public boolean setConcurrencyPriority(String s) {
   1149         return doBooleanCommand("P2P_SET conc_pref " + s);
   1150     }
   1151 
   1152     public boolean p2pFind() {
   1153         return doBooleanCommand("P2P_FIND");
   1154     }
   1155 
   1156     public boolean p2pFind(int timeout) {
   1157         if (timeout <= 0) {
   1158             return p2pFind();
   1159         }
   1160         return doBooleanCommand("P2P_FIND " + timeout);
   1161     }
   1162 
   1163     public boolean p2pStopFind() {
   1164        return doBooleanCommand("P2P_STOP_FIND");
   1165     }
   1166 
   1167     public boolean p2pListen() {
   1168         return doBooleanCommand("P2P_LISTEN");
   1169     }
   1170 
   1171     public boolean p2pListen(int timeout) {
   1172         if (timeout <= 0) {
   1173             return p2pListen();
   1174         }
   1175         return doBooleanCommand("P2P_LISTEN " + timeout);
   1176     }
   1177 
   1178     public boolean p2pExtListen(boolean enable, int period, int interval) {
   1179         if (enable && interval < period) {
   1180             return false;
   1181         }
   1182         return doBooleanCommand("P2P_EXT_LISTEN"
   1183                     + (enable ? (" " + period + " " + interval) : ""));
   1184     }
   1185 
   1186     public boolean p2pSetChannel(int lc, int oc) {
   1187         if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc);
   1188 
   1189         synchronized (sLock) {
   1190             if (lc >=1 && lc <= 11) {
   1191                 if (!doBooleanCommand("P2P_SET listen_channel " + lc)) {
   1192                     return false;
   1193                 }
   1194             } else if (lc != 0) {
   1195                 return false;
   1196             }
   1197 
   1198             if (oc >= 1 && oc <= 165 ) {
   1199                 int freq = (oc <= 14 ? 2407 : 5000) + oc * 5;
   1200                 return doBooleanCommand("P2P_SET disallow_freq 1000-"
   1201                         + (freq - 5) + "," + (freq + 5) + "-6000");
   1202             } else if (oc == 0) {
   1203                 /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */
   1204                 return doBooleanCommand("P2P_SET disallow_freq \"\"");
   1205             }
   1206         }
   1207         return false;
   1208     }
   1209 
   1210     public boolean p2pFlush() {
   1211         return doBooleanCommand("P2P_FLUSH");
   1212     }
   1213 
   1214     private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
   1215     /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad]
   1216         [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */
   1217     public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) {
   1218         if (config == null) return null;
   1219         List<String> args = new ArrayList<String>();
   1220         WpsInfo wps = config.wps;
   1221         args.add(config.deviceAddress);
   1222 
   1223         switch (wps.setup) {
   1224             case WpsInfo.PBC:
   1225                 args.add("pbc");
   1226                 break;
   1227             case WpsInfo.DISPLAY:
   1228                 if (TextUtils.isEmpty(wps.pin)) {
   1229                     args.add("pin");
   1230                 } else {
   1231                     args.add(wps.pin);
   1232                 }
   1233                 args.add("display");
   1234                 break;
   1235             case WpsInfo.KEYPAD:
   1236                 args.add(wps.pin);
   1237                 args.add("keypad");
   1238                 break;
   1239             case WpsInfo.LABEL:
   1240                 args.add(wps.pin);
   1241                 args.add("label");
   1242             default:
   1243                 break;
   1244         }
   1245 
   1246         if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) {
   1247             args.add("persistent");
   1248         }
   1249 
   1250         if (joinExistingGroup) {
   1251             args.add("join");
   1252         } else {
   1253             //TODO: This can be adapted based on device plugged in state and
   1254             //device battery state
   1255             int groupOwnerIntent = config.groupOwnerIntent;
   1256             if (groupOwnerIntent < 0 || groupOwnerIntent > 15) {
   1257                 groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT;
   1258             }
   1259             args.add("go_intent=" + groupOwnerIntent);
   1260         }
   1261 
   1262         String command = "P2P_CONNECT ";
   1263         for (String s : args) command += s + " ";
   1264 
   1265         return doStringCommand(command);
   1266     }
   1267 
   1268     public boolean p2pCancelConnect() {
   1269         return doBooleanCommand("P2P_CANCEL");
   1270     }
   1271 
   1272     public boolean p2pProvisionDiscovery(WifiP2pConfig config) {
   1273         if (config == null) return false;
   1274 
   1275         switch (config.wps.setup) {
   1276             case WpsInfo.PBC:
   1277                 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc");
   1278             case WpsInfo.DISPLAY:
   1279                 //We are doing display, so provision discovery is keypad
   1280                 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad");
   1281             case WpsInfo.KEYPAD:
   1282                 //We are doing keypad, so provision discovery is display
   1283                 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display");
   1284             default:
   1285                 break;
   1286         }
   1287         return false;
   1288     }
   1289 
   1290     public boolean p2pGroupAdd(boolean persistent) {
   1291         if (persistent) {
   1292             return doBooleanCommand("P2P_GROUP_ADD persistent");
   1293         }
   1294         return doBooleanCommand("P2P_GROUP_ADD");
   1295     }
   1296 
   1297     public boolean p2pGroupAdd(int netId) {
   1298         return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId);
   1299     }
   1300 
   1301     public boolean p2pGroupRemove(String iface) {
   1302         if (TextUtils.isEmpty(iface)) return false;
   1303         synchronized (sLock) {
   1304             return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
   1305         }
   1306     }
   1307 
   1308     public boolean p2pReject(String deviceAddress) {
   1309         return doBooleanCommand("P2P_REJECT " + deviceAddress);
   1310     }
   1311 
   1312     /* Invite a peer to a group */
   1313     public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) {
   1314         if (TextUtils.isEmpty(deviceAddress)) return false;
   1315 
   1316         if (group == null) {
   1317             return doBooleanCommand("P2P_INVITE peer=" + deviceAddress);
   1318         } else {
   1319             return doBooleanCommand("P2P_INVITE group=" + group.getInterface()
   1320                     + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress);
   1321         }
   1322     }
   1323 
   1324     /* Reinvoke a persistent connection */
   1325     public boolean p2pReinvoke(int netId, String deviceAddress) {
   1326         if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false;
   1327 
   1328         return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress);
   1329     }
   1330 
   1331     public String p2pGetSsid(String deviceAddress) {
   1332         return p2pGetParam(deviceAddress, "oper_ssid");
   1333     }
   1334 
   1335     public String p2pGetDeviceAddress() {
   1336         Log.d(TAG, "p2pGetDeviceAddress");
   1337 
   1338         String status = null;
   1339 
   1340         /* Explicitly calling the API without IFNAME= prefix to take care of the devices that
   1341         don't have p2p0 interface. Supplicant seems to be returning the correct address anyway. */
   1342 
   1343         synchronized (sLock) {
   1344             status = doStringCommandNative("STATUS");
   1345         }
   1346 
   1347         String result = "";
   1348         if (status != null) {
   1349             String[] tokens = status.split("\n");
   1350             for (String token : tokens) {
   1351                 if (token.startsWith("p2p_device_address=")) {
   1352                     String[] nameValue = token.split("=");
   1353                     if (nameValue.length != 2)
   1354                         break;
   1355                     result = nameValue[1];
   1356                 }
   1357             }
   1358         }
   1359 
   1360         Log.d(TAG, "p2pGetDeviceAddress returning " + result);
   1361         return result;
   1362     }
   1363 
   1364     public int getGroupCapability(String deviceAddress) {
   1365         int gc = 0;
   1366         if (TextUtils.isEmpty(deviceAddress)) return gc;
   1367         String peerInfo = p2pPeer(deviceAddress);
   1368         if (TextUtils.isEmpty(peerInfo)) return gc;
   1369 
   1370         String[] tokens = peerInfo.split("\n");
   1371         for (String token : tokens) {
   1372             if (token.startsWith("group_capab=")) {
   1373                 String[] nameValue = token.split("=");
   1374                 if (nameValue.length != 2) break;
   1375                 try {
   1376                     return Integer.decode(nameValue[1]);
   1377                 } catch(NumberFormatException e) {
   1378                     return gc;
   1379                 }
   1380             }
   1381         }
   1382         return gc;
   1383     }
   1384 
   1385     public String p2pPeer(String deviceAddress) {
   1386         return doStringCommand("P2P_PEER " + deviceAddress);
   1387     }
   1388 
   1389     private String p2pGetParam(String deviceAddress, String key) {
   1390         if (deviceAddress == null) return null;
   1391 
   1392         String peerInfo = p2pPeer(deviceAddress);
   1393         if (peerInfo == null) return null;
   1394         String[] tokens= peerInfo.split("\n");
   1395 
   1396         key += "=";
   1397         for (String token : tokens) {
   1398             if (token.startsWith(key)) {
   1399                 String[] nameValue = token.split("=");
   1400                 if (nameValue.length != 2) break;
   1401                 return nameValue[1];
   1402             }
   1403         }
   1404         return null;
   1405     }
   1406 
   1407     public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) {
   1408         /*
   1409          * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump>
   1410          * P2P_SERVICE_ADD upnp <version hex> <service>
   1411          *
   1412          * e.g)
   1413          * [Bonjour]
   1414          * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.)
   1415          * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027
   1416          * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript)
   1417          * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001
   1418          *  09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074
   1419          *
   1420          * [UPnP]
   1421          * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
   1422          * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice
   1423          * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp
   1424          * -org:device:InternetGatewayDevice:1
   1425          * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp
   1426          * -org:service:ContentDirectory:2
   1427          */
   1428         synchronized (sLock) {
   1429             for (String s : servInfo.getSupplicantQueryList()) {
   1430                 String command = "P2P_SERVICE_ADD";
   1431                 command += (" " + s);
   1432                 if (!doBooleanCommand(command)) {
   1433                     return false;
   1434                 }
   1435             }
   1436         }
   1437         return true;
   1438     }
   1439 
   1440     public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) {
   1441         /*
   1442          * P2P_SERVICE_DEL bonjour <query hexdump>
   1443          * P2P_SERVICE_DEL upnp <version hex> <service>
   1444          */
   1445         synchronized (sLock) {
   1446             for (String s : servInfo.getSupplicantQueryList()) {
   1447                 String command = "P2P_SERVICE_DEL ";
   1448 
   1449                 String[] data = s.split(" ");
   1450                 if (data.length < 2) {
   1451                     return false;
   1452                 }
   1453                 if ("upnp".equals(data[0])) {
   1454                     command += s;
   1455                 } else if ("bonjour".equals(data[0])) {
   1456                     command += data[0];
   1457                     command += (" " + data[1]);
   1458                 } else {
   1459                     return false;
   1460                 }
   1461                 if (!doBooleanCommand(command)) {
   1462                     return false;
   1463                 }
   1464             }
   1465         }
   1466         return true;
   1467     }
   1468 
   1469     public boolean p2pServiceFlush() {
   1470         return doBooleanCommand("P2P_SERVICE_FLUSH");
   1471     }
   1472 
   1473     public String p2pServDiscReq(String addr, String query) {
   1474         String command = "P2P_SERV_DISC_REQ";
   1475         command += (" " + addr);
   1476         command += (" " + query);
   1477 
   1478         return doStringCommand(command);
   1479     }
   1480 
   1481     public boolean p2pServDiscCancelReq(String id) {
   1482         return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id);
   1483     }
   1484 
   1485     /* Set the current mode of miracast operation.
   1486      *  0 = disabled
   1487      *  1 = operating as source
   1488      *  2 = operating as sink
   1489      */
   1490     public void setMiracastMode(int mode) {
   1491         // Note: optional feature on the driver. It is ok for this to fail.
   1492         doBooleanCommand("DRIVER MIRACAST " + mode);
   1493     }
   1494 
   1495     public boolean fetchAnqp(String bssid, String subtypes) {
   1496         return doBooleanCommand("ANQP_GET " + bssid + " " + subtypes);
   1497     }
   1498 
   1499     /*
   1500      * NFC-related calls
   1501      */
   1502     public String getNfcWpsConfigurationToken(int netId) {
   1503         return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId);
   1504     }
   1505 
   1506     public String getNfcHandoverRequest() {
   1507         return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR");
   1508     }
   1509 
   1510     public String getNfcHandoverSelect() {
   1511         return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR");
   1512     }
   1513 
   1514     public boolean initiatorReportNfcHandover(String selectMessage) {
   1515         return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage);
   1516     }
   1517 
   1518     public boolean responderReportNfcHandover(String requestMessage) {
   1519         return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00");
   1520     }
   1521 
   1522 
   1523     /* kernel logging support */
   1524     private static native byte[] readKernelLogNative();
   1525 
   1526     synchronized public String readKernelLog() {
   1527         byte[] bytes = readKernelLogNative();
   1528         if (bytes != null) {
   1529             CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
   1530             try {
   1531                 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
   1532                 return decoded.toString();
   1533             } catch (CharacterCodingException cce) {
   1534                 return new String(bytes, StandardCharsets.ISO_8859_1);
   1535             }
   1536         } else {
   1537             return "*** failed to read kernel log ***";
   1538         }
   1539     }
   1540 
   1541     /* WIFI HAL support */
   1542 
   1543     // HAL command ids
   1544     private static int sCmdId = 1;
   1545     private static int getNewCmdIdLocked() {
   1546         return sCmdId++;
   1547     }
   1548 
   1549     private static final String TAG = "WifiNative-HAL";
   1550     private static long sWifiHalHandle = 0;             /* used by JNI to save wifi_handle */
   1551     private static long[] sWifiIfaceHandles = null;     /* used by JNI to save interface handles */
   1552     public static int sWlan0Index = -1;
   1553     private static MonitorThread sThread;
   1554     private static final int STOP_HAL_TIMEOUT_MS = 1000;
   1555 
   1556     private static native boolean startHalNative();
   1557     private static native void stopHalNative();
   1558     private static native void waitForHalEventNative();
   1559 
   1560     private static class MonitorThread extends Thread {
   1561         public void run() {
   1562             Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle));
   1563             waitForHalEventNative();
   1564         }
   1565     }
   1566 
   1567     public boolean startHal() {
   1568         String debugLog = "startHal stack: ";
   1569         java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace();
   1570         for (int i = 2; i < elements.length && i <= 7; i++ ) {
   1571             debugLog = debugLog + " - " + elements[i].getMethodName();
   1572         }
   1573 
   1574         sLocalLog.log(debugLog);
   1575 
   1576         synchronized (sLock) {
   1577             if (startHalNative()) {
   1578                 int wlan0Index = queryInterfaceIndex(mInterfaceName);
   1579                 if (wlan0Index == -1) {
   1580                     if (DBG) sLocalLog.log("Could not find interface with name: " + mInterfaceName);
   1581                     return false;
   1582                 }
   1583                 sWlan0Index = wlan0Index;
   1584                 sThread = new MonitorThread();
   1585                 sThread.start();
   1586                 return true;
   1587             } else {
   1588                 if (DBG) sLocalLog.log("Could not start hal");
   1589                 Log.e(TAG, "Could not start hal");
   1590                 return false;
   1591             }
   1592         }
   1593     }
   1594 
   1595     public void stopHal() {
   1596         synchronized (sLock) {
   1597             if (isHalStarted()) {
   1598                 stopHalNative();
   1599                 try {
   1600                     sThread.join(STOP_HAL_TIMEOUT_MS);
   1601                     Log.d(TAG, "HAL event thread stopped successfully");
   1602                 } catch (InterruptedException e) {
   1603                     Log.e(TAG, "Could not stop HAL cleanly");
   1604                 }
   1605                 sThread = null;
   1606                 sWifiHalHandle = 0;
   1607                 sWifiIfaceHandles = null;
   1608                 sWlan0Index = -1;
   1609             }
   1610         }
   1611     }
   1612 
   1613     public boolean isHalStarted() {
   1614         return (sWifiHalHandle != 0);
   1615     }
   1616     private static native int getInterfacesNative();
   1617 
   1618     public int queryInterfaceIndex(String interfaceName) {
   1619         synchronized (sLock) {
   1620             if (isHalStarted()) {
   1621                 int num = getInterfacesNative();
   1622                 for (int i = 0; i < num; i++) {
   1623                     String name = getInterfaceNameNative(i);
   1624                     if (name.equals(interfaceName)) {
   1625                         return i;
   1626                     }
   1627                 }
   1628             }
   1629         }
   1630         return -1;
   1631     }
   1632 
   1633     private static native String getInterfaceNameNative(int index);
   1634     public String getInterfaceName(int index) {
   1635         synchronized (sLock) {
   1636             return getInterfaceNameNative(index);
   1637         }
   1638     }
   1639 
   1640     // TODO: Change variable names to camel style.
   1641     public static class ScanCapabilities {
   1642         public int  max_scan_cache_size;
   1643         public int  max_scan_buckets;
   1644         public int  max_ap_cache_per_scan;
   1645         public int  max_rssi_sample_size;
   1646         public int  max_scan_reporting_threshold;
   1647         public int  max_hotlist_bssids;
   1648         public int  max_significant_wifi_change_aps;
   1649         public int  max_bssid_history_entries;
   1650         public int  max_number_epno_networks;
   1651         public int  max_number_epno_networks_by_ssid;
   1652         public int  max_number_of_white_listed_ssid;
   1653     }
   1654 
   1655     public boolean getScanCapabilities(ScanCapabilities capabilities) {
   1656         synchronized (sLock) {
   1657             return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities);
   1658         }
   1659     }
   1660 
   1661     private static native boolean getScanCapabilitiesNative(
   1662             int iface, ScanCapabilities capabilities);
   1663 
   1664     private static native boolean startScanNative(int iface, int id, ScanSettings settings);
   1665     private static native boolean stopScanNative(int iface, int id);
   1666     private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush);
   1667     private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface);
   1668     private static native void setWifiLinkLayerStatsNative(int iface, int enable);
   1669 
   1670     public static class ChannelSettings {
   1671         public int frequency;
   1672         public int dwell_time_ms;
   1673         public boolean passive;
   1674     }
   1675 
   1676     public static class BucketSettings {
   1677         public int bucket;
   1678         public int band;
   1679         public int period_ms;
   1680         public int max_period_ms;
   1681         public int step_count;
   1682         public int report_events;
   1683         public int num_channels;
   1684         public ChannelSettings[] channels;
   1685     }
   1686 
   1687     public static class ScanSettings {
   1688         public int base_period_ms;
   1689         public int max_ap_per_scan;
   1690         public int report_threshold_percent;
   1691         public int report_threshold_num_scans;
   1692         public int num_buckets;
   1693         /* Not part of gscan HAL API. Used only for wpa_supplicant scanning */
   1694         public int[] hiddenNetworkIds;
   1695         public BucketSettings[] buckets;
   1696     }
   1697 
   1698     /**
   1699      * Network parameters to start PNO scan.
   1700      */
   1701     public static class PnoNetwork {
   1702         public String ssid;
   1703         public int networkId;
   1704         public int priority;
   1705         public byte flags;
   1706         public byte auth_bit_field;
   1707 
   1708         @Override
   1709         public boolean equals(Object otherObj) {
   1710             if (this == otherObj) {
   1711                 return true;
   1712             } else if (otherObj == null || getClass() != otherObj.getClass()) {
   1713                 return false;
   1714             }
   1715             PnoNetwork other = (PnoNetwork) otherObj;
   1716             return ((Objects.equals(ssid, other.ssid)) && (networkId == other.networkId)
   1717                     && (priority == other.priority) && (flags == other.flags)
   1718                     && (auth_bit_field == other.auth_bit_field));
   1719         }
   1720     }
   1721 
   1722     /**
   1723      * Parameters to start PNO scan. This holds the list of networks which are going to used for
   1724      * PNO scan.
   1725      */
   1726     public static class PnoSettings {
   1727         public int min5GHzRssi;
   1728         public int min24GHzRssi;
   1729         public int initialScoreMax;
   1730         public int currentConnectionBonus;
   1731         public int sameNetworkBonus;
   1732         public int secureBonus;
   1733         public int band5GHzBonus;
   1734         public boolean isConnected;
   1735         public PnoNetwork[] networkList;
   1736     }
   1737 
   1738     /**
   1739      * Wi-Fi channel information.
   1740      */
   1741     public static class WifiChannelInfo {
   1742         int mPrimaryFrequency;
   1743         int mCenterFrequency0;
   1744         int mCenterFrequency1;
   1745         int mChannelWidth;
   1746         // TODO: add preamble once available in HAL.
   1747     }
   1748 
   1749     public static interface ScanEventHandler {
   1750         /**
   1751          * Called for each AP as it is found with the entire contents of the beacon/probe response.
   1752          * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified.
   1753          */
   1754         void onFullScanResult(ScanResult fullScanResult, int bucketsScanned);
   1755         /**
   1756          * Callback on an event during a gscan scan.
   1757          * See WifiNative.WIFI_SCAN_* for possible values.
   1758          */
   1759         void onScanStatus(int event);
   1760         /**
   1761          * Called with the current cached scan results when gscan is paused.
   1762          */
   1763         void onScanPaused(WifiScanner.ScanData[] data);
   1764         /**
   1765          * Called with the current cached scan results when gscan is resumed.
   1766          */
   1767         void onScanRestarted();
   1768     }
   1769 
   1770     /**
   1771      * Handler to notify the occurrence of various events during PNO scan.
   1772      */
   1773     public interface PnoEventHandler {
   1774         /**
   1775          * Callback to notify when one of the shortlisted networks is found during PNO scan.
   1776          * @param results List of Scan results received.
   1777          */
   1778         void onPnoNetworkFound(ScanResult[] results);
   1779 
   1780         /**
   1781          * Callback to notify when the PNO scan schedule fails.
   1782          */
   1783         void onPnoScanFailed();
   1784     }
   1785 
   1786     /* scan status, keep these values in sync with gscan.h */
   1787     public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
   1788     public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
   1789     public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
   1790     public static final int WIFI_SCAN_FAILED = 3;
   1791 
   1792     // Callback from native
   1793     private static void onScanStatus(int id, int event) {
   1794         ScanEventHandler handler = sScanEventHandler;
   1795         if (handler != null) {
   1796             handler.onScanStatus(event);
   1797         }
   1798     }
   1799 
   1800     public static  WifiSsid createWifiSsid(byte[] rawSsid) {
   1801         String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid));
   1802 
   1803         if (ssidHexString == null) {
   1804             return null;
   1805         }
   1806 
   1807         WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString);
   1808 
   1809         return wifiSsid;
   1810     }
   1811 
   1812     public static String ssidConvert(byte[] rawSsid) {
   1813         String ssid;
   1814 
   1815         CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
   1816         try {
   1817             CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid));
   1818             ssid = decoded.toString();
   1819         } catch (CharacterCodingException cce) {
   1820             ssid = null;
   1821         }
   1822 
   1823         if (ssid == null) {
   1824             ssid = new String(rawSsid, StandardCharsets.ISO_8859_1);
   1825         }
   1826 
   1827         return ssid;
   1828     }
   1829 
   1830     // Called from native
   1831     public static boolean setSsid(byte[] rawSsid, ScanResult result) {
   1832         if (rawSsid == null || rawSsid.length == 0 || result == null) {
   1833             return false;
   1834         }
   1835 
   1836         result.SSID = ssidConvert(rawSsid);
   1837         result.wifiSsid = createWifiSsid(rawSsid);
   1838         return true;
   1839     }
   1840 
   1841     private static void populateScanResult(ScanResult result, int beaconCap, String dbg) {
   1842         if (dbg == null) dbg = "";
   1843 
   1844         InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation();
   1845         InformationElementUtil.VhtOperation vhtOperation =
   1846                 new InformationElementUtil.VhtOperation();
   1847         InformationElementUtil.ExtendedCapabilities extendedCaps =
   1848                 new InformationElementUtil.ExtendedCapabilities();
   1849 
   1850         ScanResult.InformationElement elements[] =
   1851                 InformationElementUtil.parseInformationElements(result.bytes);
   1852         for (ScanResult.InformationElement ie : elements) {
   1853             if(ie.id == ScanResult.InformationElement.EID_HT_OPERATION) {
   1854                 htOperation.from(ie);
   1855             } else if(ie.id == ScanResult.InformationElement.EID_VHT_OPERATION) {
   1856                 vhtOperation.from(ie);
   1857             } else if (ie.id == ScanResult.InformationElement.EID_EXTENDED_CAPS) {
   1858                 extendedCaps.from(ie);
   1859             }
   1860         }
   1861 
   1862         if (extendedCaps.is80211McRTTResponder) {
   1863             result.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
   1864         } else {
   1865             result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER);
   1866         }
   1867 
   1868         //handle RTT related information
   1869         if (vhtOperation.isValid()) {
   1870             result.channelWidth = vhtOperation.getChannelWidth();
   1871             result.centerFreq0 = vhtOperation.getCenterFreq0();
   1872             result.centerFreq1 = vhtOperation.getCenterFreq1();
   1873         } else {
   1874             result.channelWidth = htOperation.getChannelWidth();
   1875             result.centerFreq0 = htOperation.getCenterFreq0(result.frequency);
   1876             result.centerFreq1  = 0;
   1877         }
   1878 
   1879         // build capabilities string
   1880         BitSet beaconCapBits = new BitSet(16);
   1881         for (int i = 0; i < 16; i++) {
   1882             if ((beaconCap & (1 << i)) != 0) {
   1883                 beaconCapBits.set(i);
   1884             }
   1885         }
   1886         result.capabilities = InformationElementUtil.Capabilities.buildCapabilities(elements,
   1887                                                beaconCapBits);
   1888 
   1889         if(DBG) {
   1890             Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth
   1891                     + " PrimaryFreq: " + result.frequency + " mCenterfreq0: " + result.centerFreq0
   1892                     + " mCenterfreq1: " + result.centerFreq1 + (extendedCaps.is80211McRTTResponder
   1893                     ? "Support RTT reponder: " : "Do not support RTT responder")
   1894                     + " Capabilities: " + result.capabilities);
   1895         }
   1896 
   1897         result.informationElements = elements;
   1898     }
   1899 
   1900     // Callback from native
   1901     private static void onFullScanResult(int id, ScanResult result,
   1902             int bucketsScanned, int beaconCap) {
   1903         if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID);
   1904 
   1905         ScanEventHandler handler = sScanEventHandler;
   1906         if (handler != null) {
   1907             populateScanResult(result, beaconCap, " onFullScanResult ");
   1908             handler.onFullScanResult(result, bucketsScanned);
   1909         }
   1910     }
   1911 
   1912     private static int sScanCmdId = 0;
   1913     private static ScanEventHandler sScanEventHandler;
   1914     private static ScanSettings sScanSettings;
   1915 
   1916     public boolean startScan(ScanSettings settings, ScanEventHandler eventHandler) {
   1917         synchronized (sLock) {
   1918             if (isHalStarted()) {
   1919                 if (sScanCmdId != 0) {
   1920                     stopScan();
   1921                 } else if (sScanSettings != null || sScanEventHandler != null) {
   1922                 /* current scan is paused; no need to stop it */
   1923                 }
   1924 
   1925                 sScanCmdId = getNewCmdIdLocked();
   1926 
   1927                 sScanSettings = settings;
   1928                 sScanEventHandler = eventHandler;
   1929 
   1930                 if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) {
   1931                     sScanEventHandler = null;
   1932                     sScanSettings = null;
   1933                     sScanCmdId = 0;
   1934                     return false;
   1935                 }
   1936 
   1937                 return true;
   1938             } else {
   1939                 return false;
   1940             }
   1941         }
   1942     }
   1943 
   1944     public void stopScan() {
   1945         synchronized (sLock) {
   1946             if (isHalStarted()) {
   1947                 if (sScanCmdId != 0) {
   1948                     stopScanNative(sWlan0Index, sScanCmdId);
   1949                 }
   1950                 sScanSettings = null;
   1951                 sScanEventHandler = null;
   1952                 sScanCmdId = 0;
   1953             }
   1954         }
   1955     }
   1956 
   1957     public void pauseScan() {
   1958         synchronized (sLock) {
   1959             if (isHalStarted()) {
   1960                 if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) {
   1961                     Log.d(TAG, "Pausing scan");
   1962                     WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true);
   1963                     stopScanNative(sWlan0Index, sScanCmdId);
   1964                     sScanCmdId = 0;
   1965                     sScanEventHandler.onScanPaused(scanData);
   1966                 }
   1967             }
   1968         }
   1969     }
   1970 
   1971     public void restartScan() {
   1972         synchronized (sLock) {
   1973             if (isHalStarted()) {
   1974                 if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) {
   1975                     Log.d(TAG, "Restarting scan");
   1976                     ScanEventHandler handler = sScanEventHandler;
   1977                     ScanSettings settings = sScanSettings;
   1978                     if (startScan(sScanSettings, sScanEventHandler)) {
   1979                         sScanEventHandler.onScanRestarted();
   1980                     } else {
   1981                     /* we are still paused; don't change state */
   1982                         sScanEventHandler = handler;
   1983                         sScanSettings = settings;
   1984                     }
   1985                 }
   1986             }
   1987         }
   1988     }
   1989 
   1990     public WifiScanner.ScanData[] getScanResults(boolean flush) {
   1991         synchronized (sLock) {
   1992             WifiScanner.ScanData[] sd = null;
   1993             if (isHalStarted()) {
   1994                 sd = getScanResultsNative(sWlan0Index, flush);
   1995             }
   1996 
   1997             if (sd != null) {
   1998                 return sd;
   1999             } else {
   2000                 return new WifiScanner.ScanData[0];
   2001             }
   2002         }
   2003     }
   2004 
   2005     public static interface HotlistEventHandler {
   2006         void onHotlistApFound (ScanResult[] result);
   2007         void onHotlistApLost  (ScanResult[] result);
   2008     }
   2009 
   2010     private static int sHotlistCmdId = 0;
   2011     private static HotlistEventHandler sHotlistEventHandler;
   2012 
   2013     private native static boolean setHotlistNative(int iface, int id,
   2014             WifiScanner.HotlistSettings settings);
   2015     private native static boolean resetHotlistNative(int iface, int id);
   2016 
   2017     public boolean setHotlist(WifiScanner.HotlistSettings settings,
   2018             HotlistEventHandler eventHandler) {
   2019         synchronized (sLock) {
   2020             if (isHalStarted()) {
   2021                 if (sHotlistCmdId != 0) {
   2022                     return false;
   2023                 } else {
   2024                     sHotlistCmdId = getNewCmdIdLocked();
   2025                 }
   2026 
   2027                 sHotlistEventHandler = eventHandler;
   2028                 if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) {
   2029                     sHotlistEventHandler = null;
   2030                     return false;
   2031                 }
   2032 
   2033                 return true;
   2034             } else {
   2035                 return false;
   2036             }
   2037         }
   2038     }
   2039 
   2040     public void resetHotlist() {
   2041         synchronized (sLock) {
   2042             if (isHalStarted()) {
   2043                 if (sHotlistCmdId != 0) {
   2044                     resetHotlistNative(sWlan0Index, sHotlistCmdId);
   2045                     sHotlistCmdId = 0;
   2046                     sHotlistEventHandler = null;
   2047                 }
   2048             }
   2049         }
   2050     }
   2051 
   2052     // Callback from native
   2053     private static void onHotlistApFound(int id, ScanResult[] results) {
   2054         HotlistEventHandler handler = sHotlistEventHandler;
   2055         if (handler != null) {
   2056             handler.onHotlistApFound(results);
   2057         } else {
   2058             /* this can happen because of race conditions */
   2059             Log.d(TAG, "Ignoring hotlist AP found event");
   2060         }
   2061     }
   2062 
   2063     // Callback from native
   2064     private static void onHotlistApLost(int id, ScanResult[] results) {
   2065         HotlistEventHandler handler = sHotlistEventHandler;
   2066         if (handler != null) {
   2067             handler.onHotlistApLost(results);
   2068         } else {
   2069             /* this can happen because of race conditions */
   2070             Log.d(TAG, "Ignoring hotlist AP lost event");
   2071         }
   2072     }
   2073 
   2074     public static interface SignificantWifiChangeEventHandler {
   2075         void onChangesFound(ScanResult[] result);
   2076     }
   2077 
   2078     private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler;
   2079     private static int sSignificantWifiChangeCmdId;
   2080 
   2081     private static native boolean trackSignificantWifiChangeNative(
   2082             int iface, int id, WifiScanner.WifiChangeSettings settings);
   2083     private static native boolean untrackSignificantWifiChangeNative(int iface, int id);
   2084 
   2085     public boolean trackSignificantWifiChange(
   2086             WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
   2087         synchronized (sLock) {
   2088             if (isHalStarted()) {
   2089                 if (sSignificantWifiChangeCmdId != 0) {
   2090                     return false;
   2091                 } else {
   2092                     sSignificantWifiChangeCmdId = getNewCmdIdLocked();
   2093                 }
   2094 
   2095                 sSignificantWifiChangeHandler = handler;
   2096                 if (trackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId,
   2097                         settings) == false) {
   2098                     sSignificantWifiChangeHandler = null;
   2099                     return false;
   2100                 }
   2101 
   2102                 return true;
   2103             } else {
   2104                 return false;
   2105             }
   2106 
   2107         }
   2108     }
   2109 
   2110     public void untrackSignificantWifiChange() {
   2111         synchronized (sLock) {
   2112             if (isHalStarted()) {
   2113                 if (sSignificantWifiChangeCmdId != 0) {
   2114                     untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId);
   2115                     sSignificantWifiChangeCmdId = 0;
   2116                     sSignificantWifiChangeHandler = null;
   2117                 }
   2118             }
   2119         }
   2120     }
   2121 
   2122     // Callback from native
   2123     private static void onSignificantWifiChange(int id, ScanResult[] results) {
   2124         SignificantWifiChangeEventHandler handler = sSignificantWifiChangeHandler;
   2125         if (handler != null) {
   2126             handler.onChangesFound(results);
   2127         } else {
   2128             /* this can happen because of race conditions */
   2129             Log.d(TAG, "Ignoring significant wifi change");
   2130         }
   2131     }
   2132 
   2133     public WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
   2134         // TODO: use correct iface name to Index translation
   2135         if (iface == null) return null;
   2136         synchronized (sLock) {
   2137             if (isHalStarted()) {
   2138                 return getWifiLinkLayerStatsNative(sWlan0Index);
   2139             } else {
   2140                 return null;
   2141             }
   2142         }
   2143     }
   2144 
   2145     public void setWifiLinkLayerStats(String iface, int enable) {
   2146         if (iface == null) return;
   2147         synchronized (sLock) {
   2148             if (isHalStarted()) {
   2149                 setWifiLinkLayerStatsNative(sWlan0Index, enable);
   2150             }
   2151         }
   2152     }
   2153 
   2154     public static native int getSupportedFeatureSetNative(int iface);
   2155     public int getSupportedFeatureSet() {
   2156         synchronized (sLock) {
   2157             if (isHalStarted()) {
   2158                 return getSupportedFeatureSetNative(sWlan0Index);
   2159             } else {
   2160                 Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started");
   2161                 return 0;
   2162             }
   2163         }
   2164     }
   2165 
   2166     /* Rtt related commands/events */
   2167     public static interface RttEventHandler {
   2168         void onRttResults(RttManager.RttResult[] result);
   2169     }
   2170 
   2171     private static RttEventHandler sRttEventHandler;
   2172     private static int sRttCmdId;
   2173 
   2174     // Callback from native
   2175     private static void onRttResults(int id, RttManager.RttResult[] results) {
   2176         RttEventHandler handler = sRttEventHandler;
   2177         if (handler != null && id == sRttCmdId) {
   2178             Log.d(TAG, "Received " + results.length + " rtt results");
   2179             handler.onRttResults(results);
   2180             sRttCmdId = 0;
   2181         } else {
   2182             Log.d(TAG, "RTT Received event for unknown cmd = " + id +
   2183                     ", current id = " + sRttCmdId);
   2184         }
   2185     }
   2186 
   2187     private static native boolean requestRangeNative(
   2188             int iface, int id, RttManager.RttParams[] params);
   2189     private static native boolean cancelRangeRequestNative(
   2190             int iface, int id, RttManager.RttParams[] params);
   2191 
   2192     public boolean requestRtt(
   2193             RttManager.RttParams[] params, RttEventHandler handler) {
   2194         synchronized (sLock) {
   2195             if (isHalStarted()) {
   2196                 if (sRttCmdId != 0) {
   2197                     Log.w(TAG, "Last one is still under measurement!");
   2198                     return false;
   2199                 } else {
   2200                     sRttCmdId = getNewCmdIdLocked();
   2201                 }
   2202                 sRttEventHandler = handler;
   2203                 return requestRangeNative(sWlan0Index, sRttCmdId, params);
   2204             } else {
   2205                 return false;
   2206             }
   2207         }
   2208     }
   2209 
   2210     public boolean cancelRtt(RttManager.RttParams[] params) {
   2211         synchronized (sLock) {
   2212             if (isHalStarted()) {
   2213                 if (sRttCmdId == 0) {
   2214                     return false;
   2215                 }
   2216 
   2217                 sRttCmdId = 0;
   2218 
   2219                 if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) {
   2220                     sRttEventHandler = null;
   2221                     return true;
   2222                 } else {
   2223                     Log.e(TAG, "RTT cancel Request failed");
   2224                     return false;
   2225                 }
   2226             } else {
   2227                 return false;
   2228             }
   2229         }
   2230     }
   2231 
   2232     private static int sRttResponderCmdId = 0;
   2233 
   2234     private static native ResponderConfig enableRttResponderNative(int iface, int commandId,
   2235             int timeoutSeconds, WifiChannelInfo channelHint);
   2236     /**
   2237      * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder
   2238      * role is successfully enabled, {@code null} otherwise.
   2239      */
   2240     @Nullable
   2241     public ResponderConfig enableRttResponder(int timeoutSeconds) {
   2242         synchronized (sLock) {
   2243             if (!isHalStarted()) return null;
   2244             if (sRttResponderCmdId != 0) {
   2245                 if (DBG) Log.e(mTAG, "responder mode already enabled - this shouldn't happen");
   2246                 return null;
   2247             }
   2248             int id = getNewCmdIdLocked();
   2249             ResponderConfig config = enableRttResponderNative(
   2250                     sWlan0Index, id, timeoutSeconds, null);
   2251             if (config != null) sRttResponderCmdId = id;
   2252             if (DBG) Log.d(TAG, "enabling rtt " + (config != null));
   2253             return config;
   2254         }
   2255     }
   2256 
   2257     private static native boolean disableRttResponderNative(int iface, int commandId);
   2258     /**
   2259      * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled,
   2260      * {@code false} otherwise.
   2261      */
   2262     public boolean disableRttResponder() {
   2263         synchronized (sLock) {
   2264             if (!isHalStarted()) return false;
   2265             if (sRttResponderCmdId == 0) {
   2266                 Log.e(mTAG, "responder role not enabled yet");
   2267                 return true;
   2268             }
   2269             sRttResponderCmdId = 0;
   2270             return disableRttResponderNative(sWlan0Index, sRttResponderCmdId);
   2271         }
   2272     }
   2273 
   2274     private static native boolean setScanningMacOuiNative(int iface, byte[] oui);
   2275 
   2276     public boolean setScanningMacOui(byte[] oui) {
   2277         synchronized (sLock) {
   2278             if (isHalStarted()) {
   2279                 return setScanningMacOuiNative(sWlan0Index, oui);
   2280             } else {
   2281                 return false;
   2282             }
   2283         }
   2284     }
   2285 
   2286     private static native int[] getChannelsForBandNative(
   2287             int iface, int band);
   2288 
   2289     public int [] getChannelsForBand(int band) {
   2290         synchronized (sLock) {
   2291             if (isHalStarted()) {
   2292                 return getChannelsForBandNative(sWlan0Index, band);
   2293             } else {
   2294                 return null;
   2295             }
   2296         }
   2297     }
   2298 
   2299     private static native boolean isGetChannelsForBandSupportedNative();
   2300     public boolean isGetChannelsForBandSupported(){
   2301         synchronized (sLock) {
   2302             if (isHalStarted()) {
   2303                 return isGetChannelsForBandSupportedNative();
   2304             } else {
   2305                 return false;
   2306             }
   2307         }
   2308     }
   2309 
   2310     private static native boolean setDfsFlagNative(int iface, boolean dfsOn);
   2311     public boolean setDfsFlag(boolean dfsOn) {
   2312         synchronized (sLock) {
   2313             if (isHalStarted()) {
   2314                 return setDfsFlagNative(sWlan0Index, dfsOn);
   2315             } else {
   2316                 return false;
   2317             }
   2318         }
   2319     }
   2320 
   2321     private static native boolean setInterfaceUpNative(boolean up);
   2322     public boolean setInterfaceUp(boolean up) {
   2323         synchronized (sLock) {
   2324             if (isHalStarted()) {
   2325                 return setInterfaceUpNative(up);
   2326             } else {
   2327                 return false;
   2328             }
   2329         }
   2330     }
   2331 
   2332     private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface);
   2333     public RttManager.RttCapabilities getRttCapabilities() {
   2334         synchronized (sLock) {
   2335             if (isHalStarted()) {
   2336                 return getRttCapabilitiesNative(sWlan0Index);
   2337             } else {
   2338                 return null;
   2339             }
   2340         }
   2341     }
   2342 
   2343     private static native ApfCapabilities getApfCapabilitiesNative(int iface);
   2344     public ApfCapabilities getApfCapabilities() {
   2345         synchronized (sLock) {
   2346             if (isHalStarted()) {
   2347                 return getApfCapabilitiesNative(sWlan0Index);
   2348             } else {
   2349                 return null;
   2350             }
   2351         }
   2352     }
   2353 
   2354     private static native boolean installPacketFilterNative(int iface, byte[] filter);
   2355     public boolean installPacketFilter(byte[] filter) {
   2356         synchronized (sLock) {
   2357             if (isHalStarted()) {
   2358                 return installPacketFilterNative(sWlan0Index, filter);
   2359             } else {
   2360                 return false;
   2361             }
   2362         }
   2363     }
   2364 
   2365     private static native boolean setCountryCodeHalNative(int iface, String CountryCode);
   2366     public boolean setCountryCodeHal(String CountryCode) {
   2367         synchronized (sLock) {
   2368             if (isHalStarted()) {
   2369                 return setCountryCodeHalNative(sWlan0Index, CountryCode);
   2370             } else {
   2371                 return false;
   2372             }
   2373         }
   2374     }
   2375 
   2376     /* Rtt related commands/events */
   2377     public abstract class TdlsEventHandler {
   2378         abstract public void onTdlsStatus(String macAddr, int status, int reason);
   2379     }
   2380 
   2381     private static TdlsEventHandler sTdlsEventHandler;
   2382 
   2383     private static native boolean enableDisableTdlsNative(int iface, boolean enable,
   2384             String macAddr);
   2385     public boolean enableDisableTdls(boolean enable, String macAdd, TdlsEventHandler tdlsCallBack) {
   2386         synchronized (sLock) {
   2387             sTdlsEventHandler = tdlsCallBack;
   2388             return enableDisableTdlsNative(sWlan0Index, enable, macAdd);
   2389         }
   2390     }
   2391 
   2392     // Once TDLS per mac and event feature is implemented, this class definition should be
   2393     // moved to the right place, like WifiManager etc
   2394     public static class TdlsStatus {
   2395         int channel;
   2396         int global_operating_class;
   2397         int state;
   2398         int reason;
   2399     }
   2400     private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr);
   2401     public TdlsStatus getTdlsStatus(String macAdd) {
   2402         synchronized (sLock) {
   2403             if (isHalStarted()) {
   2404                 return getTdlsStatusNative(sWlan0Index, macAdd);
   2405             } else {
   2406                 return null;
   2407             }
   2408         }
   2409     }
   2410 
   2411     //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be
   2412     // moved to the right place, like WifiStateMachine etc
   2413     public static class TdlsCapabilities {
   2414         /* Maximum TDLS session number can be supported by the Firmware and hardware */
   2415         int maxConcurrentTdlsSessionNumber;
   2416         boolean isGlobalTdlsSupported;
   2417         boolean isPerMacTdlsSupported;
   2418         boolean isOffChannelTdlsSupported;
   2419     }
   2420 
   2421 
   2422 
   2423     private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface);
   2424     public TdlsCapabilities getTdlsCapabilities () {
   2425         synchronized (sLock) {
   2426             if (isHalStarted()) {
   2427                 return getTdlsCapabilitiesNative(sWlan0Index);
   2428             } else {
   2429                 return null;
   2430             }
   2431         }
   2432     }
   2433 
   2434     private static boolean onTdlsStatus(String macAddr, int status, int reason) {
   2435         TdlsEventHandler handler = sTdlsEventHandler;
   2436         if (handler == null) {
   2437             return false;
   2438         } else {
   2439             handler.onTdlsStatus(macAddr, status, reason);
   2440             return true;
   2441         }
   2442     }
   2443 
   2444     //---------------------------------------------------------------------------------
   2445 
   2446     /* Wifi Logger commands/events */
   2447 
   2448     public static interface WifiLoggerEventHandler {
   2449         void onRingBufferData(RingBufferStatus status, byte[] buffer);
   2450         void onWifiAlert(int errorCode, byte[] buffer);
   2451     }
   2452 
   2453     private static WifiLoggerEventHandler sWifiLoggerEventHandler = null;
   2454 
   2455     // Callback from native
   2456     private static void onRingBufferData(RingBufferStatus status, byte[] buffer) {
   2457         WifiLoggerEventHandler handler = sWifiLoggerEventHandler;
   2458         if (handler != null)
   2459             handler.onRingBufferData(status, buffer);
   2460     }
   2461 
   2462     // Callback from native
   2463     private static void onWifiAlert(byte[] buffer, int errorCode) {
   2464         WifiLoggerEventHandler handler = sWifiLoggerEventHandler;
   2465         if (handler != null)
   2466             handler.onWifiAlert(errorCode, buffer);
   2467     }
   2468 
   2469     private static int sLogCmdId = -1;
   2470     private static native boolean setLoggingEventHandlerNative(int iface, int id);
   2471     public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
   2472         synchronized (sLock) {
   2473             if (isHalStarted()) {
   2474                 int oldId =  sLogCmdId;
   2475                 sLogCmdId = getNewCmdIdLocked();
   2476                 if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) {
   2477                     sLogCmdId = oldId;
   2478                     return false;
   2479                 }
   2480                 sWifiLoggerEventHandler = handler;
   2481                 return true;
   2482             } else {
   2483                 return false;
   2484             }
   2485         }
   2486     }
   2487 
   2488     private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel,
   2489             int flags, int minIntervalSec ,int minDataSize, String ringName);
   2490     public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
   2491             int minDataSize, String ringName){
   2492         synchronized (sLock) {
   2493             if (isHalStarted()) {
   2494                 return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval,
   2495                         minDataSize, ringName);
   2496             } else {
   2497                 return false;
   2498             }
   2499         }
   2500     }
   2501 
   2502     private static native int getSupportedLoggerFeatureSetNative(int iface);
   2503     public int getSupportedLoggerFeatureSet() {
   2504         synchronized (sLock) {
   2505             if (isHalStarted()) {
   2506                 return getSupportedLoggerFeatureSetNative(sWlan0Index);
   2507             } else {
   2508                 return 0;
   2509             }
   2510         }
   2511     }
   2512 
   2513     private static native boolean resetLogHandlerNative(int iface, int id);
   2514     public boolean resetLogHandler() {
   2515         synchronized (sLock) {
   2516             if (isHalStarted()) {
   2517                 if (sLogCmdId == -1) {
   2518                     Log.e(TAG,"Can not reset handler Before set any handler");
   2519                     return false;
   2520                 }
   2521                 sWifiLoggerEventHandler = null;
   2522                 if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) {
   2523                     sLogCmdId = -1;
   2524                     return true;
   2525                 } else {
   2526                     return false;
   2527                 }
   2528             } else {
   2529                 return false;
   2530             }
   2531         }
   2532     }
   2533 
   2534     private static native String getDriverVersionNative(int iface);
   2535     public String getDriverVersion() {
   2536         synchronized (sLock) {
   2537             if (isHalStarted()) {
   2538                 return getDriverVersionNative(sWlan0Index);
   2539             } else {
   2540                 return "";
   2541             }
   2542         }
   2543     }
   2544 
   2545 
   2546     private static native String getFirmwareVersionNative(int iface);
   2547     public String getFirmwareVersion() {
   2548         synchronized (sLock) {
   2549             if (isHalStarted()) {
   2550                 return getFirmwareVersionNative(sWlan0Index);
   2551             } else {
   2552                 return "";
   2553             }
   2554         }
   2555     }
   2556 
   2557     public static class RingBufferStatus{
   2558         String name;
   2559         int flag;
   2560         int ringBufferId;
   2561         int ringBufferByteSize;
   2562         int verboseLevel;
   2563         int writtenBytes;
   2564         int readBytes;
   2565         int writtenRecords;
   2566 
   2567         @Override
   2568         public String toString() {
   2569             return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
   2570                     " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
   2571                     " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
   2572                     " writtenRecords: " + writtenRecords;
   2573         }
   2574     }
   2575 
   2576     private static native RingBufferStatus[] getRingBufferStatusNative(int iface);
   2577     public RingBufferStatus[] getRingBufferStatus() {
   2578         synchronized (sLock) {
   2579             if (isHalStarted()) {
   2580                 return getRingBufferStatusNative(sWlan0Index);
   2581             } else {
   2582                 return null;
   2583             }
   2584         }
   2585     }
   2586 
   2587     private static native boolean getRingBufferDataNative(int iface, String ringName);
   2588     public boolean getRingBufferData(String ringName) {
   2589         synchronized (sLock) {
   2590             if (isHalStarted()) {
   2591                 return getRingBufferDataNative(sWlan0Index, ringName);
   2592             } else {
   2593                 return false;
   2594             }
   2595         }
   2596     }
   2597 
   2598     private static byte[] mFwMemoryDump;
   2599     // Callback from native
   2600     private static void onWifiFwMemoryAvailable(byte[] buffer) {
   2601         mFwMemoryDump = buffer;
   2602         if (DBG) {
   2603             Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " +
   2604                     (buffer == null ? 0 :  buffer.length));
   2605         }
   2606     }
   2607 
   2608     private static native boolean getFwMemoryDumpNative(int iface);
   2609     public byte[] getFwMemoryDump() {
   2610         synchronized (sLock) {
   2611             if (isHalStarted()) {
   2612                 if(getFwMemoryDumpNative(sWlan0Index)) {
   2613                     byte[] fwMemoryDump = mFwMemoryDump;
   2614                     mFwMemoryDump = null;
   2615                     return fwMemoryDump;
   2616                 } else {
   2617                     return null;
   2618                 }
   2619             }
   2620             return null;
   2621         }
   2622     }
   2623 
   2624     private static native byte[] getDriverStateDumpNative(int iface);
   2625     /** Fetch the driver state, for driver debugging. */
   2626     public byte[] getDriverStateDump() {
   2627         synchronized (sLock) {
   2628             if (isHalStarted()) {
   2629                 return getDriverStateDumpNative(sWlan0Index);
   2630             } else {
   2631                 return null;
   2632             }
   2633         }
   2634     }
   2635 
   2636     //---------------------------------------------------------------------------------
   2637     /* Packet fate API */
   2638 
   2639     @Immutable
   2640     abstract static class FateReport {
   2641         final static int USEC_PER_MSEC = 1000;
   2642         // The driver timestamp is a 32-bit counter, in microseconds. This field holds the
   2643         // maximal value of a driver timestamp in milliseconds.
   2644         final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000);
   2645         final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
   2646 
   2647         final byte mFate;
   2648         final long mDriverTimestampUSec;
   2649         final byte mFrameType;
   2650         final byte[] mFrameBytes;
   2651         final long mEstimatedWallclockMSec;
   2652 
   2653         FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
   2654             mFate = fate;
   2655             mDriverTimestampUSec = driverTimestampUSec;
   2656             mEstimatedWallclockMSec =
   2657                     convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec);
   2658             mFrameType = frameType;
   2659             mFrameBytes = frameBytes;
   2660         }
   2661 
   2662         public String toTableRowString() {
   2663             StringWriter sw = new StringWriter();
   2664             PrintWriter pw = new PrintWriter(sw);
   2665             FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
   2666             dateFormatter.setTimeZone(TimeZone.getDefault());
   2667             pw.format("%-15s  %12s  %-9s  %-32s  %-12s  %-23s  %s\n",
   2668                     mDriverTimestampUSec,
   2669                     dateFormatter.format(new Date(mEstimatedWallclockMSec)),
   2670                     directionToString(), fateToString(), parser.mMostSpecificProtocolString,
   2671                     parser.mTypeString, parser.mResultString);
   2672             return sw.toString();
   2673         }
   2674 
   2675         public String toVerboseStringWithPiiAllowed() {
   2676             StringWriter sw = new StringWriter();
   2677             PrintWriter pw = new PrintWriter(sw);
   2678             FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
   2679             pw.format("Frame direction: %s\n", directionToString());
   2680             pw.format("Frame timestamp: %d\n", mDriverTimestampUSec);
   2681             pw.format("Frame fate: %s\n", fateToString());
   2682             pw.format("Frame type: %s\n", frameTypeToString(mFrameType));
   2683             pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString);
   2684             pw.format("Frame protocol type: %s\n", parser.mTypeString);
   2685             pw.format("Frame length: %d\n", mFrameBytes.length);
   2686             pw.append("Frame bytes");
   2687             pw.append(HexDump.dumpHexString(mFrameBytes));  // potentially contains PII
   2688             pw.append("\n");
   2689             return sw.toString();
   2690         }
   2691 
   2692         /* Returns a header to match the output of toTableRowString(). */
   2693         public static String getTableHeader() {
   2694             StringWriter sw = new StringWriter();
   2695             PrintWriter pw = new PrintWriter(sw);
   2696             pw.format("\n%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
   2697                     "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result");
   2698             pw.format("%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
   2699                     "---------", "--------", "---------", "----", "--------", "----", "------");
   2700             return sw.toString();
   2701         }
   2702 
   2703         protected abstract String directionToString();
   2704 
   2705         protected abstract String fateToString();
   2706 
   2707         private static String frameTypeToString(byte frameType) {
   2708             switch (frameType) {
   2709                 case WifiLoggerHal.FRAME_TYPE_UNKNOWN:
   2710                     return "unknown";
   2711                 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II:
   2712                     return "data";
   2713                 case WifiLoggerHal.FRAME_TYPE_80211_MGMT:
   2714                     return "802.11 management";
   2715                 default:
   2716                     return Byte.toString(frameType);
   2717             }
   2718         }
   2719 
   2720         /**
   2721          * Converts a driver timestamp to a wallclock time, based on the current
   2722          * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of
   2723          * microseconds, with the same base as BOOTTIME.
   2724          */
   2725         private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) {
   2726             final long wallclockMillisNow = System.currentTimeMillis();
   2727             final long boottimeMillisNow = SystemClock.elapsedRealtime();
   2728             final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC;
   2729 
   2730             long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC;
   2731             if (boottimeTimestampMillis < driverTimestampMillis) {
   2732                 // The 32-bit microsecond count has wrapped between the time that the driver
   2733                 // recorded the packet, and the call to this function. Adjust the BOOTTIME
   2734                 // timestamp, to compensate.
   2735                 //
   2736                 // Note that overflow is not a concern here, since the result is less than
   2737                 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above,
   2738                 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since
   2739                 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit
   2740                 // within a long.
   2741                 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC;
   2742             }
   2743 
   2744             final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis;
   2745             return wallclockMillisNow - millisSincePacketTimestamp;
   2746         }
   2747     }
   2748 
   2749     /**
   2750      * Represents the fate information for one outbound packet.
   2751      */
   2752     @Immutable
   2753     public static final class TxFateReport extends FateReport {
   2754         TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
   2755             super(fate, driverTimestampUSec, frameType, frameBytes);
   2756         }
   2757 
   2758         @Override
   2759         protected String directionToString() {
   2760             return "TX";
   2761         }
   2762 
   2763         @Override
   2764         protected String fateToString() {
   2765             switch (mFate) {
   2766                 case WifiLoggerHal.TX_PKT_FATE_ACKED:
   2767                     return "acked";
   2768                 case WifiLoggerHal.TX_PKT_FATE_SENT:
   2769                     return "sent";
   2770                 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED:
   2771                     return "firmware queued";
   2772                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID:
   2773                     return "firmware dropped (invalid frame)";
   2774                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS:
   2775                     return "firmware dropped (no bufs)";
   2776                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER:
   2777                     return "firmware dropped (other)";
   2778                 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED:
   2779                     return "driver queued";
   2780                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID:
   2781                     return "driver dropped (invalid frame)";
   2782                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS:
   2783                     return "driver dropped (no bufs)";
   2784                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER:
   2785                     return "driver dropped (other)";
   2786                 default:
   2787                     return Byte.toString(mFate);
   2788             }
   2789         }
   2790     }
   2791 
   2792     /**
   2793      * Represents the fate information for one inbound packet.
   2794      */
   2795     @Immutable
   2796     public static final class RxFateReport extends FateReport {
   2797         RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
   2798             super(fate, driverTimestampUSec, frameType, frameBytes);
   2799         }
   2800 
   2801         @Override
   2802         protected String directionToString() {
   2803             return "RX";
   2804         }
   2805 
   2806         @Override
   2807         protected String fateToString() {
   2808             switch (mFate) {
   2809                 case WifiLoggerHal.RX_PKT_FATE_SUCCESS:
   2810                     return "success";
   2811                 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED:
   2812                     return "firmware queued";
   2813                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER:
   2814                     return "firmware dropped (filter)";
   2815                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID:
   2816                     return "firmware dropped (invalid frame)";
   2817                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS:
   2818                     return "firmware dropped (no bufs)";
   2819                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER:
   2820                     return "firmware dropped (other)";
   2821                 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED:
   2822                     return "driver queued";
   2823                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER:
   2824                     return "driver dropped (filter)";
   2825                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID:
   2826                     return "driver dropped (invalid frame)";
   2827                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS:
   2828                     return "driver dropped (no bufs)";
   2829                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER:
   2830                     return "driver dropped (other)";
   2831                 default:
   2832                     return Byte.toString(mFate);
   2833             }
   2834         }
   2835     }
   2836 
   2837     private static native int startPktFateMonitoringNative(int iface);
   2838     /**
   2839      * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started.
   2840      */
   2841     public boolean startPktFateMonitoring() {
   2842         synchronized (sLock) {
   2843             if (isHalStarted()) {
   2844                 return startPktFateMonitoringNative(sWlan0Index) == WIFI_SUCCESS;
   2845             } else {
   2846                 return false;
   2847             }
   2848         }
   2849     }
   2850 
   2851     private static native int getTxPktFatesNative(int iface, TxFateReport[] reportBufs);
   2852     /**
   2853      * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started.
   2854      */
   2855     public boolean getTxPktFates(TxFateReport[] reportBufs) {
   2856         synchronized (sLock) {
   2857             if (isHalStarted()) {
   2858                 int res = getTxPktFatesNative(sWlan0Index, reportBufs);
   2859                 if (res != WIFI_SUCCESS) {
   2860                     Log.e(TAG, "getTxPktFatesNative returned " + res);
   2861                     return false;
   2862                 } else {
   2863                     return true;
   2864                 }
   2865             } else {
   2866                 return false;
   2867             }
   2868         }
   2869     }
   2870 
   2871     private static native int getRxPktFatesNative(int iface, RxFateReport[] reportBufs);
   2872     /**
   2873      * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started.
   2874      */
   2875     public boolean getRxPktFates(RxFateReport[] reportBufs) {
   2876         synchronized (sLock) {
   2877             if (isHalStarted()) {
   2878                 int res = getRxPktFatesNative(sWlan0Index, reportBufs);
   2879                 if (res != WIFI_SUCCESS) {
   2880                     Log.e(TAG, "getRxPktFatesNative returned " + res);
   2881                     return false;
   2882                 } else {
   2883                     return true;
   2884                 }
   2885             } else {
   2886                 return false;
   2887             }
   2888         }
   2889     }
   2890 
   2891     //---------------------------------------------------------------------------------
   2892     /* Configure ePNO/PNO */
   2893     private static PnoEventHandler sPnoEventHandler;
   2894     private static int sPnoCmdId = 0;
   2895 
   2896     private static native boolean setPnoListNative(int iface, int id, PnoSettings settings);
   2897 
   2898     /**
   2899      * Set the PNO settings & the network list in HAL to start PNO.
   2900      * @param settings PNO settings and network list.
   2901      * @param eventHandler Handler to receive notifications back during PNO scan.
   2902      * @return true if success, false otherwise
   2903      */
   2904     public boolean setPnoList(PnoSettings settings, PnoEventHandler eventHandler) {
   2905         Log.e(TAG, "setPnoList cmd " + sPnoCmdId);
   2906 
   2907         synchronized (sLock) {
   2908             if (isHalStarted()) {
   2909                 sPnoCmdId = getNewCmdIdLocked();
   2910                 sPnoEventHandler = eventHandler;
   2911                 if (setPnoListNative(sWlan0Index, sPnoCmdId, settings)) {
   2912                     return true;
   2913                 }
   2914             }
   2915             sPnoEventHandler = null;
   2916             return false;
   2917         }
   2918     }
   2919 
   2920     /**
   2921      * Set the PNO network list in HAL to start PNO.
   2922      * @param list PNO network list.
   2923      * @param eventHandler Handler to receive notifications back during PNO scan.
   2924      * @return true if success, false otherwise
   2925      */
   2926     public boolean setPnoList(PnoNetwork[] list, PnoEventHandler eventHandler) {
   2927         PnoSettings settings = new PnoSettings();
   2928         settings.networkList = list;
   2929         return setPnoList(settings, eventHandler);
   2930     }
   2931 
   2932     private static native boolean resetPnoListNative(int iface, int id);
   2933 
   2934     /**
   2935      * Reset the PNO settings in HAL to stop PNO.
   2936      * @return true if success, false otherwise
   2937      */
   2938     public boolean resetPnoList() {
   2939         Log.e(TAG, "resetPnoList cmd " + sPnoCmdId);
   2940 
   2941         synchronized (sLock) {
   2942             if (isHalStarted()) {
   2943                 sPnoCmdId = getNewCmdIdLocked();
   2944                 sPnoEventHandler = null;
   2945                 if (resetPnoListNative(sWlan0Index, sPnoCmdId)) {
   2946                     return true;
   2947                 }
   2948             }
   2949             return false;
   2950         }
   2951     }
   2952 
   2953     // Callback from native
   2954     private static void onPnoNetworkFound(int id, ScanResult[] results, int[] beaconCaps) {
   2955         if (results == null) {
   2956             Log.e(TAG, "onPnoNetworkFound null results");
   2957             return;
   2958 
   2959         }
   2960         Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length);
   2961 
   2962         PnoEventHandler handler = sPnoEventHandler;
   2963         if (sPnoCmdId != 0 && handler != null) {
   2964             for (int i=0; i<results.length; i++) {
   2965                 Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID
   2966                         + " " + results[i].level + " " + results[i].frequency);
   2967 
   2968                 populateScanResult(results[i], beaconCaps[i], "onPnoNetworkFound ");
   2969                 results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID);
   2970             }
   2971 
   2972             handler.onPnoNetworkFound(results);
   2973         } else {
   2974             /* this can happen because of race conditions */
   2975             Log.d(TAG, "Ignoring Pno Network found event");
   2976         }
   2977     }
   2978 
   2979     private native static boolean setBssidBlacklistNative(int iface, int id,
   2980                                               String list[]);
   2981 
   2982     public boolean setBssidBlacklist(String list[]) {
   2983         int size = 0;
   2984         if (list != null) {
   2985             size = list.length;
   2986         }
   2987         Log.e(TAG, "setBssidBlacklist cmd " + sPnoCmdId + " size " + size);
   2988 
   2989         synchronized (sLock) {
   2990             if (isHalStarted()) {
   2991                 sPnoCmdId = getNewCmdIdLocked();
   2992                 return setBssidBlacklistNative(sWlan0Index, sPnoCmdId, list);
   2993             } else {
   2994                 return false;
   2995             }
   2996         }
   2997     }
   2998 
   2999     private native static int startSendingOffloadedPacketNative(int iface, int idx,
   3000                                     byte[] srcMac, byte[] dstMac, byte[] pktData, int period);
   3001 
   3002     public int
   3003     startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) {
   3004         Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period);
   3005 
   3006         String[] macAddrStr = getMacAddress().split(":");
   3007         byte[] srcMac = new byte[6];
   3008         for(int i = 0; i < 6; i++) {
   3009             Integer hexVal = Integer.parseInt(macAddrStr[i], 16);
   3010             srcMac[i] = hexVal.byteValue();
   3011         }
   3012         synchronized (sLock) {
   3013             if (isHalStarted()) {
   3014                 return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac,
   3015                         keepAlivePacket.dstMac, keepAlivePacket.data, period);
   3016             } else {
   3017                 return -1;
   3018             }
   3019         }
   3020     }
   3021 
   3022     private native static int stopSendingOffloadedPacketNative(int iface, int idx);
   3023 
   3024     public int
   3025     stopSendingOffloadedPacket(int slot) {
   3026         Log.d(TAG, "stopSendingOffloadedPacket " + slot);
   3027         synchronized (sLock) {
   3028             if (isHalStarted()) {
   3029                 return stopSendingOffloadedPacketNative(sWlan0Index, slot);
   3030             } else {
   3031                 return -1;
   3032             }
   3033         }
   3034     }
   3035 
   3036     public static interface WifiRssiEventHandler {
   3037         void onRssiThresholdBreached(byte curRssi);
   3038     }
   3039 
   3040     private static WifiRssiEventHandler sWifiRssiEventHandler;
   3041 
   3042     // Callback from native
   3043     private static void onRssiThresholdBreached(int id, byte curRssi) {
   3044         WifiRssiEventHandler handler = sWifiRssiEventHandler;
   3045         if (handler != null) {
   3046             handler.onRssiThresholdBreached(curRssi);
   3047         }
   3048     }
   3049 
   3050     private native static int startRssiMonitoringNative(int iface, int id,
   3051                                         byte maxRssi, byte minRssi);
   3052 
   3053     private static int sRssiMonitorCmdId = 0;
   3054 
   3055     public int startRssiMonitoring(byte maxRssi, byte minRssi,
   3056                                                 WifiRssiEventHandler rssiEventHandler) {
   3057         Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi);
   3058         synchronized (sLock) {
   3059             sWifiRssiEventHandler = rssiEventHandler;
   3060             if (isHalStarted()) {
   3061                 if (sRssiMonitorCmdId != 0) {
   3062                     stopRssiMonitoring();
   3063                 }
   3064 
   3065                 sRssiMonitorCmdId = getNewCmdIdLocked();
   3066                 Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId);
   3067                 int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId,
   3068                         maxRssi, minRssi);
   3069                 if (ret != 0) { // if not success
   3070                     sRssiMonitorCmdId = 0;
   3071                 }
   3072                 return ret;
   3073             } else {
   3074                 return -1;
   3075             }
   3076         }
   3077     }
   3078 
   3079     private native static int stopRssiMonitoringNative(int iface, int idx);
   3080 
   3081     public int stopRssiMonitoring() {
   3082         Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId);
   3083         synchronized (sLock) {
   3084             if (isHalStarted()) {
   3085                 int ret = 0;
   3086                 if (sRssiMonitorCmdId != 0) {
   3087                     ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId);
   3088                 }
   3089                 sRssiMonitorCmdId = 0;
   3090                 return ret;
   3091             } else {
   3092                 return -1;
   3093             }
   3094         }
   3095     }
   3096 
   3097     private static native WifiWakeReasonAndCounts getWlanWakeReasonCountNative(int iface);
   3098 
   3099     /**
   3100      * Fetch the host wakeup reasons stats from wlan driver.
   3101      * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver.
   3102      */
   3103     public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
   3104         Log.d(TAG, "getWlanWakeReasonCount " + sWlan0Index);
   3105         synchronized (sLock) {
   3106             if (isHalStarted()) {
   3107                 return getWlanWakeReasonCountNative(sWlan0Index);
   3108             } else {
   3109                 return null;
   3110             }
   3111         }
   3112     }
   3113 
   3114     private static native int configureNeighborDiscoveryOffload(int iface, boolean enabled);
   3115 
   3116     public boolean configureNeighborDiscoveryOffload(boolean enabled) {
   3117         final String logMsg =  "configureNeighborDiscoveryOffload(" + enabled + ")";
   3118         Log.d(mTAG, logMsg);
   3119         synchronized (sLock) {
   3120             if (isHalStarted()) {
   3121                 final int ret = configureNeighborDiscoveryOffload(sWlan0Index, enabled);
   3122                 if (ret != 0) {
   3123                     Log.d(mTAG, logMsg + " returned: " + ret);
   3124                 }
   3125                 return (ret == 0);
   3126             }
   3127         }
   3128         return false;
   3129     }
   3130 }
   3131