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