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