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