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