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