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