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