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