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