WifiNative.java revision 7b97c836ad5ef97635329d09f7772f845713aea6
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.net.wifi.BatchedScanSettings;
20import android.net.wifi.RttManager;
21import android.net.wifi.ScanResult;
22import android.net.wifi.WifiConfiguration;
23import android.net.wifi.WifiLinkLayerStats;
24import android.net.wifi.WifiManager;
25import android.net.wifi.WifiScanner;
26import android.net.wifi.RttManager;
27import android.net.wifi.WifiSsid;
28import android.net.wifi.WpsInfo;
29import android.net.wifi.p2p.WifiP2pConfig;
30import android.net.wifi.p2p.WifiP2pGroup;
31import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
32import android.net.wifi.WifiEnterpriseConfig;
33import android.os.SystemClock;
34import android.text.TextUtils;
35import android.util.Base64;
36import android.util.LocalLog;
37import android.util.Log;
38
39import com.android.server.connectivity.KeepalivePacketData;
40
41import java.io.ByteArrayOutputStream;
42import java.io.IOException;
43import java.nio.ByteBuffer;
44import java.nio.CharBuffer;
45import java.nio.charset.CharacterCodingException;
46import java.nio.charset.CharsetDecoder;
47import java.nio.charset.StandardCharsets;
48import java.util.ArrayList;
49import java.util.List;
50import java.util.Locale;
51import java.util.zip.Deflater;
52import libcore.util.HexEncoding;
53/**
54 * Native calls for bring up/shut down of the supplicant daemon and for
55 * sending requests to the supplicant daemon
56 *
57 * waitForEvent() is called on the monitor thread for events. All other methods
58 * must be serialized from the framework.
59 *
60 * {@hide}
61 */
62public class WifiNative {
63
64    private static boolean DBG = false;
65    private final String mTAG;
66    private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
67
68    static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED     = 0;
69    static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED    = 1;
70    static final int BLUETOOTH_COEXISTENCE_MODE_SENSE       = 2;
71
72    static final int SCAN_WITHOUT_CONNECTION_SETUP          = 1;
73    static final int SCAN_WITH_CONNECTION_SETUP             = 2;
74
75    // Hold this lock before calling supplicant - it is required to
76    // mutually exclude access from Wifi and P2p state machines
77    static final Object mLock = new Object();
78
79    public final String mInterfaceName;
80    public final String mInterfacePrefix;
81
82    private boolean mSuspendOptEnabled = false;
83
84    private static final int EID_HT_OPERATION = 61;
85    private static final int EID_VHT_OPERATION = 192;
86    private static final int EID_EXTENDED_CAPS = 127;
87    private static final int RTT_RESP_ENABLE_BIT = 70;
88    /* Register native functions */
89
90    static {
91        /* Native functions are defined in libwifi-service.so */
92        System.loadLibrary("wifi-service");
93        registerNatives();
94    }
95
96    private static native int registerNatives();
97
98    public native static boolean loadDriver();
99
100    public native static boolean isDriverLoaded();
101
102    public native static boolean unloadDriver();
103
104    public native static boolean startSupplicant(boolean p2pSupported);
105
106    /* Sends a kill signal to supplicant. To be used when we have lost connection
107       or when the supplicant is hung */
108    public native static boolean killSupplicant(boolean p2pSupported);
109
110    private native boolean connectToSupplicantNative();
111
112    private native void closeSupplicantConnectionNative();
113
114    /**
115     * Wait for the supplicant to send an event, returning the event string.
116     * @return the event string sent by the supplicant.
117     */
118    private native String waitForEventNative();
119
120    private native boolean doBooleanCommandNative(String command);
121
122    private native int doIntCommandNative(String command);
123
124    private native String doStringCommandNative(String command);
125
126    public WifiNative(String interfaceName) {
127        mInterfaceName = interfaceName;
128        mTAG = "WifiNative-" + interfaceName;
129        if (!interfaceName.equals("p2p0")) {
130            mInterfacePrefix = "IFNAME=" + interfaceName + " ";
131        } else {
132            // commands for p2p0 interface don't need prefix
133            mInterfacePrefix = "";
134        }
135    }
136
137    void enableVerboseLogging(int verbose) {
138        if (verbose > 0) {
139            DBG = true;
140        } else {
141            DBG = false;
142        }
143    }
144
145    private static final LocalLog mLocalLog = new LocalLog(16384);
146
147    // hold mLock before accessing mCmdIdLock
148    private static int sCmdId;
149
150    public static LocalLog getLocalLog() {
151        return mLocalLog;
152    }
153
154    private static int getNewCmdIdLocked() {
155        return sCmdId++;
156    }
157
158    private void localLog(String s) {
159        if (mLocalLog != null)
160            mLocalLog.log(mInterfaceName + ": " + s);
161    }
162
163    public boolean connectToSupplicant() {
164        synchronized(mLock) {
165            localLog(mInterfacePrefix + "connectToSupplicant");
166            return connectToSupplicantNative();
167        }
168    }
169
170    public void closeSupplicantConnection() {
171        synchronized(mLock) {
172            localLog(mInterfacePrefix + "closeSupplicantConnection");
173            closeSupplicantConnectionNative();
174        }
175    }
176
177    public String waitForEvent() {
178        // No synchronization necessary .. it is implemented in WifiMonitor
179        return waitForEventNative();
180    }
181
182    private boolean doBooleanCommand(String command) {
183        if (DBG) Log.d(mTAG, "doBoolean: " + command);
184        synchronized (mLock) {
185            int cmdId = getNewCmdIdLocked();
186            String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command;
187            boolean result = doBooleanCommandNative(mInterfacePrefix + command);
188            localLog(toLog + " -> " + result);
189            if (DBG) Log.d(mTAG, command + ": returned " + result);
190            return result;
191        }
192    }
193
194    private boolean doBooleanCommandWithoutLogging(String command) {
195        if (DBG) Log.d(mTAG, "doBooleanCommandWithoutLogging: " + command);
196        synchronized (mLock) {
197            int cmdId = getNewCmdIdLocked();
198            boolean result = doBooleanCommandNative(mInterfacePrefix + command);
199            if (DBG) Log.d(mTAG, command + ": returned " + result);
200            return result;
201        }
202    }
203
204    private int doIntCommand(String command) {
205        if (DBG) Log.d(mTAG, "doInt: " + command);
206        synchronized (mLock) {
207            int cmdId = getNewCmdIdLocked();
208            String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command;
209            int result = doIntCommandNative(mInterfacePrefix + command);
210            localLog(toLog + " -> " + result);
211            if (DBG) Log.d(mTAG, "   returned " + result);
212            return result;
213        }
214    }
215
216    private String doStringCommand(String command) {
217        if (DBG) {
218            //GET_NETWORK commands flood the logs
219            if (!command.startsWith("GET_NETWORK")) {
220                Log.d(mTAG, "doString: [" + command + "]");
221            }
222        }
223        synchronized (mLock) {
224            int cmdId = getNewCmdIdLocked();
225            String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command;
226            String result = doStringCommandNative(mInterfacePrefix + command);
227            if (result == null) {
228                if (DBG) Log.d(mTAG, "doStringCommandNative no result");
229            } else {
230                if (!command.startsWith("STATUS-")) {
231                    localLog(toLog + " -> " + result);
232                }
233                if (DBG) Log.d(mTAG, "   returned " + result.replace("\n", " "));
234            }
235            return result;
236        }
237    }
238
239    private String doStringCommandWithoutLogging(String command) {
240        if (DBG) {
241            //GET_NETWORK commands flood the logs
242            if (!command.startsWith("GET_NETWORK")) {
243                Log.d(mTAG, "doString: [" + command + "]");
244            }
245        }
246        synchronized (mLock) {
247            return doStringCommandNative(mInterfacePrefix + command);
248        }
249    }
250
251    public boolean ping() {
252        String pong = doStringCommand("PING");
253        return (pong != null && pong.equals("PONG"));
254    }
255
256    public void setSupplicantLogLevel(String level) {
257        doStringCommand("LOG_LEVEL " + level);
258    }
259
260    public String getFreqCapability() {
261        return doStringCommand("GET_CAPABILITY freq");
262    }
263
264    public boolean scan(int type, String freqList) {
265        if (type == SCAN_WITHOUT_CONNECTION_SETUP) {
266            if (freqList == null) return doBooleanCommand("SCAN TYPE=ONLY");
267            else return doBooleanCommand("SCAN TYPE=ONLY freq=" + freqList);
268        } else if (type == SCAN_WITH_CONNECTION_SETUP) {
269            if (freqList == null) return doBooleanCommand("SCAN");
270            else return doBooleanCommand("SCAN freq=" + freqList);
271        } else {
272            throw new IllegalArgumentException("Invalid scan type");
273        }
274    }
275
276    /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta.
277     *
278     * Note that underneath we use a harsh-sounding "terminate" supplicant command
279     * for a graceful stop and a mild-sounding "stop" interface
280     * to kill the process
281     */
282    public boolean stopSupplicant() {
283        return doBooleanCommand("TERMINATE");
284    }
285
286    public String listNetworks() {
287        return doStringCommand("LIST_NETWORKS");
288    }
289
290    public String listNetworks(int last_id) {
291        return doStringCommand("LIST_NETWORKS LAST_ID=" + last_id);
292    }
293
294    public int addNetwork() {
295        return doIntCommand("ADD_NETWORK");
296    }
297
298    public boolean setNetworkVariable(int netId, String name, String value) {
299        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false;
300        if (name.equals(WifiConfiguration.pskVarName)
301                || name.equals(WifiEnterpriseConfig.PASSWORD_KEY)) {
302            return doBooleanCommandWithoutLogging("SET_NETWORK " + netId + " " + name + " " + value);
303        } else {
304            return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value);
305        }
306    }
307
308    public String getNetworkVariable(int netId, String name) {
309        if (TextUtils.isEmpty(name)) return null;
310
311        // GET_NETWORK will likely flood the logs ...
312        return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name);
313    }
314
315    public boolean removeNetwork(int netId) {
316        return doBooleanCommand("REMOVE_NETWORK " + netId);
317    }
318
319
320    private void logDbg(String debug) {
321        long now = SystemClock.elapsedRealtimeNanos();
322        String ts = String.format("[%,d us] ", now/1000);
323        Log.e("WifiNative: ", ts+debug+ " stack:"
324                + Thread.currentThread().getStackTrace()[2].getMethodName() +" - "
325                + Thread.currentThread().getStackTrace()[3].getMethodName() +" - "
326                + Thread.currentThread().getStackTrace()[4].getMethodName() +" - "
327                + Thread.currentThread().getStackTrace()[5].getMethodName()+" - "
328                + Thread.currentThread().getStackTrace()[6].getMethodName());
329
330    }
331    public boolean enableNetwork(int netId, boolean disableOthers) {
332        if (DBG) logDbg("enableNetwork nid=" + Integer.toString(netId)
333                + " disableOthers=" + disableOthers);
334        if (disableOthers) {
335            return doBooleanCommand("SELECT_NETWORK " + netId);
336        } else {
337            return doBooleanCommand("ENABLE_NETWORK " + netId);
338        }
339    }
340
341    public boolean disableNetwork(int netId) {
342        if (DBG) logDbg("disableNetwork nid=" + Integer.toString(netId));
343        return doBooleanCommand("DISABLE_NETWORK " + netId);
344    }
345
346    public boolean selectNetwork(int netId) {
347        if (DBG) logDbg("selectNetwork nid=" + Integer.toString(netId));
348        return doBooleanCommand("SELECT_NETWORK " + netId);
349    }
350
351    public boolean reconnect() {
352        if (DBG) logDbg("RECONNECT ");
353        return doBooleanCommand("RECONNECT");
354    }
355
356    public boolean reassociate() {
357        if (DBG) logDbg("REASSOCIATE ");
358        return doBooleanCommand("REASSOCIATE");
359    }
360
361    public boolean disconnect() {
362        if (DBG) logDbg("DISCONNECT ");
363        return doBooleanCommand("DISCONNECT");
364    }
365
366    public String status() {
367        return status(false);
368    }
369
370    public String status(boolean noEvents) {
371        if (noEvents) {
372            return doStringCommand("STATUS-NO_EVENTS");
373        } else {
374            return doStringCommand("STATUS");
375        }
376    }
377
378    public String getMacAddress() {
379        //Macaddr = XX.XX.XX.XX.XX.XX
380        String ret = doStringCommand("DRIVER MACADDR");
381        if (!TextUtils.isEmpty(ret)) {
382            String[] tokens = ret.split(" = ");
383            if (tokens.length == 2) return tokens[1];
384        }
385        return null;
386    }
387
388
389
390    /**
391     * Format of results:
392     * =================
393     * id=1
394     * bssid=68:7f:74:d7:1b:6e
395     * freq=2412
396     * level=-43
397     * tsf=1344621975160944
398     * age=2623
399     * flags=[WPA2-PSK-CCMP][WPS][ESS]
400     * ssid=zubyb
401     * ====
402     *
403     * RANGE=ALL gets all scan results
404     * RANGE=ID- gets results from ID
405     * MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details
406     * 0                         0                        1                       0     2
407     *                           WPA_BSS_MASK_MESH_SCAN | WPA_BSS_MASK_DELIM    | WPA_BSS_MASK_WIFI_DISPLAY
408     * 0                         0                        0                       1     1   -> 9
409     * WPA_BSS_MASK_INTERNETW  | WPA_BSS_MASK_P2P_SCAN  | WPA_BSS_MASK_WPS_SCAN | WPA_BSS_MASK_SSID
410     * 1                         0                        0                       1     9   -> d
411     * WPA_BSS_MASK_FLAGS      | WPA_BSS_MASK_IE        | WPA_BSS_MASK_AGE      | WPA_BSS_MASK_TSF
412     * 1                         0                        0                       0     8
413     * WPA_BSS_MASK_LEVEL      | WPA_BSS_MASK_NOISE     | WPA_BSS_MASK_QUAL     | WPA_BSS_MASK_CAPABILITIES
414     * 0                         1                        1                       1     7
415     * WPA_BSS_MASK_BEACON_INT | WPA_BSS_MASK_FREQ      | WPA_BSS_MASK_BSSID    | WPA_BSS_MASK_ID
416     *
417     * WPA_BSS_MASK_INTERNETW adds ANQP info (ctrl_iface:4151-4176)
418     *
419     * ctrl_iface.c:wpa_supplicant_ctrl_iface_process:7884
420     *  wpa_supplicant_ctrl_iface_bss:4315
421     *  print_bss_info
422     */
423    public String scanResults(int sid) {
424        return doStringCommandWithoutLogging("BSS RANGE=" + sid + "- MASK=0x29d87");
425    }
426
427    public String doCustomCommand(String command) {
428        return doStringCommand(command);
429    }
430
431    /**
432     * Format of result:
433     * id=1016
434     * bssid=00:03:7f:40:84:10
435     * freq=2462
436     * beacon_int=200
437     * capabilities=0x0431
438     * qual=0
439     * noise=0
440     * level=-46
441     * tsf=0000002669008476
442     * age=5
443     * ie=00105143412d485332302d52322d54455354010882848b960c12182403010b0706555...
444     * flags=[WPA2-EAP-CCMP][ESS][P2P][HS20]
445     * ssid=QCA-HS20-R2-TEST
446     * p2p_device_name=
447     * p2p_config_methods=0x0SET_NE
448     * anqp_venue_name=02083d656e6757692d466920416c6c69616e63650a3239383920436f...
449     * anqp_network_auth_type=010000
450     * anqp_roaming_consortium=03506f9a05001bc504bd
451     * anqp_ip_addr_type_availability=0c
452     * anqp_nai_realm=0200300000246d61696c2e6578616d706c652e636f6d3b636973636f2...
453     * anqp_3gpp=000600040132f465
454     * anqp_domain_name=0b65786d61706c652e636f6d
455     * hs20_operator_friendly_name=11656e6757692d466920416c6c69616e63650e636869...
456     * hs20_wan_metrics=01c40900008001000000000a00
457     * hs20_connection_capability=0100000006140001061600000650000106bb010106bb0...
458     * hs20_osu_providers_list=0b5143412d4f53552d425353010901310015656e6757692d...
459     */
460    public String scanResult(String bssid) {
461        return doStringCommand("BSS " + bssid);
462    }
463
464    /**
465     * Format of command
466     * DRIVER WLS_BATCHING SET SCANFREQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s
467     * where x is an ascii representation of an integer number of seconds between scans
468     *       r is an ascii representation of an integer number of scans per batch
469     *       y is an ascii representation of an integer number of the max AP to remember per scan
470     *       z, w, t represent a 1..n size list of channel numbers and/or 'A', 'B' values
471     *           indicating entire ranges of channels
472     *       s is an ascii representation of an integer number of highest-strength AP
473     *           for which we'd like approximate distance reported
474     *
475     * The return value is an ascii integer representing a guess of the number of scans
476     * the firmware can remember before it runs out of buffer space or -1 on error
477     */
478    public String setBatchedScanSettings(BatchedScanSettings settings) {
479        if (settings == null) {
480            return doStringCommand("DRIVER WLS_BATCHING STOP");
481        }
482        String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec;
483        cmd += " MSCAN=" + settings.maxScansPerBatch;
484        if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
485            cmd += " BESTN=" + settings.maxApPerScan;
486        }
487        if (settings.channelSet != null && !settings.channelSet.isEmpty()) {
488            cmd += " CHANNEL=<";
489            int i = 0;
490            for (String channel : settings.channelSet) {
491                cmd += (i > 0 ? "," : "") + channel;
492                ++i;
493            }
494            cmd += ">";
495        }
496        if (settings.maxApForDistance != BatchedScanSettings.UNSPECIFIED) {
497            cmd += " RTT=" + settings.maxApForDistance;
498        }
499        return doStringCommand(cmd);
500    }
501
502    public String getBatchedScanResults() {
503        return doStringCommand("DRIVER WLS_BATCHING GET");
504    }
505
506    public boolean startDriver() {
507        return doBooleanCommand("DRIVER START");
508    }
509
510    public boolean stopDriver() {
511        return doBooleanCommand("DRIVER STOP");
512    }
513
514
515    /**
516     * Start filtering out Multicast V4 packets
517     * @return {@code true} if the operation succeeded, {@code false} otherwise
518     *
519     * Multicast filtering rules work as follows:
520     *
521     * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
522     * a power optimized mode (typically when screen goes off).
523     *
524     * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
525     * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
526     *
527     * DRIVER RXFILTER-ADD Num
528     *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
529     *
530     * and DRIVER RXFILTER-START
531     * In order to stop the usage of these rules, we do
532     *
533     * DRIVER RXFILTER-STOP
534     * DRIVER RXFILTER-REMOVE Num
535     *   where Num is as described for RXFILTER-ADD
536     *
537     * The  SETSUSPENDOPT driver command overrides the filtering rules
538     */
539    public boolean startFilteringMulticastV4Packets() {
540        return doBooleanCommand("DRIVER RXFILTER-STOP")
541            && doBooleanCommand("DRIVER RXFILTER-REMOVE 2")
542            && doBooleanCommand("DRIVER RXFILTER-START");
543    }
544
545    /**
546     * Stop filtering out Multicast V4 packets.
547     * @return {@code true} if the operation succeeded, {@code false} otherwise
548     */
549    public boolean stopFilteringMulticastV4Packets() {
550        return doBooleanCommand("DRIVER RXFILTER-STOP")
551            && doBooleanCommand("DRIVER RXFILTER-ADD 2")
552            && doBooleanCommand("DRIVER RXFILTER-START");
553    }
554
555    /**
556     * Start filtering out Multicast V6 packets
557     * @return {@code true} if the operation succeeded, {@code false} otherwise
558     */
559    public boolean startFilteringMulticastV6Packets() {
560        return doBooleanCommand("DRIVER RXFILTER-STOP")
561            && doBooleanCommand("DRIVER RXFILTER-REMOVE 3")
562            && doBooleanCommand("DRIVER RXFILTER-START");
563    }
564
565    /**
566     * Stop filtering out Multicast V6 packets.
567     * @return {@code true} if the operation succeeded, {@code false} otherwise
568     */
569    public boolean stopFilteringMulticastV6Packets() {
570        return doBooleanCommand("DRIVER RXFILTER-STOP")
571            && doBooleanCommand("DRIVER RXFILTER-ADD 3")
572            && doBooleanCommand("DRIVER RXFILTER-START");
573    }
574
575    /**
576     * Set the operational frequency band
577     * @param band One of
578     *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
579     *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
580     *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
581     * @return {@code true} if the operation succeeded, {@code false} otherwise
582     */
583    public boolean setBand(int band) {
584        String bandstr;
585
586        if (band == WifiManager.WIFI_FREQUENCY_BAND_5GHZ)
587            bandstr = "5G";
588        else if (band == WifiManager.WIFI_FREQUENCY_BAND_2GHZ)
589            bandstr = "2G";
590        else
591            bandstr = "AUTO";
592        return doBooleanCommand("SET SETBAND " + bandstr);
593    }
594
595    /**
596      * Sets the bluetooth coexistence mode.
597      *
598      * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
599      *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
600      *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
601      * @return Whether the mode was successfully set.
602      */
603    public boolean setBluetoothCoexistenceMode(int mode) {
604        return doBooleanCommand("DRIVER BTCOEXMODE " + mode);
605    }
606
607    /**
608     * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
609     * some of the low-level scan parameters used by the driver are changed to
610     * reduce interference with A2DP streaming.
611     *
612     * @param isSet whether to enable or disable this mode
613     * @return {@code true} if the command succeeded, {@code false} otherwise.
614     */
615    public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) {
616        if (setCoexScanMode) {
617            return doBooleanCommand("DRIVER BTCOEXSCAN-START");
618        } else {
619            return doBooleanCommand("DRIVER BTCOEXSCAN-STOP");
620        }
621    }
622
623    public void enableSaveConfig() {
624        doBooleanCommand("SET update_config 1");
625    }
626
627    public boolean saveConfig() {
628        return doBooleanCommand("SAVE_CONFIG");
629    }
630
631    public boolean addToBlacklist(String bssid) {
632        if (TextUtils.isEmpty(bssid)) return false;
633        return doBooleanCommand("BLACKLIST " + bssid);
634    }
635
636    public boolean clearBlacklist() {
637        return doBooleanCommand("BLACKLIST clear");
638    }
639
640    public boolean setSuspendOptimizations(boolean enabled) {
641       // if (mSuspendOptEnabled == enabled) return true;
642        mSuspendOptEnabled = enabled;
643
644        Log.e("native", "do suspend " + enabled);
645        if (enabled) {
646            return doBooleanCommand("DRIVER SETSUSPENDMODE 1");
647        } else {
648            return doBooleanCommand("DRIVER SETSUSPENDMODE 0");
649        }
650    }
651
652    public boolean setCountryCode(String countryCode) {
653        if (countryCode != null)
654            return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
655        else
656            return doBooleanCommand("DRIVER COUNTRY");
657    }
658
659    public boolean enableBackgroundScan(boolean enable) {
660        boolean ret;
661        if (enable) {
662            ret = doBooleanCommand("SET pno 1");
663        } else {
664            ret = doBooleanCommand("SET pno 0");
665        }
666        return ret;
667    }
668
669    public void enableAutoConnect(boolean enable) {
670        if (enable) {
671            doBooleanCommand("STA_AUTOCONNECT 1");
672        } else {
673            doBooleanCommand("STA_AUTOCONNECT 0");
674        }
675    }
676
677    public void setScanInterval(int scanInterval) {
678        doBooleanCommand("SCAN_INTERVAL " + scanInterval);
679    }
680
681    public void setHs20(boolean hs20) {
682        if (hs20) {
683            doBooleanCommand("SET HS20 1");
684        } else {
685            doBooleanCommand("SET HS20 0");
686        }
687    }
688
689    public void startTdls(String macAddr, boolean enable) {
690        if (enable) {
691            doBooleanCommand("TDLS_DISCOVER " + macAddr);
692            doBooleanCommand("TDLS_SETUP " + macAddr);
693        } else {
694            doBooleanCommand("TDLS_TEARDOWN " + macAddr);
695        }
696    }
697
698    /** Example output:
699     * RSSI=-65
700     * LINKSPEED=48
701     * NOISE=9999
702     * FREQUENCY=0
703     */
704    public String signalPoll() {
705        return doStringCommandWithoutLogging("SIGNAL_POLL");
706    }
707
708    /** Example outout:
709     * TXGOOD=396
710     * TXBAD=1
711     */
712    public String pktcntPoll() {
713        return doStringCommand("PKTCNT_POLL");
714    }
715
716    public void bssFlush() {
717        doBooleanCommand("BSS_FLUSH 0");
718    }
719
720    public boolean startWpsPbc(String bssid) {
721        if (TextUtils.isEmpty(bssid)) {
722            return doBooleanCommand("WPS_PBC");
723        } else {
724            return doBooleanCommand("WPS_PBC " + bssid);
725        }
726    }
727
728    public boolean startWpsPbc(String iface, String bssid) {
729        synchronized (mLock) {
730            if (TextUtils.isEmpty(bssid)) {
731                return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
732            } else {
733                return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
734            }
735        }
736    }
737
738    public boolean startWpsPinKeypad(String pin) {
739        if (TextUtils.isEmpty(pin)) return false;
740        return doBooleanCommand("WPS_PIN any " + pin);
741    }
742
743    public boolean startWpsPinKeypad(String iface, String pin) {
744        if (TextUtils.isEmpty(pin)) return false;
745        synchronized (mLock) {
746            return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
747        }
748    }
749
750
751    public String startWpsPinDisplay(String bssid) {
752        if (TextUtils.isEmpty(bssid)) {
753            return doStringCommand("WPS_PIN any");
754        } else {
755            return doStringCommand("WPS_PIN " + bssid);
756        }
757    }
758
759    public String startWpsPinDisplay(String iface, String bssid) {
760        synchronized (mLock) {
761            if (TextUtils.isEmpty(bssid)) {
762                return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
763            } else {
764                return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
765            }
766        }
767    }
768
769    public boolean setExternalSim(boolean external) {
770        synchronized (mLock) {
771            String value = external ? "1" : "0";
772            Log.d(TAG, "Setting external_sim to " + value);
773            return doBooleanCommand("SET external_sim " + value);
774        }
775    }
776
777    public boolean simAuthResponse(int id, String type, String response) {
778        // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS
779        synchronized (mLock) {
780            return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response);
781        }
782    }
783
784    public boolean simIdentityResponse(int id, String response) {
785        synchronized (mLock) {
786            return doBooleanCommand("CTRL-RSP-IDENTITY-" + id + ":" + response);
787        }
788    }
789
790    /* Configures an access point connection */
791    public boolean startWpsRegistrar(String bssid, String pin) {
792        if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false;
793        return doBooleanCommand("WPS_REG " + bssid + " " + pin);
794    }
795
796    public boolean cancelWps() {
797        return doBooleanCommand("WPS_CANCEL");
798    }
799
800    public boolean setPersistentReconnect(boolean enabled) {
801        int value = (enabled == true) ? 1 : 0;
802        return doBooleanCommand("SET persistent_reconnect " + value);
803    }
804
805    public boolean setDeviceName(String name) {
806        return doBooleanCommand("SET device_name " + name);
807    }
808
809    public boolean setDeviceType(String type) {
810        return doBooleanCommand("SET device_type " + type);
811    }
812
813    public boolean setConfigMethods(String cfg) {
814        return doBooleanCommand("SET config_methods " + cfg);
815    }
816
817    public boolean setManufacturer(String value) {
818        return doBooleanCommand("SET manufacturer " + value);
819    }
820
821    public boolean setModelName(String value) {
822        return doBooleanCommand("SET model_name " + value);
823    }
824
825    public boolean setModelNumber(String value) {
826        return doBooleanCommand("SET model_number " + value);
827    }
828
829    public boolean setSerialNumber(String value) {
830        return doBooleanCommand("SET serial_number " + value);
831    }
832
833    public boolean setP2pSsidPostfix(String postfix) {
834        return doBooleanCommand("SET p2p_ssid_postfix " + postfix);
835    }
836
837    public boolean setP2pGroupIdle(String iface, int time) {
838        synchronized (mLock) {
839            return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
840        }
841    }
842
843    public void setPowerSave(boolean enabled) {
844        if (enabled) {
845            doBooleanCommand("SET ps 1");
846        } else {
847            doBooleanCommand("SET ps 0");
848        }
849    }
850
851    public boolean setP2pPowerSave(String iface, boolean enabled) {
852        synchronized (mLock) {
853            if (enabled) {
854                return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
855            } else {
856                return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
857            }
858        }
859    }
860
861    public boolean setWfdEnable(boolean enable) {
862        return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0"));
863    }
864
865    public boolean setWfdDeviceInfo(String hex) {
866        return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex);
867    }
868
869    /**
870     * "sta" prioritizes STA connection over P2P and "p2p" prioritizes
871     * P2P connection over STA
872     */
873    public boolean setConcurrencyPriority(String s) {
874        return doBooleanCommand("P2P_SET conc_pref " + s);
875    }
876
877    public boolean p2pFind() {
878        return doBooleanCommand("P2P_FIND");
879    }
880
881    public boolean p2pFind(int timeout) {
882        if (timeout <= 0) {
883            return p2pFind();
884        }
885        return doBooleanCommand("P2P_FIND " + timeout);
886    }
887
888    public boolean p2pStopFind() {
889       return doBooleanCommand("P2P_STOP_FIND");
890    }
891
892    public boolean p2pListen() {
893        return doBooleanCommand("P2P_LISTEN");
894    }
895
896    public boolean p2pListen(int timeout) {
897        if (timeout <= 0) {
898            return p2pListen();
899        }
900        return doBooleanCommand("P2P_LISTEN " + timeout);
901    }
902
903    public boolean p2pExtListen(boolean enable, int period, int interval) {
904        if (enable && interval < period) {
905            return false;
906        }
907        return doBooleanCommand("P2P_EXT_LISTEN"
908                    + (enable ? (" " + period + " " + interval) : ""));
909    }
910
911    public boolean p2pSetChannel(int lc, int oc) {
912        if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc);
913
914        if (lc >=1 && lc <= 11) {
915            if (!doBooleanCommand("P2P_SET listen_channel " + lc)) {
916                return false;
917            }
918        } else if (lc != 0) {
919            return false;
920        }
921
922        if (oc >= 1 && oc <= 165 ) {
923            int freq = (oc <= 14 ? 2407 : 5000) + oc * 5;
924            return doBooleanCommand("P2P_SET disallow_freq 1000-"
925                    + (freq - 5) + "," + (freq + 5) + "-6000");
926        } else if (oc == 0) {
927            /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */
928            return doBooleanCommand("P2P_SET disallow_freq \"\"");
929        }
930
931        return false;
932    }
933
934    public boolean p2pFlush() {
935        return doBooleanCommand("P2P_FLUSH");
936    }
937
938    /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad]
939        [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */
940    public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) {
941        if (config == null) return null;
942        List<String> args = new ArrayList<String>();
943        WpsInfo wps = config.wps;
944        args.add(config.deviceAddress);
945
946        switch (wps.setup) {
947            case WpsInfo.PBC:
948                args.add("pbc");
949                break;
950            case WpsInfo.DISPLAY:
951                if (TextUtils.isEmpty(wps.pin)) {
952                    args.add("pin");
953                } else {
954                    args.add(wps.pin);
955                }
956                args.add("display");
957                break;
958            case WpsInfo.KEYPAD:
959                args.add(wps.pin);
960                args.add("keypad");
961                break;
962            case WpsInfo.LABEL:
963                args.add(wps.pin);
964                args.add("label");
965            default:
966                break;
967        }
968
969        if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) {
970            args.add("persistent");
971        }
972
973        if (joinExistingGroup) {
974            args.add("join");
975        } else {
976            //TODO: This can be adapted based on device plugged in state and
977            //device battery state
978            int groupOwnerIntent = config.groupOwnerIntent;
979            if (groupOwnerIntent < 0 || groupOwnerIntent > 15) {
980                groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT;
981            }
982            args.add("go_intent=" + groupOwnerIntent);
983        }
984
985        String command = "P2P_CONNECT ";
986        for (String s : args) command += s + " ";
987
988        return doStringCommand(command);
989    }
990
991    public boolean p2pCancelConnect() {
992        return doBooleanCommand("P2P_CANCEL");
993    }
994
995    public boolean p2pProvisionDiscovery(WifiP2pConfig config) {
996        if (config == null) return false;
997
998        switch (config.wps.setup) {
999            case WpsInfo.PBC:
1000                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc");
1001            case WpsInfo.DISPLAY:
1002                //We are doing display, so provision discovery is keypad
1003                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad");
1004            case WpsInfo.KEYPAD:
1005                //We are doing keypad, so provision discovery is display
1006                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display");
1007            default:
1008                break;
1009        }
1010        return false;
1011    }
1012
1013    public boolean p2pGroupAdd(boolean persistent) {
1014        if (persistent) {
1015            return doBooleanCommand("P2P_GROUP_ADD persistent");
1016        }
1017        return doBooleanCommand("P2P_GROUP_ADD");
1018    }
1019
1020    public boolean p2pGroupAdd(int netId) {
1021        return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId);
1022    }
1023
1024    public boolean p2pGroupRemove(String iface) {
1025        if (TextUtils.isEmpty(iface)) return false;
1026        synchronized (mLock) {
1027            return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
1028        }
1029    }
1030
1031    public boolean p2pReject(String deviceAddress) {
1032        return doBooleanCommand("P2P_REJECT " + deviceAddress);
1033    }
1034
1035    /* Invite a peer to a group */
1036    public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) {
1037        if (TextUtils.isEmpty(deviceAddress)) return false;
1038
1039        if (group == null) {
1040            return doBooleanCommand("P2P_INVITE peer=" + deviceAddress);
1041        } else {
1042            return doBooleanCommand("P2P_INVITE group=" + group.getInterface()
1043                    + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress);
1044        }
1045    }
1046
1047    /* Reinvoke a persistent connection */
1048    public boolean p2pReinvoke(int netId, String deviceAddress) {
1049        if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false;
1050
1051        return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress);
1052    }
1053
1054    public String p2pGetSsid(String deviceAddress) {
1055        return p2pGetParam(deviceAddress, "oper_ssid");
1056    }
1057
1058    public String p2pGetDeviceAddress() {
1059
1060        Log.d(TAG, "p2pGetDeviceAddress");
1061
1062        String status = null;
1063
1064        /* Explicitly calling the API without IFNAME= prefix to take care of the devices that
1065        don't have p2p0 interface. Supplicant seems to be returning the correct address anyway. */
1066
1067        synchronized (mLock) {
1068            status = doStringCommandNative("STATUS");
1069        }
1070
1071        String result = "";
1072        if (status != null) {
1073            String[] tokens = status.split("\n");
1074            for (String token : tokens) {
1075                if (token.startsWith("p2p_device_address=")) {
1076                    String[] nameValue = token.split("=");
1077                    if (nameValue.length != 2)
1078                        break;
1079                    result = nameValue[1];
1080                }
1081            }
1082        }
1083
1084        Log.d(TAG, "p2pGetDeviceAddress returning " + result);
1085        return result;
1086    }
1087
1088    public int getGroupCapability(String deviceAddress) {
1089        int gc = 0;
1090        if (TextUtils.isEmpty(deviceAddress)) return gc;
1091        String peerInfo = p2pPeer(deviceAddress);
1092        if (TextUtils.isEmpty(peerInfo)) return gc;
1093
1094        String[] tokens = peerInfo.split("\n");
1095        for (String token : tokens) {
1096            if (token.startsWith("group_capab=")) {
1097                String[] nameValue = token.split("=");
1098                if (nameValue.length != 2) break;
1099                try {
1100                    return Integer.decode(nameValue[1]);
1101                } catch(NumberFormatException e) {
1102                    return gc;
1103                }
1104            }
1105        }
1106        return gc;
1107    }
1108
1109    public String p2pPeer(String deviceAddress) {
1110        return doStringCommand("P2P_PEER " + deviceAddress);
1111    }
1112
1113    private String p2pGetParam(String deviceAddress, String key) {
1114        if (deviceAddress == null) return null;
1115
1116        String peerInfo = p2pPeer(deviceAddress);
1117        if (peerInfo == null) return null;
1118        String[] tokens= peerInfo.split("\n");
1119
1120        key += "=";
1121        for (String token : tokens) {
1122            if (token.startsWith(key)) {
1123                String[] nameValue = token.split("=");
1124                if (nameValue.length != 2) break;
1125                return nameValue[1];
1126            }
1127        }
1128        return null;
1129    }
1130
1131    public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) {
1132        /*
1133         * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump>
1134         * P2P_SERVICE_ADD upnp <version hex> <service>
1135         *
1136         * e.g)
1137         * [Bonjour]
1138         * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.)
1139         * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027
1140         * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript)
1141         * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001
1142         *  09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074
1143         *
1144         * [UPnP]
1145         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
1146         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice
1147         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp
1148         * -org:device:InternetGatewayDevice:1
1149         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp
1150         * -org:service:ContentDirectory:2
1151         */
1152        for (String s : servInfo.getSupplicantQueryList()) {
1153            String command = "P2P_SERVICE_ADD";
1154            command += (" " + s);
1155            if (!doBooleanCommand(command)) {
1156                return false;
1157            }
1158        }
1159        return true;
1160    }
1161
1162    public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) {
1163        /*
1164         * P2P_SERVICE_DEL bonjour <query hexdump>
1165         * P2P_SERVICE_DEL upnp <version hex> <service>
1166         */
1167        for (String s : servInfo.getSupplicantQueryList()) {
1168            String command = "P2P_SERVICE_DEL ";
1169
1170            String[] data = s.split(" ");
1171            if (data.length < 2) {
1172                return false;
1173            }
1174            if ("upnp".equals(data[0])) {
1175                command += s;
1176            } else if ("bonjour".equals(data[0])) {
1177                command += data[0];
1178                command += (" " + data[1]);
1179            } else {
1180                return false;
1181            }
1182            if (!doBooleanCommand(command)) {
1183                return false;
1184            }
1185        }
1186        return true;
1187    }
1188
1189    public boolean p2pServiceFlush() {
1190        return doBooleanCommand("P2P_SERVICE_FLUSH");
1191    }
1192
1193    public String p2pServDiscReq(String addr, String query) {
1194        String command = "P2P_SERV_DISC_REQ";
1195        command += (" " + addr);
1196        command += (" " + query);
1197
1198        return doStringCommand(command);
1199    }
1200
1201    public boolean p2pServDiscCancelReq(String id) {
1202        return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id);
1203    }
1204
1205    /* Set the current mode of miracast operation.
1206     *  0 = disabled
1207     *  1 = operating as source
1208     *  2 = operating as sink
1209     */
1210    public void setMiracastMode(int mode) {
1211        // Note: optional feature on the driver. It is ok for this to fail.
1212        doBooleanCommand("DRIVER MIRACAST " + mode);
1213    }
1214
1215    public boolean fetchAnqp(String bssid, String subtypes) {
1216        return doBooleanCommand("ANQP_GET " + bssid + " " + subtypes);
1217    }
1218
1219    /*
1220     * NFC-related calls
1221     */
1222    public String getNfcWpsConfigurationToken(int netId) {
1223        return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId);
1224    }
1225
1226    public String getNfcHandoverRequest() {
1227        return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR");
1228    }
1229
1230    public String getNfcHandoverSelect() {
1231        return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR");
1232    }
1233
1234    public boolean initiatorReportNfcHandover(String selectMessage) {
1235        return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage);
1236    }
1237
1238    public boolean responderReportNfcHandover(String requestMessage) {
1239        return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00");
1240    }
1241
1242    /* WIFI HAL support */
1243
1244    private static final String TAG = "WifiNative-HAL";
1245    private static long sWifiHalHandle = 0;             /* used by JNI to save wifi_handle */
1246    private static long[] sWifiIfaceHandles = null;     /* used by JNI to save interface handles */
1247    private static int sWlan0Index = -1;
1248    private static int sP2p0Index = -1;
1249    private static MonitorThread sThread;
1250    private static final int STOP_HAL_TIMEOUT_MS = 1000;
1251
1252    private static native boolean startHalNative();
1253    private static native void stopHalNative();
1254    private static native void waitForHalEventNative();
1255
1256    private static class MonitorThread extends Thread {
1257        public void run() {
1258            Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle));
1259            waitForHalEventNative();
1260        }
1261    }
1262
1263    synchronized public static boolean startHal() {
1264
1265        String debugLog = "startHal stack: ";
1266        java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace();
1267        for (int i = 2; i < elements.length && i <= 7; i++ ) {
1268            debugLog = debugLog + " - " + elements[i].getMethodName();
1269        }
1270
1271        mLocalLog.log(debugLog);
1272
1273        synchronized (mLock) {
1274            if (startHalNative() && (getInterfaces() != 0) && (sWlan0Index != -1)) {
1275                sThread = new MonitorThread();
1276                sThread.start();
1277                return true;
1278            } else {
1279                if (DBG) mLocalLog.log("Could not start hal");
1280                Log.e(TAG, "Could not start hal");
1281                return false;
1282            }
1283        }
1284    }
1285
1286    synchronized public static void stopHal() {
1287        synchronized (mLock) {
1288            if (isHalStarted()) {
1289                stopHalNative();
1290                try {
1291                    sThread.join(STOP_HAL_TIMEOUT_MS);
1292                    Log.d(TAG, "HAL event thread stopped successfully");
1293                } catch (InterruptedException e) {
1294                    Log.e(TAG, "Could not stop HAL cleanly");
1295                }
1296                sThread = null;
1297                sWifiHalHandle = 0;
1298                sWifiIfaceHandles = null;
1299                sWlan0Index = -1;
1300                sP2p0Index = -1;
1301            }
1302        }
1303    }
1304
1305    public static boolean isHalStarted() {
1306        return (sWifiHalHandle != 0);
1307    }
1308    private static native int getInterfacesNative();
1309
1310    synchronized public static int getInterfaces() {
1311        synchronized (mLock) {
1312            if (isHalStarted()) {
1313                if (sWifiIfaceHandles == null) {
1314                    int num = getInterfacesNative();
1315                    int wifi_num = 0;
1316                    for (int i = 0; i < num; i++) {
1317                        String name = getInterfaceNameNative(i);
1318                        Log.i(TAG, "interface[" + i + "] = " + name);
1319                        if (name.equals("wlan0")) {
1320                            sWlan0Index = i;
1321                            wifi_num++;
1322                        } else if (name.equals("p2p0")) {
1323                            sP2p0Index = i;
1324                            wifi_num++;
1325                        }
1326                    }
1327                    return wifi_num;
1328                } else {
1329                    return sWifiIfaceHandles.length;
1330                }
1331            } else {
1332                return 0;
1333            }
1334        }
1335    }
1336
1337    private static native String getInterfaceNameNative(int index);
1338    synchronized public static String getInterfaceName(int index) {
1339        return getInterfaceNameNative(index);
1340    }
1341
1342    public static class ScanCapabilities {
1343        public int  max_scan_cache_size;                 // in number of scan results??
1344        public int  max_scan_buckets;
1345        public int  max_ap_cache_per_scan;
1346        public int  max_rssi_sample_size;
1347        public int  max_scan_reporting_threshold;        // in number of scan results??
1348        public int  max_hotlist_bssids;
1349        public int  max_significant_wifi_change_aps;
1350    }
1351
1352    synchronized public static boolean getScanCapabilities(ScanCapabilities capabilities) {
1353        synchronized (mLock) {
1354            return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities);
1355        }
1356    }
1357
1358    private static native boolean getScanCapabilitiesNative(
1359            int iface, ScanCapabilities capabilities);
1360
1361    private static native boolean startScanNative(int iface, int id, ScanSettings settings);
1362    private static native boolean stopScanNative(int iface, int id);
1363    private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush);
1364    private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface);
1365    private static native void setWifiLinkLayerStatsNative(int iface, int enable);
1366
1367    public static class ChannelSettings {
1368        int frequency;
1369        int dwell_time_ms;
1370        boolean passive;
1371    }
1372
1373    public static class BucketSettings {
1374        int bucket;
1375        int band;
1376        int period_ms;
1377        int report_events;
1378        int num_channels;
1379        ChannelSettings channels[];
1380    }
1381
1382    public static class ScanSettings {
1383        int base_period_ms;
1384        int max_ap_per_scan;
1385        int report_threshold_percent;
1386        int report_threshold_num_scans;
1387        int num_buckets;
1388        BucketSettings buckets[];
1389    }
1390
1391    public static interface ScanEventHandler {
1392        void onScanResultsAvailable();
1393        void onFullScanResult(ScanResult fullScanResult);
1394        void onScanStatus();
1395        void onScanPaused(WifiScanner.ScanData[] data);
1396        void onScanRestarted();
1397    }
1398
1399    synchronized static void onScanResultsAvailable(int id) {
1400        if (sScanEventHandler  != null) {
1401            sScanEventHandler.onScanResultsAvailable();
1402        }
1403    }
1404
1405    /* scan status, keep these values in sync with gscan.h */
1406    private static int WIFI_SCAN_BUFFER_FULL = 0;
1407    private static int WIFI_SCAN_COMPLETE = 1;
1408
1409    synchronized static void onScanStatus(int status) {
1410        if (status == WIFI_SCAN_BUFFER_FULL) {
1411            /* we have a separate event to take care of this */
1412        } else if (status == WIFI_SCAN_COMPLETE) {
1413            if (sScanEventHandler  != null) {
1414                sScanEventHandler.onScanStatus();
1415            }
1416        }
1417    }
1418
1419    public static  WifiSsid createWifiSsid (byte[] rawSsid) {
1420        String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid));
1421
1422        if (ssidHexString == null) {
1423            return null;
1424        }
1425
1426        WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString);
1427
1428        return wifiSsid;
1429    }
1430
1431    public static String ssidConvert(byte[] rawSsid) {
1432        String ssid;
1433
1434        CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
1435        try {
1436            CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid));
1437            ssid = decoded.toString();
1438        } catch (CharacterCodingException cce) {
1439            ssid = null;
1440        }
1441
1442        if (ssid == null) {
1443            ssid = new String(rawSsid, StandardCharsets.ISO_8859_1);
1444        }
1445
1446        return ssid;
1447    }
1448
1449    public static boolean setSsid(byte[] rawSsid, ScanResult result) {
1450        if (rawSsid == null || rawSsid.length == 0 || result == null) {
1451            return false;
1452        }
1453
1454        result.SSID = ssidConvert(rawSsid);
1455        result.wifiSsid = createWifiSsid(rawSsid);
1456        return true;
1457    }
1458
1459    static void populateScanResult(ScanResult result, byte bytes[], String dbg) {
1460        int num = 0;
1461        if (bytes == null) return;
1462        if (dbg == null) dbg = "";
1463        for (int i = 0; i < bytes.length - 1; ) {
1464            int type  = bytes[i] & 0xFF;
1465            int len = bytes[i + 1] & 0xFF;
1466            if (i + len + 2 > bytes.length) {
1467                Log.w(TAG, dbg + "bad length " + len + " of IE " + type + " from " + result.BSSID);
1468                Log.w(TAG, dbg + "ignoring the rest of the IEs");
1469                break;
1470            }
1471            num++;
1472            if (DBG) Log.i(TAG, dbg + "bytes[" + i + "] = [" + type + ", " + len + "]" + ", " +
1473                    "next = " + (i + len + 2));
1474            i += len + 2;
1475        }
1476
1477        int secondChanelOffset = 0;
1478        byte channelMode = 0;
1479        int centerFreqIndex1 = 0;
1480        int centerFreqIndex2 = 0;
1481
1482        boolean is80211McRTTResponder = false;
1483
1484        ScanResult.InformationElement elements[] = new ScanResult.InformationElement[num];
1485        for (int i = 0, index = 0; i < num; i++) {
1486            int type  = bytes[index] & 0xFF;
1487            int len = bytes[index + 1] & 0xFF;
1488            if (DBG) Log.i(TAG, dbg + "index = " + index + ", type = " + type + ", len = " + len);
1489            ScanResult.InformationElement elem = new ScanResult.InformationElement();
1490            elem.id = type;
1491            elem.bytes = new byte[len];
1492            for (int j = 0; j < len; j++) {
1493                elem.bytes[j] = bytes[index + j + 2];
1494            }
1495            elements[i] = elem;
1496            int inforStart = index + 2;
1497            index += (len + 2);
1498
1499            if(type == EID_HT_OPERATION) {
1500                secondChanelOffset = bytes[inforStart + 1] & 0x3;
1501            } else if(type == EID_VHT_OPERATION) {
1502                channelMode = bytes[inforStart];
1503                centerFreqIndex1 = bytes[inforStart + 1] & 0xFF;
1504                centerFreqIndex2 = bytes[inforStart + 2] & 0xFF;
1505            } else if (type == EID_EXTENDED_CAPS) {
1506                int tempIndex = RTT_RESP_ENABLE_BIT / 8;
1507                byte offset = RTT_RESP_ENABLE_BIT % 8;
1508
1509                if(len < tempIndex + 1) {
1510                    is80211McRTTResponder = false;
1511                } else {
1512                    if ((bytes[inforStart + tempIndex] & ((byte)0x1 << offset)) != 0) {
1513                        is80211McRTTResponder = true;
1514                    } else {
1515                        is80211McRTTResponder = false;
1516                    }
1517                }
1518            }
1519        }
1520
1521        if (is80211McRTTResponder) {
1522            result.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
1523        } else {
1524            result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER);
1525        }
1526
1527        //handle RTT related information
1528        if (channelMode != 0) {
1529            // 80 or 160 MHz
1530            result.channelWidth = channelMode + 1;
1531
1532            //convert channel index to frequency in MHz, channel 36 is 5180MHz
1533            result.centerFreq0 = (centerFreqIndex1 - 36) * 5 + 5180;
1534
1535            if(channelMode > 1) { //160MHz
1536                result.centerFreq1 = (centerFreqIndex2 - 36) * 5 + 5180;
1537            } else {
1538                result.centerFreq1 = 0;
1539            }
1540        } else {
1541            //20 or 40 MHz
1542            if (secondChanelOffset != 0) {//40MHz
1543                result.channelWidth = 1;
1544                if (secondChanelOffset == 1) {
1545                    result.centerFreq0 = result.frequency + 20;
1546                } else if (secondChanelOffset == 3) {
1547                    result.centerFreq0 = result.frequency - 20;
1548                } else {
1549                    result.centerFreq0 = 0;
1550                    Log.e(TAG, dbg + ": Error on secondChanelOffset");
1551                }
1552            } else {
1553                result.centerFreq0  = 0;
1554                result.centerFreq1  = 0;
1555            }
1556            result.centerFreq1  = 0;
1557        }
1558        if(DBG) {
1559            Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth +
1560                    " PrimaryFreq: " + result.frequency +" mCenterfreq0: " + result.centerFreq0 +
1561                    " mCenterfreq1: " + result.centerFreq1 + (is80211McRTTResponder ?
1562                    "Support RTT reponder: " : "Do not support RTT responder"));
1563        }
1564
1565        result.informationElements = elements;
1566    }
1567
1568    synchronized static void onFullScanResult(int id, ScanResult result, byte bytes[]) {
1569        if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID + ", " +
1570                "num = " + bytes.length);
1571
1572        if (sScanEventHandler == null) {
1573            return;
1574        }
1575        populateScanResult(result, bytes, " onFullScanResult ");
1576
1577        sScanEventHandler.onFullScanResult(result);
1578    }
1579
1580    private static int sScanCmdId = 0;
1581    private static ScanEventHandler sScanEventHandler;
1582    private static ScanSettings sScanSettings;
1583
1584    synchronized public static boolean startScan(
1585            ScanSettings settings, ScanEventHandler eventHandler) {
1586        synchronized (mLock) {
1587            if (isHalStarted()) {
1588
1589                if (sScanCmdId != 0) {
1590                    stopScan();
1591                } else if (sScanSettings != null || sScanEventHandler != null) {
1592                /* current scan is paused; no need to stop it */
1593                }
1594
1595                sScanCmdId = getNewCmdIdLocked();
1596
1597                sScanSettings = settings;
1598                sScanEventHandler = eventHandler;
1599
1600                if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) {
1601                    sScanEventHandler = null;
1602                    sScanSettings = null;
1603                    sScanCmdId = 0;
1604                    return false;
1605                }
1606
1607                return true;
1608            } else {
1609                return false;
1610            }
1611        }
1612    }
1613
1614    synchronized public static void stopScan() {
1615        synchronized (mLock) {
1616            if (isHalStarted()) {
1617                if (sScanCmdId != 0) {
1618                    stopScanNative(sWlan0Index, sScanCmdId);
1619                }
1620                sScanSettings = null;
1621                sScanEventHandler = null;
1622                sScanCmdId = 0;
1623            }
1624        }
1625    }
1626
1627    synchronized public static void pauseScan() {
1628        synchronized (mLock) {
1629            if (isHalStarted()) {
1630                if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) {
1631                    Log.d(TAG, "Pausing scan");
1632                    WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true);
1633                    stopScanNative(sWlan0Index, sScanCmdId);
1634                    sScanCmdId = 0;
1635                    sScanEventHandler.onScanPaused(scanData);
1636                }
1637            }
1638        }
1639    }
1640
1641    synchronized public static void restartScan() {
1642        synchronized (mLock) {
1643            if (isHalStarted()) {
1644                if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) {
1645                    Log.d(TAG, "Restarting scan");
1646                    ScanEventHandler handler = sScanEventHandler;
1647                    ScanSettings settings = sScanSettings;
1648                    if (startScan(sScanSettings, sScanEventHandler)) {
1649                        sScanEventHandler.onScanRestarted();
1650                    } else {
1651                    /* we are still paused; don't change state */
1652                        sScanEventHandler = handler;
1653                        sScanSettings = settings;
1654                    }
1655                }
1656            }
1657        }
1658    }
1659
1660    synchronized public static WifiScanner.ScanData[] getScanResults(boolean flush) {
1661        synchronized (mLock) {
1662            if (isHalStarted()) {
1663                return getScanResultsNative(sWlan0Index, flush);
1664            } else {
1665                return null;
1666            }
1667        }
1668    }
1669
1670    public static interface HotlistEventHandler {
1671        void onHotlistApFound (ScanResult[] result);
1672        void onHotlistApLost  (ScanResult[] result);
1673    }
1674
1675    private static int sHotlistCmdId = 0;
1676    private static HotlistEventHandler sHotlistEventHandler;
1677
1678    private native static boolean setHotlistNative(int iface, int id,
1679            WifiScanner.HotlistSettings settings);
1680    private native static boolean resetHotlistNative(int iface, int id);
1681
1682    synchronized public static boolean setHotlist(WifiScanner.HotlistSettings settings,
1683                                    HotlistEventHandler eventHandler) {
1684        synchronized (mLock) {
1685            if (isHalStarted()) {
1686                if (sHotlistCmdId != 0) {
1687                    return false;
1688                } else {
1689                    sHotlistCmdId = getNewCmdIdLocked();
1690                }
1691
1692                sHotlistEventHandler = eventHandler;
1693                if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) {
1694                    sHotlistEventHandler = null;
1695                    return false;
1696                }
1697
1698                return true;
1699            } else {
1700                return false;
1701            }
1702        }
1703    }
1704
1705    synchronized public static void resetHotlist() {
1706        synchronized (mLock) {
1707            if (isHalStarted()) {
1708                if (sHotlistCmdId != 0) {
1709                    resetHotlistNative(sWlan0Index, sHotlistCmdId);
1710                    sHotlistCmdId = 0;
1711                    sHotlistEventHandler = null;
1712                }
1713            }
1714        }
1715    }
1716
1717    synchronized public static void onHotlistApFound(int id, ScanResult[] results) {
1718        synchronized (mLock) {
1719            if (isHalStarted()) {
1720                if (sHotlistCmdId != 0) {
1721                    sHotlistEventHandler.onHotlistApFound(results);
1722                } else {
1723                /* this can happen because of race conditions */
1724                    Log.d(TAG, "Ignoring hotlist AP found event");
1725                }
1726            }
1727        }
1728    }
1729
1730    synchronized public static void onHotlistApLost(int id, ScanResult[] results) {
1731        synchronized (mLock) {
1732            if (isHalStarted()) {
1733                if (sHotlistCmdId != 0) {
1734                    sHotlistEventHandler.onHotlistApLost(results);
1735                } else {
1736                /* this can happen because of race conditions */
1737                    Log.d(TAG, "Ignoring hotlist AP lost event");
1738                }
1739            }
1740        }
1741    }
1742
1743    public static interface SignificantWifiChangeEventHandler {
1744        void onChangesFound(ScanResult[] result);
1745    }
1746
1747    private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler;
1748    private static int sSignificantWifiChangeCmdId;
1749
1750    private static native boolean trackSignificantWifiChangeNative(
1751            int iface, int id, WifiScanner.WifiChangeSettings settings);
1752    private static native boolean untrackSignificantWifiChangeNative(int iface, int id);
1753
1754    synchronized public static boolean trackSignificantWifiChange(
1755            WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
1756        synchronized (mLock) {
1757            if (isHalStarted()) {
1758                if (sSignificantWifiChangeCmdId != 0) {
1759                    return false;
1760                } else {
1761                    sSignificantWifiChangeCmdId = getNewCmdIdLocked();
1762                }
1763
1764                sSignificantWifiChangeHandler = handler;
1765                if (trackSignificantWifiChangeNative(sWlan0Index, sScanCmdId, settings) == false) {
1766                    sSignificantWifiChangeHandler = null;
1767                    return false;
1768                }
1769
1770                return true;
1771            } else {
1772                return false;
1773            }
1774
1775        }
1776    }
1777
1778    synchronized static void untrackSignificantWifiChange() {
1779        synchronized (mLock) {
1780            if (isHalStarted()) {
1781                if (sSignificantWifiChangeCmdId != 0) {
1782                    untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId);
1783                    sSignificantWifiChangeCmdId = 0;
1784                    sSignificantWifiChangeHandler = null;
1785                }
1786            }
1787        }
1788    }
1789
1790    synchronized static void onSignificantWifiChange(int id, ScanResult[] results) {
1791        synchronized (mLock) {
1792            if (sSignificantWifiChangeCmdId != 0) {
1793                sSignificantWifiChangeHandler.onChangesFound(results);
1794            } else {
1795            /* this can happen because of race conditions */
1796                Log.d(TAG, "Ignoring significant wifi change");
1797            }
1798        }
1799    }
1800
1801    synchronized public static WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
1802        // TODO: use correct iface name to Index translation
1803        if (iface == null) return null;
1804        synchronized (mLock) {
1805            if (isHalStarted()) {
1806                return getWifiLinkLayerStatsNative(sWlan0Index);
1807            } else {
1808                return null;
1809            }
1810        }
1811    }
1812
1813    synchronized public static void setWifiLinkLayerStats(String iface, int enable) {
1814        if (iface == null) return;
1815        synchronized (mLock) {
1816            if (isHalStarted()) {
1817                setWifiLinkLayerStatsNative(sWlan0Index, enable);
1818            }
1819        }
1820    }
1821
1822    public static native int getSupportedFeatureSetNative(int iface);
1823    synchronized public static int getSupportedFeatureSet() {
1824        synchronized (mLock) {
1825            if (isHalStarted()) {
1826                return getSupportedFeatureSetNative(sWlan0Index);
1827            } else {
1828                Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started");
1829                return 0;
1830            }
1831        }
1832    }
1833
1834    /* Rtt related commands/events */
1835    public static interface RttEventHandler {
1836        void onRttResults(RttManager.RttResult[] result);
1837    }
1838
1839    private static RttEventHandler sRttEventHandler;
1840    private static int sRttCmdId;
1841
1842    synchronized private static void onRttResults(int id, RttManager.RttResult[] results) {
1843        if (id == sRttCmdId) {
1844            Log.d(TAG, "Received " + results.length + " rtt results");
1845            sRttEventHandler.onRttResults(results);
1846            sRttCmdId = 0;
1847        } else {
1848            Log.d(TAG, "RTT Received event for unknown cmd = " + id + ", current id = " + sRttCmdId);
1849        }
1850    }
1851
1852    private static native boolean requestRangeNative(
1853            int iface, int id, RttManager.RttParams[] params);
1854    private static native boolean cancelRangeRequestNative(
1855            int iface, int id, RttManager.RttParams[] params);
1856
1857    synchronized public static boolean requestRtt(
1858            RttManager.RttParams[] params, RttEventHandler handler) {
1859        synchronized (mLock) {
1860            if (isHalStarted()) {
1861                if (sRttCmdId != 0) {
1862                    Log.v("TAG", "Last one is still under measurement!");
1863                    return false;
1864                } else {
1865                    sRttCmdId = getNewCmdIdLocked();
1866                }
1867                sRttEventHandler = handler;
1868                Log.v(TAG, "native issue RTT request");
1869                return requestRangeNative(sWlan0Index, sRttCmdId, params);
1870            } else {
1871                return false;
1872            }
1873        }
1874    }
1875
1876    synchronized public static boolean cancelRtt(RttManager.RttParams[] params) {
1877        synchronized(mLock) {
1878            if (isHalStarted()) {
1879                if (sRttCmdId == 0) {
1880                    return false;
1881                }
1882
1883                sRttCmdId = 0;
1884
1885                if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) {
1886                    sRttEventHandler = null;
1887                    Log.v(TAG, "RTT cancel Request Successfully");
1888                    return true;
1889                } else {
1890                    Log.e(TAG, "RTT cancel Request failed");
1891                    return false;
1892                }
1893            } else {
1894                return false;
1895            }
1896        }
1897    }
1898
1899    private static native boolean setScanningMacOuiNative(int iface, byte[] oui);
1900
1901    synchronized public static boolean setScanningMacOui(byte[] oui) {
1902        synchronized (mLock) {
1903            if (isHalStarted()) {
1904                return setScanningMacOuiNative(sWlan0Index, oui);
1905            } else {
1906                return false;
1907            }
1908        }
1909    }
1910
1911    private static native int[] getChannelsForBandNative(
1912            int iface, int band);
1913
1914    synchronized public static int [] getChannelsForBand(int band) {
1915        synchronized (mLock) {
1916            if (isHalStarted()) {
1917                return getChannelsForBandNative(sWlan0Index, band);
1918	    } else {
1919                return null;
1920            }
1921        }
1922    }
1923
1924    private static native boolean isGetChannelsForBandSupportedNative();
1925    synchronized public static boolean isGetChannelsForBandSupported(){
1926        synchronized (mLock) {
1927            if (isHalStarted()) {
1928                return isGetChannelsForBandSupportedNative();
1929	    } else {
1930                return false;
1931            }
1932        }
1933    }
1934
1935    private static native boolean setDfsFlagNative(int iface, boolean dfsOn);
1936    synchronized public static boolean setDfsFlag(boolean dfsOn) {
1937        synchronized (mLock) {
1938            if (isHalStarted()) {
1939                return setDfsFlagNative(sWlan0Index, dfsOn);
1940            } else {
1941                return false;
1942            }
1943        }
1944    }
1945
1946    private static native boolean toggleInterfaceNative(int on);
1947    synchronized public static boolean toggleInterface(int on) {
1948        synchronized (mLock) {
1949            if (isHalStarted()) {
1950                return toggleInterfaceNative(0);
1951            } else {
1952                return false;
1953            }
1954        }
1955    }
1956
1957    private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface);
1958    synchronized public static RttManager.RttCapabilities getRttCapabilities() {
1959        synchronized (mLock) {
1960            if (isHalStarted()) {
1961                return getRttCapabilitiesNative(sWlan0Index);
1962            }else {
1963                return null;
1964            }
1965        }
1966    }
1967
1968    private static native boolean setCountryCodeHalNative(int iface, String CountryCode);
1969    synchronized public static boolean setCountryCodeHal( String CountryCode) {
1970        synchronized (mLock) {
1971            if (isHalStarted()) {
1972                return setCountryCodeHalNative(sWlan0Index, CountryCode);
1973            } else {
1974                return false;
1975            }
1976        }
1977    }
1978
1979    /* Rtt related commands/events */
1980    public abstract class TdlsEventHandler {
1981        abstract public void onTdlsStatus(String macAddr, int status, int reason);
1982    }
1983
1984    private static TdlsEventHandler sTdlsEventHandler;
1985
1986    private static native boolean enableDisableTdlsNative(int iface, boolean enable,
1987            String macAddr);
1988    synchronized public static boolean enableDisableTdls(boolean enable, String macAdd,
1989            TdlsEventHandler tdlsCallBack) {
1990        synchronized (mLock) {
1991            sTdlsEventHandler = tdlsCallBack;
1992            return enableDisableTdlsNative(sWlan0Index, enable, macAdd);
1993        }
1994    }
1995
1996    // Once TDLS per mac and event feature is implemented, this class definition should be
1997    // moved to the right place, like WifiManager etc
1998    public static class TdlsStatus {
1999        int channel;
2000        int global_operating_class;
2001        int state;
2002        int reason;
2003    }
2004    private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr);
2005    synchronized public static TdlsStatus getTdlsStatus (String macAdd) {
2006        synchronized (mLock) {
2007            if (isHalStarted()) {
2008                return getTdlsStatusNative(sWlan0Index, macAdd);
2009            } else {
2010                return null;
2011            }
2012        }
2013    }
2014
2015    //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be
2016    // moved to the right place, like WifiStateMachine etc
2017    public static class TdlsCapabilities {
2018        /* Maximum TDLS session number can be supported by the Firmware and hardware */
2019        int maxConcurrentTdlsSessionNumber;
2020        boolean isGlobalTdlsSupported;
2021        boolean isPerMacTdlsSupported;
2022        boolean isOffChannelTdlsSupported;
2023    }
2024
2025
2026
2027    private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface);
2028    synchronized public static TdlsCapabilities getTdlsCapabilities () {
2029        synchronized (mLock) {
2030            if (isHalStarted()) {
2031                return getTdlsCapabilitiesNative(sWlan0Index);
2032            } else {
2033                return null;
2034            }
2035        }
2036    }
2037
2038    synchronized private static boolean onTdlsStatus(String macAddr, int status, int reason) {
2039         if (sTdlsEventHandler == null) {
2040             return false;
2041         } else {
2042             sTdlsEventHandler.onTdlsStatus(macAddr, status, reason);
2043             return true;
2044         }
2045    }
2046
2047    //---------------------------------------------------------------------------------
2048
2049    /* Wifi Logger commands/events */
2050
2051    public static native boolean startLogging(int iface);
2052
2053    public static interface WifiLoggerEventHandler {
2054        void onRingBufferData(RingBufferStatus status, byte[] buffer);
2055        void onWifiAlert(int errorCode, byte[] buffer);
2056    }
2057
2058    private static WifiLoggerEventHandler sWifiLoggerEventHandler = null;
2059
2060    private static void onRingBufferData(RingBufferStatus status, byte[] buffer) {
2061        if (sWifiLoggerEventHandler != null)
2062            sWifiLoggerEventHandler.onRingBufferData(status, buffer);
2063    }
2064
2065    private static void onWifiAlert(byte[] buffer, int errorCode) {
2066        if (sWifiLoggerEventHandler != null)
2067            sWifiLoggerEventHandler.onWifiAlert(errorCode, buffer);
2068    }
2069
2070    private static int sLogCmdId = -1;
2071    private static native boolean setLoggingEventHandlerNative(int iface, int id);
2072    synchronized public static boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
2073        synchronized (mLock) {
2074            if (isHalStarted()) {
2075                int oldId =  sLogCmdId;
2076                sLogCmdId = getNewCmdIdLocked();
2077                if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) {
2078                    sLogCmdId = oldId;
2079                    return false;
2080                }
2081                sWifiLoggerEventHandler = handler;
2082                return true;
2083            } else {
2084                return false;
2085            }
2086        }
2087    }
2088
2089    private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel,
2090            int flags, int minIntervalSec ,int minDataSize, String ringName);
2091    synchronized public static boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
2092            int minDataSize, String ringName){
2093        synchronized (mLock) {
2094            if (isHalStarted()) {
2095                return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval,
2096                        minDataSize, ringName);
2097            } else {
2098                return false;
2099            }
2100        }
2101    }
2102
2103    private static native int getSupportedLoggerFeatureSetNative(int iface);
2104    synchronized public static int getSupportedLoggerFeatureSet() {
2105        synchronized (mLock) {
2106            if (isHalStarted()) {
2107                return getSupportedLoggerFeatureSetNative(sWlan0Index);
2108            } else {
2109                return 0;
2110            }
2111        }
2112    }
2113
2114    private static native boolean resetLogHandlerNative(int iface, int id);
2115    synchronized public static boolean resetLogHandler() {
2116        synchronized (mLock) {
2117            if (isHalStarted()) {
2118                if (sLogCmdId == -1) {
2119                    Log.e(TAG,"Can not reset handler Before set any handler");
2120                    return false;
2121                }
2122                sWifiLoggerEventHandler = null;
2123                if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) {
2124                    sLogCmdId = -1;
2125                    return true;
2126                } else {
2127                    return false;
2128                }
2129            } else {
2130                return false;
2131            }
2132        }
2133    }
2134
2135    private static native String getDriverVersionNative(int iface);
2136    synchronized public static String getDriverVersion() {
2137        synchronized (mLock) {
2138            if (isHalStarted()) {
2139                return getDriverVersionNative(sWlan0Index);
2140            } else {
2141                return "";
2142            }
2143        }
2144    }
2145
2146
2147    private static native String getFirmwareVersionNative(int iface);
2148    synchronized public static String getFirmwareVersion() {
2149        synchronized (mLock) {
2150            if (isHalStarted()) {
2151                return getFirmwareVersionNative(sWlan0Index);
2152            } else {
2153                return "";
2154            }
2155        }
2156    }
2157
2158    public static class RingBufferStatus{
2159        String name;
2160        int flag;
2161        int ringBufferId;
2162        int ringBufferByteSize;
2163        int verboseLevel;
2164        int writtenBytes;
2165        int readBytes;
2166        int writtenRecords;
2167
2168        @Override
2169        public String toString() {
2170            return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
2171                    " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
2172                    " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
2173                    " writtenRecords: " + writtenRecords;
2174        }
2175    }
2176
2177    private static native RingBufferStatus[] getRingBufferStatusNative(int iface);
2178    synchronized public static RingBufferStatus[] getRingBufferStatus() {
2179        synchronized (mLock) {
2180            if (isHalStarted()) {
2181                return getRingBufferStatusNative(sWlan0Index);
2182            } else {
2183                return null;
2184            }
2185        }
2186    }
2187
2188    private static native boolean getRingBufferDataNative(int iface, String ringName);
2189    synchronized public static boolean getRingBufferData(String ringName) {
2190        synchronized (mLock) {
2191            if (isHalStarted()) {
2192                return getRingBufferDataNative(sWlan0Index, ringName);
2193            } else {
2194                return false;
2195            }
2196        }
2197    }
2198
2199    static private byte[] mFwMemoryDump;
2200    private static void onWifiFwMemoryAvailable(byte[] buffer) {
2201        mFwMemoryDump = buffer;
2202        if (DBG) {
2203            Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " +
2204                    (buffer == null ? 0 :  buffer.length));
2205        }
2206    }
2207
2208    private static native boolean getFwMemoryDumpNative(int iface);
2209    synchronized public static byte[] getFwMemoryDump() {
2210        synchronized (mLock) {
2211            if (isHalStarted()) {
2212                if(getFwMemoryDumpNative(sWlan0Index)) {
2213                    byte[] fwMemoryDump = mFwMemoryDump;
2214                    mFwMemoryDump = null;
2215                    return fwMemoryDump;
2216                } else {
2217                    return null;
2218                }
2219            }
2220
2221            return null;
2222        }
2223    }
2224
2225    //---------------------------------------------------------------------------------
2226    /* Configure ePNO */
2227
2228    public class WifiPnoNetwork {
2229        String SSID;
2230        int rssi_threshold;
2231        int flags;
2232        int auth;
2233        String configKey; // kept for reference
2234
2235        WifiPnoNetwork(WifiConfiguration config, int threshold) {
2236            if (config.SSID == null) {
2237                this.SSID = "";
2238                this.flags = 1;
2239            } else {
2240                this.SSID = config.SSID;
2241            }
2242            this.rssi_threshold = threshold;
2243            if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
2244                auth |= 2;
2245            } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) ||
2246                    config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) {
2247                auth |= 4;
2248            } else if (config.wepKeys[0] != null) {
2249                auth |= 1;
2250            } else {
2251                auth |= 1;
2252            }
2253//            auth = 0;
2254            flags |= 6; //A and G
2255            configKey = config.configKey();
2256        }
2257
2258        @Override
2259        public String toString() {
2260            StringBuilder sbuf = new StringBuilder();
2261            sbuf.append(this.SSID);
2262            sbuf.append(" flags=").append(this.flags);
2263            sbuf.append(" rssi=").append(this.rssi_threshold);
2264            sbuf.append(" auth=").append(this.auth);
2265            return sbuf.toString();
2266        }
2267    }
2268
2269    public static interface WifiPnoEventHandler {
2270        void onPnoNetworkFound(ScanResult results[]);
2271    }
2272
2273    private static WifiPnoEventHandler sWifiPnoEventHandler;
2274
2275    private static int sPnoCmdId = 0;
2276
2277    private native static boolean setPnoListNative(int iface, int id, WifiPnoNetwork list[]);
2278
2279    synchronized public static boolean setPnoList(WifiPnoNetwork list[],
2280                                                  WifiPnoEventHandler eventHandler) {
2281        Log.e(TAG, "setPnoList cmd " + sPnoCmdId);
2282
2283        synchronized (mLock) {
2284            if (isHalStarted()) {
2285
2286                sPnoCmdId = getNewCmdIdLocked();
2287
2288                sWifiPnoEventHandler = eventHandler;
2289                if (setPnoListNative(sWlan0Index, sPnoCmdId, list)) {
2290                    return true;
2291                }
2292            }
2293
2294            sWifiPnoEventHandler = null;
2295            return false;
2296        }
2297    }
2298
2299    synchronized public static void onPnoNetworkFound(int id, ScanResult[] results) {
2300
2301        if (results == null) {
2302            Log.e(TAG, "onPnoNetworkFound null results");
2303            return;
2304
2305        }
2306        Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length);
2307
2308        //Log.e(TAG, "onPnoNetworkFound length " + results.length);
2309        //return;
2310        for (int i=0; i<results.length; i++) {
2311            Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID
2312                    + " " + results[i].level + " " + results[i].frequency);
2313
2314            populateScanResult(results[i], results[i].bytes, "onPnoNetworkFound ");
2315            results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID);
2316        }
2317        synchronized (mLock) {
2318            if (sPnoCmdId != 0 && sWifiPnoEventHandler != null) {
2319                sWifiPnoEventHandler.onPnoNetworkFound(results);
2320            } else {
2321                /* this can happen because of race conditions */
2322                Log.d(TAG, "Ignoring Pno Network found event");
2323            }
2324        }
2325    }
2326
2327    public class WifiLazyRoamParams {
2328        int A_band_boost_threshold;
2329        int A_band_penalty_threshold;
2330        int A_band_boost_factor;
2331        int A_band_penalty_factor;
2332        int A_band_max_boost;
2333        int lazy_roam_hysteresis;
2334        int alert_roam_rssi_trigger;
2335
2336        WifiLazyRoamParams() {
2337        }
2338
2339        @Override
2340        public String toString() {
2341            StringBuilder sbuf = new StringBuilder();
2342            sbuf.append(" A_band_boost_threshold=").append(this.A_band_boost_threshold);
2343            sbuf.append(" A_band_penalty_threshold=").append(this.A_band_penalty_threshold);
2344            sbuf.append(" A_band_boost_factor=").append(this.A_band_boost_factor);
2345            sbuf.append(" A_band_penalty_factor=").append(this.A_band_penalty_factor);
2346            sbuf.append(" A_band_max_boost=").append(this.A_band_max_boost);
2347            sbuf.append(" lazy_roam_hysteresis=").append(this.lazy_roam_hysteresis);
2348            sbuf.append(" alert_roam_rssi_trigger=").append(this.alert_roam_rssi_trigger);
2349            return sbuf.toString();
2350        }
2351    }
2352
2353    private native static boolean setLazyRoamNative(int iface, int id,
2354                                              boolean enabled, WifiLazyRoamParams param);
2355
2356    synchronized public static boolean setLazyRoam(boolean enabled, WifiLazyRoamParams params) {
2357        synchronized (mLock) {
2358            if (isHalStarted()) {
2359                sPnoCmdId = getNewCmdIdLocked();
2360                return setLazyRoamNative(sWlan0Index, sPnoCmdId, enabled, params);
2361            } else {
2362                return false;
2363            }
2364        }
2365    }
2366
2367    private native static boolean setBssidBlacklistNative(int iface, int id,
2368                                              String list[]);
2369
2370    synchronized public static boolean setBssidBlacklist(String list[]) {
2371        int size = 0;
2372        if (list != null) {
2373            size = list.length;
2374        }
2375        Log.e(TAG, "setBssidBlacklist cmd " + sPnoCmdId + " size " + size);
2376
2377        synchronized (mLock) {
2378            if (isHalStarted()) {
2379                sPnoCmdId = getNewCmdIdLocked();
2380                return setBssidBlacklistNative(sWlan0Index, sPnoCmdId, list);
2381            } else {
2382                return false;
2383            }
2384        }
2385    }
2386
2387    private native static boolean setSsidWhitelistNative(int iface, int id, String list[]);
2388
2389    synchronized public static boolean setSsidWhitelist(String list[]) {
2390        int size = 0;
2391        if (list != null) {
2392            size = list.length;
2393        }
2394        Log.e(TAG, "setSsidWhitelist cmd " + sPnoCmdId + " size " + size);
2395
2396        synchronized (mLock) {
2397            if (isHalStarted()) {
2398                sPnoCmdId = getNewCmdIdLocked();
2399
2400                return setSsidWhitelistNative(sWlan0Index, sPnoCmdId, list);
2401            } else {
2402                return false;
2403            }
2404        }
2405    }
2406
2407    private native static int startSendingOffloadedPacketNative(int iface, int idx,
2408                                    byte[] srcMac, byte[] dstMac, byte[] pktData, int period);
2409
2410    synchronized public int
2411    startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) {
2412        Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period);
2413
2414        String[] macAddrStr = getMacAddress().split(":");
2415        byte[] srcMac = new byte[6];
2416        for(int i = 0; i < 6; i++) {
2417            Integer hexVal = Integer.parseInt(macAddrStr[i], 16);
2418            srcMac[i] = hexVal.byteValue();
2419        }
2420        synchronized (mLock) {
2421            if (isHalStarted()) {
2422                return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac,
2423                                keepAlivePacket.dstMac, keepAlivePacket.data, period);
2424            } else {
2425                return -1;
2426            }
2427        }
2428    }
2429
2430    private native static int stopSendingOffloadedPacketNative(int iface, int idx);
2431
2432    synchronized public int
2433    stopSendingOffloadedPacket(int slot) {
2434        Log.d(TAG, "stopSendingOffloadedPacket " + slot);
2435        synchronized (mLock) {
2436            if (isHalStarted()) {
2437                return stopSendingOffloadedPacketNative(sWlan0Index, slot);
2438            } else {
2439                return -1;
2440            }
2441        }
2442    }
2443
2444    public static interface WifiRssiEventHandler {
2445        void onRssiThresholdBreached(byte curRssi);
2446    }
2447
2448    private static WifiRssiEventHandler sWifiRssiEventHandler;
2449
2450    synchronized static void onRssiThresholdBreached(int id, byte curRssi) {
2451        sWifiRssiEventHandler.onRssiThresholdBreached(curRssi);
2452    }
2453
2454    private native static int startRssiMonitoringNative(int iface, int id,
2455                                        byte maxRssi, byte minRssi);
2456
2457    private static int sRssiMonitorCmdId = 0;
2458
2459    synchronized public int startRssiMonitoring(byte maxRssi, byte minRssi,
2460                                                WifiRssiEventHandler rssiEventHandler) {
2461        Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi);
2462        sWifiRssiEventHandler = rssiEventHandler;
2463        synchronized (mLock) {
2464            if (isHalStarted()) {
2465                if (sRssiMonitorCmdId != 0) {
2466                    stopRssiMonitoring();
2467                }
2468
2469                sRssiMonitorCmdId = getNewCmdIdLocked();
2470                Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId);
2471                int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId,
2472                        maxRssi, minRssi);
2473                if (ret != 0) { // if not success
2474                    sRssiMonitorCmdId = 0;
2475                }
2476                return ret;
2477            } else {
2478                return -1;
2479            }
2480        }
2481    }
2482
2483    private native static int stopRssiMonitoringNative(int iface, int idx);
2484
2485    synchronized public int stopRssiMonitoring() {
2486        Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId);
2487        synchronized (mLock) {
2488            if (isHalStarted()) {
2489                int ret = 0;
2490                if (sRssiMonitorCmdId != 0) {
2491                    ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId);
2492                }
2493                sRssiMonitorCmdId = 0;
2494                return ret;
2495            } else {
2496                return -1;
2497            }
2498        }
2499    }
2500}
2501