WifiNative.java revision af2b79e4cfc1da793b3d8fb4a96c144deefc7d58
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        final Object mPnoLock = new Object();
943        private final AlarmManager mAlarmManager =
944                (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
945        private final PendingIntent mPnoIntent;
946
947        public PnoMonitor() {
948            Intent intent = new Intent(ACTION_TOGGLE_PNO, null);
949            intent.setPackage("android");
950            mPnoIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
951
952            mContext.registerReceiver(
953                new BroadcastReceiver() {
954                    @Override
955                    public void onReceive(Context context, Intent intent) {
956                        synchronized(mPnoLock) {
957                            if (DBG) Log.d(mTAG, "PNO timer expire, PNO should change to " +
958                                    mExpectedPnoState);
959                            if (mCurrentPnoState != mExpectedPnoState) {
960                                if (DBG) Log.d(mTAG, "change PNO from " + mCurrentPnoState + " to "
961                                        + mExpectedPnoState);
962                                boolean ret = setPno(
963                                        mExpectedPnoState, mExpectedPnoNetworkList);
964                                if (!ret) {
965                                    Log.e(mTAG, "set PNO failure");
966                                }
967                            } else {
968                                if (DBG) Log.d(mTAG, "Do not change PNO since current is expected");
969                            }
970                            mWaitForTimer = false;
971                        }
972                    }
973                },
974                new IntentFilter(ACTION_TOGGLE_PNO));
975        }
976
977        /**
978         * Enable/Disable PNO with updated network priorities.
979         * @param enable boolean indicating whether PNO is being enabled or disabled.
980         * @param pnoNetworkList list of networks with priorities to be set before PNO setting.
981         */
982        private boolean setPno(boolean enable, List<PnoNetwork> pnoNetworkList) {
983            // TODO: Couple of cases yet to be handled:
984            // 1. What if the network priority update fails, should we bail out of PNO setting?
985            // 2. If PNO setting fails below, should we go back and revert this priority change?
986            if (pnoNetworkList != null) {
987                if (DBG) Log.i(mTAG, "Update priorities for PNO. Enable: " + enable);
988                for (PnoNetwork pnoNetwork : pnoNetworkList) {
989                    // What if this fails? Should we bail out?
990                    boolean isSuccess = setNetworkVariable(pnoNetwork.networkId,
991                            WifiConfiguration.priorityVarName,
992                            Integer.toString(pnoNetwork.priority));
993                    if (!isSuccess) {
994                        Log.e(mTAG, "Update priority failed for :" + pnoNetwork.networkId);
995                    }
996                }
997            }
998            boolean ret = WifiNative.this.setPnoScan(enable);
999            mLastPnoChangeTimeStamp = System.currentTimeMillis();
1000            if (ret) {
1001                mCurrentPnoState = enable;
1002            }
1003            return ret;
1004        }
1005
1006        public boolean enableBackgroundScan(
1007                boolean enable,
1008                List<PnoNetwork> pnoNetworkList) {
1009            synchronized(mPnoLock) {
1010                if (mWaitForTimer) {
1011                    //already has a timer
1012                    mExpectedPnoState = enable;
1013                    mExpectedPnoNetworkList = pnoNetworkList;
1014                    if (DBG) Log.d(mTAG, "update expected PNO to " +  mExpectedPnoState);
1015                } else {
1016                    if (mCurrentPnoState == enable) {
1017                        return true;
1018                    }
1019                    long timeDifference = System.currentTimeMillis() - mLastPnoChangeTimeStamp;
1020                    if (timeDifference >= MINIMUM_PNO_GAP) {
1021                        return setPno(enable, pnoNetworkList);
1022                    } else {
1023                        mExpectedPnoState = enable;
1024                        mExpectedPnoNetworkList = pnoNetworkList;
1025                        mWaitForTimer = true;
1026                        if (DBG) Log.d(mTAG, "start PNO timer with delay:" + timeDifference);
1027                        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
1028                                System.currentTimeMillis() + timeDifference, mPnoIntent);
1029                    }
1030                }
1031                return true;
1032            }
1033        }
1034    }
1035
1036    public boolean enableBackgroundScan(
1037            boolean enable,
1038            List<PnoNetwork> pnoNetworkList) {
1039        if (mPnoMonitor != null) {
1040            return mPnoMonitor.enableBackgroundScan(enable, pnoNetworkList);
1041        } else {
1042            return false;
1043        }
1044    }
1045
1046    public void enableAutoConnect(boolean enable) {
1047        if (enable) {
1048            doBooleanCommand("STA_AUTOCONNECT 1");
1049        } else {
1050            doBooleanCommand("STA_AUTOCONNECT 0");
1051        }
1052    }
1053
1054    public void setScanInterval(int scanInterval) {
1055        doBooleanCommand("SCAN_INTERVAL " + scanInterval);
1056    }
1057
1058    public void setHs20(boolean hs20) {
1059        if (hs20) {
1060            doBooleanCommand("SET HS20 1");
1061        } else {
1062            doBooleanCommand("SET HS20 0");
1063        }
1064    }
1065
1066    public void startTdls(String macAddr, boolean enable) {
1067        if (enable) {
1068            synchronized (sLock) {
1069                doBooleanCommand("TDLS_DISCOVER " + macAddr);
1070                doBooleanCommand("TDLS_SETUP " + macAddr);
1071            }
1072        } else {
1073            doBooleanCommand("TDLS_TEARDOWN " + macAddr);
1074        }
1075    }
1076
1077    /** Example output:
1078     * RSSI=-65
1079     * LINKSPEED=48
1080     * NOISE=9999
1081     * FREQUENCY=0
1082     */
1083    public String signalPoll() {
1084        return doStringCommandWithoutLogging("SIGNAL_POLL");
1085    }
1086
1087    /** Example outout:
1088     * TXGOOD=396
1089     * TXBAD=1
1090     */
1091    public String pktcntPoll() {
1092        return doStringCommand("PKTCNT_POLL");
1093    }
1094
1095    public void bssFlush() {
1096        doBooleanCommand("BSS_FLUSH 0");
1097    }
1098
1099    public boolean startWpsPbc(String bssid) {
1100        if (TextUtils.isEmpty(bssid)) {
1101            return doBooleanCommand("WPS_PBC");
1102        } else {
1103            return doBooleanCommand("WPS_PBC " + bssid);
1104        }
1105    }
1106
1107    public boolean startWpsPbc(String iface, String bssid) {
1108        synchronized (sLock) {
1109            if (TextUtils.isEmpty(bssid)) {
1110                return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
1111            } else {
1112                return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
1113            }
1114        }
1115    }
1116
1117    public boolean startWpsPinKeypad(String pin) {
1118        if (TextUtils.isEmpty(pin)) return false;
1119        return doBooleanCommand("WPS_PIN any " + pin);
1120    }
1121
1122    public boolean startWpsPinKeypad(String iface, String pin) {
1123        if (TextUtils.isEmpty(pin)) return false;
1124        synchronized (sLock) {
1125            return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
1126        }
1127    }
1128
1129
1130    public String startWpsPinDisplay(String bssid) {
1131        if (TextUtils.isEmpty(bssid)) {
1132            return doStringCommand("WPS_PIN any");
1133        } else {
1134            return doStringCommand("WPS_PIN " + bssid);
1135        }
1136    }
1137
1138    public String startWpsPinDisplay(String iface, String bssid) {
1139        synchronized (sLock) {
1140            if (TextUtils.isEmpty(bssid)) {
1141                return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
1142            } else {
1143                return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
1144            }
1145        }
1146    }
1147
1148    public boolean setExternalSim(boolean external) {
1149        String value = external ? "1" : "0";
1150        Log.d(TAG, "Setting external_sim to " + value);
1151        return doBooleanCommand("SET external_sim " + value);
1152    }
1153
1154    public boolean simAuthResponse(int id, String type, String response) {
1155        // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS
1156        return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response);
1157    }
1158
1159    public boolean simAuthFailedResponse(int id) {
1160        // should be used with type GSM-AUTH
1161        return doBooleanCommand("CTRL-RSP-SIM-" + id + ":GSM-FAIL");
1162    }
1163
1164    public boolean umtsAuthFailedResponse(int id) {
1165        // should be used with type UMTS-AUTH
1166        return doBooleanCommand("CTRL-RSP-SIM-" + id + ":UMTS-FAIL");
1167    }
1168
1169    public boolean simIdentityResponse(int id, String response) {
1170        return doBooleanCommand("CTRL-RSP-IDENTITY-" + id + ":" + response);
1171    }
1172
1173    /* Configures an access point connection */
1174    public boolean startWpsRegistrar(String bssid, String pin) {
1175        if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false;
1176        return doBooleanCommand("WPS_REG " + bssid + " " + pin);
1177    }
1178
1179    public boolean cancelWps() {
1180        return doBooleanCommand("WPS_CANCEL");
1181    }
1182
1183    public boolean setPersistentReconnect(boolean enabled) {
1184        int value = (enabled == true) ? 1 : 0;
1185        return doBooleanCommand("SET persistent_reconnect " + value);
1186    }
1187
1188    public boolean setDeviceName(String name) {
1189        return doBooleanCommand("SET device_name " + name);
1190    }
1191
1192    public boolean setDeviceType(String type) {
1193        return doBooleanCommand("SET device_type " + type);
1194    }
1195
1196    public boolean setConfigMethods(String cfg) {
1197        return doBooleanCommand("SET config_methods " + cfg);
1198    }
1199
1200    public boolean setManufacturer(String value) {
1201        return doBooleanCommand("SET manufacturer " + value);
1202    }
1203
1204    public boolean setModelName(String value) {
1205        return doBooleanCommand("SET model_name " + value);
1206    }
1207
1208    public boolean setModelNumber(String value) {
1209        return doBooleanCommand("SET model_number " + value);
1210    }
1211
1212    public boolean setSerialNumber(String value) {
1213        return doBooleanCommand("SET serial_number " + value);
1214    }
1215
1216    public boolean setP2pSsidPostfix(String postfix) {
1217        return doBooleanCommand("SET p2p_ssid_postfix " + postfix);
1218    }
1219
1220    public boolean setP2pGroupIdle(String iface, int time) {
1221        synchronized (sLock) {
1222            return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
1223        }
1224    }
1225
1226    public void setPowerSave(boolean enabled) {
1227        if (enabled) {
1228            doBooleanCommand("SET ps 1");
1229        } else {
1230            doBooleanCommand("SET ps 0");
1231        }
1232    }
1233
1234    public boolean setP2pPowerSave(String iface, boolean enabled) {
1235        synchronized (sLock) {
1236            if (enabled) {
1237                return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
1238            } else {
1239                return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
1240            }
1241        }
1242    }
1243
1244    public boolean setWfdEnable(boolean enable) {
1245        return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0"));
1246    }
1247
1248    public boolean setWfdDeviceInfo(String hex) {
1249        return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex);
1250    }
1251
1252    /**
1253     * "sta" prioritizes STA connection over P2P and "p2p" prioritizes
1254     * P2P connection over STA
1255     */
1256    public boolean setConcurrencyPriority(String s) {
1257        return doBooleanCommand("P2P_SET conc_pref " + s);
1258    }
1259
1260    public boolean p2pFind() {
1261        return doBooleanCommand("P2P_FIND");
1262    }
1263
1264    public boolean p2pFind(int timeout) {
1265        if (timeout <= 0) {
1266            return p2pFind();
1267        }
1268        return doBooleanCommand("P2P_FIND " + timeout);
1269    }
1270
1271    public boolean p2pStopFind() {
1272       return doBooleanCommand("P2P_STOP_FIND");
1273    }
1274
1275    public boolean p2pListen() {
1276        return doBooleanCommand("P2P_LISTEN");
1277    }
1278
1279    public boolean p2pListen(int timeout) {
1280        if (timeout <= 0) {
1281            return p2pListen();
1282        }
1283        return doBooleanCommand("P2P_LISTEN " + timeout);
1284    }
1285
1286    public boolean p2pExtListen(boolean enable, int period, int interval) {
1287        if (enable && interval < period) {
1288            return false;
1289        }
1290        return doBooleanCommand("P2P_EXT_LISTEN"
1291                    + (enable ? (" " + period + " " + interval) : ""));
1292    }
1293
1294    public boolean p2pSetChannel(int lc, int oc) {
1295        if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc);
1296
1297        synchronized (sLock) {
1298            if (lc >=1 && lc <= 11) {
1299                if (!doBooleanCommand("P2P_SET listen_channel " + lc)) {
1300                    return false;
1301                }
1302            } else if (lc != 0) {
1303                return false;
1304            }
1305
1306            if (oc >= 1 && oc <= 165 ) {
1307                int freq = (oc <= 14 ? 2407 : 5000) + oc * 5;
1308                return doBooleanCommand("P2P_SET disallow_freq 1000-"
1309                        + (freq - 5) + "," + (freq + 5) + "-6000");
1310            } else if (oc == 0) {
1311                /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */
1312                return doBooleanCommand("P2P_SET disallow_freq \"\"");
1313            }
1314        }
1315        return false;
1316    }
1317
1318    public boolean p2pFlush() {
1319        return doBooleanCommand("P2P_FLUSH");
1320    }
1321
1322    private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
1323    /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad]
1324        [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */
1325    public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) {
1326        if (config == null) return null;
1327        List<String> args = new ArrayList<String>();
1328        WpsInfo wps = config.wps;
1329        args.add(config.deviceAddress);
1330
1331        switch (wps.setup) {
1332            case WpsInfo.PBC:
1333                args.add("pbc");
1334                break;
1335            case WpsInfo.DISPLAY:
1336                if (TextUtils.isEmpty(wps.pin)) {
1337                    args.add("pin");
1338                } else {
1339                    args.add(wps.pin);
1340                }
1341                args.add("display");
1342                break;
1343            case WpsInfo.KEYPAD:
1344                args.add(wps.pin);
1345                args.add("keypad");
1346                break;
1347            case WpsInfo.LABEL:
1348                args.add(wps.pin);
1349                args.add("label");
1350            default:
1351                break;
1352        }
1353
1354        if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) {
1355            args.add("persistent");
1356        }
1357
1358        if (joinExistingGroup) {
1359            args.add("join");
1360        } else {
1361            //TODO: This can be adapted based on device plugged in state and
1362            //device battery state
1363            int groupOwnerIntent = config.groupOwnerIntent;
1364            if (groupOwnerIntent < 0 || groupOwnerIntent > 15) {
1365                groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT;
1366            }
1367            args.add("go_intent=" + groupOwnerIntent);
1368        }
1369
1370        String command = "P2P_CONNECT ";
1371        for (String s : args) command += s + " ";
1372
1373        return doStringCommand(command);
1374    }
1375
1376    public boolean p2pCancelConnect() {
1377        return doBooleanCommand("P2P_CANCEL");
1378    }
1379
1380    public boolean p2pProvisionDiscovery(WifiP2pConfig config) {
1381        if (config == null) return false;
1382
1383        switch (config.wps.setup) {
1384            case WpsInfo.PBC:
1385                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc");
1386            case WpsInfo.DISPLAY:
1387                //We are doing display, so provision discovery is keypad
1388                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad");
1389            case WpsInfo.KEYPAD:
1390                //We are doing keypad, so provision discovery is display
1391                return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display");
1392            default:
1393                break;
1394        }
1395        return false;
1396    }
1397
1398    public boolean p2pGroupAdd(boolean persistent) {
1399        if (persistent) {
1400            return doBooleanCommand("P2P_GROUP_ADD persistent");
1401        }
1402        return doBooleanCommand("P2P_GROUP_ADD");
1403    }
1404
1405    public boolean p2pGroupAdd(int netId) {
1406        return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId);
1407    }
1408
1409    public boolean p2pGroupRemove(String iface) {
1410        if (TextUtils.isEmpty(iface)) return false;
1411        synchronized (sLock) {
1412            return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
1413        }
1414    }
1415
1416    public boolean p2pReject(String deviceAddress) {
1417        return doBooleanCommand("P2P_REJECT " + deviceAddress);
1418    }
1419
1420    /* Invite a peer to a group */
1421    public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) {
1422        if (TextUtils.isEmpty(deviceAddress)) return false;
1423
1424        if (group == null) {
1425            return doBooleanCommand("P2P_INVITE peer=" + deviceAddress);
1426        } else {
1427            return doBooleanCommand("P2P_INVITE group=" + group.getInterface()
1428                    + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress);
1429        }
1430    }
1431
1432    /* Reinvoke a persistent connection */
1433    public boolean p2pReinvoke(int netId, String deviceAddress) {
1434        if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false;
1435
1436        return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress);
1437    }
1438
1439    public String p2pGetSsid(String deviceAddress) {
1440        return p2pGetParam(deviceAddress, "oper_ssid");
1441    }
1442
1443    public String p2pGetDeviceAddress() {
1444        Log.d(TAG, "p2pGetDeviceAddress");
1445
1446        String status = null;
1447
1448        /* Explicitly calling the API without IFNAME= prefix to take care of the devices that
1449        don't have p2p0 interface. Supplicant seems to be returning the correct address anyway. */
1450
1451        synchronized (sLock) {
1452            status = doStringCommandNative("STATUS");
1453        }
1454
1455        String result = "";
1456        if (status != null) {
1457            String[] tokens = status.split("\n");
1458            for (String token : tokens) {
1459                if (token.startsWith("p2p_device_address=")) {
1460                    String[] nameValue = token.split("=");
1461                    if (nameValue.length != 2)
1462                        break;
1463                    result = nameValue[1];
1464                }
1465            }
1466        }
1467
1468        Log.d(TAG, "p2pGetDeviceAddress returning " + result);
1469        return result;
1470    }
1471
1472    public int getGroupCapability(String deviceAddress) {
1473        int gc = 0;
1474        if (TextUtils.isEmpty(deviceAddress)) return gc;
1475        String peerInfo = p2pPeer(deviceAddress);
1476        if (TextUtils.isEmpty(peerInfo)) return gc;
1477
1478        String[] tokens = peerInfo.split("\n");
1479        for (String token : tokens) {
1480            if (token.startsWith("group_capab=")) {
1481                String[] nameValue = token.split("=");
1482                if (nameValue.length != 2) break;
1483                try {
1484                    return Integer.decode(nameValue[1]);
1485                } catch(NumberFormatException e) {
1486                    return gc;
1487                }
1488            }
1489        }
1490        return gc;
1491    }
1492
1493    public String p2pPeer(String deviceAddress) {
1494        return doStringCommand("P2P_PEER " + deviceAddress);
1495    }
1496
1497    private String p2pGetParam(String deviceAddress, String key) {
1498        if (deviceAddress == null) return null;
1499
1500        String peerInfo = p2pPeer(deviceAddress);
1501        if (peerInfo == null) return null;
1502        String[] tokens= peerInfo.split("\n");
1503
1504        key += "=";
1505        for (String token : tokens) {
1506            if (token.startsWith(key)) {
1507                String[] nameValue = token.split("=");
1508                if (nameValue.length != 2) break;
1509                return nameValue[1];
1510            }
1511        }
1512        return null;
1513    }
1514
1515    public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) {
1516        /*
1517         * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump>
1518         * P2P_SERVICE_ADD upnp <version hex> <service>
1519         *
1520         * e.g)
1521         * [Bonjour]
1522         * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.)
1523         * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027
1524         * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript)
1525         * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001
1526         *  09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074
1527         *
1528         * [UPnP]
1529         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
1530         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice
1531         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp
1532         * -org:device:InternetGatewayDevice:1
1533         * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp
1534         * -org:service:ContentDirectory:2
1535         */
1536        synchronized (sLock) {
1537            for (String s : servInfo.getSupplicantQueryList()) {
1538                String command = "P2P_SERVICE_ADD";
1539                command += (" " + s);
1540                if (!doBooleanCommand(command)) {
1541                    return false;
1542                }
1543            }
1544        }
1545        return true;
1546    }
1547
1548    public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) {
1549        /*
1550         * P2P_SERVICE_DEL bonjour <query hexdump>
1551         * P2P_SERVICE_DEL upnp <version hex> <service>
1552         */
1553        synchronized (sLock) {
1554            for (String s : servInfo.getSupplicantQueryList()) {
1555                String command = "P2P_SERVICE_DEL ";
1556
1557                String[] data = s.split(" ");
1558                if (data.length < 2) {
1559                    return false;
1560                }
1561                if ("upnp".equals(data[0])) {
1562                    command += s;
1563                } else if ("bonjour".equals(data[0])) {
1564                    command += data[0];
1565                    command += (" " + data[1]);
1566                } else {
1567                    return false;
1568                }
1569                if (!doBooleanCommand(command)) {
1570                    return false;
1571                }
1572            }
1573        }
1574        return true;
1575    }
1576
1577    public boolean p2pServiceFlush() {
1578        return doBooleanCommand("P2P_SERVICE_FLUSH");
1579    }
1580
1581    public String p2pServDiscReq(String addr, String query) {
1582        String command = "P2P_SERV_DISC_REQ";
1583        command += (" " + addr);
1584        command += (" " + query);
1585
1586        return doStringCommand(command);
1587    }
1588
1589    public boolean p2pServDiscCancelReq(String id) {
1590        return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id);
1591    }
1592
1593    /* Set the current mode of miracast operation.
1594     *  0 = disabled
1595     *  1 = operating as source
1596     *  2 = operating as sink
1597     */
1598    public void setMiracastMode(int mode) {
1599        // Note: optional feature on the driver. It is ok for this to fail.
1600        doBooleanCommand("DRIVER MIRACAST " + mode);
1601    }
1602
1603    public boolean fetchAnqp(String bssid, String subtypes) {
1604        return doBooleanCommand("ANQP_GET " + bssid + " " + subtypes);
1605    }
1606
1607    /*
1608     * NFC-related calls
1609     */
1610    public String getNfcWpsConfigurationToken(int netId) {
1611        return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId);
1612    }
1613
1614    public String getNfcHandoverRequest() {
1615        return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR");
1616    }
1617
1618    public String getNfcHandoverSelect() {
1619        return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR");
1620    }
1621
1622    public boolean initiatorReportNfcHandover(String selectMessage) {
1623        return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage);
1624    }
1625
1626    public boolean responderReportNfcHandover(String requestMessage) {
1627        return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00");
1628    }
1629
1630
1631    /* kernel logging support */
1632    private static native byte[] readKernelLogNative();
1633
1634    synchronized public String readKernelLog() {
1635        byte[] bytes = readKernelLogNative();
1636        if (bytes != null) {
1637            CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
1638            try {
1639                CharBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
1640                return decoded.toString();
1641            } catch (CharacterCodingException cce) {
1642                return new String(bytes, StandardCharsets.ISO_8859_1);
1643            }
1644        } else {
1645            return "*** failed to read kernel log ***";
1646        }
1647    }
1648
1649    /* WIFI HAL support */
1650
1651    // HAL command ids
1652    private static int sCmdId = 1;
1653    private static int getNewCmdIdLocked() {
1654        return sCmdId++;
1655    }
1656
1657    private static final String TAG = "WifiNative-HAL";
1658    private static long sWifiHalHandle = 0;             /* used by JNI to save wifi_handle */
1659    private static long[] sWifiIfaceHandles = null;     /* used by JNI to save interface handles */
1660    public static int sWlan0Index = -1;
1661    private static int sP2p0Index = -1;
1662    private static MonitorThread sThread;
1663    private static final int STOP_HAL_TIMEOUT_MS = 1000;
1664
1665    private static native boolean startHalNative();
1666    private static native void stopHalNative();
1667    private static native void waitForHalEventNative();
1668
1669    private static class MonitorThread extends Thread {
1670        public void run() {
1671            Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle));
1672            waitForHalEventNative();
1673        }
1674    }
1675
1676    public boolean startHal() {
1677        String debugLog = "startHal stack: ";
1678        java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace();
1679        for (int i = 2; i < elements.length && i <= 7; i++ ) {
1680            debugLog = debugLog + " - " + elements[i].getMethodName();
1681        }
1682
1683        sLocalLog.log(debugLog);
1684
1685        synchronized (sLock) {
1686            if (startHalNative() && (getInterfaces() != 0) && (sWlan0Index != -1)) {
1687                sThread = new MonitorThread();
1688                sThread.start();
1689                return true;
1690            } else {
1691                if (DBG) sLocalLog.log("Could not start hal");
1692                Log.e(TAG, "Could not start hal");
1693                return false;
1694            }
1695        }
1696    }
1697
1698    public void stopHal() {
1699        synchronized (sLock) {
1700            if (isHalStarted()) {
1701                stopHalNative();
1702                try {
1703                    sThread.join(STOP_HAL_TIMEOUT_MS);
1704                    Log.d(TAG, "HAL event thread stopped successfully");
1705                } catch (InterruptedException e) {
1706                    Log.e(TAG, "Could not stop HAL cleanly");
1707                }
1708                sThread = null;
1709                sWifiHalHandle = 0;
1710                sWifiIfaceHandles = null;
1711                sWlan0Index = -1;
1712                sP2p0Index = -1;
1713            }
1714        }
1715    }
1716
1717    public boolean isHalStarted() {
1718        return (sWifiHalHandle != 0);
1719    }
1720    private static native int getInterfacesNative();
1721
1722    public int getInterfaces() {
1723        synchronized (sLock) {
1724            if (isHalStarted()) {
1725                if (sWifiIfaceHandles == null) {
1726                    int num = getInterfacesNative();
1727                    int wifi_num = 0;
1728                    for (int i = 0; i < num; i++) {
1729                        String name = getInterfaceNameNative(i);
1730                        Log.i(TAG, "interface[" + i + "] = " + name);
1731                        if (name.equals("wlan0")) {
1732                            sWlan0Index = i;
1733                            wifi_num++;
1734                        } else if (name.equals("p2p0")) {
1735                            sP2p0Index = i;
1736                            wifi_num++;
1737                        }
1738                    }
1739                    return wifi_num;
1740                } else {
1741                    return sWifiIfaceHandles.length;
1742                }
1743            } else {
1744                return 0;
1745            }
1746        }
1747    }
1748
1749    private static native String getInterfaceNameNative(int index);
1750    public String getInterfaceName(int index) {
1751        synchronized (sLock) {
1752            return getInterfaceNameNative(index);
1753        }
1754    }
1755
1756    // TODO: Change variable names to camel style.
1757    public static class ScanCapabilities {
1758        public int  max_scan_cache_size;
1759        public int  max_scan_buckets;
1760        public int  max_ap_cache_per_scan;
1761        public int  max_rssi_sample_size;
1762        public int  max_scan_reporting_threshold;
1763        public int  max_hotlist_bssids;
1764        public int  max_significant_wifi_change_aps;
1765    }
1766
1767    public boolean getScanCapabilities(ScanCapabilities capabilities) {
1768        synchronized (sLock) {
1769            return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities);
1770        }
1771    }
1772
1773    private static native boolean getScanCapabilitiesNative(
1774            int iface, ScanCapabilities capabilities);
1775
1776    private static native boolean startScanNative(int iface, int id, ScanSettings settings);
1777    private static native boolean stopScanNative(int iface, int id);
1778    private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush);
1779    private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface);
1780    private static native void setWifiLinkLayerStatsNative(int iface, int enable);
1781
1782    public static class ChannelSettings {
1783        public int frequency;
1784        public int dwell_time_ms;
1785        public boolean passive;
1786    }
1787
1788    public static class BucketSettings {
1789        public int bucket;
1790        public int band;
1791        public int period_ms;
1792        public int max_period_ms;
1793        public int step_count;
1794        public int report_events;
1795        public int num_channels;
1796        public ChannelSettings[] channels;
1797    }
1798
1799    public static class ScanSettings {
1800        public int base_period_ms;
1801        public int max_ap_per_scan;
1802        public int report_threshold_percent;
1803        public int report_threshold_num_scans;
1804        public int num_buckets;
1805        public BucketSettings[] buckets;
1806    }
1807
1808    /**
1809     * Network parameters to start PNO scan.
1810     */
1811    public static class PnoNetwork {
1812        public String ssid;
1813        public int networkId;
1814        public int priority;
1815        public byte flags;
1816        public byte auth_bit_field;
1817    }
1818
1819    /**
1820     * Parameters to start PNO scan. This holds the list of networks which are going to used for
1821     * PNO scan.
1822     */
1823    public static class PnoSettings {
1824        public int min5GHzRssi;
1825        public int min24GHzRssi;
1826        public int initialScoreMax;
1827        public int currentConnectionBonus;
1828        public int sameNetworkBonus;
1829        public int secureBonus;
1830        public int band5GHzBonus;
1831        public PnoNetwork[] networkList;
1832    }
1833
1834    /**
1835     * Wi-Fi channel information.
1836     */
1837    public static class WifiChannelInfo {
1838        int mPrimaryFrequency;
1839        int mCenterFrequency0;
1840        int mCenterFrequency1;
1841        int mChannelWidth;
1842        // TODO: add preamble once available in HAL.
1843    }
1844
1845    public static interface ScanEventHandler {
1846        /**
1847         * Called for each AP as it is found with the entire contents of the beacon/probe response.
1848         * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified.
1849         */
1850        void onFullScanResult(ScanResult fullScanResult);
1851        /**
1852         * Callback on an event during a gscan scan.
1853         * See WifiNative.WIFI_SCAN_* for possible values.
1854         */
1855        void onScanStatus(int event);
1856        /**
1857         * Called with the current cached scan results when gscan is paused.
1858         */
1859        void onScanPaused(WifiScanner.ScanData[] data);
1860        /**
1861         * Called with the current cached scan results when gscan is resumed.
1862         */
1863        void onScanRestarted();
1864    }
1865
1866    /**
1867     * Handler to notify the occurrence of various events during PNO scan.
1868     */
1869    public interface PnoEventHandler {
1870        /**
1871         * Callback to notify when one of the shortlisted networks is found during PNO scan.
1872         * @param results List of Scan results received.
1873         */
1874        void onPnoNetworkFound(ScanResult[] results);
1875    }
1876
1877    /* scan status, keep these values in sync with gscan.h */
1878    public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
1879    public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
1880    public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
1881    public static final int WIFI_SCAN_FAILED = 3;
1882
1883    // Callback from native
1884    private static void onScanStatus(int id, int event) {
1885        ScanEventHandler handler = sScanEventHandler;
1886        if (handler != null) {
1887            handler.onScanStatus(event);
1888        }
1889    }
1890
1891    public static  WifiSsid createWifiSsid(byte[] rawSsid) {
1892        String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid));
1893
1894        if (ssidHexString == null) {
1895            return null;
1896        }
1897
1898        WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString);
1899
1900        return wifiSsid;
1901    }
1902
1903    public static String ssidConvert(byte[] rawSsid) {
1904        String ssid;
1905
1906        CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
1907        try {
1908            CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid));
1909            ssid = decoded.toString();
1910        } catch (CharacterCodingException cce) {
1911            ssid = null;
1912        }
1913
1914        if (ssid == null) {
1915            ssid = new String(rawSsid, StandardCharsets.ISO_8859_1);
1916        }
1917
1918        return ssid;
1919    }
1920
1921    // Called from native
1922    public static boolean setSsid(byte[] rawSsid, ScanResult result) {
1923        if (rawSsid == null || rawSsid.length == 0 || result == null) {
1924            return false;
1925        }
1926
1927        result.SSID = ssidConvert(rawSsid);
1928        result.wifiSsid = createWifiSsid(rawSsid);
1929        return true;
1930    }
1931
1932    private static void populateScanResult(ScanResult result, int beaconCap, String dbg) {
1933        if (dbg == null) dbg = "";
1934
1935        InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation();
1936        InformationElementUtil.VhtOperation vhtOperation =
1937                new InformationElementUtil.VhtOperation();
1938        InformationElementUtil.ExtendedCapabilities extendedCaps =
1939                new InformationElementUtil.ExtendedCapabilities();
1940
1941        ScanResult.InformationElement elements[] =
1942                InformationElementUtil.parseInformationElements(result.bytes);
1943        for (ScanResult.InformationElement ie : elements) {
1944            if(ie.id == ScanResult.InformationElement.EID_HT_OPERATION) {
1945                htOperation.from(ie);
1946            } else if(ie.id == ScanResult.InformationElement.EID_VHT_OPERATION) {
1947                vhtOperation.from(ie);
1948            } else if (ie.id == ScanResult.InformationElement.EID_EXTENDED_CAPS) {
1949                extendedCaps.from(ie);
1950            }
1951        }
1952
1953        if (extendedCaps.is80211McRTTResponder) {
1954            result.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
1955        } else {
1956            result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER);
1957        }
1958
1959        //handle RTT related information
1960        if (vhtOperation.isValid()) {
1961            result.channelWidth = vhtOperation.getChannelWidth();
1962            result.centerFreq0 = vhtOperation.getCenterFreq0();
1963            result.centerFreq1 = vhtOperation.getCenterFreq1();
1964        } else {
1965            result.channelWidth = htOperation.getChannelWidth();
1966            result.centerFreq0 = htOperation.getCenterFreq0(result.frequency);
1967            result.centerFreq1  = 0;
1968        }
1969
1970        // build capabilities string
1971        BitSet beaconCapBits = new BitSet(16);
1972        for (int i = 0; i < 16; i++) {
1973            if ((beaconCap & (1 << i)) != 0) {
1974                beaconCapBits.set(i);
1975            }
1976        }
1977        result.capabilities = InformationElementUtil.Capabilities.buildCapabilities(elements,
1978                                               beaconCapBits);
1979
1980        if(DBG) {
1981            Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth
1982                    + " PrimaryFreq: " + result.frequency + " mCenterfreq0: " + result.centerFreq0
1983                    + " mCenterfreq1: " + result.centerFreq1 + (extendedCaps.is80211McRTTResponder
1984                    ? "Support RTT reponder: " : "Do not support RTT responder")
1985                    + " Capabilities: " + result.capabilities);
1986        }
1987
1988        result.informationElements = elements;
1989    }
1990
1991    // Callback from native
1992    private static void onFullScanResult(int id, ScanResult result,
1993            int bucketsScanned, int beaconCap) {
1994        if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID);
1995
1996        ScanEventHandler handler = sScanEventHandler;
1997        if (handler != null) {
1998            populateScanResult(result, beaconCap, " onFullScanResult ");
1999            handler.onFullScanResult(result);
2000        }
2001    }
2002
2003    private static int sScanCmdId = 0;
2004    private static ScanEventHandler sScanEventHandler;
2005    private static ScanSettings sScanSettings;
2006
2007    public boolean startScan(ScanSettings settings, ScanEventHandler eventHandler) {
2008        synchronized (sLock) {
2009            if (isHalStarted()) {
2010                if (sScanCmdId != 0) {
2011                    stopScan();
2012                } else if (sScanSettings != null || sScanEventHandler != null) {
2013                /* current scan is paused; no need to stop it */
2014                }
2015
2016                sScanCmdId = getNewCmdIdLocked();
2017
2018                sScanSettings = settings;
2019                sScanEventHandler = eventHandler;
2020
2021                if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) {
2022                    sScanEventHandler = null;
2023                    sScanSettings = null;
2024                    sScanCmdId = 0;
2025                    return false;
2026                }
2027
2028                return true;
2029            } else {
2030                return false;
2031            }
2032        }
2033    }
2034
2035    public void stopScan() {
2036        synchronized (sLock) {
2037            if (isHalStarted()) {
2038                if (sScanCmdId != 0) {
2039                    stopScanNative(sWlan0Index, sScanCmdId);
2040                }
2041                sScanSettings = null;
2042                sScanEventHandler = null;
2043                sScanCmdId = 0;
2044            }
2045        }
2046    }
2047
2048    public void pauseScan() {
2049        synchronized (sLock) {
2050            if (isHalStarted()) {
2051                if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) {
2052                    Log.d(TAG, "Pausing scan");
2053                    WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true);
2054                    stopScanNative(sWlan0Index, sScanCmdId);
2055                    sScanCmdId = 0;
2056                    sScanEventHandler.onScanPaused(scanData);
2057                }
2058            }
2059        }
2060    }
2061
2062    public void restartScan() {
2063        synchronized (sLock) {
2064            if (isHalStarted()) {
2065                if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) {
2066                    Log.d(TAG, "Restarting scan");
2067                    ScanEventHandler handler = sScanEventHandler;
2068                    ScanSettings settings = sScanSettings;
2069                    if (startScan(sScanSettings, sScanEventHandler)) {
2070                        sScanEventHandler.onScanRestarted();
2071                    } else {
2072                    /* we are still paused; don't change state */
2073                        sScanEventHandler = handler;
2074                        sScanSettings = settings;
2075                    }
2076                }
2077            }
2078        }
2079    }
2080
2081    public WifiScanner.ScanData[] getScanResults(boolean flush) {
2082        synchronized (sLock) {
2083            WifiScanner.ScanData[] sd = null;
2084            if (isHalStarted()) {
2085                sd = getScanResultsNative(sWlan0Index, flush);
2086            }
2087
2088            if (sd != null) {
2089                return sd;
2090            } else {
2091                return new WifiScanner.ScanData[0];
2092            }
2093        }
2094    }
2095
2096    public static interface HotlistEventHandler {
2097        void onHotlistApFound (ScanResult[] result);
2098        void onHotlistApLost  (ScanResult[] result);
2099    }
2100
2101    private static int sHotlistCmdId = 0;
2102    private static HotlistEventHandler sHotlistEventHandler;
2103
2104    private native static boolean setHotlistNative(int iface, int id,
2105            WifiScanner.HotlistSettings settings);
2106    private native static boolean resetHotlistNative(int iface, int id);
2107
2108    public boolean setHotlist(WifiScanner.HotlistSettings settings,
2109            HotlistEventHandler eventHandler) {
2110        synchronized (sLock) {
2111            if (isHalStarted()) {
2112                if (sHotlistCmdId != 0) {
2113                    return false;
2114                } else {
2115                    sHotlistCmdId = getNewCmdIdLocked();
2116                }
2117
2118                sHotlistEventHandler = eventHandler;
2119                if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) {
2120                    sHotlistEventHandler = null;
2121                    return false;
2122                }
2123
2124                return true;
2125            } else {
2126                return false;
2127            }
2128        }
2129    }
2130
2131    public void resetHotlist() {
2132        synchronized (sLock) {
2133            if (isHalStarted()) {
2134                if (sHotlistCmdId != 0) {
2135                    resetHotlistNative(sWlan0Index, sHotlistCmdId);
2136                    sHotlistCmdId = 0;
2137                    sHotlistEventHandler = null;
2138                }
2139            }
2140        }
2141    }
2142
2143    // Callback from native
2144    private static void onHotlistApFound(int id, ScanResult[] results) {
2145        HotlistEventHandler handler = sHotlistEventHandler;
2146        if (handler != null) {
2147            handler.onHotlistApFound(results);
2148        } else {
2149            /* this can happen because of race conditions */
2150            Log.d(TAG, "Ignoring hotlist AP found event");
2151        }
2152    }
2153
2154    // Callback from native
2155    private static void onHotlistApLost(int id, ScanResult[] results) {
2156        HotlistEventHandler handler = sHotlistEventHandler;
2157        if (handler != null) {
2158            handler.onHotlistApLost(results);
2159        } else {
2160            /* this can happen because of race conditions */
2161            Log.d(TAG, "Ignoring hotlist AP lost event");
2162        }
2163    }
2164
2165    public static interface SignificantWifiChangeEventHandler {
2166        void onChangesFound(ScanResult[] result);
2167    }
2168
2169    private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler;
2170    private static int sSignificantWifiChangeCmdId;
2171
2172    private static native boolean trackSignificantWifiChangeNative(
2173            int iface, int id, WifiScanner.WifiChangeSettings settings);
2174    private static native boolean untrackSignificantWifiChangeNative(int iface, int id);
2175
2176    public boolean trackSignificantWifiChange(
2177            WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
2178        synchronized (sLock) {
2179            if (isHalStarted()) {
2180                if (sSignificantWifiChangeCmdId != 0) {
2181                    return false;
2182                } else {
2183                    sSignificantWifiChangeCmdId = getNewCmdIdLocked();
2184                }
2185
2186                sSignificantWifiChangeHandler = handler;
2187                if (trackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId,
2188                        settings) == false) {
2189                    sSignificantWifiChangeHandler = null;
2190                    return false;
2191                }
2192
2193                return true;
2194            } else {
2195                return false;
2196            }
2197
2198        }
2199    }
2200
2201    public void untrackSignificantWifiChange() {
2202        synchronized (sLock) {
2203            if (isHalStarted()) {
2204                if (sSignificantWifiChangeCmdId != 0) {
2205                    untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId);
2206                    sSignificantWifiChangeCmdId = 0;
2207                    sSignificantWifiChangeHandler = null;
2208                }
2209            }
2210        }
2211    }
2212
2213    // Callback from native
2214    private static void onSignificantWifiChange(int id, ScanResult[] results) {
2215        SignificantWifiChangeEventHandler handler = sSignificantWifiChangeHandler;
2216        if (handler != null) {
2217            handler.onChangesFound(results);
2218        } else {
2219            /* this can happen because of race conditions */
2220            Log.d(TAG, "Ignoring significant wifi change");
2221        }
2222    }
2223
2224    public WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
2225        // TODO: use correct iface name to Index translation
2226        if (iface == null) return null;
2227        synchronized (sLock) {
2228            if (isHalStarted()) {
2229                return getWifiLinkLayerStatsNative(sWlan0Index);
2230            } else {
2231                return null;
2232            }
2233        }
2234    }
2235
2236    public void setWifiLinkLayerStats(String iface, int enable) {
2237        if (iface == null) return;
2238        synchronized (sLock) {
2239            if (isHalStarted()) {
2240                setWifiLinkLayerStatsNative(sWlan0Index, enable);
2241            }
2242        }
2243    }
2244
2245    public static native int getSupportedFeatureSetNative(int iface);
2246    public int getSupportedFeatureSet() {
2247        synchronized (sLock) {
2248            if (isHalStarted()) {
2249                return getSupportedFeatureSetNative(sWlan0Index);
2250            } else {
2251                Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started");
2252                return 0;
2253            }
2254        }
2255    }
2256
2257    /* Rtt related commands/events */
2258    public static interface RttEventHandler {
2259        void onRttResults(RttManager.RttResult[] result);
2260    }
2261
2262    private static RttEventHandler sRttEventHandler;
2263    private static int sRttCmdId;
2264
2265    // Callback from native
2266    private static void onRttResults(int id, RttManager.RttResult[] results) {
2267        RttEventHandler handler = sRttEventHandler;
2268        if (handler != null && id == sRttCmdId) {
2269            Log.d(TAG, "Received " + results.length + " rtt results");
2270            handler.onRttResults(results);
2271            sRttCmdId = 0;
2272        } else {
2273            Log.d(TAG, "RTT Received event for unknown cmd = " + id +
2274                    ", current id = " + sRttCmdId);
2275        }
2276    }
2277
2278    private static native boolean requestRangeNative(
2279            int iface, int id, RttManager.RttParams[] params);
2280    private static native boolean cancelRangeRequestNative(
2281            int iface, int id, RttManager.RttParams[] params);
2282
2283    public boolean requestRtt(
2284            RttManager.RttParams[] params, RttEventHandler handler) {
2285        synchronized (sLock) {
2286            if (isHalStarted()) {
2287                if (sRttCmdId != 0) {
2288                    Log.v("TAG", "Last one is still under measurement!");
2289                    return false;
2290                } else {
2291                    sRttCmdId = getNewCmdIdLocked();
2292                }
2293                sRttEventHandler = handler;
2294                Log.v(TAG, "native issue RTT request");
2295                return requestRangeNative(sWlan0Index, sRttCmdId, params);
2296            } else {
2297                return false;
2298            }
2299        }
2300    }
2301
2302    public boolean cancelRtt(RttManager.RttParams[] params) {
2303        synchronized (sLock) {
2304            if (isHalStarted()) {
2305                if (sRttCmdId == 0) {
2306                    return false;
2307                }
2308
2309                sRttCmdId = 0;
2310
2311                if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) {
2312                    sRttEventHandler = null;
2313                    Log.v(TAG, "RTT cancel Request Successfully");
2314                    return true;
2315                } else {
2316                    Log.e(TAG, "RTT cancel Request failed");
2317                    return false;
2318                }
2319            } else {
2320                return false;
2321            }
2322        }
2323    }
2324
2325    private static int sRttResponderCmdId = 0;
2326
2327    private static native ResponderConfig enableRttResponderNative(int iface, int commandId,
2328            int timeoutSeconds, WifiChannelInfo channelHint);
2329    /**
2330     * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder
2331     * role is successfully enabled, {@code null} otherwise.
2332     */
2333    @Nullable
2334    public ResponderConfig enableRttResponder(int timeoutSeconds) {
2335        synchronized (sLock) {
2336            if (!isHalStarted()) return null;
2337            if (sRttResponderCmdId != 0) {
2338                if (DBG) Log.e(mTAG, "responder mode already enabled - this shouldn't happen");
2339                return null;
2340            }
2341            int id = getNewCmdIdLocked();
2342            ResponderConfig config = enableRttResponderNative(
2343                    sWlan0Index, id, timeoutSeconds, null);
2344            if (config != null) sRttResponderCmdId = id;
2345            if (DBG) Log.d(TAG, "enabling rtt " + (config != null));
2346            return config;
2347        }
2348    }
2349
2350    private static native boolean disableRttResponderNative(int iface, int commandId);
2351    /**
2352     * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled,
2353     * {@code false} otherwise.
2354     */
2355    public boolean disableRttResponder() {
2356        synchronized (sLock) {
2357            if (!isHalStarted()) return false;
2358            if (sRttResponderCmdId == 0) {
2359                Log.e(mTAG, "responder role not enabled yet");
2360                return true;
2361            }
2362            sRttResponderCmdId = 0;
2363            return disableRttResponderNative(sWlan0Index, sRttResponderCmdId);
2364        }
2365    }
2366
2367    private static native boolean setScanningMacOuiNative(int iface, byte[] oui);
2368
2369    public boolean setScanningMacOui(byte[] oui) {
2370        synchronized (sLock) {
2371            if (isHalStarted()) {
2372                return setScanningMacOuiNative(sWlan0Index, oui);
2373            } else {
2374                return false;
2375            }
2376        }
2377    }
2378
2379    private static native int[] getChannelsForBandNative(
2380            int iface, int band);
2381
2382    public int [] getChannelsForBand(int band) {
2383        synchronized (sLock) {
2384            if (isHalStarted()) {
2385                return getChannelsForBandNative(sWlan0Index, band);
2386            } else {
2387                return null;
2388            }
2389        }
2390    }
2391
2392    private static native boolean isGetChannelsForBandSupportedNative();
2393    public boolean isGetChannelsForBandSupported(){
2394        synchronized (sLock) {
2395            if (isHalStarted()) {
2396                return isGetChannelsForBandSupportedNative();
2397            } else {
2398                return false;
2399            }
2400        }
2401    }
2402
2403    private static native boolean setDfsFlagNative(int iface, boolean dfsOn);
2404    public boolean setDfsFlag(boolean dfsOn) {
2405        synchronized (sLock) {
2406            if (isHalStarted()) {
2407                return setDfsFlagNative(sWlan0Index, dfsOn);
2408            } else {
2409                return false;
2410            }
2411        }
2412    }
2413
2414    private static native boolean toggleInterfaceNative(int on);
2415    public boolean toggleInterface(int on) {
2416        synchronized (sLock) {
2417            if (isHalStarted()) {
2418                return toggleInterfaceNative(on);
2419            } else {
2420                return false;
2421            }
2422        }
2423    }
2424
2425    private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface);
2426    public RttManager.RttCapabilities getRttCapabilities() {
2427        synchronized (sLock) {
2428            if (isHalStarted()) {
2429                return getRttCapabilitiesNative(sWlan0Index);
2430            } else {
2431                return null;
2432            }
2433        }
2434    }
2435
2436    public static final class PacketFilterCapabilities {
2437        /**
2438         * Version of APF instruction set supported for packet filtering.  0 indicates no support for
2439         * packet filtering using APF programs.
2440         */
2441        public int apfVersionSupported;
2442
2443        /**
2444         * Maximum size of APF program allowed.
2445         */
2446        public int maximumApfProgramSize;
2447    }
2448    private static native PacketFilterCapabilities getPacketFilterCapabilitiesNative(int iface);
2449    public PacketFilterCapabilities getPacketFilterCapabilities() {
2450        synchronized (sLock) {
2451            if (isHalStarted()) {
2452                return getPacketFilterCapabilitiesNative(sWlan0Index);
2453            } else {
2454                return null;
2455            }
2456        }
2457    }
2458
2459    private static native boolean installPacketFilterNative(int iface, byte[] filter);
2460    public boolean installPacketFilter(byte[] filter) {
2461        synchronized (sLock) {
2462            if (isHalStarted()) {
2463                return installPacketFilterNative(sWlan0Index, filter);
2464            } else {
2465                return false;
2466            }
2467        }
2468    }
2469
2470    private static native boolean setCountryCodeHalNative(int iface, String CountryCode);
2471    public boolean setCountryCodeHal(String CountryCode) {
2472        synchronized (sLock) {
2473            if (isHalStarted()) {
2474                return setCountryCodeHalNative(sWlan0Index, CountryCode);
2475            } else {
2476                return false;
2477            }
2478        }
2479    }
2480
2481    /* Rtt related commands/events */
2482    public abstract class TdlsEventHandler {
2483        abstract public void onTdlsStatus(String macAddr, int status, int reason);
2484    }
2485
2486    private static TdlsEventHandler sTdlsEventHandler;
2487
2488    private static native boolean enableDisableTdlsNative(int iface, boolean enable,
2489            String macAddr);
2490    public boolean enableDisableTdls(boolean enable, String macAdd, TdlsEventHandler tdlsCallBack) {
2491        synchronized (sLock) {
2492            sTdlsEventHandler = tdlsCallBack;
2493            return enableDisableTdlsNative(sWlan0Index, enable, macAdd);
2494        }
2495    }
2496
2497    // Once TDLS per mac and event feature is implemented, this class definition should be
2498    // moved to the right place, like WifiManager etc
2499    public static class TdlsStatus {
2500        int channel;
2501        int global_operating_class;
2502        int state;
2503        int reason;
2504    }
2505    private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr);
2506    public TdlsStatus getTdlsStatus(String macAdd) {
2507        synchronized (sLock) {
2508            if (isHalStarted()) {
2509                return getTdlsStatusNative(sWlan0Index, macAdd);
2510            } else {
2511                return null;
2512            }
2513        }
2514    }
2515
2516    //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be
2517    // moved to the right place, like WifiStateMachine etc
2518    public static class TdlsCapabilities {
2519        /* Maximum TDLS session number can be supported by the Firmware and hardware */
2520        int maxConcurrentTdlsSessionNumber;
2521        boolean isGlobalTdlsSupported;
2522        boolean isPerMacTdlsSupported;
2523        boolean isOffChannelTdlsSupported;
2524    }
2525
2526
2527
2528    private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface);
2529    public TdlsCapabilities getTdlsCapabilities () {
2530        synchronized (sLock) {
2531            if (isHalStarted()) {
2532                return getTdlsCapabilitiesNative(sWlan0Index);
2533            } else {
2534                return null;
2535            }
2536        }
2537    }
2538
2539    private static boolean onTdlsStatus(String macAddr, int status, int reason) {
2540        TdlsEventHandler handler = sTdlsEventHandler;
2541        if (handler == null) {
2542            return false;
2543        } else {
2544            handler.onTdlsStatus(macAddr, status, reason);
2545            return true;
2546        }
2547    }
2548
2549    //---------------------------------------------------------------------------------
2550
2551    /* Wifi Logger commands/events */
2552
2553    public static interface WifiLoggerEventHandler {
2554        void onRingBufferData(RingBufferStatus status, byte[] buffer);
2555        void onWifiAlert(int errorCode, byte[] buffer);
2556    }
2557
2558    private static WifiLoggerEventHandler sWifiLoggerEventHandler = null;
2559
2560    // Callback from native
2561    private static void onRingBufferData(RingBufferStatus status, byte[] buffer) {
2562        WifiLoggerEventHandler handler = sWifiLoggerEventHandler;
2563        if (handler != null)
2564            handler.onRingBufferData(status, buffer);
2565    }
2566
2567    // Callback from native
2568    private static void onWifiAlert(byte[] buffer, int errorCode) {
2569        WifiLoggerEventHandler handler = sWifiLoggerEventHandler;
2570        if (handler != null)
2571            handler.onWifiAlert(errorCode, buffer);
2572    }
2573
2574    private static int sLogCmdId = -1;
2575    private static native boolean setLoggingEventHandlerNative(int iface, int id);
2576    public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
2577        synchronized (sLock) {
2578            if (isHalStarted()) {
2579                int oldId =  sLogCmdId;
2580                sLogCmdId = getNewCmdIdLocked();
2581                if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) {
2582                    sLogCmdId = oldId;
2583                    return false;
2584                }
2585                sWifiLoggerEventHandler = handler;
2586                return true;
2587            } else {
2588                return false;
2589            }
2590        }
2591    }
2592
2593    private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel,
2594            int flags, int minIntervalSec ,int minDataSize, String ringName);
2595    public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
2596            int minDataSize, String ringName){
2597        synchronized (sLock) {
2598            if (isHalStarted()) {
2599                return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval,
2600                        minDataSize, ringName);
2601            } else {
2602                return false;
2603            }
2604        }
2605    }
2606
2607    private static native int getSupportedLoggerFeatureSetNative(int iface);
2608    public int getSupportedLoggerFeatureSet() {
2609        synchronized (sLock) {
2610            if (isHalStarted()) {
2611                return getSupportedLoggerFeatureSetNative(sWlan0Index);
2612            } else {
2613                return 0;
2614            }
2615        }
2616    }
2617
2618    private static native boolean resetLogHandlerNative(int iface, int id);
2619    public boolean resetLogHandler() {
2620        synchronized (sLock) {
2621            if (isHalStarted()) {
2622                if (sLogCmdId == -1) {
2623                    Log.e(TAG,"Can not reset handler Before set any handler");
2624                    return false;
2625                }
2626                sWifiLoggerEventHandler = null;
2627                if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) {
2628                    sLogCmdId = -1;
2629                    return true;
2630                } else {
2631                    return false;
2632                }
2633            } else {
2634                return false;
2635            }
2636        }
2637    }
2638
2639    private static native String getDriverVersionNative(int iface);
2640    public String getDriverVersion() {
2641        synchronized (sLock) {
2642            if (isHalStarted()) {
2643                return getDriverVersionNative(sWlan0Index);
2644            } else {
2645                return "";
2646            }
2647        }
2648    }
2649
2650
2651    private static native String getFirmwareVersionNative(int iface);
2652    public String getFirmwareVersion() {
2653        synchronized (sLock) {
2654            if (isHalStarted()) {
2655                return getFirmwareVersionNative(sWlan0Index);
2656            } else {
2657                return "";
2658            }
2659        }
2660    }
2661
2662    public static class RingBufferStatus{
2663        String name;
2664        int flag;
2665        int ringBufferId;
2666        int ringBufferByteSize;
2667        int verboseLevel;
2668        int writtenBytes;
2669        int readBytes;
2670        int writtenRecords;
2671
2672        @Override
2673        public String toString() {
2674            return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
2675                    " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
2676                    " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
2677                    " writtenRecords: " + writtenRecords;
2678        }
2679    }
2680
2681    private static native RingBufferStatus[] getRingBufferStatusNative(int iface);
2682    public RingBufferStatus[] getRingBufferStatus() {
2683        synchronized (sLock) {
2684            if (isHalStarted()) {
2685                return getRingBufferStatusNative(sWlan0Index);
2686            } else {
2687                return null;
2688            }
2689        }
2690    }
2691
2692    private static native boolean getRingBufferDataNative(int iface, String ringName);
2693    public boolean getRingBufferData(String ringName) {
2694        synchronized (sLock) {
2695            if (isHalStarted()) {
2696                return getRingBufferDataNative(sWlan0Index, ringName);
2697            } else {
2698                return false;
2699            }
2700        }
2701    }
2702
2703    private static byte[] mFwMemoryDump;
2704    // Callback from native
2705    private static void onWifiFwMemoryAvailable(byte[] buffer) {
2706        mFwMemoryDump = buffer;
2707        if (DBG) {
2708            Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " +
2709                    (buffer == null ? 0 :  buffer.length));
2710        }
2711    }
2712
2713    private static native boolean getFwMemoryDumpNative(int iface);
2714    public byte[] getFwMemoryDump() {
2715        synchronized (sLock) {
2716            if (isHalStarted()) {
2717                if(getFwMemoryDumpNative(sWlan0Index)) {
2718                    byte[] fwMemoryDump = mFwMemoryDump;
2719                    mFwMemoryDump = null;
2720                    return fwMemoryDump;
2721                } else {
2722                    return null;
2723                }
2724            }
2725            return null;
2726        }
2727    }
2728
2729    //---------------------------------------------------------------------------------
2730    /* Configure ePNO/PNO */
2731    private static PnoEventHandler sPnoEventHandler;
2732    private static int sPnoCmdId = 0;
2733
2734    private static native boolean setPnoListNative(int iface, int id, PnoSettings settings);
2735
2736    /**
2737     * Set the PNO settings & the network list in HAL to start PNO.
2738     * @param settings PNO settings and network list.
2739     * @param eventHandler Handler to receive notifications back during PNO scan.
2740     * @return true if success, false otherwise
2741     */
2742    public boolean setPnoList(PnoSettings settings, PnoEventHandler eventHandler) {
2743        Log.e(TAG, "setPnoList cmd " + sPnoCmdId);
2744
2745        synchronized (sLock) {
2746            if (isHalStarted()) {
2747                sPnoCmdId = getNewCmdIdLocked();
2748                sPnoEventHandler = eventHandler;
2749                if (setPnoListNative(sWlan0Index, sPnoCmdId, settings)) {
2750                    return true;
2751                }
2752            }
2753            sPnoEventHandler = null;
2754            return false;
2755        }
2756    }
2757
2758    /**
2759     * Set the PNO network list in HAL to start PNO.
2760     * @param list PNO network list.
2761     * @param eventHandler Handler to receive notifications back during PNO scan.
2762     * @return true if success, false otherwise
2763     */
2764    public boolean setPnoList(PnoNetwork[] list, PnoEventHandler eventHandler) {
2765        PnoSettings settings = new PnoSettings();
2766        settings.networkList = list;
2767        return setPnoList(settings, eventHandler);
2768    }
2769
2770    private static native boolean resetPnoListNative(int iface, int id);
2771
2772    /**
2773     * Reset the PNO settings in HAL to stop PNO.
2774     * @return true if success, false otherwise
2775     */
2776    public boolean resetPnoList() {
2777        Log.e(TAG, "resetPnoList cmd " + sPnoCmdId);
2778
2779        synchronized (sLock) {
2780            if (isHalStarted()) {
2781                sPnoCmdId = getNewCmdIdLocked();
2782                sPnoEventHandler = null;
2783                if (resetPnoListNative(sWlan0Index, sPnoCmdId)) {
2784                    return true;
2785                }
2786            }
2787            return false;
2788        }
2789    }
2790
2791    // Callback from native
2792    private static void onPnoNetworkFound(int id, ScanResult[] results, int[] beaconCaps) {
2793        if (results == null) {
2794            Log.e(TAG, "onPnoNetworkFound null results");
2795            return;
2796
2797        }
2798        Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length);
2799
2800        PnoEventHandler handler = sPnoEventHandler;
2801        if (sPnoCmdId != 0 && handler != null) {
2802            for (int i=0; i<results.length; i++) {
2803                Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID
2804                        + " " + results[i].level + " " + results[i].frequency);
2805
2806                populateScanResult(results[i], beaconCaps[i], "onPnoNetworkFound ");
2807                results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID);
2808            }
2809
2810            handler.onPnoNetworkFound(results);
2811        } else {
2812            /* this can happen because of race conditions */
2813            Log.d(TAG, "Ignoring Pno Network found event");
2814        }
2815    }
2816
2817    private native static boolean setBssidBlacklistNative(int iface, int id,
2818                                              String list[]);
2819
2820    public boolean setBssidBlacklist(String list[]) {
2821        int size = 0;
2822        if (list != null) {
2823            size = list.length;
2824        }
2825        Log.e(TAG, "setBssidBlacklist cmd " + sPnoCmdId + " size " + size);
2826
2827        synchronized (sLock) {
2828            if (isHalStarted()) {
2829                sPnoCmdId = getNewCmdIdLocked();
2830                return setBssidBlacklistNative(sWlan0Index, sPnoCmdId, list);
2831            } else {
2832                return false;
2833            }
2834        }
2835    }
2836
2837    private native static int startSendingOffloadedPacketNative(int iface, int idx,
2838                                    byte[] srcMac, byte[] dstMac, byte[] pktData, int period);
2839
2840    public int
2841    startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) {
2842        Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period);
2843
2844        String[] macAddrStr = getMacAddress().split(":");
2845        byte[] srcMac = new byte[6];
2846        for(int i = 0; i < 6; i++) {
2847            Integer hexVal = Integer.parseInt(macAddrStr[i], 16);
2848            srcMac[i] = hexVal.byteValue();
2849        }
2850        synchronized (sLock) {
2851            if (isHalStarted()) {
2852                return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac,
2853                        keepAlivePacket.dstMac, keepAlivePacket.data, period);
2854            } else {
2855                return -1;
2856            }
2857        }
2858    }
2859
2860    private native static int stopSendingOffloadedPacketNative(int iface, int idx);
2861
2862    public int
2863    stopSendingOffloadedPacket(int slot) {
2864        Log.d(TAG, "stopSendingOffloadedPacket " + slot);
2865        synchronized (sLock) {
2866            if (isHalStarted()) {
2867                return stopSendingOffloadedPacketNative(sWlan0Index, slot);
2868            } else {
2869                return -1;
2870            }
2871        }
2872    }
2873
2874    public static interface WifiRssiEventHandler {
2875        void onRssiThresholdBreached(byte curRssi);
2876    }
2877
2878    private static WifiRssiEventHandler sWifiRssiEventHandler;
2879
2880    // Callback from native
2881    private static void onRssiThresholdBreached(int id, byte curRssi) {
2882        WifiRssiEventHandler handler = sWifiRssiEventHandler;
2883        if (handler != null) {
2884            handler.onRssiThresholdBreached(curRssi);
2885        }
2886    }
2887
2888    private native static int startRssiMonitoringNative(int iface, int id,
2889                                        byte maxRssi, byte minRssi);
2890
2891    private static int sRssiMonitorCmdId = 0;
2892
2893    public int startRssiMonitoring(byte maxRssi, byte minRssi,
2894                                                WifiRssiEventHandler rssiEventHandler) {
2895        Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi);
2896        synchronized (sLock) {
2897            sWifiRssiEventHandler = rssiEventHandler;
2898            if (isHalStarted()) {
2899                if (sRssiMonitorCmdId != 0) {
2900                    stopRssiMonitoring();
2901                }
2902
2903                sRssiMonitorCmdId = getNewCmdIdLocked();
2904                Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId);
2905                int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId,
2906                        maxRssi, minRssi);
2907                if (ret != 0) { // if not success
2908                    sRssiMonitorCmdId = 0;
2909                }
2910                return ret;
2911            } else {
2912                return -1;
2913            }
2914        }
2915    }
2916
2917    private native static int stopRssiMonitoringNative(int iface, int idx);
2918
2919    public int stopRssiMonitoring() {
2920        Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId);
2921        synchronized (sLock) {
2922            if (isHalStarted()) {
2923                int ret = 0;
2924                if (sRssiMonitorCmdId != 0) {
2925                    ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId);
2926                }
2927                sRssiMonitorCmdId = 0;
2928                return ret;
2929            } else {
2930                return -1;
2931            }
2932        }
2933    }
2934
2935    private static native WifiWakeReasonAndCounts getWlanWakeReasonCountNative(int iface);
2936
2937    /**
2938     * Fetch the host wakeup reasons stats from wlan driver.
2939     * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver.
2940     */
2941    public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
2942        Log.d(TAG, "getWlanWakeReasonCount " + sWlan0Index);
2943        synchronized (sLock) {
2944            if (isHalStarted()) {
2945                return getWlanWakeReasonCountNative(sWlan0Index);
2946            } else {
2947                return null;
2948            }
2949        }
2950    }
2951
2952    private static native int configureNeighborDiscoveryOffload(int iface, boolean enabled);
2953
2954    public boolean configureNeighborDiscoveryOffload(boolean enabled) {
2955        final String logMsg =  "configureNeighborDiscoveryOffload(" + enabled + ")";
2956        Log.d(mTAG, logMsg);
2957        synchronized (sLock) {
2958            if (isHalStarted()) {
2959                final int ret = configureNeighborDiscoveryOffload(sWlan0Index, enabled);
2960                if (ret != 0) {
2961                    Log.d(mTAG, logMsg + " returned: " + ret);
2962                }
2963                return (ret == 0);
2964            }
2965        }
2966        return false;
2967    }
2968}
2969