WifiNative.java revision da10b1588be241c59434d5f464463e7f8c7bcc5e
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi;
18
19import android.annotation.Nullable;
20import android.app.AlarmManager;
21import android.app.PendingIntent;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.net.wifi.RttManager;
27import android.net.wifi.RttManager.ResponderConfig;
28import android.net.wifi.ScanResult;
29import android.net.wifi.WifiConfiguration;
30import android.net.wifi.WifiEnterpriseConfig;
31import android.net.wifi.WifiLinkLayerStats;
32import android.net.wifi.WifiManager;
33import android.net.wifi.WifiScanner;
34import android.net.wifi.WifiSsid;
35import android.net.wifi.WifiWakeReasonAndCounts;
36import android.net.wifi.WpsInfo;
37import android.net.wifi.p2p.WifiP2pConfig;
38import android.net.wifi.p2p.WifiP2pGroup;
39import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
40import android.os.SystemClock;
41import android.os.SystemProperties;
42import android.text.TextUtils;
43import android.util.LocalLog;
44import android.util.Log;
45
46import com.android.server.connectivity.KeepalivePacketData;
47import com.android.server.wifi.hotspot2.NetworkDetail;
48import com.android.server.wifi.hotspot2.SupplicantBridge;
49import com.android.server.wifi.hotspot2.Utils;
50import com.android.server.wifi.util.InformationElementUtil;
51
52import libcore.util.HexEncoding;
53
54import org.json.JSONException;
55import org.json.JSONObject;
56
57import java.io.UnsupportedEncodingException;
58import java.net.URLDecoder;
59import java.net.URLEncoder;
60import java.nio.ByteBuffer;
61import java.nio.CharBuffer;
62import java.nio.charset.CharacterCodingException;
63import java.nio.charset.CharsetDecoder;
64import java.nio.charset.StandardCharsets;
65import java.util.ArrayList;
66import java.util.BitSet;
67import java.util.HashMap;
68import java.util.Iterator;
69import java.util.List;
70import java.util.Locale;
71import java.util.Map;
72import java.util.Set;
73
74
75/**
76 * Native calls for bring up/shut down of the supplicant daemon and for
77 * sending requests to the supplicant daemon
78 *
79 * waitForEvent() is called on the monitor thread for events. All other methods
80 * must be serialized from the framework.
81 *
82 * {@hide}
83 */
84public class WifiNative {
85    private static boolean DBG = false;
86
87    /**
88     * Hold this lock before calling supplicant or HAL methods
89     * it is required to mutually exclude access to the driver
90     */
91    public static final Object sLock = new Object();
92
93    private static final LocalLog sLocalLog = new LocalLog(16384);
94
95    public static LocalLog getLocalLog() {
96        return sLocalLog;
97    }
98
99    /* Register native functions */
100    static {
101        /* Native functions are defined in libwifi-service.so */
102        System.loadLibrary("wifi-service");
103        registerNatives();
104    }
105
106    private static native int registerNatives();
107
108    /*
109     * Singleton WifiNative instances
110     */
111    private static WifiNative wlanNativeInterface =
112            new WifiNative(SystemProperties.get("wifi.interface", "wlan0"));
113    public static WifiNative getWlanNativeInterface() {
114        return wlanNativeInterface;
115    }
116
117    //STOPSHIP: get interface name from native side
118    private static WifiNative p2pNativeInterface = new WifiNative("p2p0");
119    public static WifiNative getP2pNativeInterface() {
120        return p2pNativeInterface;
121    }
122
123
124    private final String mTAG;
125    private final String mInterfaceName;
126    private final String mInterfacePrefix;
127
128    private Context mContext = null;
129    private PnoMonitor mPnoMonitor = null;
130    public void initContext(Context context) {
131        if (mContext == null && context != null) {
132            mContext = context;
133            mPnoMonitor = new PnoMonitor();
134        }
135    }
136
137    private WifiNative(String interfaceName) {
138        mInterfaceName = interfaceName;
139        mTAG = "WifiNative-" + interfaceName;
140
141        if (!interfaceName.equals("p2p0")) {
142            mInterfacePrefix = "IFNAME=" + interfaceName + " ";
143        } else {
144            // commands for p2p0 interface don't need prefix
145            mInterfacePrefix = "";
146        }
147    }
148
149    public String getInterfaceName() {
150        return mInterfaceName;
151    }
152
153    // Note this affects logging on for all interfaces
154    void enableVerboseLogging(int verbose) {
155        if (verbose > 0) {
156            DBG = true;
157        } else {
158            DBG = false;
159        }
160    }
161
162    private void localLog(String s) {
163        if (sLocalLog != null) sLocalLog.log(mInterfaceName + ": " + s);
164    }
165
166
167
168    /*
169     * Driver and Supplicant management
170     */
171    private native static boolean loadDriverNative();
172    public boolean loadDriver() {
173        synchronized (sLock) {
174            return loadDriverNative();
175        }
176    }
177
178    private native static boolean isDriverLoadedNative();
179    public boolean isDriverLoaded() {
180        synchronized (sLock) {
181            return isDriverLoadedNative();
182        }
183    }
184
185    private native static boolean unloadDriverNative();
186    public boolean unloadDriver() {
187        synchronized (sLock) {
188            return unloadDriverNative();
189        }
190    }
191
192    private native static boolean startSupplicantNative(boolean p2pSupported);
193    public boolean startSupplicant(boolean p2pSupported) {
194        synchronized (sLock) {
195            return startSupplicantNative(p2pSupported);
196        }
197    }
198
199    /* Sends a kill signal to supplicant. To be used when we have lost connection
200       or when the supplicant is hung */
201    private native static boolean killSupplicantNative(boolean p2pSupported);
202    public boolean killSupplicant(boolean p2pSupported) {
203        synchronized (sLock) {
204            return killSupplicantNative(p2pSupported);
205        }
206    }
207
208    private native static boolean connectToSupplicantNative();
209    public boolean connectToSupplicant() {
210        synchronized (sLock) {
211            localLog(mInterfacePrefix + "connectToSupplicant");
212            return connectToSupplicantNative();
213        }
214    }
215
216    private native static void closeSupplicantConnectionNative();
217    public void closeSupplicantConnection() {
218        synchronized (sLock) {
219            localLog(mInterfacePrefix + "closeSupplicantConnection");
220            closeSupplicantConnectionNative();
221        }
222    }
223
224    /**
225     * Wait for the supplicant to send an event, returning the event string.
226     * @return the event string sent by the supplicant.
227     */
228    private native static String waitForEventNative();
229    public String waitForEvent() {
230        // No synchronization necessary .. it is implemented in WifiMonitor
231        return waitForEventNative();
232    }
233
234
235    /*
236     * Supplicant Command Primitives
237     */
238    private native boolean doBooleanCommandNative(String command);
239
240    private native int doIntCommandNative(String command);
241
242    private native String doStringCommandNative(String command);
243
244    private boolean doBooleanCommand(String command) {
245        if (DBG) Log.d(mTAG, "doBoolean: " + command);
246        synchronized (sLock) {
247            String toLog = mInterfacePrefix + command;
248            boolean result = doBooleanCommandNative(mInterfacePrefix + command);
249            localLog(toLog + " -> " + result);
250            if (DBG) Log.d(mTAG, command + ": returned " + result);
251            return result;
252        }
253    }
254
255    private boolean doBooleanCommandWithoutLogging(String command) {
256        if (DBG) Log.d(mTAG, "doBooleanCommandWithoutLogging: " + command);
257        synchronized (sLock) {
258            boolean result = doBooleanCommandNative(mInterfacePrefix + command);
259            if (DBG) Log.d(mTAG, command + ": returned " + result);
260            return result;
261        }
262    }
263
264    private int doIntCommand(String command) {
265        if (DBG) Log.d(mTAG, "doInt: " + command);
266        synchronized (sLock) {
267            String toLog = mInterfacePrefix + command;
268            int result = doIntCommandNative(mInterfacePrefix + command);
269            localLog(toLog + " -> " + result);
270            if (DBG) Log.d(mTAG, "   returned " + result);
271            return result;
272        }
273    }
274
275    private String doStringCommand(String command) {
276        if (DBG) {
277            //GET_NETWORK commands flood the logs
278            if (!command.startsWith("GET_NETWORK")) {
279                Log.d(mTAG, "doString: [" + command + "]");
280            }
281        }
282        synchronized (sLock) {
283            String toLog = mInterfacePrefix + command;
284            String result = doStringCommandNative(mInterfacePrefix + command);
285            if (result == null) {
286                if (DBG) Log.d(mTAG, "doStringCommandNative no result");
287            } else {
288                if (!command.startsWith("STATUS-")) {
289                    localLog(toLog + " -> " + result);
290                }
291                if (DBG) Log.d(mTAG, "   returned " + result.replace("\n", " "));
292            }
293            return result;
294        }
295    }
296
297    private String doStringCommandWithoutLogging(String command) {
298        if (DBG) {
299            //GET_NETWORK commands flood the logs
300            if (!command.startsWith("GET_NETWORK")) {
301                Log.d(mTAG, "doString: [" + command + "]");
302            }
303        }
304        synchronized (sLock) {
305            return doStringCommandNative(mInterfacePrefix + command);
306        }
307    }
308
309    public String doCustomSupplicantCommand(String command) {
310        return doStringCommand(command);
311    }
312
313    /*
314     * Wrappers for supplicant commands
315     */
316    public boolean ping() {
317        String pong = doStringCommand("PING");
318        return (pong != null && pong.equals("PONG"));
319    }
320
321    public void setSupplicantLogLevel(String level) {
322        doStringCommand("LOG_LEVEL " + level);
323    }
324
325    public String getFreqCapability() {
326        return doStringCommand("GET_CAPABILITY freq");
327    }
328
329    /**
330     * Create a comma separate string from integer set.
331     * @param values List of integers.
332     * @return comma separated string.
333     */
334    private static String createCSVStringFromIntegerSet(Set<Integer> values) {
335        StringBuilder list = new StringBuilder();
336        boolean first = true;
337        for (Integer value : values) {
338            if (!first) {
339                list.append(",");
340            }
341            list.append(value);
342            first = false;
343        }
344        return list.toString();
345    }
346
347    /**
348     * Start a scan using wpa_supplicant for the given frequencies.
349     * @param freqs list of frequencies to scan for, if null scan all supported channels.
350     * @param hiddenNetworkIds List of hidden networks to be scanned for.
351     */
352    public boolean scan(Set<Integer> freqs, Set<Integer> hiddenNetworkIds) {
353        String freqList = null;
354        String hiddenNetworkIdList = null;
355        if (freqs != null && freqs.size() != 0) {
356            freqList = createCSVStringFromIntegerSet(freqs);
357        }
358        if (hiddenNetworkIds != null && hiddenNetworkIds.size() != 0) {
359            hiddenNetworkIdList = createCSVStringFromIntegerSet(hiddenNetworkIds);
360        }
361        return scanWithParams(freqList, hiddenNetworkIdList);
362    }
363
364    private boolean scanWithParams(String freqList, String hiddenNetworkIdList) {
365        StringBuilder scanCommand = new StringBuilder();
366        scanCommand.append("SCAN TYPE=ONLY");
367        if (freqList != null) {
368            scanCommand.append(" freq=" + freqList);
369        }
370        if (hiddenNetworkIdList != null) {
371            scanCommand.append(" scan_id=" + hiddenNetworkIdList);
372        }
373        return doBooleanCommand(scanCommand.toString());
374    }
375
376    /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta.
377     *
378     * Note that underneath we use a harsh-sounding "terminate" supplicant command
379     * for a graceful stop and a mild-sounding "stop" interface
380     * to kill the process
381     */
382    public boolean stopSupplicant() {
383        return doBooleanCommand("TERMINATE");
384    }
385
386    public String listNetworks() {
387        return doStringCommand("LIST_NETWORKS");
388    }
389
390    public String listNetworks(int last_id) {
391        return doStringCommand("LIST_NETWORKS LAST_ID=" + last_id);
392    }
393
394    public int addNetwork() {
395        return doIntCommand("ADD_NETWORK");
396    }
397
398    public boolean setNetworkExtra(int netId, String name, Map<String, String> values) {
399        final String encoded;
400        try {
401            encoded = URLEncoder.encode(new JSONObject(values).toString(), "UTF-8");
402        } catch (NullPointerException e) {
403            Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
404            return false;
405        } catch (UnsupportedEncodingException e) {
406            Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
407            return false;
408        }
409        return setNetworkVariable(netId, name, "\"" + encoded + "\"");
410    }
411
412    public boolean setNetworkVariable(int netId, String name, String value) {
413        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false;
414        if (name.equals(WifiConfiguration.pskVarName)
415                || name.equals(WifiEnterpriseConfig.PASSWORD_KEY)) {
416            return doBooleanCommandWithoutLogging("SET_NETWORK " + netId + " " + name + " " + value);
417        } else {
418            return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value);
419        }
420    }
421
422    public Map<String, String> getNetworkExtra(int netId, String name) {
423        final String wrapped = getNetworkVariable(netId, name);
424        if (wrapped == null || !wrapped.startsWith("\"") || !wrapped.endsWith("\"")) {
425            return null;
426        }
427        try {
428            final String encoded = wrapped.substring(1, wrapped.length() - 1);
429            // This method reads a JSON dictionary that was written by setNetworkExtra(). However,
430            // on devices that upgraded from Marshmallow, it may encounter a legacy value instead -
431            // an FQDN stored as a plain string. If such a value is encountered, the JSONObject
432            // constructor will thrown a JSONException and the method will return null.
433            final JSONObject json = new JSONObject(URLDecoder.decode(encoded, "UTF-8"));
434            final Map<String, String> values = new HashMap<String, String>();
435            final Iterator<?> it = json.keys();
436            while (it.hasNext()) {
437                final String key = (String) it.next();
438                final Object value = json.get(key);
439                if (value instanceof String) {
440                    values.put(key, (String) value);
441                }
442            }
443            return values;
444        } catch (UnsupportedEncodingException e) {
445            Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
446            return null;
447        } catch (JSONException e) {
448            // This is not necessarily an error. This exception will also occur if we encounter a
449            // legacy FQDN stored as a plain string. We want to return null in this case as no JSON
450            // dictionary of extras was found.
451            return null;
452        }
453    }
454
455    public String getNetworkVariable(int netId, String name) {
456        if (TextUtils.isEmpty(name)) return null;
457
458        // GET_NETWORK will likely flood the logs ...
459        return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name);
460    }
461
462    public boolean removeNetwork(int netId) {
463        return doBooleanCommand("REMOVE_NETWORK " + netId);
464    }
465
466
467    private void logDbg(String debug) {
468        long now = SystemClock.elapsedRealtimeNanos();
469        String ts = String.format("[%,d us] ", now/1000);
470        Log.e("WifiNative: ", ts+debug+ " stack:"
471                + Thread.currentThread().getStackTrace()[2].getMethodName() +" - "
472                + Thread.currentThread().getStackTrace()[3].getMethodName() +" - "
473                + Thread.currentThread().getStackTrace()[4].getMethodName() +" - "
474                + Thread.currentThread().getStackTrace()[5].getMethodName()+" - "
475                + Thread.currentThread().getStackTrace()[6].getMethodName());
476
477    }
478
479    /**
480     * Enables a network in wpa_supplicant.
481     * @param netId - Network ID of the network to be enabled.
482     * @return true if command succeeded, false otherwise.
483     */
484    public boolean enableNetwork(int netId) {
485        if (DBG) logDbg("enableNetwork nid=" + Integer.toString(netId));
486        return doBooleanCommand("ENABLE_NETWORK " + netId);
487    }
488
489    /**
490     * Enable a network in wpa_supplicant, do not connect.
491     * @param netId - Network ID of the network to be enabled.
492     * @return true if command succeeded, false otherwise.
493     */
494    public boolean enableNetworkWithoutConnect(int netId) {
495        if (DBG) logDbg("enableNetworkWithoutConnect nid=" + Integer.toString(netId));
496        return doBooleanCommand("ENABLE_NETWORK " + netId + " " + "no-connect");
497    }
498
499    /**
500     * Disables a network in wpa_supplicant.
501     * @param netId - Network ID of the network to be disabled.
502     * @return true if command succeeded, false otherwise.
503     */
504    public boolean disableNetwork(int netId) {
505        if (DBG) logDbg("disableNetwork nid=" + Integer.toString(netId));
506        return doBooleanCommand("DISABLE_NETWORK " + netId);
507    }
508
509    /**
510     * Select a network in wpa_supplicant (Disables all others).
511     * @param netId - Network ID of the network to be selected.
512     * @return true if command succeeded, false otherwise.
513     */
514    public boolean selectNetwork(int netId) {
515        if (DBG) logDbg("selectNetwork nid=" + Integer.toString(netId));
516        return doBooleanCommand("SELECT_NETWORK " + netId);
517    }
518
519    public boolean reconnect() {
520        if (DBG) logDbg("RECONNECT ");
521        return doBooleanCommand("RECONNECT");
522    }
523
524    public boolean reassociate() {
525        if (DBG) logDbg("REASSOCIATE ");
526        return doBooleanCommand("REASSOCIATE");
527    }
528
529    public boolean disconnect() {
530        if (DBG) logDbg("DISCONNECT ");
531        return doBooleanCommand("DISCONNECT");
532    }
533
534    public String status() {
535        return status(false);
536    }
537
538    public String status(boolean noEvents) {
539        if (noEvents) {
540            return doStringCommand("STATUS-NO_EVENTS");
541        } else {
542            return doStringCommand("STATUS");
543        }
544    }
545
546    public String getMacAddress() {
547        //Macaddr = XX.XX.XX.XX.XX.XX
548        String ret = doStringCommand("DRIVER MACADDR");
549        if (!TextUtils.isEmpty(ret)) {
550            String[] tokens = ret.split(" = ");
551            if (tokens.length == 2) return tokens[1];
552        }
553        return null;
554    }
555
556
557
558    /**
559     * Format of results:
560     * =================
561     * id=1
562     * bssid=68:7f:76:d7:1a:6e
563     * freq=2412
564     * level=-44
565     * tsf=1344626243700342
566     * flags=[WPA2-PSK-CCMP][WPS][ESS]
567     * ssid=zfdy
568     * ====
569     * id=2
570     * bssid=68:5f:74:d7:1a:6f
571     * freq=5180
572     * level=-73
573     * tsf=1344626243700373
574     * flags=[WPA2-PSK-CCMP][WPS][ESS]
575     * ssid=zuby
576     * ====
577     *
578     * RANGE=ALL gets all scan results
579     * RANGE=ID- gets results from ID
580     * MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details
581     * 0                         0                        1                       0     2
582     *                           WPA_BSS_MASK_MESH_SCAN | WPA_BSS_MASK_DELIM    | WPA_BSS_MASK_WIFI_DISPLAY
583     * 0                         0                        0                       1     1   -> 9
584     * WPA_BSS_MASK_INTERNETW  | WPA_BSS_MASK_P2P_SCAN  | WPA_BSS_MASK_WPS_SCAN | WPA_BSS_MASK_SSID
585     * 1                         0                        0                       1     9   -> d
586     * WPA_BSS_MASK_FLAGS      | WPA_BSS_MASK_IE        | WPA_BSS_MASK_AGE      | WPA_BSS_MASK_TSF
587     * 1                         0                        0                       0     8
588     * WPA_BSS_MASK_LEVEL      | WPA_BSS_MASK_NOISE     | WPA_BSS_MASK_QUAL     | WPA_BSS_MASK_CAPABILITIES
589     * 0                         1                        1                       1     7
590     * WPA_BSS_MASK_BEACON_INT | WPA_BSS_MASK_FREQ      | WPA_BSS_MASK_BSSID    | WPA_BSS_MASK_ID
591     *
592     * WPA_BSS_MASK_INTERNETW adds ANQP info (ctrl_iface:4151-4176)
593     *
594     * ctrl_iface.c:wpa_supplicant_ctrl_iface_process:7884
595     *  wpa_supplicant_ctrl_iface_bss:4315
596     *  print_bss_info
597     */
598    private String getRawScanResults(String range) {
599        return doStringCommandWithoutLogging("BSS RANGE=" + range + " MASK=0x29d87");
600    }
601
602    private static final String BSS_IE_STR = "ie=";
603    private static final String BSS_ID_STR = "id=";
604    private static final String BSS_BSSID_STR = "bssid=";
605    private static final String BSS_FREQ_STR = "freq=";
606    private static final String BSS_LEVEL_STR = "level=";
607    private static final String BSS_TSF_STR = "tsf=";
608    private static final String BSS_FLAGS_STR = "flags=";
609    private static final String BSS_SSID_STR = "ssid=";
610    private static final String BSS_DELIMITER_STR = "====";
611    private static final String BSS_END_STR = "####";
612
613    public ArrayList<ScanDetail> getScanResults() {
614        int next_sid = 0;
615        ArrayList<ScanDetail> results = new ArrayList<>();
616        while(next_sid >= 0) {
617            String rawResult = getRawScanResults(next_sid+"-");
618            next_sid = -1;
619
620            if (TextUtils.isEmpty(rawResult))
621                break;
622
623            String[] lines = rawResult.split("\n");
624
625
626            // note that all these splits and substrings keep references to the original
627            // huge string buffer while the amount we really want is generally pretty small
628            // so make copies instead (one example b/11087956 wasted 400k of heap here).
629            final int bssidStrLen = BSS_BSSID_STR.length();
630            final int flagLen = BSS_FLAGS_STR.length();
631
632            String bssid = "";
633            int level = 0;
634            int freq = 0;
635            long tsf = 0;
636            String flags = "";
637            WifiSsid wifiSsid = null;
638            String infoElementsStr = null;
639            List<String> anqpLines = null;
640
641            for (String line : lines) {
642                if (line.startsWith(BSS_ID_STR)) { // Will find the last id line
643                    try {
644                        next_sid = Integer.parseInt(line.substring(BSS_ID_STR.length())) + 1;
645                    } catch (NumberFormatException e) {
646                        // Nothing to do
647                    }
648                } else if (line.startsWith(BSS_BSSID_STR)) {
649                    bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen);
650                } else if (line.startsWith(BSS_FREQ_STR)) {
651                    try {
652                        freq = Integer.parseInt(line.substring(BSS_FREQ_STR.length()));
653                    } catch (NumberFormatException e) {
654                        freq = 0;
655                    }
656                } else if (line.startsWith(BSS_LEVEL_STR)) {
657                    try {
658                        level = Integer.parseInt(line.substring(BSS_LEVEL_STR.length()));
659                        /* some implementations avoid negative values by adding 256
660                         * so we need to adjust for that here.
661                         */
662                        if (level > 0) level -= 256;
663                    } catch (NumberFormatException e) {
664                        level = 0;
665                    }
666                } else if (line.startsWith(BSS_TSF_STR)) {
667                    try {
668                        tsf = Long.parseLong(line.substring(BSS_TSF_STR.length()));
669                    } catch (NumberFormatException e) {
670                        tsf = 0;
671                    }
672                } else if (line.startsWith(BSS_FLAGS_STR)) {
673                    flags = new String(line.getBytes(), flagLen, line.length() - flagLen);
674                } else if (line.startsWith(BSS_SSID_STR)) {
675                    wifiSsid = WifiSsid.createFromAsciiEncoded(
676                            line.substring(BSS_SSID_STR.length()));
677                } else if (line.startsWith(BSS_IE_STR)) {
678                    infoElementsStr = line;
679                } else if (SupplicantBridge.isAnqpAttribute(line)) {
680                    if (anqpLines == null) {
681                        anqpLines = new ArrayList<>();
682                    }
683                    anqpLines.add(line);
684                } else if (line.startsWith(BSS_DELIMITER_STR) || line.startsWith(BSS_END_STR)) {
685                    if (bssid != null) {
686                        try {
687                            if (infoElementsStr == null) {
688                                throw new IllegalArgumentException("Null information element data");
689                            }
690                            int seperator = infoElementsStr.indexOf('=');
691                            if (seperator < 0) {
692                                throw new IllegalArgumentException("No element separator");
693                            }
694
695                            ScanResult.InformationElement[] infoElements =
696                                        InformationElementUtil.parseInformationElements(
697                                        Utils.hexToBytes(infoElementsStr.substring(seperator + 1)));
698
699                            NetworkDetail networkDetail = new NetworkDetail(bssid,
700                                    infoElements, anqpLines, freq);
701                            if (DBG) {
702                                Log.v(TAG + ":DTIM", "SSID" + networkDetail.getSSID()
703                                        + ", DTIM=" + networkDetail.getDtimInterval() + ", "
704                                        + " IEstr:" + infoElementsStr);
705                            }
706                            String xssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
707                            if (!xssid.equals(networkDetail.getTrimmedSSID())) {
708                                Log.d(TAG, String.format(
709                                        "Inconsistent SSID on BSSID '%s': '%s' vs '%s': %s",
710                                        bssid, xssid, networkDetail.getSSID(), infoElementsStr));
711                            }
712
713                            if (networkDetail.hasInterworking()) {
714                                if (DBG) Log.d(TAG, "HSNwk: '" + networkDetail);
715                            }
716                            ScanDetail scan = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
717                                    level, freq, tsf, infoElements, anqpLines);
718                            results.add(scan);
719                        } catch (IllegalArgumentException iae) {
720                            Log.d(TAG, "Failed to parse information elements: " + iae);
721                        }
722                    }
723                    bssid = null;
724                    level = 0;
725                    freq = 0;
726                    tsf = 0;
727                    flags = "";
728                    wifiSsid = null;
729                    infoElementsStr = null;
730                    anqpLines = null;
731                }
732            }
733        }
734        return results;
735    }
736
737    /**
738     * Format of result:
739     * id=1016
740     * bssid=00:03:7f:40:84:10
741     * freq=2462
742     * beacon_int=200
743     * capabilities=0x0431
744     * qual=0
745     * noise=0
746     * level=-46
747     * tsf=0000002669008476
748     * age=5
749     * ie=00105143412d485332302d52322d54455354010882848b960c12182403010b0706555...
750     * flags=[WPA2-EAP-CCMP][ESS][P2P][HS20]
751     * ssid=QCA-HS20-R2-TEST
752     * p2p_device_name=
753     * p2p_config_methods=0x0SET_NE
754     * anqp_venue_name=02083d656e6757692d466920416c6c69616e63650a3239383920436f...
755     * anqp_network_auth_type=010000
756     * anqp_roaming_consortium=03506f9a05001bc504bd
757     * anqp_ip_addr_type_availability=0c
758     * anqp_nai_realm=0200300000246d61696c2e6578616d706c652e636f6d3b636973636f2...
759     * anqp_3gpp=000600040132f465
760     * anqp_domain_name=0b65786d61706c652e636f6d
761     * hs20_operator_friendly_name=11656e6757692d466920416c6c69616e63650e636869...
762     * hs20_wan_metrics=01c40900008001000000000a00
763     * hs20_connection_capability=0100000006140001061600000650000106bb010106bb0...
764     * hs20_osu_providers_list=0b5143412d4f53552d425353010901310015656e6757692d...
765     */
766    public String scanResult(String bssid) {
767        return doStringCommand("BSS " + bssid);
768    }
769
770    public boolean startDriver() {
771        return doBooleanCommand("DRIVER START");
772    }
773
774    public boolean stopDriver() {
775        return doBooleanCommand("DRIVER STOP");
776    }
777
778
779    /**
780     * Start filtering out Multicast V4 packets
781     * @return {@code true} if the operation succeeded, {@code false} otherwise
782     *
783     * Multicast filtering rules work as follows:
784     *
785     * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
786     * a power optimized mode (typically when screen goes off).
787     *
788     * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
789     * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
790     *
791     * DRIVER RXFILTER-ADD Num
792     *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
793     *
794     * and DRIVER RXFILTER-START
795     * In order to stop the usage of these rules, we do
796     *
797     * DRIVER RXFILTER-STOP
798     * DRIVER RXFILTER-REMOVE Num
799     *   where Num is as described for RXFILTER-ADD
800     *
801     * The  SETSUSPENDOPT driver command overrides the filtering rules
802     */
803    public boolean startFilteringMulticastV4Packets() {
804        return doBooleanCommand("DRIVER RXFILTER-STOP")
805            && doBooleanCommand("DRIVER RXFILTER-REMOVE 2")
806            && doBooleanCommand("DRIVER RXFILTER-START");
807    }
808
809    /**
810     * Stop filtering out Multicast V4 packets.
811     * @return {@code true} if the operation succeeded, {@code false} otherwise
812     */
813    public boolean stopFilteringMulticastV4Packets() {
814        return doBooleanCommand("DRIVER RXFILTER-STOP")
815            && doBooleanCommand("DRIVER RXFILTER-ADD 2")
816            && doBooleanCommand("DRIVER RXFILTER-START");
817    }
818
819    /**
820     * Start filtering out Multicast V6 packets
821     * @return {@code true} if the operation succeeded, {@code false} otherwise
822     */
823    public boolean startFilteringMulticastV6Packets() {
824        return doBooleanCommand("DRIVER RXFILTER-STOP")
825            && doBooleanCommand("DRIVER RXFILTER-REMOVE 3")
826            && doBooleanCommand("DRIVER RXFILTER-START");
827    }
828
829    /**
830     * Stop filtering out Multicast V6 packets.
831     * @return {@code true} if the operation succeeded, {@code false} otherwise
832     */
833    public boolean stopFilteringMulticastV6Packets() {
834        return doBooleanCommand("DRIVER RXFILTER-STOP")
835            && doBooleanCommand("DRIVER RXFILTER-ADD 3")
836            && doBooleanCommand("DRIVER RXFILTER-START");
837    }
838
839    /**
840     * Set the operational frequency band
841     * @param band One of
842     *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
843     *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
844     *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
845     * @return {@code true} if the operation succeeded, {@code false} otherwise
846     */
847    public boolean setBand(int band) {
848        String bandstr;
849
850        if (band == WifiManager.WIFI_FREQUENCY_BAND_5GHZ)
851            bandstr = "5G";
852        else if (band == WifiManager.WIFI_FREQUENCY_BAND_2GHZ)
853            bandstr = "2G";
854        else
855            bandstr = "AUTO";
856        return doBooleanCommand("SET SETBAND " + bandstr);
857    }
858
859    public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED     = 0;
860    public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED    = 1;
861    public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE       = 2;
862    /**
863      * Sets the bluetooth coexistence mode.
864      *
865      * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
866      *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
867      *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
868      * @return Whether the mode was successfully set.
869      */
870    public boolean setBluetoothCoexistenceMode(int mode) {
871        return doBooleanCommand("DRIVER BTCOEXMODE " + mode);
872    }
873
874    /**
875     * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
876     * some of the low-level scan parameters used by the driver are changed to
877     * reduce interference with A2DP streaming.
878     *
879     * @param isSet whether to enable or disable this mode
880     * @return {@code true} if the command succeeded, {@code false} otherwise.
881     */
882    public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) {
883        if (setCoexScanMode) {
884            return doBooleanCommand("DRIVER BTCOEXSCAN-START");
885        } else {
886            return doBooleanCommand("DRIVER BTCOEXSCAN-STOP");
887        }
888    }
889
890    public void enableSaveConfig() {
891        doBooleanCommand("SET update_config 1");
892    }
893
894    public boolean saveConfig() {
895        return doBooleanCommand("SAVE_CONFIG");
896    }
897
898    public boolean addToBlacklist(String bssid) {
899        if (TextUtils.isEmpty(bssid)) return false;
900        return doBooleanCommand("BLACKLIST " + bssid);
901    }
902
903    public boolean clearBlacklist() {
904        return doBooleanCommand("BLACKLIST clear");
905    }
906
907    public boolean setSuspendOptimizations(boolean enabled) {
908        if (enabled) {
909            return doBooleanCommand("DRIVER SETSUSPENDMODE 1");
910        } else {
911            return doBooleanCommand("DRIVER SETSUSPENDMODE 0");
912        }
913    }
914
915    public boolean setCountryCode(String countryCode) {
916        if (countryCode != null)
917            return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
918        else
919            return doBooleanCommand("DRIVER COUNTRY");
920    }
921
922    /**
923     * Start/Stop PNO scan.
924     * @param enable boolean indicating whether PNO is being enabled or disabled.
925     */
926    public boolean setPnoScan(boolean enable) {
927        String cmd = enable ? "SET pno 1" : "SET pno 0";
928        return doBooleanCommand(cmd);
929    }
930
931    // TODO(rpius): Move PnoMonitor to SupplicantWifiScannerImpl.
932    //PNO Monitor
933    private class PnoMonitor {
934        private static final int MINIMUM_PNO_GAP = 5 * 1000;
935        private static final String ACTION_TOGGLE_PNO =
936            "com.android.server.Wifi.action.TOGGLE_PNO";
937        long mLastPnoChangeTimeStamp = -1L;
938        boolean mExpectedPnoState = false;
939        List<PnoNetwork> mExpectedPnoNetworkList = null;
940        boolean mCurrentPnoState = false;;
941        boolean mWaitForTimer = false;
942        private boolean mIsPaused = false;
943        final Object mPnoLock = new Object();
944        private final AlarmManager mAlarmManager =
945                (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
946        private final PendingIntent mPnoIntent;
947
948        public PnoMonitor() {
949            Intent intent = new Intent(ACTION_TOGGLE_PNO, null);
950            intent.setPackage("android");
951            mPnoIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
952
953            mContext.registerReceiver(
954                new BroadcastReceiver() {
955                    @Override
956                    public void onReceive(Context context, Intent intent) {
957                        synchronized(mPnoLock) {
958                            if (DBG) {
959                                Log.d(mTAG, "PNO timer expire, PNO should change to "
960                                        + mExpectedPnoState);
961                            }
962                            boolean ret = setPno(mExpectedPnoState, mExpectedPnoNetworkList);
963                            if (!ret) {
964                                Log.e(mTAG, "set PNO failure");
965                            }
966                            mWaitForTimer = false;
967                        }
968                    }
969                },
970                new IntentFilter(ACTION_TOGGLE_PNO));
971        }
972
973        /**
974         * Enable/Disable PNO with updated network priorities.
975         * @param enable boolean indicating whether PNO is being enabled or disabled.
976         * @param pnoNetworkList list of networks with priorities to be set before PNO setting.
977         */
978        private boolean setPno(boolean enable, List<PnoNetwork> pnoNetworkList) {
979            if (mIsPaused) {
980                if (DBG) Log.d(mTAG, "Do not change PNO state since it is paused");
981                return true;
982            }
983            if (mCurrentPnoState == enable) {
984                if (DBG) Log.d(mTAG, "Do not change PNO since current is expected");
985                return true;
986            }
987            if (DBG) {
988                Log.d(mTAG, "change PNO from " + mCurrentPnoState + " to " + enable);
989            }
990            // TODO: Couple of cases yet to be handled:
991            // 1. What if the network priority update fails, should we bail out of PNO setting?
992            // 2. If PNO setting fails below, should we go back and revert this priority change?
993            if (pnoNetworkList != null) {
994                if (DBG) Log.i(mTAG, "update priorities for PNO. Enable: " + enable);
995                for (PnoNetwork pnoNetwork : pnoNetworkList) {
996                    // What if this fails? Should we bail out?
997                    boolean isSuccess = setNetworkVariable(pnoNetwork.networkId,
998                            WifiConfiguration.priorityVarName,
999                            Integer.toString(pnoNetwork.priority));
1000                    if (!isSuccess) {
1001                        Log.e(mTAG, "update priority failed for :" + pnoNetwork.networkId);
1002                    }
1003                }
1004            }
1005            boolean ret = WifiNative.this.setPnoScan(enable);
1006            mLastPnoChangeTimeStamp = System.currentTimeMillis();
1007            if (ret) {
1008                mCurrentPnoState = enable;
1009            }
1010            return ret;
1011        }
1012
1013        public boolean enableBackgroundScan(
1014                boolean enable,
1015                List<PnoNetwork> pnoNetworkList) {
1016            synchronized(mPnoLock) {
1017                Log.i(mTAG, "set expected PNO to " +  enable);
1018                mExpectedPnoState = enable;
1019                mExpectedPnoNetworkList = pnoNetworkList;
1020                if (mWaitForTimer) {
1021                    //already has a timer
1022                    if (DBG) Log.d(mTAG, "update expected PNO to " +  mExpectedPnoState);
1023                } else {
1024                    long timeDifference = System.currentTimeMillis() - mLastPnoChangeTimeStamp;
1025                    if (timeDifference >= MINIMUM_PNO_GAP) {
1026                        return setPno(enable, pnoNetworkList);
1027                    } else {
1028                        mWaitForTimer = true;
1029                        if (DBG) Log.d(mTAG, "start PNO timer with delay:" + timeDifference);
1030                        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
1031                                System.currentTimeMillis() + timeDifference, mPnoIntent);
1032                    }
1033                }
1034                return true;
1035            }
1036        }
1037
1038        /**
1039         * Pause PNO scanning.
1040         */
1041        public void pauseBackgroundScan() {
1042            synchronized (mPnoLock) {
1043                if (!mIsPaused) {
1044                    Log.i(mTAG, "Pausing Pno scan. Current state: " + mCurrentPnoState);
1045                    if (mCurrentPnoState) {
1046                        setPno(false, null);
1047                    }
1048                    mIsPaused = true;
1049                }
1050            }
1051        }
1052
1053        /**
1054         * Resume PNO scanning.
1055         */
1056        public void resumeBackgroundScan() {
1057            synchronized (mPnoLock) {
1058                if (mIsPaused) {
1059                    Log.i(mTAG, "Resuming Pno scan. Expected state: " + mExpectedPnoState);
1060                    mIsPaused = false;
1061                    if (mExpectedPnoState) {
1062                        setPno(true, null);
1063                    }
1064                }
1065            }
1066        }
1067    }
1068
1069    public boolean enableBackgroundScan(
1070            boolean enable,
1071            List<PnoNetwork> pnoNetworkList) {
1072        if (mPnoMonitor != null) {
1073            return mPnoMonitor.enableBackgroundScan(enable, pnoNetworkList);
1074        } else {
1075            return false;
1076        }
1077    }
1078
1079    /**
1080     * Pause PNO scanning.
1081     * Note: If Pno is currently running, the stop might take a little while to take effect!
1082     */
1083    public void pauseBackgroundScan() {
1084        if (mPnoMonitor != null) {
1085            mPnoMonitor.pauseBackgroundScan();
1086        }
1087    }
1088
1089    /**
1090     * Resume PNO scanning.
1091     */
1092    public void resumeBackgroundScan() {
1093        if (mPnoMonitor != null) {
1094            mPnoMonitor.resumeBackgroundScan();
1095        }
1096    }
1097
1098    public void enableAutoConnect(boolean enable) {
1099        if (enable) {
1100            doBooleanCommand("STA_AUTOCONNECT 1");
1101        } else {
1102            doBooleanCommand("STA_AUTOCONNECT 0");
1103        }
1104    }
1105
1106    public void setScanInterval(int scanInterval) {
1107        doBooleanCommand("SCAN_INTERVAL " + scanInterval);
1108    }
1109
1110    public void setHs20(boolean hs20) {
1111        if (hs20) {
1112            doBooleanCommand("SET HS20 1");
1113        } else {
1114            doBooleanCommand("SET HS20 0");
1115        }
1116    }
1117
1118    public void startTdls(String macAddr, boolean enable) {
1119        if (enable) {
1120            synchronized (sLock) {
1121                doBooleanCommand("TDLS_DISCOVER " + macAddr);
1122                doBooleanCommand("TDLS_SETUP " + macAddr);
1123            }
1124        } else {
1125            doBooleanCommand("TDLS_TEARDOWN " + macAddr);
1126        }
1127    }
1128
1129    /** Example output:
1130     * RSSI=-65
1131     * LINKSPEED=48
1132     * NOISE=9999
1133     * FREQUENCY=0
1134     */
1135    public String signalPoll() {
1136        return doStringCommandWithoutLogging("SIGNAL_POLL");
1137    }
1138
1139    /** Example outout:
1140     * TXGOOD=396
1141     * TXBAD=1
1142     */
1143    public String pktcntPoll() {
1144        return doStringCommand("PKTCNT_POLL");
1145    }
1146
1147    public void bssFlush() {
1148        doBooleanCommand("BSS_FLUSH 0");
1149    }
1150
1151    public boolean startWpsPbc(String bssid) {
1152        if (TextUtils.isEmpty(bssid)) {
1153            return doBooleanCommand("WPS_PBC");
1154        } else {
1155            return doBooleanCommand("WPS_PBC " + bssid);
1156        }
1157    }
1158
1159    public boolean startWpsPbc(String iface, String bssid) {
1160        synchronized (sLock) {
1161            if (TextUtils.isEmpty(bssid)) {
1162                return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
1163            } else {
1164                return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
1165            }
1166        }
1167    }
1168
1169    public boolean startWpsPinKeypad(String pin) {
1170        if (TextUtils.isEmpty(pin)) return false;
1171        return doBooleanCommand("WPS_PIN any " + pin);
1172    }
1173
1174    public boolean startWpsPinKeypad(String iface, String pin) {
1175        if (TextUtils.isEmpty(pin)) return false;
1176        synchronized (sLock) {
1177            return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
1178        }
1179    }
1180
1181
1182    public String startWpsPinDisplay(String bssid) {
1183        if (TextUtils.isEmpty(bssid)) {
1184            return doStringCommand("WPS_PIN any");
1185        } else {
1186            return doStringCommand("WPS_PIN " + bssid);
1187        }
1188    }
1189
1190    public String startWpsPinDisplay(String iface, String bssid) {
1191        synchronized (sLock) {
1192            if (TextUtils.isEmpty(bssid)) {
1193                return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
1194            } else {
1195                return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
1196            }
1197        }
1198    }
1199
1200    public boolean setExternalSim(boolean external) {
1201        String value = external ? "1" : "0";
1202        Log.d(TAG, "Setting external_sim to " + value);
1203        return doBooleanCommand("SET external_sim " + value);
1204    }
1205
1206    public boolean simAuthResponse(int id, String type, String response) {
1207        // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS
1208        return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response);
1209    }
1210
1211    public boolean simAuthFailedResponse(int id) {
1212        // should be used with type GSM-AUTH
1213        return doBooleanCommand("CTRL-RSP-SIM-" + id + ":GSM-FAIL");
1214    }
1215
1216    public boolean umtsAuthFailedResponse(int id) {
1217        // should be used with type UMTS-AUTH
1218        return doBooleanCommand("CTRL-RSP-SIM-" + id + ":UMTS-FAIL");
1219    }
1220
1221    public boolean simIdentityResponse(int id, String response) {
1222        return doBooleanCommand("CTRL-RSP-IDENTITY-" + id + ":" + response);
1223    }
1224
1225    /* Configures an access point connection */
1226    public boolean startWpsRegistrar(String bssid, String pin) {
1227        if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false;
1228        return doBooleanCommand("WPS_REG " + bssid + " " + pin);
1229    }
1230
1231    public boolean cancelWps() {
1232        return doBooleanCommand("WPS_CANCEL");
1233    }
1234
1235    public boolean setPersistentReconnect(boolean enabled) {
1236        int value = (enabled == true) ? 1 : 0;
1237        return doBooleanCommand("SET persistent_reconnect " + value);
1238    }
1239
1240    public boolean setDeviceName(String name) {
1241        return doBooleanCommand("SET device_name " + name);
1242    }
1243
1244    public boolean setDeviceType(String type) {
1245        return doBooleanCommand("SET device_type " + type);
1246    }
1247
1248    public boolean setConfigMethods(String cfg) {
1249        return doBooleanCommand("SET config_methods " + cfg);
1250    }
1251
1252    public boolean setManufacturer(String value) {
1253        return doBooleanCommand("SET manufacturer " + value);
1254    }
1255
1256    public boolean setModelName(String value) {
1257        return doBooleanCommand("SET model_name " + value);
1258    }
1259
1260    public boolean setModelNumber(String value) {
1261        return doBooleanCommand("SET model_number " + value);
1262    }
1263
1264    public boolean setSerialNumber(String value) {
1265        return doBooleanCommand("SET serial_number " + value);
1266    }
1267
1268    public boolean setP2pSsidPostfix(String postfix) {
1269        return doBooleanCommand("SET p2p_ssid_postfix " + postfix);
1270    }
1271
1272    public boolean setP2pGroupIdle(String iface, int time) {
1273        synchronized (sLock) {
1274            return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
1275        }
1276    }
1277
1278    public void setPowerSave(boolean enabled) {
1279        if (enabled) {
1280            doBooleanCommand("SET ps 1");
1281        } else {
1282            doBooleanCommand("SET ps 0");
1283        }
1284    }
1285
1286    public boolean setP2pPowerSave(String iface, boolean enabled) {
1287        synchronized (sLock) {
1288            if (enabled) {
1289                return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
1290            } else {
1291                return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
1292            }
1293        }
1294    }
1295
1296    public boolean setWfdEnable(boolean enable) {
1297        return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0"));
1298    }
1299
1300    public boolean setWfdDeviceInfo(String hex) {
1301        return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex);
1302    }
1303
1304    /**
1305     * "sta" prioritizes STA connection over P2P and "p2p" prioritizes
1306     * P2P connection over STA
1307     */
1308    public boolean setConcurrencyPriority(String s) {
1309        return doBooleanCommand("P2P_SET conc_pref " + s);
1310    }
1311
1312    public boolean p2pFind() {
1313        return doBooleanCommand("P2P_FIND");
1314    }
1315
1316    public boolean p2pFind(int timeout) {
1317        if (timeout <= 0) {
1318            return p2pFind();
1319        }
1320        return doBooleanCommand("P2P_FIND " + timeout);
1321    }
1322
1323    public boolean p2pStopFind() {
1324       return doBooleanCommand("P2P_STOP_FIND");
1325    }
1326
1327    public boolean p2pListen() {
1328        return doBooleanCommand("P2P_LISTEN");
1329    }
1330
1331    public boolean p2pListen(int timeout) {
1332        if (timeout <= 0) {
1333            return p2pListen();
1334        }
1335        return doBooleanCommand("P2P_LISTEN " + timeout);
1336    }
1337
1338    public boolean p2pExtListen(boolean enable, int period, int interval) {
1339        if (enable && interval < period) {
1340            return false;
1341        }
1342        return doBooleanCommand("P2P_EXT_LISTEN"
1343                    + (enable ? (" " + period + " " + interval) : ""));
1344    }
1345
1346    public boolean p2pSetChannel(int lc, int oc) {
1347        if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc);
1348
1349        synchronized (sLock) {
1350            if (lc >=1 && lc <= 11) {
1351                if (!doBooleanCommand("P2P_SET listen_channel " + lc)) {
1352                    return false;
1353                }
1354            } else if (lc != 0) {
1355                return false;
1356            }
1357
1358            if (oc >= 1 && oc <= 165 ) {
1359                int freq = (oc <= 14 ? 2407 : 5000) + oc * 5;
1360                return doBooleanCommand("P2P_SET disallow_freq 1000-"
1361                        + (freq - 5) + "," + (freq + 5) + "-6000");
1362            } else if (oc == 0) {
1363                /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */
1364                return doBooleanCommand("P2P_SET disallow_freq \"\"");
1365            }
1366        }
1367        return false;
1368    }
1369
1370    public boolean p2pFlush() {
1371        return doBooleanCommand("P2P_FLUSH");
1372    }
1373
1374    private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
1375    /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad]
1376        [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */
1377    public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) {
1378        if (config == null) return null;
1379        List<String> args = new ArrayList<String>();
1380        WpsInfo wps = config.wps;
1381        args.add(config.deviceAddress);
1382
1383        switch (wps.setup) {
1384            case WpsInfo.PBC:
1385                args.add("pbc");
1386                break;
1387            case WpsInfo.DISPLAY:
1388                if (TextUtils.isEmpty(wps.pin)) {
1389                    args.add("pin");
1390                } else {
1391                    args.add(wps.pin);
1392                }
1393                args.add("display");
1394                break;
1395            case WpsInfo.KEYPAD:
1396                args.add(wps.pin);
1397                args.add("keypad");
1398                break;
1399            case WpsInfo.LABEL:
1400                args.add(wps.pin);
1401                args.add("label");
1402            default:
1403                break;
1404        }
1405
1406        if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) {
1407            args.add("persistent");
1408        }
1409
1410        if (joinExistingGroup) {
1411            args.add("join");
1412        } else {
1413            //TODO: This can be adapted based on device plugged in state and
1414            //device battery state
1415            int groupOwnerIntent = config.groupOwnerIntent;
1416            if (groupOwnerIntent < 0 || groupOwnerIntent > 15) {
1417                groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT;
1418            }
1419            args.add("go_intent=" + groupOwnerIntent);
1420        }
1421
1422        String command = "P2P_CONNECT ";
1423        for (String s : args) command += s + " ";
1424
1425        return doStringCommand(command);
1426    }
1427
1428    public boolean p2pCancelConnect() {
1429        return doBooleanCommand("P2P_CANCEL");
1430    }
1431
1432    public boolean p2pProvisionDiscovery(WifiP2pConfig config) {
1433        if (config == null) return false;
1434
1435        switch (config.wps.setup) {
1436            case WpsInfo.PBC:
1437                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc");
1438            case WpsInfo.DISPLAY:
1439                //We are doing display, so provision discovery is keypad
1440                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad");
1441            case WpsInfo.KEYPAD:
1442                //We are doing keypad, so provision discovery is display
1443                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display");
1444            default:
1445                break;
1446        }
1447        return false;
1448    }
1449
1450    public boolean p2pGroupAdd(boolean persistent) {
1451        if (persistent) {
1452            return doBooleanCommand("P2P_GROUP_ADD persistent");
1453        }
1454        return doBooleanCommand("P2P_GROUP_ADD");
1455    }
1456
1457    public boolean p2pGroupAdd(int netId) {
1458        return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId);
1459    }
1460
1461    public boolean p2pGroupRemove(String iface) {
1462        if (TextUtils.isEmpty(iface)) return false;
1463        synchronized (sLock) {
1464            return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
1465        }
1466    }
1467
1468    public boolean p2pReject(String deviceAddress) {
1469        return doBooleanCommand("P2P_REJECT " + deviceAddress);
1470    }
1471
1472    /* Invite a peer to a group */
1473    public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) {
1474        if (TextUtils.isEmpty(deviceAddress)) return false;
1475
1476        if (group == null) {
1477            return doBooleanCommand("P2P_INVITE peer=" + deviceAddress);
1478        } else {
1479            return doBooleanCommand("P2P_INVITE group=" + group.getInterface()
1480                    + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress);
1481        }
1482    }
1483
1484    /* Reinvoke a persistent connection */
1485    public boolean p2pReinvoke(int netId, String deviceAddress) {
1486        if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false;
1487
1488        return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress);
1489    }
1490
1491    public String p2pGetSsid(String deviceAddress) {
1492        return p2pGetParam(deviceAddress, "oper_ssid");
1493    }
1494
1495    public String p2pGetDeviceAddress() {
1496        Log.d(TAG, "p2pGetDeviceAddress");
1497
1498        String status = null;
1499
1500        /* Explicitly calling the API without IFNAME= prefix to take care of the devices that
1501        don't have p2p0 interface. Supplicant seems to be returning the correct address anyway. */
1502
1503        synchronized (sLock) {
1504            status = doStringCommandNative("STATUS");
1505        }
1506
1507        String result = "";
1508        if (status != null) {
1509            String[] tokens = status.split("\n");
1510            for (String token : tokens) {
1511                if (token.startsWith("p2p_device_address=")) {
1512                    String[] nameValue = token.split("=");
1513                    if (nameValue.length != 2)
1514                        break;
1515                    result = nameValue[1];
1516                }
1517            }
1518        }
1519
1520        Log.d(TAG, "p2pGetDeviceAddress returning " + result);
1521        return result;
1522    }
1523
1524    public int getGroupCapability(String deviceAddress) {
1525        int gc = 0;
1526        if (TextUtils.isEmpty(deviceAddress)) return gc;
1527        String peerInfo = p2pPeer(deviceAddress);
1528        if (TextUtils.isEmpty(peerInfo)) return gc;
1529
1530        String[] tokens = peerInfo.split("\n");
1531        for (String token : tokens) {
1532            if (token.startsWith("group_capab=")) {
1533                String[] nameValue = token.split("=");
1534                if (nameValue.length != 2) break;
1535                try {
1536                    return Integer.decode(nameValue[1]);
1537                } catch(NumberFormatException e) {
1538                    return gc;
1539                }
1540            }
1541        }
1542        return gc;
1543    }
1544
1545    public String p2pPeer(String deviceAddress) {
1546        return doStringCommand("P2P_PEER " + deviceAddress);
1547    }
1548
1549    private String p2pGetParam(String deviceAddress, String key) {
1550        if (deviceAddress == null) return null;
1551
1552        String peerInfo = p2pPeer(deviceAddress);
1553        if (peerInfo == null) return null;
1554        String[] tokens= peerInfo.split("\n");
1555
1556        key += "=";
1557        for (String token : tokens) {
1558            if (token.startsWith(key)) {
1559                String[] nameValue = token.split("=");
1560                if (nameValue.length != 2) break;
1561                return nameValue[1];
1562            }
1563        }
1564        return null;
1565    }
1566
1567    public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) {
1568        /*
1569         * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump>
1570         * P2P_SERVICE_ADD upnp <version hex> <service>
1571         *
1572         * e.g)
1573         * [Bonjour]
1574         * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.)
1575         * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027
1576         * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript)
1577         * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001
1578         *  09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074
1579         *
1580         * [UPnP]
1581         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
1582         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice
1583         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp
1584         * -org:device:InternetGatewayDevice:1
1585         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp
1586         * -org:service:ContentDirectory:2
1587         */
1588        synchronized (sLock) {
1589            for (String s : servInfo.getSupplicantQueryList()) {
1590                String command = "P2P_SERVICE_ADD";
1591                command += (" " + s);
1592                if (!doBooleanCommand(command)) {
1593                    return false;
1594                }
1595            }
1596        }
1597        return true;
1598    }
1599
1600    public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) {
1601        /*
1602         * P2P_SERVICE_DEL bonjour <query hexdump>
1603         * P2P_SERVICE_DEL upnp <version hex> <service>
1604         */
1605        synchronized (sLock) {
1606            for (String s : servInfo.getSupplicantQueryList()) {
1607                String command = "P2P_SERVICE_DEL ";
1608
1609                String[] data = s.split(" ");
1610                if (data.length < 2) {
1611                    return false;
1612                }
1613                if ("upnp".equals(data[0])) {
1614                    command += s;
1615                } else if ("bonjour".equals(data[0])) {
1616                    command += data[0];
1617                    command += (" " + data[1]);
1618                } else {
1619                    return false;
1620                }
1621                if (!doBooleanCommand(command)) {
1622                    return false;
1623                }
1624            }
1625        }
1626        return true;
1627    }
1628
1629    public boolean p2pServiceFlush() {
1630        return doBooleanCommand("P2P_SERVICE_FLUSH");
1631    }
1632
1633    public String p2pServDiscReq(String addr, String query) {
1634        String command = "P2P_SERV_DISC_REQ";
1635        command += (" " + addr);
1636        command += (" " + query);
1637
1638        return doStringCommand(command);
1639    }
1640
1641    public boolean p2pServDiscCancelReq(String id) {
1642        return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id);
1643    }
1644
1645    /* Set the current mode of miracast operation.
1646     *  0 = disabled
1647     *  1 = operating as source
1648     *  2 = operating as sink
1649     */
1650    public void setMiracastMode(int mode) {
1651        // Note: optional feature on the driver. It is ok for this to fail.
1652        doBooleanCommand("DRIVER MIRACAST " + mode);
1653    }
1654
1655    public boolean fetchAnqp(String bssid, String subtypes) {
1656        return doBooleanCommand("ANQP_GET " + bssid + " " + subtypes);
1657    }
1658
1659    /*
1660     * NFC-related calls
1661     */
1662    public String getNfcWpsConfigurationToken(int netId) {
1663        return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId);
1664    }
1665
1666    public String getNfcHandoverRequest() {
1667        return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR");
1668    }
1669
1670    public String getNfcHandoverSelect() {
1671        return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR");
1672    }
1673
1674    public boolean initiatorReportNfcHandover(String selectMessage) {
1675        return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage);
1676    }
1677
1678    public boolean responderReportNfcHandover(String requestMessage) {
1679        return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00");
1680    }
1681
1682
1683    /* kernel logging support */
1684    private static native byte[] readKernelLogNative();
1685
1686    synchronized public String readKernelLog() {
1687        byte[] bytes = readKernelLogNative();
1688        if (bytes != null) {
1689            CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
1690            try {
1691                CharBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
1692                return decoded.toString();
1693            } catch (CharacterCodingException cce) {
1694                return new String(bytes, StandardCharsets.ISO_8859_1);
1695            }
1696        } else {
1697            return "*** failed to read kernel log ***";
1698        }
1699    }
1700
1701    /* WIFI HAL support */
1702
1703    // HAL command ids
1704    private static int sCmdId = 1;
1705    private static int getNewCmdIdLocked() {
1706        return sCmdId++;
1707    }
1708
1709    private static final String TAG = "WifiNative-HAL";
1710    private static long sWifiHalHandle = 0;             /* used by JNI to save wifi_handle */
1711    private static long[] sWifiIfaceHandles = null;     /* used by JNI to save interface handles */
1712    public static int sWlan0Index = -1;
1713    private static MonitorThread sThread;
1714    private static final int STOP_HAL_TIMEOUT_MS = 1000;
1715
1716    private static native boolean startHalNative();
1717    private static native void stopHalNative();
1718    private static native void waitForHalEventNative();
1719
1720    private static class MonitorThread extends Thread {
1721        public void run() {
1722            Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle));
1723            waitForHalEventNative();
1724        }
1725    }
1726
1727    public boolean startHal() {
1728        String debugLog = "startHal stack: ";
1729        java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace();
1730        for (int i = 2; i < elements.length && i <= 7; i++ ) {
1731            debugLog = debugLog + " - " + elements[i].getMethodName();
1732        }
1733
1734        sLocalLog.log(debugLog);
1735
1736        synchronized (sLock) {
1737            if (startHalNative()) {
1738                if (!setInterfaceUp(true)) {
1739                    sLocalLog.log("Could not bring up interface: " + mInterfaceName);
1740                    return false;
1741                }
1742                int wlan0Index = queryInterfaceIndex(mInterfaceName);
1743                if (wlan0Index == -1) {
1744                    if (DBG) sLocalLog.log("Could not find interface with name: " + mInterfaceName);
1745                    return false;
1746                }
1747                sWlan0Index = wlan0Index;
1748                sThread = new MonitorThread();
1749                sThread.start();
1750                return true;
1751            } else {
1752                if (DBG) sLocalLog.log("Could not start hal");
1753                Log.e(TAG, "Could not start hal");
1754                return false;
1755            }
1756        }
1757    }
1758
1759    public void stopHal() {
1760        synchronized (sLock) {
1761            if (isHalStarted()) {
1762                stopHalNative();
1763                try {
1764                    sThread.join(STOP_HAL_TIMEOUT_MS);
1765                    Log.d(TAG, "HAL event thread stopped successfully");
1766                    if (!setInterfaceUp(false)) {
1767                        if (DBG) sLocalLog.log("Could not bring down interface: " + mInterfaceName);
1768                    }
1769                } catch (InterruptedException e) {
1770                    Log.e(TAG, "Could not stop HAL cleanly");
1771                }
1772                sThread = null;
1773                sWifiHalHandle = 0;
1774                sWifiIfaceHandles = null;
1775                sWlan0Index = -1;
1776            }
1777        }
1778    }
1779
1780    public boolean isHalStarted() {
1781        return (sWifiHalHandle != 0);
1782    }
1783    private static native int getInterfacesNative();
1784
1785    public int queryInterfaceIndex(String interfaceName) {
1786        synchronized (sLock) {
1787            if (isHalStarted()) {
1788                int num = getInterfacesNative();
1789                for (int i = 0; i < num; i++) {
1790                    String name = getInterfaceNameNative(i);
1791                    if (name.equals(interfaceName)) {
1792                        return i;
1793                    }
1794                }
1795            }
1796        }
1797        return -1;
1798    }
1799
1800    private static native String getInterfaceNameNative(int index);
1801    public String getInterfaceName(int index) {
1802        synchronized (sLock) {
1803            return getInterfaceNameNative(index);
1804        }
1805    }
1806
1807    // TODO: Change variable names to camel style.
1808    public static class ScanCapabilities {
1809        public int  max_scan_cache_size;
1810        public int  max_scan_buckets;
1811        public int  max_ap_cache_per_scan;
1812        public int  max_rssi_sample_size;
1813        public int  max_scan_reporting_threshold;
1814        public int  max_hotlist_bssids;
1815        public int  max_significant_wifi_change_aps;
1816        public int  max_bssid_history_entries;
1817        public int  max_number_epno_networks;
1818        public int  max_number_epno_networks_by_ssid;
1819        public int  max_number_of_white_listed_ssid;
1820    }
1821
1822    public boolean getScanCapabilities(ScanCapabilities capabilities) {
1823        synchronized (sLock) {
1824            return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities);
1825        }
1826    }
1827
1828    private static native boolean getScanCapabilitiesNative(
1829            int iface, ScanCapabilities capabilities);
1830
1831    private static native boolean startScanNative(int iface, int id, ScanSettings settings);
1832    private static native boolean stopScanNative(int iface, int id);
1833    private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush);
1834    private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface);
1835    private static native void setWifiLinkLayerStatsNative(int iface, int enable);
1836
1837    public static class ChannelSettings {
1838        public int frequency;
1839        public int dwell_time_ms;
1840        public boolean passive;
1841    }
1842
1843    public static class BucketSettings {
1844        public int bucket;
1845        public int band;
1846        public int period_ms;
1847        public int max_period_ms;
1848        public int step_count;
1849        public int report_events;
1850        public int num_channels;
1851        public ChannelSettings[] channels;
1852    }
1853
1854    public static class ScanSettings {
1855        public int base_period_ms;
1856        public int max_ap_per_scan;
1857        public int report_threshold_percent;
1858        public int report_threshold_num_scans;
1859        public int num_buckets;
1860        /* Not part of gscan HAL API. Used only for wpa_supplicant scanning */
1861        public int[] hiddenNetworkIds;
1862        public BucketSettings[] buckets;
1863    }
1864
1865    /**
1866     * Network parameters to start PNO scan.
1867     */
1868    public static class PnoNetwork {
1869        public String ssid;
1870        public int networkId;
1871        public int priority;
1872        public byte flags;
1873        public byte auth_bit_field;
1874    }
1875
1876    /**
1877     * Parameters to start PNO scan. This holds the list of networks which are going to used for
1878     * PNO scan.
1879     */
1880    public static class PnoSettings {
1881        public int min5GHzRssi;
1882        public int min24GHzRssi;
1883        public int initialScoreMax;
1884        public int currentConnectionBonus;
1885        public int sameNetworkBonus;
1886        public int secureBonus;
1887        public int band5GHzBonus;
1888        public boolean isConnected;
1889        public PnoNetwork[] networkList;
1890    }
1891
1892    /**
1893     * Wi-Fi channel information.
1894     */
1895    public static class WifiChannelInfo {
1896        int mPrimaryFrequency;
1897        int mCenterFrequency0;
1898        int mCenterFrequency1;
1899        int mChannelWidth;
1900        // TODO: add preamble once available in HAL.
1901    }
1902
1903    public static interface ScanEventHandler {
1904        /**
1905         * Called for each AP as it is found with the entire contents of the beacon/probe response.
1906         * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified.
1907         */
1908        void onFullScanResult(ScanResult fullScanResult);
1909        /**
1910         * Callback on an event during a gscan scan.
1911         * See WifiNative.WIFI_SCAN_* for possible values.
1912         */
1913        void onScanStatus(int event);
1914        /**
1915         * Called with the current cached scan results when gscan is paused.
1916         */
1917        void onScanPaused(WifiScanner.ScanData[] data);
1918        /**
1919         * Called with the current cached scan results when gscan is resumed.
1920         */
1921        void onScanRestarted();
1922    }
1923
1924    /**
1925     * Handler to notify the occurrence of various events during PNO scan.
1926     */
1927    public interface PnoEventHandler {
1928        /**
1929         * Callback to notify when one of the shortlisted networks is found during PNO scan.
1930         * @param results List of Scan results received.
1931         */
1932        void onPnoNetworkFound(ScanResult[] results);
1933
1934        /**
1935         * Callback to notify when the PNO scan schedule fails.
1936         */
1937        void onPnoScanFailed();
1938    }
1939
1940    /* scan status, keep these values in sync with gscan.h */
1941    public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
1942    public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
1943    public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
1944    public static final int WIFI_SCAN_FAILED = 3;
1945
1946    // Callback from native
1947    private static void onScanStatus(int id, int event) {
1948        ScanEventHandler handler = sScanEventHandler;
1949        if (handler != null) {
1950            handler.onScanStatus(event);
1951        }
1952    }
1953
1954    public static  WifiSsid createWifiSsid(byte[] rawSsid) {
1955        String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid));
1956
1957        if (ssidHexString == null) {
1958            return null;
1959        }
1960
1961        WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString);
1962
1963        return wifiSsid;
1964    }
1965
1966    public static String ssidConvert(byte[] rawSsid) {
1967        String ssid;
1968
1969        CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
1970        try {
1971            CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid));
1972            ssid = decoded.toString();
1973        } catch (CharacterCodingException cce) {
1974            ssid = null;
1975        }
1976
1977        if (ssid == null) {
1978            ssid = new String(rawSsid, StandardCharsets.ISO_8859_1);
1979        }
1980
1981        return ssid;
1982    }
1983
1984    // Called from native
1985    public static boolean setSsid(byte[] rawSsid, ScanResult result) {
1986        if (rawSsid == null || rawSsid.length == 0 || result == null) {
1987            return false;
1988        }
1989
1990        result.SSID = ssidConvert(rawSsid);
1991        result.wifiSsid = createWifiSsid(rawSsid);
1992        return true;
1993    }
1994
1995    private static void populateScanResult(ScanResult result, int beaconCap, String dbg) {
1996        if (dbg == null) dbg = "";
1997
1998        InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation();
1999        InformationElementUtil.VhtOperation vhtOperation =
2000                new InformationElementUtil.VhtOperation();
2001        InformationElementUtil.ExtendedCapabilities extendedCaps =
2002                new InformationElementUtil.ExtendedCapabilities();
2003
2004        ScanResult.InformationElement elements[] =
2005                InformationElementUtil.parseInformationElements(result.bytes);
2006        for (ScanResult.InformationElement ie : elements) {
2007            if(ie.id == ScanResult.InformationElement.EID_HT_OPERATION) {
2008                htOperation.from(ie);
2009            } else if(ie.id == ScanResult.InformationElement.EID_VHT_OPERATION) {
2010                vhtOperation.from(ie);
2011            } else if (ie.id == ScanResult.InformationElement.EID_EXTENDED_CAPS) {
2012                extendedCaps.from(ie);
2013            }
2014        }
2015
2016        if (extendedCaps.is80211McRTTResponder) {
2017            result.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
2018        } else {
2019            result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER);
2020        }
2021
2022        //handle RTT related information
2023        if (vhtOperation.isValid()) {
2024            result.channelWidth = vhtOperation.getChannelWidth();
2025            result.centerFreq0 = vhtOperation.getCenterFreq0();
2026            result.centerFreq1 = vhtOperation.getCenterFreq1();
2027        } else {
2028            result.channelWidth = htOperation.getChannelWidth();
2029            result.centerFreq0 = htOperation.getCenterFreq0(result.frequency);
2030            result.centerFreq1  = 0;
2031        }
2032
2033        // build capabilities string
2034        BitSet beaconCapBits = new BitSet(16);
2035        for (int i = 0; i < 16; i++) {
2036            if ((beaconCap & (1 << i)) != 0) {
2037                beaconCapBits.set(i);
2038            }
2039        }
2040        result.capabilities = InformationElementUtil.Capabilities.buildCapabilities(elements,
2041                                               beaconCapBits);
2042
2043        if(DBG) {
2044            Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth
2045                    + " PrimaryFreq: " + result.frequency + " mCenterfreq0: " + result.centerFreq0
2046                    + " mCenterfreq1: " + result.centerFreq1 + (extendedCaps.is80211McRTTResponder
2047                    ? "Support RTT reponder: " : "Do not support RTT responder")
2048                    + " Capabilities: " + result.capabilities);
2049        }
2050
2051        result.informationElements = elements;
2052    }
2053
2054    // Callback from native
2055    private static void onFullScanResult(int id, ScanResult result,
2056            int bucketsScanned, int beaconCap) {
2057        if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID);
2058
2059        ScanEventHandler handler = sScanEventHandler;
2060        if (handler != null) {
2061            populateScanResult(result, beaconCap, " onFullScanResult ");
2062            handler.onFullScanResult(result);
2063        }
2064    }
2065
2066    private static int sScanCmdId = 0;
2067    private static ScanEventHandler sScanEventHandler;
2068    private static ScanSettings sScanSettings;
2069
2070    public boolean startScan(ScanSettings settings, ScanEventHandler eventHandler) {
2071        synchronized (sLock) {
2072            if (isHalStarted()) {
2073                if (sScanCmdId != 0) {
2074                    stopScan();
2075                } else if (sScanSettings != null || sScanEventHandler != null) {
2076                /* current scan is paused; no need to stop it */
2077                }
2078
2079                sScanCmdId = getNewCmdIdLocked();
2080
2081                sScanSettings = settings;
2082                sScanEventHandler = eventHandler;
2083
2084                if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) {
2085                    sScanEventHandler = null;
2086                    sScanSettings = null;
2087                    sScanCmdId = 0;
2088                    return false;
2089                }
2090
2091                return true;
2092            } else {
2093                return false;
2094            }
2095        }
2096    }
2097
2098    public void stopScan() {
2099        synchronized (sLock) {
2100            if (isHalStarted()) {
2101                if (sScanCmdId != 0) {
2102                    stopScanNative(sWlan0Index, sScanCmdId);
2103                }
2104                sScanSettings = null;
2105                sScanEventHandler = null;
2106                sScanCmdId = 0;
2107            }
2108        }
2109    }
2110
2111    public void pauseScan() {
2112        synchronized (sLock) {
2113            if (isHalStarted()) {
2114                if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) {
2115                    Log.d(TAG, "Pausing scan");
2116                    WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true);
2117                    stopScanNative(sWlan0Index, sScanCmdId);
2118                    sScanCmdId = 0;
2119                    sScanEventHandler.onScanPaused(scanData);
2120                }
2121            }
2122        }
2123    }
2124
2125    public void restartScan() {
2126        synchronized (sLock) {
2127            if (isHalStarted()) {
2128                if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) {
2129                    Log.d(TAG, "Restarting scan");
2130                    ScanEventHandler handler = sScanEventHandler;
2131                    ScanSettings settings = sScanSettings;
2132                    if (startScan(sScanSettings, sScanEventHandler)) {
2133                        sScanEventHandler.onScanRestarted();
2134                    } else {
2135                    /* we are still paused; don't change state */
2136                        sScanEventHandler = handler;
2137                        sScanSettings = settings;
2138                    }
2139                }
2140            }
2141        }
2142    }
2143
2144    public WifiScanner.ScanData[] getScanResults(boolean flush) {
2145        synchronized (sLock) {
2146            WifiScanner.ScanData[] sd = null;
2147            if (isHalStarted()) {
2148                sd = getScanResultsNative(sWlan0Index, flush);
2149            }
2150
2151            if (sd != null) {
2152                return sd;
2153            } else {
2154                return new WifiScanner.ScanData[0];
2155            }
2156        }
2157    }
2158
2159    public static interface HotlistEventHandler {
2160        void onHotlistApFound (ScanResult[] result);
2161        void onHotlistApLost  (ScanResult[] result);
2162    }
2163
2164    private static int sHotlistCmdId = 0;
2165    private static HotlistEventHandler sHotlistEventHandler;
2166
2167    private native static boolean setHotlistNative(int iface, int id,
2168            WifiScanner.HotlistSettings settings);
2169    private native static boolean resetHotlistNative(int iface, int id);
2170
2171    public boolean setHotlist(WifiScanner.HotlistSettings settings,
2172            HotlistEventHandler eventHandler) {
2173        synchronized (sLock) {
2174            if (isHalStarted()) {
2175                if (sHotlistCmdId != 0) {
2176                    return false;
2177                } else {
2178                    sHotlistCmdId = getNewCmdIdLocked();
2179                }
2180
2181                sHotlistEventHandler = eventHandler;
2182                if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) {
2183                    sHotlistEventHandler = null;
2184                    return false;
2185                }
2186
2187                return true;
2188            } else {
2189                return false;
2190            }
2191        }
2192    }
2193
2194    public void resetHotlist() {
2195        synchronized (sLock) {
2196            if (isHalStarted()) {
2197                if (sHotlistCmdId != 0) {
2198                    resetHotlistNative(sWlan0Index, sHotlistCmdId);
2199                    sHotlistCmdId = 0;
2200                    sHotlistEventHandler = null;
2201                }
2202            }
2203        }
2204    }
2205
2206    // Callback from native
2207    private static void onHotlistApFound(int id, ScanResult[] results) {
2208        HotlistEventHandler handler = sHotlistEventHandler;
2209        if (handler != null) {
2210            handler.onHotlistApFound(results);
2211        } else {
2212            /* this can happen because of race conditions */
2213            Log.d(TAG, "Ignoring hotlist AP found event");
2214        }
2215    }
2216
2217    // Callback from native
2218    private static void onHotlistApLost(int id, ScanResult[] results) {
2219        HotlistEventHandler handler = sHotlistEventHandler;
2220        if (handler != null) {
2221            handler.onHotlistApLost(results);
2222        } else {
2223            /* this can happen because of race conditions */
2224            Log.d(TAG, "Ignoring hotlist AP lost event");
2225        }
2226    }
2227
2228    public static interface SignificantWifiChangeEventHandler {
2229        void onChangesFound(ScanResult[] result);
2230    }
2231
2232    private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler;
2233    private static int sSignificantWifiChangeCmdId;
2234
2235    private static native boolean trackSignificantWifiChangeNative(
2236            int iface, int id, WifiScanner.WifiChangeSettings settings);
2237    private static native boolean untrackSignificantWifiChangeNative(int iface, int id);
2238
2239    public boolean trackSignificantWifiChange(
2240            WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
2241        synchronized (sLock) {
2242            if (isHalStarted()) {
2243                if (sSignificantWifiChangeCmdId != 0) {
2244                    return false;
2245                } else {
2246                    sSignificantWifiChangeCmdId = getNewCmdIdLocked();
2247                }
2248
2249                sSignificantWifiChangeHandler = handler;
2250                if (trackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId,
2251                        settings) == false) {
2252                    sSignificantWifiChangeHandler = null;
2253                    return false;
2254                }
2255
2256                return true;
2257            } else {
2258                return false;
2259            }
2260
2261        }
2262    }
2263
2264    public void untrackSignificantWifiChange() {
2265        synchronized (sLock) {
2266            if (isHalStarted()) {
2267                if (sSignificantWifiChangeCmdId != 0) {
2268                    untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId);
2269                    sSignificantWifiChangeCmdId = 0;
2270                    sSignificantWifiChangeHandler = null;
2271                }
2272            }
2273        }
2274    }
2275
2276    // Callback from native
2277    private static void onSignificantWifiChange(int id, ScanResult[] results) {
2278        SignificantWifiChangeEventHandler handler = sSignificantWifiChangeHandler;
2279        if (handler != null) {
2280            handler.onChangesFound(results);
2281        } else {
2282            /* this can happen because of race conditions */
2283            Log.d(TAG, "Ignoring significant wifi change");
2284        }
2285    }
2286
2287    public WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
2288        // TODO: use correct iface name to Index translation
2289        if (iface == null) return null;
2290        synchronized (sLock) {
2291            if (isHalStarted()) {
2292                return getWifiLinkLayerStatsNative(sWlan0Index);
2293            } else {
2294                return null;
2295            }
2296        }
2297    }
2298
2299    public void setWifiLinkLayerStats(String iface, int enable) {
2300        if (iface == null) return;
2301        synchronized (sLock) {
2302            if (isHalStarted()) {
2303                setWifiLinkLayerStatsNative(sWlan0Index, enable);
2304            }
2305        }
2306    }
2307
2308    public static native int getSupportedFeatureSetNative(int iface);
2309    public int getSupportedFeatureSet() {
2310        synchronized (sLock) {
2311            if (isHalStarted()) {
2312                return getSupportedFeatureSetNative(sWlan0Index);
2313            } else {
2314                Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started");
2315                return 0;
2316            }
2317        }
2318    }
2319
2320    /* Rtt related commands/events */
2321    public static interface RttEventHandler {
2322        void onRttResults(RttManager.RttResult[] result);
2323    }
2324
2325    private static RttEventHandler sRttEventHandler;
2326    private static int sRttCmdId;
2327
2328    // Callback from native
2329    private static void onRttResults(int id, RttManager.RttResult[] results) {
2330        RttEventHandler handler = sRttEventHandler;
2331        if (handler != null && id == sRttCmdId) {
2332            Log.d(TAG, "Received " + results.length + " rtt results");
2333            handler.onRttResults(results);
2334            sRttCmdId = 0;
2335        } else {
2336            Log.d(TAG, "RTT Received event for unknown cmd = " + id +
2337                    ", current id = " + sRttCmdId);
2338        }
2339    }
2340
2341    private static native boolean requestRangeNative(
2342            int iface, int id, RttManager.RttParams[] params);
2343    private static native boolean cancelRangeRequestNative(
2344            int iface, int id, RttManager.RttParams[] params);
2345
2346    public boolean requestRtt(
2347            RttManager.RttParams[] params, RttEventHandler handler) {
2348        synchronized (sLock) {
2349            if (isHalStarted()) {
2350                if (sRttCmdId != 0) {
2351                    Log.v("TAG", "Last one is still under measurement!");
2352                    return false;
2353                } else {
2354                    sRttCmdId = getNewCmdIdLocked();
2355                }
2356                sRttEventHandler = handler;
2357                Log.v(TAG, "native issue RTT request");
2358                return requestRangeNative(sWlan0Index, sRttCmdId, params);
2359            } else {
2360                return false;
2361            }
2362        }
2363    }
2364
2365    public boolean cancelRtt(RttManager.RttParams[] params) {
2366        synchronized (sLock) {
2367            if (isHalStarted()) {
2368                if (sRttCmdId == 0) {
2369                    return false;
2370                }
2371
2372                sRttCmdId = 0;
2373
2374                if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) {
2375                    sRttEventHandler = null;
2376                    Log.v(TAG, "RTT cancel Request Successfully");
2377                    return true;
2378                } else {
2379                    Log.e(TAG, "RTT cancel Request failed");
2380                    return false;
2381                }
2382            } else {
2383                return false;
2384            }
2385        }
2386    }
2387
2388    private static int sRttResponderCmdId = 0;
2389
2390    private static native ResponderConfig enableRttResponderNative(int iface, int commandId,
2391            int timeoutSeconds, WifiChannelInfo channelHint);
2392    /**
2393     * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder
2394     * role is successfully enabled, {@code null} otherwise.
2395     */
2396    @Nullable
2397    public ResponderConfig enableRttResponder(int timeoutSeconds) {
2398        synchronized (sLock) {
2399            if (!isHalStarted()) return null;
2400            if (sRttResponderCmdId != 0) {
2401                if (DBG) Log.e(mTAG, "responder mode already enabled - this shouldn't happen");
2402                return null;
2403            }
2404            int id = getNewCmdIdLocked();
2405            ResponderConfig config = enableRttResponderNative(
2406                    sWlan0Index, id, timeoutSeconds, null);
2407            if (config != null) sRttResponderCmdId = id;
2408            if (DBG) Log.d(TAG, "enabling rtt " + (config != null));
2409            return config;
2410        }
2411    }
2412
2413    private static native boolean disableRttResponderNative(int iface, int commandId);
2414    /**
2415     * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled,
2416     * {@code false} otherwise.
2417     */
2418    public boolean disableRttResponder() {
2419        synchronized (sLock) {
2420            if (!isHalStarted()) return false;
2421            if (sRttResponderCmdId == 0) {
2422                Log.e(mTAG, "responder role not enabled yet");
2423                return true;
2424            }
2425            sRttResponderCmdId = 0;
2426            return disableRttResponderNative(sWlan0Index, sRttResponderCmdId);
2427        }
2428    }
2429
2430    private static native boolean setScanningMacOuiNative(int iface, byte[] oui);
2431
2432    public boolean setScanningMacOui(byte[] oui) {
2433        synchronized (sLock) {
2434            if (isHalStarted()) {
2435                return setScanningMacOuiNative(sWlan0Index, oui);
2436            } else {
2437                return false;
2438            }
2439        }
2440    }
2441
2442    private static native int[] getChannelsForBandNative(
2443            int iface, int band);
2444
2445    public int [] getChannelsForBand(int band) {
2446        synchronized (sLock) {
2447            if (isHalStarted()) {
2448                return getChannelsForBandNative(sWlan0Index, band);
2449            } else {
2450                return null;
2451            }
2452        }
2453    }
2454
2455    private static native boolean isGetChannelsForBandSupportedNative();
2456    public boolean isGetChannelsForBandSupported(){
2457        synchronized (sLock) {
2458            if (isHalStarted()) {
2459                return isGetChannelsForBandSupportedNative();
2460            } else {
2461                return false;
2462            }
2463        }
2464    }
2465
2466    private static native boolean setDfsFlagNative(int iface, boolean dfsOn);
2467    public boolean setDfsFlag(boolean dfsOn) {
2468        synchronized (sLock) {
2469            if (isHalStarted()) {
2470                return setDfsFlagNative(sWlan0Index, dfsOn);
2471            } else {
2472                return false;
2473            }
2474        }
2475    }
2476
2477    private static native boolean setInterfaceUpNative(String interfaceName, boolean up);
2478    public boolean setInterfaceUp(boolean up) {
2479        synchronized (sLock) {
2480            if (isHalStarted()) {
2481                return setInterfaceUpNative(mInterfaceName, up);
2482            } else {
2483                return false;
2484            }
2485        }
2486    }
2487
2488    private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface);
2489    public RttManager.RttCapabilities getRttCapabilities() {
2490        synchronized (sLock) {
2491            if (isHalStarted()) {
2492                return getRttCapabilitiesNative(sWlan0Index);
2493            } else {
2494                return null;
2495            }
2496        }
2497    }
2498
2499    public static final class PacketFilterCapabilities {
2500        /**
2501         * Version of APF instruction set supported for packet filtering.  0 indicates no support for
2502         * packet filtering using APF programs.
2503         */
2504        public int apfVersionSupported;
2505
2506        /**
2507         * Maximum size of APF program allowed.
2508         */
2509        public int maximumApfProgramSize;
2510    }
2511    private static native PacketFilterCapabilities getPacketFilterCapabilitiesNative(int iface);
2512    public PacketFilterCapabilities getPacketFilterCapabilities() {
2513        synchronized (sLock) {
2514            if (isHalStarted()) {
2515                return getPacketFilterCapabilitiesNative(sWlan0Index);
2516            } else {
2517                return null;
2518            }
2519        }
2520    }
2521
2522    private static native boolean installPacketFilterNative(int iface, byte[] filter);
2523    public boolean installPacketFilter(byte[] filter) {
2524        synchronized (sLock) {
2525            if (isHalStarted()) {
2526                return installPacketFilterNative(sWlan0Index, filter);
2527            } else {
2528                return false;
2529            }
2530        }
2531    }
2532
2533    private static native boolean setCountryCodeHalNative(int iface, String CountryCode);
2534    public boolean setCountryCodeHal(String CountryCode) {
2535        synchronized (sLock) {
2536            if (isHalStarted()) {
2537                return setCountryCodeHalNative(sWlan0Index, CountryCode);
2538            } else {
2539                return false;
2540            }
2541        }
2542    }
2543
2544    /* Rtt related commands/events */
2545    public abstract class TdlsEventHandler {
2546        abstract public void onTdlsStatus(String macAddr, int status, int reason);
2547    }
2548
2549    private static TdlsEventHandler sTdlsEventHandler;
2550
2551    private static native boolean enableDisableTdlsNative(int iface, boolean enable,
2552            String macAddr);
2553    public boolean enableDisableTdls(boolean enable, String macAdd, TdlsEventHandler tdlsCallBack) {
2554        synchronized (sLock) {
2555            sTdlsEventHandler = tdlsCallBack;
2556            return enableDisableTdlsNative(sWlan0Index, enable, macAdd);
2557        }
2558    }
2559
2560    // Once TDLS per mac and event feature is implemented, this class definition should be
2561    // moved to the right place, like WifiManager etc
2562    public static class TdlsStatus {
2563        int channel;
2564        int global_operating_class;
2565        int state;
2566        int reason;
2567    }
2568    private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr);
2569    public TdlsStatus getTdlsStatus(String macAdd) {
2570        synchronized (sLock) {
2571            if (isHalStarted()) {
2572                return getTdlsStatusNative(sWlan0Index, macAdd);
2573            } else {
2574                return null;
2575            }
2576        }
2577    }
2578
2579    //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be
2580    // moved to the right place, like WifiStateMachine etc
2581    public static class TdlsCapabilities {
2582        /* Maximum TDLS session number can be supported by the Firmware and hardware */
2583        int maxConcurrentTdlsSessionNumber;
2584        boolean isGlobalTdlsSupported;
2585        boolean isPerMacTdlsSupported;
2586        boolean isOffChannelTdlsSupported;
2587    }
2588
2589
2590
2591    private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface);
2592    public TdlsCapabilities getTdlsCapabilities () {
2593        synchronized (sLock) {
2594            if (isHalStarted()) {
2595                return getTdlsCapabilitiesNative(sWlan0Index);
2596            } else {
2597                return null;
2598            }
2599        }
2600    }
2601
2602    private static boolean onTdlsStatus(String macAddr, int status, int reason) {
2603        TdlsEventHandler handler = sTdlsEventHandler;
2604        if (handler == null) {
2605            return false;
2606        } else {
2607            handler.onTdlsStatus(macAddr, status, reason);
2608            return true;
2609        }
2610    }
2611
2612    //---------------------------------------------------------------------------------
2613
2614    /* Wifi Logger commands/events */
2615
2616    public static interface WifiLoggerEventHandler {
2617        void onRingBufferData(RingBufferStatus status, byte[] buffer);
2618        void onWifiAlert(int errorCode, byte[] buffer);
2619    }
2620
2621    private static WifiLoggerEventHandler sWifiLoggerEventHandler = null;
2622
2623    // Callback from native
2624    private static void onRingBufferData(RingBufferStatus status, byte[] buffer) {
2625        WifiLoggerEventHandler handler = sWifiLoggerEventHandler;
2626        if (handler != null)
2627            handler.onRingBufferData(status, buffer);
2628    }
2629
2630    // Callback from native
2631    private static void onWifiAlert(byte[] buffer, int errorCode) {
2632        WifiLoggerEventHandler handler = sWifiLoggerEventHandler;
2633        if (handler != null)
2634            handler.onWifiAlert(errorCode, buffer);
2635    }
2636
2637    private static int sLogCmdId = -1;
2638    private static native boolean setLoggingEventHandlerNative(int iface, int id);
2639    public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
2640        synchronized (sLock) {
2641            if (isHalStarted()) {
2642                int oldId =  sLogCmdId;
2643                sLogCmdId = getNewCmdIdLocked();
2644                if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) {
2645                    sLogCmdId = oldId;
2646                    return false;
2647                }
2648                sWifiLoggerEventHandler = handler;
2649                return true;
2650            } else {
2651                return false;
2652            }
2653        }
2654    }
2655
2656    private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel,
2657            int flags, int minIntervalSec ,int minDataSize, String ringName);
2658    public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
2659            int minDataSize, String ringName){
2660        synchronized (sLock) {
2661            if (isHalStarted()) {
2662                return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval,
2663                        minDataSize, ringName);
2664            } else {
2665                return false;
2666            }
2667        }
2668    }
2669
2670    private static native int getSupportedLoggerFeatureSetNative(int iface);
2671    public int getSupportedLoggerFeatureSet() {
2672        synchronized (sLock) {
2673            if (isHalStarted()) {
2674                return getSupportedLoggerFeatureSetNative(sWlan0Index);
2675            } else {
2676                return 0;
2677            }
2678        }
2679    }
2680
2681    private static native boolean resetLogHandlerNative(int iface, int id);
2682    public boolean resetLogHandler() {
2683        synchronized (sLock) {
2684            if (isHalStarted()) {
2685                if (sLogCmdId == -1) {
2686                    Log.e(TAG,"Can not reset handler Before set any handler");
2687                    return false;
2688                }
2689                sWifiLoggerEventHandler = null;
2690                if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) {
2691                    sLogCmdId = -1;
2692                    return true;
2693                } else {
2694                    return false;
2695                }
2696            } else {
2697                return false;
2698            }
2699        }
2700    }
2701
2702    private static native String getDriverVersionNative(int iface);
2703    public String getDriverVersion() {
2704        synchronized (sLock) {
2705            if (isHalStarted()) {
2706                return getDriverVersionNative(sWlan0Index);
2707            } else {
2708                return "";
2709            }
2710        }
2711    }
2712
2713
2714    private static native String getFirmwareVersionNative(int iface);
2715    public String getFirmwareVersion() {
2716        synchronized (sLock) {
2717            if (isHalStarted()) {
2718                return getFirmwareVersionNative(sWlan0Index);
2719            } else {
2720                return "";
2721            }
2722        }
2723    }
2724
2725    public static class RingBufferStatus{
2726        String name;
2727        int flag;
2728        int ringBufferId;
2729        int ringBufferByteSize;
2730        int verboseLevel;
2731        int writtenBytes;
2732        int readBytes;
2733        int writtenRecords;
2734
2735        @Override
2736        public String toString() {
2737            return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
2738                    " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
2739                    " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
2740                    " writtenRecords: " + writtenRecords;
2741        }
2742    }
2743
2744    private static native RingBufferStatus[] getRingBufferStatusNative(int iface);
2745    public RingBufferStatus[] getRingBufferStatus() {
2746        synchronized (sLock) {
2747            if (isHalStarted()) {
2748                return getRingBufferStatusNative(sWlan0Index);
2749            } else {
2750                return null;
2751            }
2752        }
2753    }
2754
2755    private static native boolean getRingBufferDataNative(int iface, String ringName);
2756    public boolean getRingBufferData(String ringName) {
2757        synchronized (sLock) {
2758            if (isHalStarted()) {
2759                return getRingBufferDataNative(sWlan0Index, ringName);
2760            } else {
2761                return false;
2762            }
2763        }
2764    }
2765
2766    private static byte[] mFwMemoryDump;
2767    // Callback from native
2768    private static void onWifiFwMemoryAvailable(byte[] buffer) {
2769        mFwMemoryDump = buffer;
2770        if (DBG) {
2771            Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " +
2772                    (buffer == null ? 0 :  buffer.length));
2773        }
2774    }
2775
2776    private static native boolean getFwMemoryDumpNative(int iface);
2777    public byte[] getFwMemoryDump() {
2778        synchronized (sLock) {
2779            if (isHalStarted()) {
2780                if(getFwMemoryDumpNative(sWlan0Index)) {
2781                    byte[] fwMemoryDump = mFwMemoryDump;
2782                    mFwMemoryDump = null;
2783                    return fwMemoryDump;
2784                } else {
2785                    return null;
2786                }
2787            }
2788            return null;
2789        }
2790    }
2791
2792    //---------------------------------------------------------------------------------
2793    /* Configure ePNO/PNO */
2794    private static PnoEventHandler sPnoEventHandler;
2795    private static int sPnoCmdId = 0;
2796
2797    private static native boolean setPnoListNative(int iface, int id, PnoSettings settings);
2798
2799    /**
2800     * Set the PNO settings & the network list in HAL to start PNO.
2801     * @param settings PNO settings and network list.
2802     * @param eventHandler Handler to receive notifications back during PNO scan.
2803     * @return true if success, false otherwise
2804     */
2805    public boolean setPnoList(PnoSettings settings, PnoEventHandler eventHandler) {
2806        Log.e(TAG, "setPnoList cmd " + sPnoCmdId);
2807
2808        synchronized (sLock) {
2809            if (isHalStarted()) {
2810                sPnoCmdId = getNewCmdIdLocked();
2811                sPnoEventHandler = eventHandler;
2812                if (setPnoListNative(sWlan0Index, sPnoCmdId, settings)) {
2813                    return true;
2814                }
2815            }
2816            sPnoEventHandler = null;
2817            return false;
2818        }
2819    }
2820
2821    /**
2822     * Set the PNO network list in HAL to start PNO.
2823     * @param list PNO network list.
2824     * @param eventHandler Handler to receive notifications back during PNO scan.
2825     * @return true if success, false otherwise
2826     */
2827    public boolean setPnoList(PnoNetwork[] list, PnoEventHandler eventHandler) {
2828        PnoSettings settings = new PnoSettings();
2829        settings.networkList = list;
2830        return setPnoList(settings, eventHandler);
2831    }
2832
2833    private static native boolean resetPnoListNative(int iface, int id);
2834
2835    /**
2836     * Reset the PNO settings in HAL to stop PNO.
2837     * @return true if success, false otherwise
2838     */
2839    public boolean resetPnoList() {
2840        Log.e(TAG, "resetPnoList cmd " + sPnoCmdId);
2841
2842        synchronized (sLock) {
2843            if (isHalStarted()) {
2844                sPnoCmdId = getNewCmdIdLocked();
2845                sPnoEventHandler = null;
2846                if (resetPnoListNative(sWlan0Index, sPnoCmdId)) {
2847                    return true;
2848                }
2849            }
2850            return false;
2851        }
2852    }
2853
2854    // Callback from native
2855    private static void onPnoNetworkFound(int id, ScanResult[] results, int[] beaconCaps) {
2856        if (results == null) {
2857            Log.e(TAG, "onPnoNetworkFound null results");
2858            return;
2859
2860        }
2861        Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length);
2862
2863        PnoEventHandler handler = sPnoEventHandler;
2864        if (sPnoCmdId != 0 && handler != null) {
2865            for (int i=0; i<results.length; i++) {
2866                Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID
2867                        + " " + results[i].level + " " + results[i].frequency);
2868
2869                populateScanResult(results[i], beaconCaps[i], "onPnoNetworkFound ");
2870                results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID);
2871            }
2872
2873            handler.onPnoNetworkFound(results);
2874        } else {
2875            /* this can happen because of race conditions */
2876            Log.d(TAG, "Ignoring Pno Network found event");
2877        }
2878    }
2879
2880    private native static boolean setBssidBlacklistNative(int iface, int id,
2881                                              String list[]);
2882
2883    public boolean setBssidBlacklist(String list[]) {
2884        int size = 0;
2885        if (list != null) {
2886            size = list.length;
2887        }
2888        Log.e(TAG, "setBssidBlacklist cmd " + sPnoCmdId + " size " + size);
2889
2890        synchronized (sLock) {
2891            if (isHalStarted()) {
2892                sPnoCmdId = getNewCmdIdLocked();
2893                return setBssidBlacklistNative(sWlan0Index, sPnoCmdId, list);
2894            } else {
2895                return false;
2896            }
2897        }
2898    }
2899
2900    private native static int startSendingOffloadedPacketNative(int iface, int idx,
2901                                    byte[] srcMac, byte[] dstMac, byte[] pktData, int period);
2902
2903    public int
2904    startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) {
2905        Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period);
2906
2907        String[] macAddrStr = getMacAddress().split(":");
2908        byte[] srcMac = new byte[6];
2909        for(int i = 0; i < 6; i++) {
2910            Integer hexVal = Integer.parseInt(macAddrStr[i], 16);
2911            srcMac[i] = hexVal.byteValue();
2912        }
2913        synchronized (sLock) {
2914            if (isHalStarted()) {
2915                return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac,
2916                        keepAlivePacket.dstMac, keepAlivePacket.data, period);
2917            } else {
2918                return -1;
2919            }
2920        }
2921    }
2922
2923    private native static int stopSendingOffloadedPacketNative(int iface, int idx);
2924
2925    public int
2926    stopSendingOffloadedPacket(int slot) {
2927        Log.d(TAG, "stopSendingOffloadedPacket " + slot);
2928        synchronized (sLock) {
2929            if (isHalStarted()) {
2930                return stopSendingOffloadedPacketNative(sWlan0Index, slot);
2931            } else {
2932                return -1;
2933            }
2934        }
2935    }
2936
2937    public static interface WifiRssiEventHandler {
2938        void onRssiThresholdBreached(byte curRssi);
2939    }
2940
2941    private static WifiRssiEventHandler sWifiRssiEventHandler;
2942
2943    // Callback from native
2944    private static void onRssiThresholdBreached(int id, byte curRssi) {
2945        WifiRssiEventHandler handler = sWifiRssiEventHandler;
2946        if (handler != null) {
2947            handler.onRssiThresholdBreached(curRssi);
2948        }
2949    }
2950
2951    private native static int startRssiMonitoringNative(int iface, int id,
2952                                        byte maxRssi, byte minRssi);
2953
2954    private static int sRssiMonitorCmdId = 0;
2955
2956    public int startRssiMonitoring(byte maxRssi, byte minRssi,
2957                                                WifiRssiEventHandler rssiEventHandler) {
2958        Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi);
2959        synchronized (sLock) {
2960            sWifiRssiEventHandler = rssiEventHandler;
2961            if (isHalStarted()) {
2962                if (sRssiMonitorCmdId != 0) {
2963                    stopRssiMonitoring();
2964                }
2965
2966                sRssiMonitorCmdId = getNewCmdIdLocked();
2967                Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId);
2968                int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId,
2969                        maxRssi, minRssi);
2970                if (ret != 0) { // if not success
2971                    sRssiMonitorCmdId = 0;
2972                }
2973                return ret;
2974            } else {
2975                return -1;
2976            }
2977        }
2978    }
2979
2980    private native static int stopRssiMonitoringNative(int iface, int idx);
2981
2982    public int stopRssiMonitoring() {
2983        Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId);
2984        synchronized (sLock) {
2985            if (isHalStarted()) {
2986                int ret = 0;
2987                if (sRssiMonitorCmdId != 0) {
2988                    ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId);
2989                }
2990                sRssiMonitorCmdId = 0;
2991                return ret;
2992            } else {
2993                return -1;
2994            }
2995        }
2996    }
2997
2998    private static native WifiWakeReasonAndCounts getWlanWakeReasonCountNative(int iface);
2999
3000    /**
3001     * Fetch the host wakeup reasons stats from wlan driver.
3002     * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver.
3003     */
3004    public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
3005        Log.d(TAG, "getWlanWakeReasonCount " + sWlan0Index);
3006        synchronized (sLock) {
3007            if (isHalStarted()) {
3008                return getWlanWakeReasonCountNative(sWlan0Index);
3009            } else {
3010                return null;
3011            }
3012        }
3013    }
3014
3015    private static native int configureNeighborDiscoveryOffload(int iface, boolean enabled);
3016
3017    public boolean configureNeighborDiscoveryOffload(boolean enabled) {
3018        final String logMsg =  "configureNeighborDiscoveryOffload(" + enabled + ")";
3019        Log.d(mTAG, logMsg);
3020        synchronized (sLock) {
3021            if (isHalStarted()) {
3022                final int ret = configureNeighborDiscoveryOffload(sWlan0Index, enabled);
3023                if (ret != 0) {
3024                    Log.d(mTAG, logMsg + " returned: " + ret);
3025                }
3026                return (ret == 0);
3027            }
3028        }
3029        return false;
3030    }
3031}
3032