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