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