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