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