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