WifiNative.java revision ba3f5bc64ef27f2ec0d3eae3f53c633ea9e66268
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi;
18
19import android.annotation.Nullable;
20import android.net.apf.ApfCapabilities;
21import android.net.wifi.IApInterface;
22import android.net.wifi.IClientInterface;
23import android.net.wifi.RttManager;
24import android.net.wifi.RttManager.ResponderConfig;
25import android.net.wifi.ScanResult;
26import android.net.wifi.WifiConfiguration;
27import android.net.wifi.WifiLinkLayerStats;
28import android.net.wifi.WifiScanner;
29import android.net.wifi.WifiWakeReasonAndCounts;
30import android.os.SystemClock;
31import android.util.Log;
32import android.util.SparseArray;
33
34import com.android.internal.annotations.Immutable;
35import com.android.internal.util.HexDump;
36import com.android.server.connectivity.KeepalivePacketData;
37import com.android.server.wifi.util.FrameParser;
38
39import java.io.PrintWriter;
40import java.io.StringWriter;
41import java.nio.ByteBuffer;
42import java.nio.CharBuffer;
43import java.nio.charset.CharacterCodingException;
44import java.nio.charset.CharsetDecoder;
45import java.nio.charset.StandardCharsets;
46import java.text.SimpleDateFormat;
47import java.util.ArrayList;
48import java.util.Date;
49import java.util.Map;
50import java.util.Objects;
51import java.util.Set;
52import java.util.TimeZone;
53
54
55/**
56 * Native calls for bring up/shut down of the supplicant daemon and for
57 * sending requests to the supplicant daemon
58 *
59 * {@hide}
60 */
61public class WifiNative {
62    private final String mTAG;
63    private final String mInterfaceName;
64    private final SupplicantStaIfaceHal mSupplicantStaIfaceHal;
65    private final WifiVendorHal mWifiVendorHal;
66    private final WificondControl mWificondControl;
67
68    public WifiNative(String interfaceName, WifiVendorHal vendorHal,
69                      SupplicantStaIfaceHal staIfaceHal, WificondControl condControl) {
70        mTAG = "WifiNative-" + interfaceName;
71        mInterfaceName = interfaceName;
72        mWifiVendorHal = vendorHal;
73        mSupplicantStaIfaceHal = staIfaceHal;
74        mWificondControl = condControl;
75    }
76
77    public String getInterfaceName() {
78        return mInterfaceName;
79    }
80
81    /**
82     * Enable verbose logging for all sub modules.
83     */
84    public void enableVerboseLogging(int verbose) {
85        mWificondControl.enableVerboseLogging(verbose > 0 ? true : false);
86        mSupplicantStaIfaceHal.enableVerboseLogging(verbose > 0);
87        mWifiVendorHal.enableVerboseLogging(verbose > 0);
88    }
89
90   /********************************************************
91    * Native Initialization/Deinitialization
92    ********************************************************/
93
94   /**
95    * Setup wifi native for Client mode operations.
96    *
97    * 1. Starts the Wifi HAL and configures it in client/STA mode.
98    * 2. Setup Wificond to operate in client mode and retrieve the handle to use for client
99    * operations.
100    *
101    * @return An IClientInterface as wificond client interface binder handler.
102    * Returns null on failure.
103    */
104    public IClientInterface setupForClientMode() {
105        if (!startHal(true)) {
106            // TODO(b/34859006): Handle failures.
107            Log.e(mTAG, "Failed to start HAL for client mode");
108        }
109        return mWificondControl.setupDriverForClientMode();
110    }
111
112    /**
113     * Setup wifi native for AP mode operations.
114     *
115     * 1. Starts the Wifi HAL and configures it in AP mode.
116     * 2. Setup Wificond to operate in AP mode and retrieve the handle to use for ap operations.
117     *
118     * @return An IApInterface as wificond Ap interface binder handler.
119     * Returns null on failure.
120     */
121    public IApInterface setupForSoftApMode() {
122        if (!startHal(false)) {
123            // TODO(b/34859006): Handle failures.
124            Log.e(mTAG, "Failed to start HAL for AP mode");
125        }
126        return mWificondControl.setupDriverForSoftApMode();
127    }
128
129    /**
130     * Teardown all mode configurations in wifi native.
131     *
132     * 1. Tears down all the interfaces from Wificond.
133     * 2. Stops the Wifi HAL.
134     *
135     * @return Returns true on success.
136     */
137    public boolean tearDown() {
138        if (!mWificondControl.tearDownInterfaces()) {
139            // TODO(b/34859006): Handle failures.
140            Log.e(mTAG, "Failed to teardown interfaces from Wificond");
141            return false;
142        }
143        stopHal();
144        return true;
145    }
146
147    /********************************************************
148     * Wificond operations
149     ********************************************************/
150    /**
151     * Result of a signal poll.
152     */
153    public static class SignalPollResult {
154        // RSSI value in dBM.
155        public int currentRssi;
156        //Transmission bit rate in Mbps.
157        public int txBitrate;
158        // Association frequency in MHz.
159        public int associationFrequency;
160    }
161
162    /**
163     * WiFi interface transimission counters.
164     */
165    public static class TxPacketCounters {
166        // Number of successfully transmitted packets.
167        public int txSucceeded;
168        // Number of tramsmission failures.
169        public int txFailed;
170    }
171
172    /**
173    * Disable wpa_supplicant via wificond.
174    * @return Returns true on success.
175    */
176    public boolean disableSupplicant() {
177        return mWificondControl.disableSupplicant();
178    }
179
180    /**
181    * Enable wpa_supplicant via wificond.
182    * @return Returns true on success.
183    */
184    public boolean enableSupplicant() {
185        return mWificondControl.enableSupplicant();
186    }
187
188    /**
189    * Request signal polling to wificond.
190    * Returns an SignalPollResult object.
191    * Returns null on failure.
192    */
193    public SignalPollResult signalPoll() {
194        return mWificondControl.signalPoll();
195    }
196
197    /**
198     * Fetch TX packet counters on current connection from wificond.
199    * Returns an TxPacketCounters object.
200    * Returns null on failure.
201    */
202    public TxPacketCounters getTxPacketCounters() {
203        return mWificondControl.getTxPacketCounters();
204    }
205
206    /**
207     * Start a scan using wificond for the given parameters.
208     * @param freqs list of frequencies to scan for, if null scan all supported channels.
209     * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
210     * @return Returns true on success.
211     */
212    public boolean scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
213        return mWificondControl.scan(freqs, hiddenNetworkSSIDs);
214    }
215
216    /**
217     * Fetch the latest scan result from kernel via wificond.
218     * @return Returns an ArrayList of ScanDetail.
219     * Returns an empty ArrayList on failure.
220     */
221    public ArrayList<ScanDetail> getScanResults() {
222        return mWificondControl.getScanResults();
223    }
224
225    /**
226     * Start PNO scan.
227     * @param pnoSettings Pno scan configuration.
228     * @return true on success.
229     */
230    public boolean startPnoScan(PnoSettings pnoSettings) {
231        return mWificondControl.startPnoScan(pnoSettings);
232    }
233
234    /**
235     * Stop PNO scan.
236     * @return true on success.
237     */
238    public boolean stopPnoScan() {
239        return mWificondControl.stopPnoScan();
240    }
241
242    /********************************************************
243     * Supplicant operations
244     ********************************************************/
245
246    /**
247     * This method is called repeatedly until the connection to wpa_supplicant is established.
248     *
249     * @return true if connection is established, false otherwise.
250     * TODO: Add unit tests for these once we remove the legacy code.
251     */
252    public boolean connectToSupplicant() {
253        // Start initialization if not already started.
254        if (!mSupplicantStaIfaceHal.isInitializationStarted()
255                && !mSupplicantStaIfaceHal.initialize()) {
256            return false;
257        }
258        // Check if the initialization is complete.
259        return mSupplicantStaIfaceHal.isInitializationComplete();
260    }
261
262    /**
263     * Close supplicant connection.
264     */
265    public void closeSupplicantConnection() {
266        // Nothing to do for HIDL.
267    }
268
269    /**
270     * Set supplicant log level
271     *
272     * @param turnOnVerbose Whether to turn on verbose logging or not.
273     */
274    public void setSupplicantLogLevel(boolean turnOnVerbose) {
275        int logLevel = turnOnVerbose
276                ? SupplicantStaIfaceHal.LOG_LEVEL_DEBUG
277                : SupplicantStaIfaceHal.LOG_LEVEL_INFO;
278        mSupplicantStaIfaceHal.setLogLevel(logLevel);
279    }
280
281    /**
282     * Trigger a reconnection if the iface is disconnected.
283     *
284     * @return true if request is sent successfully, false otherwise.
285     */
286    public boolean reconnect() {
287        return mSupplicantStaIfaceHal.reconnect();
288    }
289
290    /**
291     * Trigger a reassociation even if the iface is currently connected.
292     *
293     * @return true if request is sent successfully, false otherwise.
294     */
295    public boolean reassociate() {
296        return mSupplicantStaIfaceHal.reassociate();
297    }
298
299    /**
300     * Trigger a disconnection from the currently connected network.
301     *
302     * @return true if request is sent successfully, false otherwise.
303     */
304    public boolean disconnect() {
305        return mSupplicantStaIfaceHal.disconnect();
306    }
307
308    /**
309     * Makes a callback to HIDL to getMacAddress from supplicant
310     *
311     * @return string containing the MAC address, or null on a failed call
312     */
313    public String getMacAddress() {
314        return mSupplicantStaIfaceHal.getMacAddress();
315    }
316
317    /**
318     * Start filtering out Multicast V4 packets
319     * @return {@code true} if the operation succeeded, {@code false} otherwise
320     *
321     * Multicast filtering rules work as follows:
322     *
323     * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
324     * a power optimized mode (typically when screen goes off).
325     *
326     * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
327     * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
328     *
329     * DRIVER RXFILTER-ADD Num
330     *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
331     *
332     * and DRIVER RXFILTER-START
333     * In order to stop the usage of these rules, we do
334     *
335     * DRIVER RXFILTER-STOP
336     * DRIVER RXFILTER-REMOVE Num
337     *   where Num is as described for RXFILTER-ADD
338     *
339     * The  SETSUSPENDOPT driver command overrides the filtering rules
340     */
341    public boolean startFilteringMulticastV4Packets() {
342        return mSupplicantStaIfaceHal.stopRxFilter()
343                && mSupplicantStaIfaceHal.removeRxFilter(
344                SupplicantStaIfaceHal.RX_FILTER_TYPE_V4_MULTICAST)
345                && mSupplicantStaIfaceHal.startRxFilter();
346    }
347
348    /**
349     * Stop filtering out Multicast V4 packets.
350     * @return {@code true} if the operation succeeded, {@code false} otherwise
351     */
352    public boolean stopFilteringMulticastV4Packets() {
353        return mSupplicantStaIfaceHal.stopRxFilter()
354                && mSupplicantStaIfaceHal.addRxFilter(
355                SupplicantStaIfaceHal.RX_FILTER_TYPE_V4_MULTICAST)
356                && mSupplicantStaIfaceHal.startRxFilter();
357    }
358
359    /**
360     * Start filtering out Multicast V6 packets
361     * @return {@code true} if the operation succeeded, {@code false} otherwise
362     */
363    public boolean startFilteringMulticastV6Packets() {
364        return mSupplicantStaIfaceHal.stopRxFilter()
365                && mSupplicantStaIfaceHal.removeRxFilter(
366                SupplicantStaIfaceHal.RX_FILTER_TYPE_V6_MULTICAST)
367                && mSupplicantStaIfaceHal.startRxFilter();
368    }
369
370    /**
371     * Stop filtering out Multicast V6 packets.
372     * @return {@code true} if the operation succeeded, {@code false} otherwise
373     */
374    public boolean stopFilteringMulticastV6Packets() {
375        return mSupplicantStaIfaceHal.stopRxFilter()
376                && mSupplicantStaIfaceHal.addRxFilter(
377                SupplicantStaIfaceHal.RX_FILTER_TYPE_V6_MULTICAST)
378                && mSupplicantStaIfaceHal.startRxFilter();
379    }
380
381    public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED  =
382            SupplicantStaIfaceHal.BT_COEX_MODE_ENABLED;
383    public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED =
384            SupplicantStaIfaceHal.BT_COEX_MODE_DISABLED;
385    public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE    =
386            SupplicantStaIfaceHal.BT_COEX_MODE_SENSE;
387    /**
388      * Sets the bluetooth coexistence mode.
389      *
390      * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
391      *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
392      *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
393      * @return Whether the mode was successfully set.
394      */
395    public boolean setBluetoothCoexistenceMode(int mode) {
396        return mSupplicantStaIfaceHal.setBtCoexistenceMode((byte) mode);
397    }
398
399    /**
400     * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
401     * some of the low-level scan parameters used by the driver are changed to
402     * reduce interference with A2DP streaming.
403     *
404     * @param setCoexScanMode whether to enable or disable this mode
405     * @return {@code true} if the command succeeded, {@code false} otherwise.
406     */
407    public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) {
408        return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled(setCoexScanMode);
409    }
410
411    /**
412     * Enable or disable suspend mode optimizations.
413     *
414     * @param enabled true to enable, false otherwise.
415     * @return true if request is sent successfully, false otherwise.
416     */
417    public boolean setSuspendOptimizations(boolean enabled) {
418        return mSupplicantStaIfaceHal.setSuspendModeEnabled(enabled);
419    }
420
421    /**
422     * Set country code.
423     *
424     * @param countryCode 2 byte ASCII string. For ex: US, CA.
425     * @return true if request is sent successfully, false otherwise.
426     */
427    public boolean setCountryCode(String countryCode) {
428        return mSupplicantStaIfaceHal.setCountryCode(countryCode);
429    }
430
431    /**
432     * Initiate TDLS discover and setup or teardown with the specified peer.
433     *
434     * @param macAddr MAC Address of the peer.
435     * @param enable true to start discovery and setup, false to teardown.
436     */
437    public void startTdls(String macAddr, boolean enable) {
438        if (enable) {
439            mSupplicantStaIfaceHal.initiateTdlsDiscover(macAddr);
440            mSupplicantStaIfaceHal.initiateTdlsSetup(macAddr);
441        } else {
442            mSupplicantStaIfaceHal.initiateTdlsTeardown(macAddr);
443        }
444    }
445
446    /**
447     * Start WPS pin display operation with the specified peer.
448     *
449     * @param bssid BSSID of the peer.
450     * @return true if request is sent successfully, false otherwise.
451     */
452    public boolean startWpsPbc(String bssid) {
453        return mSupplicantStaIfaceHal.startWpsPbc(bssid);
454    }
455
456    /**
457     * Start WPS pin keypad operation with the specified pin.
458     *
459     * @param pin Pin to be used.
460     * @return true if request is sent successfully, false otherwise.
461     */
462    public boolean startWpsPinKeypad(String pin) {
463        return mSupplicantStaIfaceHal.startWpsPinKeypad(pin);
464    }
465
466    /**
467     * Start WPS pin display operation with the specified peer.
468     *
469     * @param bssid BSSID of the peer.
470     * @return new pin generated on success, null otherwise.
471     */
472    public String startWpsPinDisplay(String bssid) {
473        return mSupplicantStaIfaceHal.startWpsPinDisplay(bssid);
474    }
475
476    /**
477     * Sets whether to use external sim for SIM/USIM processing.
478     *
479     * @param external true to enable, false otherwise.
480     * @return true if request is sent successfully, false otherwise.
481     */
482    public boolean setExternalSim(boolean external) {
483        return mSupplicantStaIfaceHal.setExternalSim(external);
484    }
485
486    /**
487     * Sim auth response types.
488     */
489    public static final String SIM_AUTH_RESP_TYPE_GSM_AUTH = "GSM-AUTH";
490    public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTH = "UMTS-AUTH";
491    public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTS = "UMTS-AUTS";
492
493    /**
494     * Send the sim auth response for the currently configured network.
495     *
496     * @param type |GSM-AUTH|, |UMTS-AUTH| or |UMTS-AUTS|.
497     * @param response Response params.
498     * @return true if succeeds, false otherwise.
499     */
500    public boolean simAuthResponse(int id, String type, String response) {
501        if (SIM_AUTH_RESP_TYPE_GSM_AUTH.equals(type)) {
502            return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse(response);
503        } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTH.equals(type)) {
504            return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse(response);
505        } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTS.equals(type)) {
506            return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse(response);
507        } else {
508            return false;
509        }
510    }
511
512    /**
513     * Send the eap sim gsm auth failure for the currently configured network.
514     *
515     * @return true if succeeds, false otherwise.
516     */
517    public boolean simAuthFailedResponse(int id) {
518        return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure();
519    }
520
521    /**
522     * Send the eap sim umts auth failure for the currently configured network.
523     *
524     * @return true if succeeds, false otherwise.
525     */
526    public boolean umtsAuthFailedResponse(int id) {
527        return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure();
528    }
529
530    /**
531     * Send the eap identity response for the currently configured network.
532     *
533     * @param response String to send.
534     * @return true if succeeds, false otherwise.
535     */
536    public boolean simIdentityResponse(int id, String response) {
537        return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(response);
538    }
539
540    /**
541     * Start WPS pin registrar operation with the specified peer and pin.
542     *
543     * @param bssid BSSID of the peer.
544     * @param pin Pin to be used.
545     * @return true if request is sent successfully, false otherwise.
546     */
547    public boolean startWpsRegistrar(String bssid, String pin) {
548        return mSupplicantStaIfaceHal.startWpsRegistrar(bssid, pin);
549    }
550
551    /**
552     * Cancels any ongoing WPS requests.
553     *
554     * @return true if request is sent successfully, false otherwise.
555     */
556    public boolean cancelWps() {
557        return mSupplicantStaIfaceHal.cancelWps();
558    }
559
560    /**
561     * Set WPS device name.
562     *
563     * @param name String to be set.
564     * @return true if request is sent successfully, false otherwise.
565     */
566    public boolean setDeviceName(String name) {
567        return mSupplicantStaIfaceHal.setWpsDeviceName(name);
568    }
569
570    /**
571     * Set WPS device type.
572     *
573     * @param type Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
574     * @return true if request is sent successfully, false otherwise.
575     */
576    public boolean setDeviceType(String type) {
577        return mSupplicantStaIfaceHal.setWpsDeviceType(type);
578    }
579
580    /**
581     * Set WPS config methods
582     *
583     * @param cfg List of config methods.
584     * @return true if request is sent successfully, false otherwise.
585     */
586    public boolean setConfigMethods(String cfg) {
587        return mSupplicantStaIfaceHal.setWpsConfigMethods(cfg);
588    }
589
590    /**
591     * Set WPS manufacturer.
592     *
593     * @param value String to be set.
594     * @return true if request is sent successfully, false otherwise.
595     */
596    public boolean setManufacturer(String value) {
597        return mSupplicantStaIfaceHal.setWpsManufacturer(value);
598    }
599
600    /**
601     * Set WPS model name.
602     *
603     * @param value String to be set.
604     * @return true if request is sent successfully, false otherwise.
605     */
606    public boolean setModelName(String value) {
607        return mSupplicantStaIfaceHal.setWpsModelName(value);
608    }
609
610    /**
611     * Set WPS model number.
612     *
613     * @param value String to be set.
614     * @return true if request is sent successfully, false otherwise.
615     */
616    public boolean setModelNumber(String value) {
617        return mSupplicantStaIfaceHal.setWpsModelNumber(value);
618    }
619
620    /**
621     * Set WPS serial number.
622     *
623     * @param value String to be set.
624     * @return true if request is sent successfully, false otherwise.
625     */
626    public boolean setSerialNumber(String value) {
627        return mSupplicantStaIfaceHal.setWpsSerialNumber(value);
628    }
629
630    /**
631     * Enable or disable power save mode.
632     *
633     * @param enabled true to enable, false to disable.
634     */
635    public void setPowerSave(boolean enabled) {
636        mSupplicantStaIfaceHal.setPowerSave(enabled);
637    }
638
639    /**
640     * Set concurrency priority between P2P & STA operations.
641     *
642     * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
643     *                            false otherwise.
644     * @return true if request is sent successfully, false otherwise.
645     */
646    public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
647        return mSupplicantStaIfaceHal.setConcurrencyPriority(isStaHigherPriority);
648    }
649
650    /**
651     * Enable/Disable auto reconnect functionality in wpa_supplicant.
652     *
653     * @param enable true to enable auto reconnecting, false to disable.
654     * @return true if request is sent successfully, false otherwise.
655     */
656    public boolean enableStaAutoReconnect(boolean enable) {
657        return mSupplicantStaIfaceHal.enableAutoReconnect(enable);
658    }
659
660    /**
661     * Migrate all the configured networks from wpa_supplicant.
662     *
663     * @param configs       Map of configuration key to configuration objects corresponding to all
664     *                      the networks.
665     * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf
666     * @return Max priority of all the configs.
667     */
668    public boolean migrateNetworksFromSupplicant(Map<String, WifiConfiguration> configs,
669                                                 SparseArray<Map<String, String>> networkExtras) {
670        return mSupplicantStaIfaceHal.loadNetworks(configs, networkExtras);
671    }
672
673    /**
674     * Add the provided network configuration to wpa_supplicant and initiate connection to it.
675     * This method does the following:
676     * 1. Triggers disconnect command to wpa_supplicant (if |shouldDisconnect| is true).
677     * 2. Remove any existing network in wpa_supplicant.
678     * 3. Add a new network to wpa_supplicant.
679     * 4. Save the provided configuration to wpa_supplicant.
680     * 5. Select the new network in wpa_supplicant.
681     * 6. Triggers reconnect command to wpa_supplicant.
682     *
683     * @param configuration WifiConfiguration parameters for the provided network.
684     * @param shouldDisconnect whether to trigger a disconnection or not.
685     * @return {@code true} if it succeeds, {@code false} otherwise
686     */
687    public boolean connectToNetwork(WifiConfiguration configuration, boolean shouldDisconnect) {
688        return mSupplicantStaIfaceHal.connectToNetwork(configuration, shouldDisconnect);
689    }
690
691    /**
692     * Initiates roaming to the already configured network in wpa_supplicant. If the network
693     * configuration provided does not match the already configured network, then this triggers
694     * a new connection attempt (instead of roam).
695     * 1. First check if we're attempting to connect to the same network as we currently have
696     * configured.
697     * 2. Set the new bssid for the network in wpa_supplicant.
698     * 3. Triggers reassociate command to wpa_supplicant.
699     *
700     * @param configuration WifiConfiguration parameters for the provided network.
701     * @return {@code true} if it succeeds, {@code false} otherwise
702     */
703    public boolean roamToNetwork(WifiConfiguration configuration) {
704        return mSupplicantStaIfaceHal.roamToNetwork(configuration);
705    }
706
707    /**
708     * Get the framework network ID corresponding to the provided supplicant network ID for the
709     * network configured in wpa_supplicant.
710     *
711     * @param supplicantNetworkId network ID in wpa_supplicant for the network.
712     * @return Corresponding framework network ID if found, -1 if network not found.
713     */
714    public int getFrameworkNetworkId(int supplicantNetworkId) {
715        return supplicantNetworkId;
716    }
717
718    /**
719     * Remove all the networks.
720     *
721     * @return {@code true} if it succeeds, {@code false} otherwise
722     */
723    public boolean removeAllNetworks() {
724        return mSupplicantStaIfaceHal.removeAllNetworks();
725    }
726
727    /**
728     * Set the BSSID for the currently configured network in wpa_supplicant.
729     *
730     * @return true if successful, false otherwise.
731     */
732    public boolean setConfiguredNetworkBSSID(String bssid) {
733        return mSupplicantStaIfaceHal.setCurrentNetworkBssid(bssid);
734    }
735
736    /**
737     * Initiate ANQP query.
738     *
739     * @param bssid BSSID of the AP to be queried
740     * @param anqpIds Set of anqp IDs.
741     * @param hs20Subtypes Set of HS20 subtypes.
742     * @return true on success, false otherwise.
743     */
744    public boolean requestAnqp(String bssid, Set<Integer> anqpIds, Set<Integer> hs20Subtypes) {
745        if (bssid == null || ((anqpIds == null || anqpIds.isEmpty())
746                && (hs20Subtypes == null || hs20Subtypes.isEmpty()))) {
747            Log.e(mTAG, "Invalid arguments for ANQP request.");
748            return false;
749        }
750        ArrayList<Short> anqpIdList = new ArrayList<>();
751        for (Integer anqpId : anqpIds) {
752            anqpIdList.add(anqpId.shortValue());
753        }
754        ArrayList<Integer> hs20SubtypeList = new ArrayList<>();
755        hs20SubtypeList.addAll(hs20Subtypes);
756        return mSupplicantStaIfaceHal.initiateAnqpQuery(bssid, anqpIdList, hs20SubtypeList);
757    }
758
759    /**
760     * Request a passpoint icon file |filename| from the specified AP |bssid|.
761     * @param bssid BSSID of the AP
762     * @param fileName name of the icon file
763     * @return true if request is sent successfully, false otherwise
764     */
765    public boolean requestIcon(String  bssid, String fileName) {
766        if (bssid == null || fileName == null) {
767            Log.e(mTAG, "Invalid arguments for Icon request.");
768            return false;
769        }
770        return mSupplicantStaIfaceHal.initiateHs20IconQuery(bssid, fileName);
771    }
772
773    /**
774     * Get the currently configured network's WPS NFC token.
775     *
776     * @return Hex string corresponding to the WPS NFC token.
777     */
778    public String getCurrentNetworkWpsNfcConfigurationToken() {
779        return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken();
780    }
781    /********************************************************
782     * Vendor HAL operations
783     ********************************************************/
784
785    /**
786     * Initializes the vendor HAL. This is just used to initialize the {@link HalDeviceManager}.
787     */
788    public boolean initializeVendorHal() {
789        return mWifiVendorHal.initialize();
790    }
791
792    /**
793     * Bring up the Vendor HAL and configure for STA mode or AP mode.
794     *
795     * @param isStaMode true to start HAL in STA mode, false to start in AP mode.
796     */
797    public boolean startHal(boolean isStaMode) {
798        return mWifiVendorHal.startVendorHal(isStaMode);
799    }
800
801    /**
802     * Stops the HAL
803     */
804    public void stopHal() {
805        mWifiVendorHal.stopVendorHal();
806    }
807
808    /**
809     * Tests whether the HAL is running or not
810     */
811    public boolean isHalStarted() {
812        return mWifiVendorHal.isHalStarted();
813    }
814
815    // TODO: Change variable names to camel style.
816    public static class ScanCapabilities {
817        public int  max_scan_cache_size;
818        public int  max_scan_buckets;
819        public int  max_ap_cache_per_scan;
820        public int  max_rssi_sample_size;
821        public int  max_scan_reporting_threshold;
822        public int  max_hotlist_bssids;
823        public int  max_significant_wifi_change_aps;
824        public int  max_bssid_history_entries;
825        public int  max_number_epno_networks;
826        public int  max_number_epno_networks_by_ssid;
827        public int  max_number_of_white_listed_ssid;
828    }
829
830    /**
831     * Gets the scan capabilities
832     *
833     * @param capabilities object to be filled in
834     * @return true for success. false for failure
835     */
836    public boolean getBgScanCapabilities(ScanCapabilities capabilities) {
837        return mWifiVendorHal.getBgScanCapabilities(capabilities);
838    }
839
840    public static class ChannelSettings {
841        public int frequency;
842        public int dwell_time_ms;
843        public boolean passive;
844    }
845
846    public static class BucketSettings {
847        public int bucket;
848        public int band;
849        public int period_ms;
850        public int max_period_ms;
851        public int step_count;
852        public int report_events;
853        public int num_channels;
854        public ChannelSettings[] channels;
855    }
856
857    /**
858     * Network parameters for hidden networks to be scanned for.
859     */
860    public static class HiddenNetwork {
861        public String ssid;
862
863        @Override
864        public boolean equals(Object otherObj) {
865            if (this == otherObj) {
866                return true;
867            } else if (otherObj == null || getClass() != otherObj.getClass()) {
868                return false;
869            }
870            HiddenNetwork other = (HiddenNetwork) otherObj;
871            return Objects.equals(ssid, other.ssid);
872        }
873
874        @Override
875        public int hashCode() {
876            return (ssid == null ? 0 : ssid.hashCode());
877        }
878    }
879
880    public static class ScanSettings {
881        public int base_period_ms;
882        public int max_ap_per_scan;
883        public int report_threshold_percent;
884        public int report_threshold_num_scans;
885        public int num_buckets;
886        /* Not used for bg scans. Only works for single scans. */
887        public HiddenNetwork[] hiddenNetworks;
888        public BucketSettings[] buckets;
889    }
890
891    /**
892     * Network parameters to start PNO scan.
893     */
894    public static class PnoNetwork {
895        public String ssid;
896        public byte flags;
897        public byte auth_bit_field;
898
899        @Override
900        public boolean equals(Object otherObj) {
901            if (this == otherObj) {
902                return true;
903            } else if (otherObj == null || getClass() != otherObj.getClass()) {
904                return false;
905            }
906            PnoNetwork other = (PnoNetwork) otherObj;
907            return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags)
908                    && (auth_bit_field == other.auth_bit_field));
909        }
910
911        @Override
912        public int hashCode() {
913            int result = (ssid == null ? 0 : ssid.hashCode());
914            result ^= ((int) flags * 31) + ((int) auth_bit_field << 8);
915            return result;
916        }
917    }
918
919    /**
920     * Parameters to start PNO scan. This holds the list of networks which are going to used for
921     * PNO scan.
922     */
923    public static class PnoSettings {
924        public int min5GHzRssi;
925        public int min24GHzRssi;
926        public int initialScoreMax;
927        public int currentConnectionBonus;
928        public int sameNetworkBonus;
929        public int secureBonus;
930        public int band5GHzBonus;
931        public int periodInMs;
932        public boolean isConnected;
933        public PnoNetwork[] networkList;
934    }
935
936    public static interface ScanEventHandler {
937        /**
938         * Called for each AP as it is found with the entire contents of the beacon/probe response.
939         * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified.
940         */
941        void onFullScanResult(ScanResult fullScanResult, int bucketsScanned);
942        /**
943         * Callback on an event during a gscan scan.
944         * See WifiNative.WIFI_SCAN_* for possible values.
945         */
946        void onScanStatus(int event);
947        /**
948         * Called with the current cached scan results when gscan is paused.
949         */
950        void onScanPaused(WifiScanner.ScanData[] data);
951        /**
952         * Called with the current cached scan results when gscan is resumed.
953         */
954        void onScanRestarted();
955    }
956
957    /**
958     * Handler to notify the occurrence of various events during PNO scan.
959     */
960    public interface PnoEventHandler {
961        /**
962         * Callback to notify when one of the shortlisted networks is found during PNO scan.
963         * @param results List of Scan results received.
964         */
965        void onPnoNetworkFound(ScanResult[] results);
966
967        /**
968         * Callback to notify when the PNO scan schedule fails.
969         */
970        void onPnoScanFailed();
971    }
972
973    public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
974    public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
975    public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
976    public static final int WIFI_SCAN_FAILED = 3;
977
978    /**
979     * Starts a background scan.
980     * Any ongoing scan will be stopped first
981     *
982     * @param settings     to control the scan
983     * @param eventHandler to call with the results
984     * @return true for success
985     */
986    public boolean startBgScan(ScanSettings settings, ScanEventHandler eventHandler) {
987        return mWifiVendorHal.startBgScan(settings, eventHandler);
988    }
989
990    /**
991     * Stops any ongoing backgound scan
992     */
993    public void stopBgScan() {
994        mWifiVendorHal.stopBgScan();
995    }
996
997    /**
998     * Pauses an ongoing backgound scan
999     */
1000    public void pauseBgScan() {
1001        mWifiVendorHal.pauseBgScan();
1002    }
1003
1004    /**
1005     * Restarts a paused scan
1006     */
1007    public void restartBgScan() {
1008        mWifiVendorHal.restartBgScan();
1009    }
1010
1011    /**
1012     * Gets the latest scan results received.
1013     */
1014    public WifiScanner.ScanData[] getBgScanResults() {
1015        return mWifiVendorHal.getBgScanResults();
1016    }
1017
1018    public static interface HotlistEventHandler {
1019        void onHotlistApFound (ScanResult[] result);
1020        void onHotlistApLost  (ScanResult[] result);
1021    }
1022
1023    public boolean setHotlist(WifiScanner.HotlistSettings settings,
1024            HotlistEventHandler eventHandler) {
1025        Log.e(mTAG, "setHotlist not supported");
1026        return false;
1027    }
1028
1029    public void resetHotlist() {
1030        Log.e(mTAG, "resetHotlist not supported");
1031    }
1032
1033    public static interface SignificantWifiChangeEventHandler {
1034        void onChangesFound(ScanResult[] result);
1035    }
1036
1037    public boolean trackSignificantWifiChange(
1038            WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
1039        Log.e(mTAG, "trackSignificantWifiChange not supported");
1040        return false;
1041    }
1042
1043    public void untrackSignificantWifiChange() {
1044        Log.e(mTAG, "untrackSignificantWifiChange not supported");
1045    }
1046
1047    public WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
1048        return mWifiVendorHal.getWifiLinkLayerStats();
1049    }
1050
1051    public void setWifiLinkLayerStats(String iface, int enable) {
1052        // TODO(b//36087365) Remove this. Link layer stats is enabled when the HAL is started.
1053    }
1054
1055    /**
1056     * Get the supported features
1057     *
1058     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
1059     */
1060    public int getSupportedFeatureSet() {
1061        return mWifiVendorHal.getSupportedFeatureSet();
1062    }
1063
1064    public static interface RttEventHandler {
1065        void onRttResults(RttManager.RttResult[] result);
1066    }
1067
1068    /**
1069     * Starts a new rtt request
1070     *
1071     * @param params RTT request params. Refer to {@link RttManager#RttParams}.
1072     * @param handler Callback to be invoked to notify any results.
1073     * @return true if the request was successful, false otherwise.
1074     */
1075    public boolean requestRtt(
1076            RttManager.RttParams[] params, RttEventHandler handler) {
1077        return mWifiVendorHal.requestRtt(params, handler);
1078    }
1079
1080    /**
1081     * Cancels an outstanding rtt request
1082     *
1083     * @param params RTT request params. Refer to {@link RttManager#RttParams}
1084     * @return true if there was an outstanding request and it was successfully cancelled
1085     */
1086    public boolean cancelRtt(RttManager.RttParams[] params) {
1087        return mWifiVendorHal.cancelRtt(params);
1088    }
1089
1090    /**
1091     * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder
1092     * role is successfully enabled, {@code null} otherwise.
1093     *
1094     * @param timeoutSeconds timeout to use for the responder.
1095     */
1096    @Nullable
1097    public ResponderConfig enableRttResponder(int timeoutSeconds) {
1098        return mWifiVendorHal.enableRttResponder(timeoutSeconds);
1099    }
1100
1101    /**
1102     * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled,
1103     * {@code false} otherwise.
1104     */
1105    public boolean disableRttResponder() {
1106        return mWifiVendorHal.disableRttResponder();
1107    }
1108
1109    /**
1110     * Set the MAC OUI during scanning.
1111     * An OUI {Organizationally Unique Identifier} is a 24-bit number that
1112     * uniquely identifies a vendor or manufacturer.
1113     *
1114     * @param oui OUI to set.
1115     * @return true for success
1116     */
1117    public boolean setScanningMacOui(byte[] oui) {
1118        return mWifiVendorHal.setScanningMacOui(oui);
1119    }
1120
1121    /**
1122     * Query the list of valid frequencies for the provided band.
1123     * The result depends on the on the country code that has been set.
1124     *
1125     * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1126     * @return frequencies vector of valid frequencies (MHz), or null for error.
1127     * @throws IllegalArgumentException if band is not recognized.
1128     */
1129    public int [] getChannelsForBand(int band) {
1130        return mWifiVendorHal.getChannelsForBand(band);
1131    }
1132
1133    /**
1134     * Indicates whether getChannelsForBand is supported.
1135     *
1136     * @return true if it is.
1137     */
1138    public boolean isGetChannelsForBandSupported() {
1139        return mWifiVendorHal.isGetChannelsForBandSupported();
1140    }
1141
1142    /**
1143     * Set DFS - actually, this is always on.
1144     *
1145     * @param dfsOn
1146     * @return success indication
1147     */
1148    public boolean setDfsFlag(boolean dfsOn) {
1149        return mWifiVendorHal.setDfsFlag(dfsOn);
1150    }
1151
1152    /**
1153     * RTT (Round Trip Time) measurement capabilities of the device.
1154     */
1155    public RttManager.RttCapabilities getRttCapabilities() {
1156        return mWifiVendorHal.getRttCapabilities();
1157    }
1158
1159    /**
1160     * Get the APF (Android Packet Filter) capabilities of the device
1161     */
1162    public ApfCapabilities getApfCapabilities() {
1163        return mWifiVendorHal.getApfCapabilities();
1164    }
1165
1166    /**
1167     * Installs an APF program on this iface, replacing any existing program.
1168     *
1169     * @param filter is the android packet filter program
1170     * @return true for success
1171     */
1172    public boolean installPacketFilter(byte[] filter) {
1173        return mWifiVendorHal.installPacketFilter(filter);
1174    }
1175
1176    /**
1177     * Set country code for this AP iface.
1178     *
1179     * @param countryCode - two-letter country code (as ISO 3166)
1180     * @return true for success
1181     */
1182    public boolean setCountryCodeHal(String countryCode) {
1183        return mWifiVendorHal.setCountryCodeHal(countryCode);
1184    }
1185
1186    //---------------------------------------------------------------------------------
1187    /* Wifi Logger commands/events */
1188    public static interface WifiLoggerEventHandler {
1189        void onRingBufferData(RingBufferStatus status, byte[] buffer);
1190        void onWifiAlert(int errorCode, byte[] buffer);
1191    }
1192
1193    /**
1194     * Registers the logger callback and enables alerts.
1195     * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
1196     *
1197     * @param handler Callback to be invoked.
1198     * @return true on success, false otherwise.
1199     */
1200    public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
1201        return mWifiVendorHal.setLoggingEventHandler(handler);
1202    }
1203
1204    /**
1205     * Control debug data collection
1206     *
1207     * @param verboseLevel 0 to 3, inclusive. 0 stops logging.
1208     * @param flags        Ignored.
1209     * @param maxInterval  Maximum interval between reports; ignore if 0.
1210     * @param minDataSize  Minimum data size in buffer for report; ignore if 0.
1211     * @param ringName     Name of the ring for which data collection is to start.
1212     * @return true for success, false otherwise.
1213     */
1214    public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
1215            int minDataSize, String ringName){
1216        return mWifiVendorHal.startLoggingRingBuffer(
1217                verboseLevel, flags, maxInterval, minDataSize, ringName);
1218    }
1219
1220    /**
1221     * Logger features exposed.
1222     * This is a no-op now, will always return -1.
1223     *
1224     * @return true on success, false otherwise.
1225     */
1226    public int getSupportedLoggerFeatureSet() {
1227        return mWifiVendorHal.getSupportedLoggerFeatureSet();
1228    }
1229
1230    /**
1231     * Stops all logging and resets the logger callback.
1232     * This stops both the alerts and ring buffer data collection.
1233     * @return true on success, false otherwise.
1234     */
1235    public boolean resetLogHandler() {
1236        return mWifiVendorHal.resetLogHandler();
1237    }
1238
1239    /**
1240     * Vendor-provided wifi driver version string
1241     *
1242     * @return String returned from the HAL.
1243     */
1244    public String getDriverVersion() {
1245        return mWifiVendorHal.getDriverVersion();
1246    }
1247
1248    /**
1249     * Vendor-provided wifi firmware version string
1250     *
1251     * @return String returned from the HAL.
1252     */
1253    public String getFirmwareVersion() {
1254        return mWifiVendorHal.getFirmwareVersion();
1255    }
1256
1257    public static class RingBufferStatus{
1258        String name;
1259        int flag;
1260        int ringBufferId;
1261        int ringBufferByteSize;
1262        int verboseLevel;
1263        int writtenBytes;
1264        int readBytes;
1265        int writtenRecords;
1266
1267        // Bit masks for interpreting |flag|
1268        public static final int HAS_BINARY_ENTRIES = (1 << 0);
1269        public static final int HAS_ASCII_ENTRIES = (1 << 1);
1270        public static final int HAS_PER_PACKET_ENTRIES = (1 << 2);
1271
1272        @Override
1273        public String toString() {
1274            return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
1275                    " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
1276                    " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
1277                    " writtenRecords: " + writtenRecords;
1278        }
1279    }
1280
1281    /**
1282     * API to get the status of all ring buffers supported by driver
1283     */
1284    public RingBufferStatus[] getRingBufferStatus() {
1285        return mWifiVendorHal.getRingBufferStatus();
1286    }
1287
1288    /**
1289     * Indicates to driver that all the data has to be uploaded urgently
1290     *
1291     * @param ringName Name of the ring buffer requested.
1292     * @return true on success, false otherwise.
1293     */
1294    public boolean getRingBufferData(String ringName) {
1295        return mWifiVendorHal.getRingBufferData(ringName);
1296    }
1297
1298    /**
1299     * Request vendor debug info from the firmware
1300     *
1301     * @return Raw data obtained from the HAL.
1302     */
1303    public byte[] getFwMemoryDump() {
1304        return mWifiVendorHal.getFwMemoryDump();
1305    }
1306
1307    /**
1308     * Request vendor debug info from the driver
1309     *
1310     * @return Raw data obtained from the HAL.
1311     */
1312    public byte[] getDriverStateDump() {
1313        return mWifiVendorHal.getDriverStateDump();
1314    }
1315
1316    //---------------------------------------------------------------------------------
1317    /* Packet fate API */
1318
1319    @Immutable
1320    abstract static class FateReport {
1321        final static int USEC_PER_MSEC = 1000;
1322        // The driver timestamp is a 32-bit counter, in microseconds. This field holds the
1323        // maximal value of a driver timestamp in milliseconds.
1324        final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000);
1325        final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
1326
1327        final byte mFate;
1328        final long mDriverTimestampUSec;
1329        final byte mFrameType;
1330        final byte[] mFrameBytes;
1331        final long mEstimatedWallclockMSec;
1332
1333        FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
1334            mFate = fate;
1335            mDriverTimestampUSec = driverTimestampUSec;
1336            mEstimatedWallclockMSec =
1337                    convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec);
1338            mFrameType = frameType;
1339            mFrameBytes = frameBytes;
1340        }
1341
1342        public String toTableRowString() {
1343            StringWriter sw = new StringWriter();
1344            PrintWriter pw = new PrintWriter(sw);
1345            FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
1346            dateFormatter.setTimeZone(TimeZone.getDefault());
1347            pw.format("%-15s  %12s  %-9s  %-32s  %-12s  %-23s  %s\n",
1348                    mDriverTimestampUSec,
1349                    dateFormatter.format(new Date(mEstimatedWallclockMSec)),
1350                    directionToString(), fateToString(), parser.mMostSpecificProtocolString,
1351                    parser.mTypeString, parser.mResultString);
1352            return sw.toString();
1353        }
1354
1355        public String toVerboseStringWithPiiAllowed() {
1356            StringWriter sw = new StringWriter();
1357            PrintWriter pw = new PrintWriter(sw);
1358            FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
1359            pw.format("Frame direction: %s\n", directionToString());
1360            pw.format("Frame timestamp: %d\n", mDriverTimestampUSec);
1361            pw.format("Frame fate: %s\n", fateToString());
1362            pw.format("Frame type: %s\n", frameTypeToString(mFrameType));
1363            pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString);
1364            pw.format("Frame protocol type: %s\n", parser.mTypeString);
1365            pw.format("Frame length: %d\n", mFrameBytes.length);
1366            pw.append("Frame bytes");
1367            pw.append(HexDump.dumpHexString(mFrameBytes));  // potentially contains PII
1368            pw.append("\n");
1369            return sw.toString();
1370        }
1371
1372        /* Returns a header to match the output of toTableRowString(). */
1373        public static String getTableHeader() {
1374            StringWriter sw = new StringWriter();
1375            PrintWriter pw = new PrintWriter(sw);
1376            pw.format("\n%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
1377                    "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result");
1378            pw.format("%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
1379                    "---------", "--------", "---------", "----", "--------", "----", "------");
1380            return sw.toString();
1381        }
1382
1383        protected abstract String directionToString();
1384
1385        protected abstract String fateToString();
1386
1387        private static String frameTypeToString(byte frameType) {
1388            switch (frameType) {
1389                case WifiLoggerHal.FRAME_TYPE_UNKNOWN:
1390                    return "unknown";
1391                case WifiLoggerHal.FRAME_TYPE_ETHERNET_II:
1392                    return "data";
1393                case WifiLoggerHal.FRAME_TYPE_80211_MGMT:
1394                    return "802.11 management";
1395                default:
1396                    return Byte.toString(frameType);
1397            }
1398        }
1399
1400        /**
1401         * Converts a driver timestamp to a wallclock time, based on the current
1402         * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of
1403         * microseconds, with the same base as BOOTTIME.
1404         */
1405        private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) {
1406            final long wallclockMillisNow = System.currentTimeMillis();
1407            final long boottimeMillisNow = SystemClock.elapsedRealtime();
1408            final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC;
1409
1410            long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC;
1411            if (boottimeTimestampMillis < driverTimestampMillis) {
1412                // The 32-bit microsecond count has wrapped between the time that the driver
1413                // recorded the packet, and the call to this function. Adjust the BOOTTIME
1414                // timestamp, to compensate.
1415                //
1416                // Note that overflow is not a concern here, since the result is less than
1417                // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above,
1418                // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since
1419                // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit
1420                // within a long.
1421                boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC;
1422            }
1423
1424            final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis;
1425            return wallclockMillisNow - millisSincePacketTimestamp;
1426        }
1427    }
1428
1429    /**
1430     * Represents the fate information for one outbound packet.
1431     */
1432    @Immutable
1433    public static final class TxFateReport extends FateReport {
1434        TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
1435            super(fate, driverTimestampUSec, frameType, frameBytes);
1436        }
1437
1438        @Override
1439        protected String directionToString() {
1440            return "TX";
1441        }
1442
1443        @Override
1444        protected String fateToString() {
1445            switch (mFate) {
1446                case WifiLoggerHal.TX_PKT_FATE_ACKED:
1447                    return "acked";
1448                case WifiLoggerHal.TX_PKT_FATE_SENT:
1449                    return "sent";
1450                case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED:
1451                    return "firmware queued";
1452                case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID:
1453                    return "firmware dropped (invalid frame)";
1454                case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS:
1455                    return "firmware dropped (no bufs)";
1456                case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER:
1457                    return "firmware dropped (other)";
1458                case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED:
1459                    return "driver queued";
1460                case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID:
1461                    return "driver dropped (invalid frame)";
1462                case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS:
1463                    return "driver dropped (no bufs)";
1464                case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER:
1465                    return "driver dropped (other)";
1466                default:
1467                    return Byte.toString(mFate);
1468            }
1469        }
1470    }
1471
1472    /**
1473     * Represents the fate information for one inbound packet.
1474     */
1475    @Immutable
1476    public static final class RxFateReport extends FateReport {
1477        RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
1478            super(fate, driverTimestampUSec, frameType, frameBytes);
1479        }
1480
1481        @Override
1482        protected String directionToString() {
1483            return "RX";
1484        }
1485
1486        @Override
1487        protected String fateToString() {
1488            switch (mFate) {
1489                case WifiLoggerHal.RX_PKT_FATE_SUCCESS:
1490                    return "success";
1491                case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED:
1492                    return "firmware queued";
1493                case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER:
1494                    return "firmware dropped (filter)";
1495                case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID:
1496                    return "firmware dropped (invalid frame)";
1497                case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS:
1498                    return "firmware dropped (no bufs)";
1499                case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER:
1500                    return "firmware dropped (other)";
1501                case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED:
1502                    return "driver queued";
1503                case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER:
1504                    return "driver dropped (filter)";
1505                case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID:
1506                    return "driver dropped (invalid frame)";
1507                case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS:
1508                    return "driver dropped (no bufs)";
1509                case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER:
1510                    return "driver dropped (other)";
1511                default:
1512                    return Byte.toString(mFate);
1513            }
1514        }
1515    }
1516
1517    /**
1518     * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started.
1519     *
1520     * @return true for success, false otherwise.
1521     */
1522    public boolean startPktFateMonitoring() {
1523        return mWifiVendorHal.startPktFateMonitoring();
1524    }
1525
1526    /**
1527     * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started.
1528     *
1529     * @return true for success, false otherwise.
1530     */
1531    public boolean getTxPktFates(TxFateReport[] reportBufs) {
1532        return mWifiVendorHal.getTxPktFates(reportBufs);
1533    }
1534
1535    /**
1536     * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started.
1537     */
1538    public boolean getRxPktFates(RxFateReport[] reportBufs) {
1539        return mWifiVendorHal.getRxPktFates(reportBufs);
1540    }
1541
1542    /**
1543     * Set the PNO settings & the network list in HAL to start PNO.
1544     * @param settings PNO settings and network list.
1545     * @param eventHandler Handler to receive notifications back during PNO scan.
1546     * @return true if success, false otherwise
1547     */
1548    public boolean setPnoList(PnoSettings settings, PnoEventHandler eventHandler) {
1549        Log.e(mTAG, "setPnoList not supported");
1550        return false;
1551    }
1552
1553    /**
1554     * Reset the PNO settings in HAL to stop PNO.
1555     * @return true if success, false otherwise
1556     */
1557    public boolean resetPnoList() {
1558        Log.e(mTAG, "resetPnoList not supported");
1559        return false;
1560    }
1561
1562    /**
1563     * Start sending the specified keep alive packets periodically.
1564     *
1565     * @param slot Integer used to identify each request.
1566     * @param keepAlivePacket Raw packet contents to send.
1567     * @param period Period to use for sending these packets.
1568     * @return 0 for success, -1 for error
1569     */
1570    public int startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket,
1571                                           int period) {
1572        String[] macAddrStr = getMacAddress().split(":");
1573        byte[] srcMac = new byte[6];
1574        for (int i = 0; i < 6; i++) {
1575            Integer hexVal = Integer.parseInt(macAddrStr[i], 16);
1576            srcMac[i] = hexVal.byteValue();
1577        }
1578        return mWifiVendorHal.startSendingOffloadedPacket(
1579                slot, srcMac, keepAlivePacket, period);
1580    }
1581
1582    /**
1583     * Stop sending the specified keep alive packets.
1584     *
1585     * @param slot id - same as startSendingOffloadedPacket call.
1586     * @return 0 for success, -1 for error
1587     */
1588    public int stopSendingOffloadedPacket(int slot) {
1589        return mWifiVendorHal.stopSendingOffloadedPacket(slot);
1590    }
1591
1592    public static interface WifiRssiEventHandler {
1593        void onRssiThresholdBreached(byte curRssi);
1594    }
1595
1596    /**
1597     * Start RSSI monitoring on the currently connected access point.
1598     *
1599     * @param maxRssi          Maximum RSSI threshold.
1600     * @param minRssi          Minimum RSSI threshold.
1601     * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
1602     * @return 0 for success, -1 for failure
1603     */
1604    public int startRssiMonitoring(byte maxRssi, byte minRssi,
1605                                   WifiRssiEventHandler rssiEventHandler) {
1606        return mWifiVendorHal.startRssiMonitoring(maxRssi, minRssi, rssiEventHandler);
1607    }
1608
1609    public int stopRssiMonitoring() {
1610        return mWifiVendorHal.stopRssiMonitoring();
1611    }
1612
1613    /**
1614     * Fetch the host wakeup reasons stats from wlan driver.
1615     *
1616     * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver.
1617     */
1618    public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
1619        return mWifiVendorHal.getWlanWakeReasonCount();
1620    }
1621
1622    /**
1623     * Enable/Disable Neighbour discovery offload functionality in the firmware.
1624     *
1625     * @param enabled true to enable, false to disable.
1626     * @return true for success, false otherwise.
1627     */
1628    public boolean configureNeighborDiscoveryOffload(boolean enabled) {
1629        return mWifiVendorHal.configureNeighborDiscoveryOffload(enabled);
1630    }
1631
1632    // Firmware roaming control.
1633
1634    /**
1635     * Class to retrieve firmware roaming capability parameters.
1636     */
1637    public static class RoamingCapabilities {
1638        public int  maxBlacklistSize;
1639        public int  maxWhitelistSize;
1640    }
1641
1642    /**
1643     * Query the firmware roaming capabilities.
1644     * @return true for success, false otherwise.
1645     */
1646    public boolean getRoamingCapabilities(RoamingCapabilities capabilities) {
1647        return mWifiVendorHal.getRoamingCapabilities(capabilities);
1648    }
1649
1650    /**
1651     * Macros for controlling firmware roaming.
1652     */
1653    public static final int DISABLE_FIRMWARE_ROAMING = 0;
1654    public static final int ENABLE_FIRMWARE_ROAMING = 1;
1655
1656    /**
1657     * Enable/disable firmware roaming.
1658     *
1659     * @return error code returned from HAL.
1660     */
1661    public int enableFirmwareRoaming(int state) {
1662        return mWifiVendorHal.enableFirmwareRoaming(state);
1663    }
1664
1665    /**
1666     * Class for specifying the roaming configurations.
1667     */
1668    public static class RoamingConfig {
1669        public ArrayList<String> blacklistBssids;
1670        public ArrayList<String> whitelistSsids;
1671    }
1672
1673    /**
1674     * Set firmware roaming configurations.
1675     */
1676    public boolean configureRoaming(RoamingConfig config) {
1677        Log.d(mTAG, "configureRoaming ");
1678        return mWifiVendorHal.configureRoaming(config);
1679    }
1680
1681    /**
1682     * Reset firmware roaming configuration.
1683     */
1684    public boolean resetRoamingConfiguration() {
1685        // Pass in an empty RoamingConfig object which translates to zero size
1686        // blacklist and whitelist to reset the firmware roaming configuration.
1687        return mWifiVendorHal.configureRoaming(new RoamingConfig());
1688    }
1689
1690    /********************************************************
1691     * JNI operations
1692     ********************************************************/
1693    /* Register native functions */
1694    static {
1695        /* Native functions are defined in libwifi-service.so */
1696        System.loadLibrary("wifi-service");
1697        registerNatives();
1698    }
1699
1700    private static native int registerNatives();
1701    /* kernel logging support */
1702    private static native byte[] readKernelLogNative();
1703
1704    /**
1705     * Fetches the latest kernel logs.
1706     */
1707    public synchronized String readKernelLog() {
1708        byte[] bytes = readKernelLogNative();
1709        if (bytes != null) {
1710            CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
1711            try {
1712                CharBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
1713                return decoded.toString();
1714            } catch (CharacterCodingException cce) {
1715                return new String(bytes, StandardCharsets.ISO_8859_1);
1716            }
1717        } else {
1718            return "*** failed to read kernel log ***";
1719        }
1720    }
1721}
1722