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