WifiNative.java revision b66b29a00da970ee75052e24f592c8d6c16bd0ed
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(1024);
138
139    // hold mLock before accessing mCmdIdLock
140    private static int sCmdId;
141
142    public 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    /* WIFI HAL support */
1184
1185    private static final String TAG = "WifiNative-HAL";
1186    private static long sWifiHalHandle = 0;  /* used by JNI to save wifi_handle */
1187    private static long[] sWifiIfaceHandles = null;  /* used by JNI to save interface handles */
1188    private static int sWlan0Index = -1;
1189    private static int sP2p0Index = -1;
1190
1191    private static boolean sHalIsStarted = false;
1192    private static boolean sHalFailed = false;
1193
1194    private static native boolean startHalNative();
1195    private static native void stopHalNative();
1196    private static native void waitForHalEventNative();
1197
1198    private static class MonitorThread extends Thread {
1199        public void run() {
1200            Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle));
1201            waitForHalEventNative();
1202        }
1203    }
1204
1205    synchronized public static boolean startHal() {
1206
1207        String debugLog = "startHal stack: ";
1208        java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace();
1209        for (int i = 2; i < elements.length && i <= 7; i++ ) {
1210            debugLog = debugLog + " - " + elements[i].getMethodName();
1211        }
1212
1213        if (DBG) mLocalLog.log(debugLog);
1214
1215        synchronized (mLock) {
1216            if (sHalFailed)
1217                return false;
1218            if (startHalNative() && (getInterfaces() != 0) && (sWlan0Index != -1)) {
1219                if(!sHalIsStarted){
1220                    new MonitorThread().start();
1221                }
1222                sHalIsStarted = true;
1223                return true;
1224            } else {
1225                Log.i(TAG, "Could not start hal");
1226                sHalIsStarted = false;
1227                sHalFailed = true;
1228                return false;
1229            }
1230        }
1231    }
1232
1233    synchronized public static void stopHal() {
1234        stopHalNative();
1235    }
1236
1237    private static native int getInterfacesNative();
1238
1239    synchronized public static int getInterfaces() {
1240        synchronized (mLock) {
1241            if (sWifiIfaceHandles == null) {
1242                int num = getInterfacesNative();
1243                int wifi_num = 0;
1244                for (int i = 0; i < num; i++) {
1245                    String name = getInterfaceNameNative(i);
1246                    Log.i(TAG, "interface[" + i + "] = " + name);
1247                    if (name.equals("wlan0")) {
1248                        sWlan0Index = i;
1249                        wifi_num++;
1250                    } else if (name.equals("p2p0")) {
1251                        sP2p0Index = i;
1252                        wifi_num++;
1253                    }
1254                }
1255                return wifi_num;
1256            } else {
1257                return sWifiIfaceHandles.length;
1258            }
1259        }
1260    }
1261
1262    private static native String getInterfaceNameNative(int index);
1263    synchronized public static String getInterfaceName(int index) {
1264        return getInterfaceNameNative(index);
1265    }
1266
1267    public static class ScanCapabilities {
1268        public int  max_scan_cache_size;                 // in number of scan results??
1269        public int  max_scan_buckets;
1270        public int  max_ap_cache_per_scan;
1271        public int  max_rssi_sample_size;
1272        public int  max_scan_reporting_threshold;        // in number of scan results??
1273        public int  max_hotlist_bssids;
1274        public int  max_significant_wifi_change_aps;
1275    }
1276
1277    public static boolean getScanCapabilities(ScanCapabilities capabilities) {
1278        return getScanCapabilitiesNative(sWlan0Index, capabilities);
1279    }
1280
1281    private static native boolean getScanCapabilitiesNative(
1282            int iface, ScanCapabilities capabilities);
1283
1284    private static native boolean startScanNative(int iface, int id, ScanSettings settings);
1285    private static native boolean stopScanNative(int iface, int id);
1286    private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush);
1287    private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface);
1288
1289    public static class ChannelSettings {
1290        int frequency;
1291        int dwell_time_ms;
1292        boolean passive;
1293    }
1294
1295    public static class BucketSettings {
1296        int bucket;
1297        int band;
1298        int period_ms;
1299        int report_events;
1300        int num_channels;
1301        ChannelSettings channels[];
1302    }
1303
1304    public static class ScanSettings {
1305        int base_period_ms;
1306        int max_ap_per_scan;
1307        int report_threshold_percent;
1308        int report_threshold_num_scans;
1309        int num_buckets;
1310        BucketSettings buckets[];
1311    }
1312
1313    public static interface ScanEventHandler {
1314        void onScanResultsAvailable();
1315        void onFullScanResult(ScanResult fullScanResult);
1316        void onScanStatus();
1317        void onScanPaused(WifiScanner.ScanData[] data);
1318        void onScanRestarted();
1319    }
1320
1321    synchronized static void onScanResultsAvailable(int id) {
1322        if (sScanEventHandler  != null) {
1323            sScanEventHandler.onScanResultsAvailable();
1324        }
1325    }
1326
1327    /* scan status, keep these values in sync with gscan.h */
1328    private static int WIFI_SCAN_BUFFER_FULL = 0;
1329    private static int WIFI_SCAN_COMPLETE = 1;
1330
1331    synchronized static void onScanStatus(int status) {
1332        Log.i(TAG, "Got a scan status changed event, status = " + status);
1333
1334        if (status == WIFI_SCAN_BUFFER_FULL) {
1335            /* we have a separate event to take care of this */
1336        } else if (status == WIFI_SCAN_COMPLETE) {
1337            if (sScanEventHandler  != null) {
1338                sScanEventHandler.onScanStatus();
1339            }
1340        }
1341    }
1342
1343    static void populateScanResult(ScanResult result, byte bytes[], String dbg) {
1344        int num = 0;
1345        if (bytes == null) return;
1346        if (dbg == null) dbg = "";
1347        for (int i = 0; i < bytes.length; ) {
1348            int type  = bytes[i] & 0xFF;
1349            int len = bytes[i + 1] & 0xFF;
1350
1351            if (i + len + 2 > bytes.length) {
1352                Log.w(TAG, dbg + "bad length " + len + " of IE " + type + " from " + result.BSSID);
1353                Log.w(TAG, dbg + "ignoring the rest of the IEs");
1354                break;
1355            }
1356            num++;
1357            i += len + 2;
1358            if (DBG) Log.i(TAG, dbg + "bytes[" + i + "] = [" + type + ", " + len + "]" + ", " +
1359                    "next = " + i);
1360        }
1361
1362        int secondChanelOffset = 0;
1363        byte channelMode = 0;
1364        byte centerFreqIndex1 = 0;
1365        byte centerFreqIndex2 = 0;
1366        result.is80211McRTTResponder = false;
1367
1368        ScanResult.InformationElement elements[] = new ScanResult.InformationElement[num];
1369        for (int i = 0, index = 0; i < num; i++) {
1370            int type  = bytes[index] & 0xFF;
1371            int len = bytes[index + 1] & 0xFF;
1372            if (DBG) Log.i(TAG, dbg + "index = " + index + ", type = " + type + ", len = " + len);
1373            ScanResult.InformationElement elem = new ScanResult.InformationElement();
1374            elem.id = type;
1375            elem.bytes = new byte[len];
1376            for (int j = 0; j < len; j++) {
1377                elem.bytes[j] = bytes[index + j + 2];
1378            }
1379            elements[i] = elem;
1380            int inforStart = index + 2;
1381            index += (len + 2);
1382
1383            if(type == EID_HT_OPERATION) {
1384                secondChanelOffset = bytes[inforStart + 1] & 0x3;
1385            } else if(type == EID_VHT_OPERATION) {
1386                channelMode = bytes[inforStart];
1387                centerFreqIndex1 = bytes[inforStart + 1];
1388                centerFreqIndex2 = bytes[inforStart + 2];
1389            } else if (type == EID_EXTENDED_CAPS) {
1390                int tempIndex = RTT_RESP_ENABLE_BIT / 8;
1391                byte offset = RTT_RESP_ENABLE_BIT % 8;
1392
1393                if(len < tempIndex + 1) {
1394                    result.is80211McRTTResponder = false;
1395                } else {
1396                    if ((bytes[inforStart + tempIndex] & ((byte)0x1 << offset)) != 0) {
1397                        result.is80211McRTTResponder = true;
1398                    } else {
1399                        result.is80211McRTTResponder = false;
1400                    }
1401                }
1402            }
1403        }
1404        //handle RTT related information
1405        if (channelMode != 0) {
1406            // 80 or 160 MHz
1407            result.channelWidth = channelMode + 1;
1408
1409            //convert channel index to frequency in MHz, channel 36 is 5180MHz
1410            result.centerFreq0 = (centerFreqIndex1 - 36) * 5 + 5180;
1411
1412            if(channelMode > 1) { //160MHz
1413                result.centerFreq1 = (centerFreqIndex2 - 36) * 5 + 5180;
1414            } else {
1415                result.centerFreq1 = 0;
1416            }
1417        } else {
1418            //20 or 40 MHz
1419            if (secondChanelOffset != 0) {//40MHz
1420                result.channelWidth = 1;
1421                if (secondChanelOffset == 1) {
1422                    result.centerFreq0 = result.frequency + 20;
1423                } else if (secondChanelOffset == 3) {
1424                    result.centerFreq0 = result.frequency - 20;
1425                } else {
1426                    result.centerFreq0 = 0;
1427                    Log.e(TAG, dbg + ": Error on secondChanelOffset");
1428                }
1429            } else {
1430                result.centerFreq0  = 0;
1431                result.centerFreq1  = 0;
1432            }
1433            result.centerFreq1  = 0;
1434        }
1435        if(DBG) {
1436            Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth +
1437                    " PrimaryFreq: " + result.frequency +" mCenterfreq0: " + result.centerFreq0 +
1438                    " mCenterfreq1: " + result.centerFreq1 + (result.is80211McRTTResponder ?
1439                    "Support RTT reponder: " : "Do not support RTT responder"));
1440        }
1441
1442        result.informationElements = elements;
1443    }
1444
1445    synchronized static void onFullScanResult(int id, ScanResult result, byte bytes[]) {
1446        if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID + ", " +
1447                "num = " + bytes.length);
1448
1449        if (sScanEventHandler == null) {
1450            return;
1451        }
1452        populateScanResult(result, bytes, " onFullScanResult ");
1453
1454        sScanEventHandler.onFullScanResult(result);
1455    }
1456
1457    private static int sScanCmdId = 0;
1458    private static ScanEventHandler sScanEventHandler;
1459    private static ScanSettings sScanSettings;
1460
1461    synchronized public static boolean startScan(
1462            ScanSettings settings, ScanEventHandler eventHandler) {
1463        synchronized (mLock) {
1464
1465            if (sScanCmdId != 0) {
1466                stopScan();
1467            } else if (sScanSettings != null || sScanEventHandler != null) {
1468                /* current scan is paused; no need to stop it */
1469            }
1470
1471            sScanCmdId = getNewCmdIdLocked();
1472
1473            sScanSettings = settings;
1474            sScanEventHandler = eventHandler;
1475
1476            if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) {
1477                sScanEventHandler = null;
1478                sScanSettings = null;
1479                sScanCmdId = 0;
1480                return false;
1481            }
1482
1483            return true;
1484        }
1485    }
1486
1487    synchronized public static void stopScan() {
1488        synchronized (mLock) {
1489            stopScanNative(sWlan0Index, sScanCmdId);
1490            sScanSettings = null;
1491            sScanEventHandler = null;
1492            sScanCmdId = 0;
1493        }
1494    }
1495
1496    synchronized public static void pauseScan() {
1497        synchronized (mLock) {
1498            if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) {
1499                Log.d(TAG, "Pausing scan");
1500                WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true);
1501                stopScanNative(sWlan0Index, sScanCmdId);
1502                sScanCmdId = 0;
1503                sScanEventHandler.onScanPaused(scanData);
1504            }
1505        }
1506    }
1507
1508    synchronized public static void restartScan() {
1509        synchronized (mLock) {
1510            if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) {
1511                Log.d(TAG, "Restarting scan");
1512                ScanEventHandler handler = sScanEventHandler;
1513                ScanSettings settings = sScanSettings;
1514                if (startScan(sScanSettings, sScanEventHandler)) {
1515                    sScanEventHandler.onScanRestarted();
1516                } else {
1517                    /* we are still paused; don't change state */
1518                    sScanEventHandler = handler;
1519                    sScanSettings = settings;
1520                }
1521            }
1522        }
1523    }
1524
1525    synchronized public static WifiScanner.ScanData[] getScanResults(boolean flush) {
1526        synchronized (mLock) {
1527            return getScanResultsNative(sWlan0Index, flush);
1528        }
1529    }
1530
1531    public static interface HotlistEventHandler {
1532        void onHotlistApFound (ScanResult[] result);
1533        void onHotlistApLost  (ScanResult[] result);
1534    }
1535
1536    private static int sHotlistCmdId = 0;
1537    private static HotlistEventHandler sHotlistEventHandler;
1538
1539    private native static boolean setHotlistNative(int iface, int id,
1540            WifiScanner.HotlistSettings settings);
1541    private native static boolean resetHotlistNative(int iface, int id);
1542
1543    synchronized public static boolean setHotlist(WifiScanner.HotlistSettings settings,
1544                                    HotlistEventHandler eventHandler) {
1545        synchronized (mLock) {
1546            if (sHotlistCmdId != 0) {
1547                return false;
1548            } else {
1549                sHotlistCmdId = getNewCmdIdLocked();
1550            }
1551
1552            sHotlistEventHandler = eventHandler;
1553            if (setHotlistNative(sWlan0Index, sScanCmdId, settings) == false) {
1554                sHotlistEventHandler = null;
1555                return false;
1556            }
1557
1558            return true;
1559        }
1560    }
1561
1562    synchronized public static void resetHotlist() {
1563        synchronized (mLock) {
1564            if (sHotlistCmdId != 0) {
1565                resetHotlistNative(sWlan0Index, sHotlistCmdId);
1566                sHotlistCmdId = 0;
1567                sHotlistEventHandler = null;
1568            }
1569        }
1570    }
1571
1572    synchronized public static void onHotlistApFound(int id, ScanResult[] results) {
1573        synchronized (mLock) {
1574            if (sHotlistCmdId != 0) {
1575                sHotlistEventHandler.onHotlistApFound(results);
1576            } else {
1577                /* this can happen because of race conditions */
1578                Log.d(TAG, "Ignoring hotlist AP found event");
1579            }
1580        }
1581    }
1582
1583    synchronized public static void onHotlistApLost(int id, ScanResult[] results) {
1584        synchronized (mLock) {
1585            if (sHotlistCmdId != 0) {
1586                sHotlistEventHandler.onHotlistApLost(results);
1587            } else {
1588                /* this can happen because of race conditions */
1589                Log.d(TAG, "Ignoring hotlist AP lost event");
1590            }
1591        }
1592    }
1593
1594    public static interface SignificantWifiChangeEventHandler {
1595        void onChangesFound(ScanResult[] result);
1596    }
1597
1598    private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler;
1599    private static int sSignificantWifiChangeCmdId;
1600
1601    private static native boolean trackSignificantWifiChangeNative(
1602            int iface, int id, WifiScanner.WifiChangeSettings settings);
1603    private static native boolean untrackSignificantWifiChangeNative(int iface, int id);
1604
1605    synchronized public static boolean trackSignificantWifiChange(
1606            WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
1607        synchronized (mLock) {
1608            if (sSignificantWifiChangeCmdId != 0) {
1609                return false;
1610            } else {
1611                sSignificantWifiChangeCmdId = getNewCmdIdLocked();
1612            }
1613
1614            sSignificantWifiChangeHandler = handler;
1615            if (trackSignificantWifiChangeNative(sWlan0Index, sScanCmdId, settings) == false) {
1616                sSignificantWifiChangeHandler = null;
1617                return false;
1618            }
1619
1620            return true;
1621        }
1622    }
1623
1624    synchronized static void untrackSignificantWifiChange() {
1625        synchronized (mLock) {
1626            if (sSignificantWifiChangeCmdId != 0) {
1627                untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId);
1628                sSignificantWifiChangeCmdId = 0;
1629                sSignificantWifiChangeHandler = null;
1630            }
1631        }
1632    }
1633
1634    synchronized static void onSignificantWifiChange(int id, ScanResult[] results) {
1635        synchronized (mLock) {
1636            if (sSignificantWifiChangeCmdId != 0) {
1637                sSignificantWifiChangeHandler.onChangesFound(results);
1638            } else {
1639                /* this can happen because of race conditions */
1640                Log.d(TAG, "Ignoring significant wifi change");
1641            }
1642        }
1643    }
1644
1645    synchronized public static WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
1646        // TODO: use correct iface name to Index translation
1647        if (iface == null) return null;
1648        synchronized (mLock) {
1649            if (!sHalIsStarted)
1650                startHal();
1651            if (sHalIsStarted)
1652                return getWifiLinkLayerStatsNative(sWlan0Index);
1653        }
1654        return null;
1655    }
1656
1657    /*
1658     * NFC-related calls
1659     */
1660    public String getNfcWpsConfigurationToken(int netId) {
1661        return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId);
1662    }
1663
1664    public String getNfcHandoverRequest() {
1665        return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR");
1666    }
1667
1668    public String getNfcHandoverSelect() {
1669        return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR");
1670    }
1671
1672    public boolean initiatorReportNfcHandover(String selectMessage) {
1673        return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage);
1674    }
1675
1676    public boolean responderReportNfcHandover(String requestMessage) {
1677        return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00");
1678    }
1679
1680    public static native int getSupportedFeatureSetNative(int iface);
1681    synchronized public static int getSupportedFeatureSet() {
1682        return getSupportedFeatureSetNative(sWlan0Index);
1683    }
1684
1685    /* Rtt related commands/events */
1686    public static interface RttEventHandler {
1687        void onRttResults(RttManager.RttResult[] result);
1688    }
1689
1690    private static RttEventHandler sRttEventHandler;
1691    private static int sRttCmdId;
1692
1693    synchronized private static void onRttResults(int id, RttManager.RttResult[] results) {
1694        if (id == sRttCmdId) {
1695            Log.d(TAG, "Received " + results.length + " rtt results");
1696            sRttEventHandler.onRttResults(results);
1697            sRttCmdId = 0;
1698        } else {
1699            Log.d(TAG, "RTT Received event for unknown cmd = " + id + ", current id = " + sRttCmdId);
1700        }
1701    }
1702
1703    private static native boolean requestRangeNative(
1704            int iface, int id, RttManager.RttParams[] params);
1705    private static native boolean cancelRangeRequestNative(
1706            int iface, int id, RttManager.RttParams[] params);
1707
1708    synchronized public static boolean requestRtt(
1709            RttManager.RttParams[] params, RttEventHandler handler) {
1710        synchronized (mLock) {
1711            if (sRttCmdId != 0) {
1712                Log.v("TAG", "Last one is still under measurement!");
1713                return false;
1714            } else {
1715                sRttCmdId = getNewCmdIdLocked();
1716            }
1717            sRttEventHandler = handler;
1718            Log.v(TAG, "native issue RTT request");
1719            return requestRangeNative(sWlan0Index, sRttCmdId, params);
1720        }
1721    }
1722
1723    synchronized public static boolean cancelRtt(RttManager.RttParams[] params) {
1724        synchronized(mLock) {
1725            if (sRttCmdId == 0) {
1726                return false;
1727            }
1728
1729            sRttCmdId = 0;
1730
1731            if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) {
1732                sRttEventHandler = null;
1733                Log.v(TAG, "Xin: RTT cancel Request Successfully");
1734                return true;
1735            } else {
1736                Log.e(TAG, "Xin:RTT cancel Request failed");
1737                return false;
1738            }
1739        }
1740    }
1741
1742    private static native boolean setScanningMacOuiNative(int iface, byte[] oui);
1743
1744    synchronized public static boolean setScanningMacOui(byte[] oui) {
1745        synchronized (mLock) {
1746            if (startHal()) {
1747                return setScanningMacOuiNative(sWlan0Index, oui);
1748            } else {
1749                return false;
1750            }
1751        }
1752    }
1753
1754    private static native int[] getChannelsForBandNative(
1755            int iface, int band);
1756
1757    synchronized public static int [] getChannelsForBand(int band) {
1758        synchronized (mLock) {
1759            if (startHal()) {
1760                return getChannelsForBandNative(sWlan0Index, band);
1761            } else {
1762                return null;
1763            }
1764        }
1765    }
1766
1767
1768    private static native boolean setDfsFlagNative(int iface, boolean dfsOn);
1769    synchronized public static boolean setDfsFlag(boolean dfsOn) {
1770        synchronized (mLock) {
1771            if (startHal()) {
1772                return setDfsFlagNative(sWlan0Index, dfsOn);
1773            } else {
1774                return false;
1775            }
1776        }
1777    }
1778
1779    private static native boolean toggleInterfaceNative(int on);
1780    synchronized public static boolean toggleInterface(int on) {
1781        synchronized (mLock) {
1782            if (startHal()) {
1783                return toggleInterfaceNative(0);
1784            } else {
1785
1786                return false;
1787            }
1788        }
1789    }
1790
1791    private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface);
1792    synchronized public static RttManager.RttCapabilities getRttCapabilities() {
1793        synchronized (mLock) {
1794            if (startHal()) {
1795                return getRttCapabilitiesNative(sWlan0Index);
1796            } else {
1797                return null;
1798            }
1799        }
1800    }
1801
1802    private static native boolean setCountryCodeHalNative(int iface, String CountryCode);
1803    synchronized public static boolean setCountryCodeHal( String CountryCode) {
1804        synchronized (mLock) {
1805            if (startHal()) {
1806                return setCountryCodeHalNative(sWlan0Index, CountryCode);
1807            } else {
1808                return false;
1809            }
1810        }
1811    }
1812
1813    /* Rtt related commands/events */
1814    public abstract class TdlsEventHandler {
1815        abstract public void onTdlsStatus(String macAddr, int status, int reason);
1816    }
1817
1818    private static TdlsEventHandler sTdlsEventHandler;
1819
1820
1821    private static native boolean enableDisableTdlsNative(int iface, boolean enable,
1822            String macAddr);
1823    synchronized public static boolean enableDisableTdls(boolean enable, String macAdd,
1824            TdlsEventHandler tdlsCallBack) {
1825        synchronized (mLock) {
1826            if (startHal()) {
1827                sTdlsEventHandler = tdlsCallBack;
1828                return enableDisableTdlsNative(sWlan0Index, enable, macAdd);
1829            } else {
1830                return false;
1831            }
1832        }
1833    }
1834
1835    // Once TDLS per mac and event feature is implemented, this class definition should be
1836    // moved to the right place, like WifiManager etc
1837    public static class TdlsStatus {
1838        int channel;
1839        int global_operating_class;
1840        int state;
1841        int reason;
1842    }
1843    private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr);
1844    synchronized public static TdlsStatus getTdlsStatus (String macAdd) {
1845        synchronized (mLock) {
1846            if (startHal()) {
1847                return getTdlsStatusNative(sWlan0Index, macAdd);
1848            } else {
1849                return null;
1850            }
1851        }
1852    }
1853
1854    //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be
1855    // moved to the right place, like WifiStateMachine etc
1856    public static class TdlsCapabilities {
1857        /* Maximum TDLS session number can be supported by the Firmware and hardware */
1858        int maxConcurrentTdlsSessionNumber;
1859        boolean isGlobalTdlsSupported;
1860        boolean isPerMacTdlsSupported;
1861        boolean isOffChannelTdlsSupported;
1862    }
1863
1864
1865
1866    private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface);
1867    synchronized public static TdlsCapabilities getTdlsCapabilities () {
1868        synchronized (mLock) {
1869            if (startHal()) {
1870                return getTdlsCapabilitiesNative(sWlan0Index);
1871            } else {
1872                return null;
1873            }
1874        }
1875    }
1876
1877    synchronized private static boolean onTdlsStatus(String macAddr, int status, int reason) {
1878         if (sTdlsEventHandler == null) {
1879             return false;
1880         } else {
1881             sTdlsEventHandler.onTdlsStatus(macAddr, status, reason);
1882             return true;
1883         }
1884    }
1885
1886    //---------------------------------------------------------------------------------
1887
1888    /* Wifi Logger commands/events */
1889
1890    public static native boolean startLogging(int iface);
1891
1892    public static interface WifiLoggerEventHandler {
1893        void onDataAvailable(char data[], int len);
1894    }
1895
1896    private static WifiLoggerEventHandler sWifiLoggerEventHandler = null;
1897
1898    public static class WifiLoggerEvent {
1899        WifiLogger.RingBufferStatus status;
1900        int entrySize;
1901        int flags;
1902        int type;
1903        long timestamp;
1904        byte[] entry;
1905
1906        public String toString() {
1907            StringBuilder str =  new StringBuilder();
1908            str.append(status + "\n entry size: " + entrySize + " flags: " + flags);
1909            str.append(" type: " + type + " timestamp: " + timestamp +"\n");
1910            if (entry != null) {
1911                str.append(android.util.Base64.encodeToString(entry, Base64.DEFAULT));
1912            } else {
1913                str.append(" empty bytes[]");
1914            }
1915            str.append("\n\n");
1916            return str.toString();
1917        }
1918    }
1919
1920    private static void onWifiLoggerEvent(WifiLoggerEvent event) {
1921        if (event != null) {
1922            Log.d(TAG, "Logger Event:" + event);
1923        }
1924    }
1925
1926    private static void onWifiAlert(byte[] buffer, int errorCode) {
1927        Log.d(TAG, "Logger Alert error code:" + errorCode);
1928        if (buffer != null) {
1929            StringBuilder str =  new StringBuilder();
1930            str.append(android.util.Base64.encodeToString(buffer, android.util.Base64.NO_WRAP));
1931            Log.e(TAG,"Logger Alert event:");
1932            Log.e(TAG, str.toString());
1933        } else {
1934            Log.e(TAG," empty Alert");
1935        }
1936    }
1937
1938    private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel,
1939            int flags, int maxInterval,int minDataSize, String ringName);
1940    synchronized public static boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
1941            int minDataSize, String ringName){
1942        synchronized (mLock) {
1943            if (startHal()) {
1944                return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval,
1945                        minDataSize, ringName);
1946            } else {
1947                return false;
1948            }
1949        }
1950    }
1951
1952    private static native int getSupportedLoggerFeatureSetNative(int iface);
1953    synchronized public static int getSupportedLoggerFeatureSet() {
1954        synchronized (mLock) {
1955            if (startHal()) {
1956                return getSupportedLoggerFeatureSetNative(sWlan0Index);
1957            } else {
1958                return -1;
1959            }
1960        }
1961    }
1962
1963    private static native String getDriverVersionNative(int iface);
1964    synchronized public static String getDriverVersion() {
1965        synchronized (mLock) {
1966            if (startHal()) {
1967                return getDriverVersionNative(sWlan0Index);
1968            } else {
1969                return null;
1970            }
1971        }
1972    }
1973
1974
1975    private static native String getFirmwareVersionNative(int iface);
1976    synchronized public static String getFirmwareVersion() {
1977        synchronized (mLock) {
1978            if (startHal()) {
1979                return getFirmwareVersionNative(sWlan0Index);
1980            } else {
1981                return null;
1982            }
1983        }
1984    }
1985
1986    private static native WifiLogger.RingBufferStatus[] getRingBufferStatusNative(int iface);
1987    synchronized public static WifiLogger.RingBufferStatus[] getRingBufferStatus() {
1988        synchronized (mLock) {
1989            if (startHal()) {
1990                return getRingBufferStatusNative(sWlan0Index);
1991            } else {
1992                return null;
1993            }
1994        }
1995    }
1996
1997    private static native boolean getRingBufferDataNative(int iface, String ringName);
1998    synchronized public static boolean getRingBufferData(String ringName) {
1999        synchronized (mLock) {
2000            if (startHal()) {
2001                return getRingBufferDataNative(sWlan0Index, ringName);
2002            } else {
2003                return false;
2004            }
2005        }
2006    }
2007
2008    static private byte[] mFwMemoryDump;
2009    private static void onWifiFwMemoryAvailable(byte[] buffer) {
2010        mFwMemoryDump = buffer;
2011        if (DBG) {
2012            Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " +
2013                    (buffer == null ? 0 :  buffer.length));
2014        }
2015    }
2016    private static native boolean getFwMemoryDumpNative(int iface);
2017    synchronized public static String getFwMemoryDump() {
2018        synchronized (mLock) {
2019            if (startHal()) {
2020                if(getFwMemoryDumpNative(sWlan0Index)) {
2021                    if(mFwMemoryDump == null || mFwMemoryDump.length == 0) {
2022                         return null;
2023                    }
2024                    String result;
2025                    //compress
2026                    Deflater compressor = new Deflater();
2027                    compressor.setLevel(Deflater.BEST_COMPRESSION);
2028                    compressor.setInput(mFwMemoryDump);
2029                    compressor.finish();
2030                    ByteArrayOutputStream bos = new ByteArrayOutputStream(mFwMemoryDump.length);
2031                    final byte[] buf = new byte[1024];
2032
2033                    while (!compressor.finished()) {
2034                        int count = compressor.deflate(buf);
2035                         bos.write(buf, 0, count);
2036                    }
2037
2038                    try {
2039                        bos.close();
2040                    } catch (IOException e) {
2041                        Log.e(TAG, "ByteArrayOutputStream close error");
2042                        result =  android.util.Base64.encodeToString(mFwMemoryDump, Base64.DEFAULT);
2043                        return result;
2044                    }
2045
2046                    byte[] compressData = bos.toByteArray();
2047                    if(DBG) {
2048                        Log.d(TAG," length is:" + (compressData == null? "0" :
2049                                compressData.length));
2050                    }
2051                    //encode
2052                    result =  android.util.Base64.encodeToString(compressData.length <
2053                            mFwMemoryDump.length ? compressData :mFwMemoryDump , Base64.DEFAULT);
2054                    if(DBG) {
2055                        Log.d(TAG, "FwMemoryDump length is :" + result.length());
2056                    }
2057
2058                    mFwMemoryDump = null;
2059                    return result;
2060                } else {
2061                    return null;
2062                }
2063            } else {
2064                return null;
2065            }
2066        }
2067    }
2068
2069    //---------------------------------------------------------------------------------
2070    /* Configure ePNO */
2071
2072    public class WifiPnoNetwork {
2073        String SSID;
2074        int rssi_threshold;
2075        int flags;
2076        int auth;
2077        String configKey; // kept for reference
2078
2079        WifiPnoNetwork(WifiConfiguration config, int threshold) {
2080            if (config.SSID == null) {
2081                this.SSID = "";
2082                this.flags = 1;
2083            } else {
2084                this.SSID = config.SSID;
2085            }
2086            this.rssi_threshold = threshold;
2087            if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
2088                auth |= 2;
2089            } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) ||
2090                    config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) {
2091                auth |= 4;
2092            } else if (config.wepKeys[0] != null) {
2093                auth |= 1;
2094            } else {
2095                auth |= 1;
2096            }
2097//            auth = 0;
2098            flags |= 6; //A and G
2099            configKey = config.configKey();
2100        }
2101
2102        @Override
2103        public String toString() {
2104            StringBuilder sbuf = new StringBuilder();
2105            sbuf.append(this.SSID);
2106            sbuf.append(" flags=").append(this.flags);
2107            sbuf.append(" rssi=").append(this.rssi_threshold);
2108            sbuf.append(" auth=").append(this.auth);
2109            return sbuf.toString();
2110        }
2111    }
2112
2113    public static interface WifiPnoEventHandler {
2114        void onPnoNetworkFound(ScanResult results[]);
2115    }
2116
2117    private static WifiPnoEventHandler sWifiPnoEventHandler;
2118
2119    private static int sPnoCmdId = 0;
2120
2121    private native static boolean setPnoListNative(int iface, int id, WifiPnoNetwork list[]);
2122
2123    synchronized public static boolean setPnoList(WifiPnoNetwork list[],
2124                                                  WifiPnoEventHandler eventHandler) {
2125        Log.e(TAG, "setPnoList cmd " + sPnoCmdId);
2126
2127        synchronized (mLock) {
2128
2129            sPnoCmdId = getNewCmdIdLocked();
2130
2131            sWifiPnoEventHandler = eventHandler;
2132            if (setPnoListNative(sWlan0Index, sPnoCmdId, list) == false) {
2133                sWifiPnoEventHandler = null;
2134                return false;
2135            }
2136
2137            return true;
2138        }
2139    }
2140
2141    synchronized public static void onPnoNetworkFound(int id, ScanResult[] results) {
2142
2143        if (results == null) {
2144            Log.e(TAG, "onPnoNetworkFound null results");
2145            return;
2146
2147        }
2148        Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length);
2149
2150        //Log.e(TAG, "onPnoNetworkFound length " + results.length);
2151        //return;
2152        for (int i=0; i<results.length; i++) {
2153            Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID
2154                    + " " + results[i].level + " " + results[i].frequency);
2155
2156            populateScanResult(results[i], results[i].bytes, "onPnoNetworkFound ");
2157            results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID);
2158        }
2159        synchronized (mLock) {
2160            if (sPnoCmdId != 0 && sWifiPnoEventHandler != null) {
2161                sWifiPnoEventHandler.onPnoNetworkFound(results);
2162            } else {
2163                /* this can happen because of race conditions */
2164                Log.d(TAG, "Ignoring Pno Network found event");
2165            }
2166        }
2167    }
2168
2169    public class WifiLazyRoamParams {
2170        int A_band_boost_threshold;
2171        int A_band_penalty_threshold;
2172        int A_band_boost_factor;
2173        int A_band_penalty_factor;
2174        int A_band_max_boost;
2175        int lazy_roam_hysteresis;
2176        int alert_roam_rssi_trigger;
2177
2178        WifiLazyRoamParams() {
2179        }
2180
2181        @Override
2182        public String toString() {
2183            StringBuilder sbuf = new StringBuilder();
2184            sbuf.append(" A_band_boost_threshold=").append(this.A_band_boost_threshold);
2185            sbuf.append(" A_band_penalty_threshold=").append(this.A_band_penalty_threshold);
2186            sbuf.append(" A_band_boost_factor=").append(this.A_band_boost_factor);
2187            sbuf.append(" A_band_penalty_factor=").append(this.A_band_penalty_factor);
2188            sbuf.append(" A_band_max_boost=").append(this.A_band_max_boost);
2189            sbuf.append(" lazy_roam_hysteresis=").append(this.lazy_roam_hysteresis);
2190            sbuf.append(" alert_roam_rssi_trigger=").append(this.alert_roam_rssi_trigger);
2191            return sbuf.toString();
2192        }
2193    }
2194
2195    private native static boolean setLazyRoamNative(int iface, int id,
2196                                              boolean enabled, WifiLazyRoamParams param);
2197
2198    synchronized public static boolean setLazyRoam(boolean enabled, WifiLazyRoamParams params) {
2199        synchronized (mLock) {
2200            if (startHal()) {
2201                sPnoCmdId = getNewCmdIdLocked();
2202
2203                return setLazyRoamNative(sWlan0Index, sPnoCmdId, enabled, params);
2204            } else {
2205                return false;
2206            }
2207        }
2208    }
2209
2210    private native static boolean setBssidBlacklistNative(int iface, int id,
2211                                              String list[]);
2212
2213    synchronized public static boolean setBssidBlacklist(String list[]) {
2214        int size = 0;
2215        if (list != null) {
2216            size = list.length;
2217        }
2218        Log.e(TAG, "setBssidBlacklist cmd " + sPnoCmdId + " size " + size);
2219
2220        synchronized (mLock) {
2221            sPnoCmdId = getNewCmdIdLocked();
2222
2223            if (setBssidBlacklistNative(sWlan0Index, sPnoCmdId, list) == false) {
2224                return false;
2225            }
2226            return true;
2227        }
2228    }
2229
2230    private native static boolean setSsidWhitelistNative(int iface, int id, String list[]);
2231
2232    synchronized public static boolean setSsidWhitelist(String list[]) {
2233        int size = 0;
2234        if (list != null) {
2235            size = list.length;
2236        }
2237        Log.e(TAG, "setSsidWhitelist cmd " + sPnoCmdId + " size " + size);
2238
2239        synchronized (mLock) {
2240            sPnoCmdId = getNewCmdIdLocked();
2241
2242            if (setSsidWhitelistNative(sWlan0Index, sPnoCmdId, list) == false) {
2243                return false;
2244            }
2245            return true;
2246        }
2247    }
2248
2249}
2250