WifiVendorHal.java revision d4c5eca00c9cae55561210479ed61a977923e0da
1/*
2 * Copyright (C) 2017 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 */
16package com.android.server.wifi;
17
18import android.hardware.wifi.V1_0.IWifiApIface;
19import android.hardware.wifi.V1_0.IWifiChip;
20import android.hardware.wifi.V1_0.IWifiChipEventCallback;
21import android.hardware.wifi.V1_0.IWifiIface;
22import android.hardware.wifi.V1_0.IWifiRttController;
23import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback;
24import android.hardware.wifi.V1_0.IWifiStaIface;
25import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback;
26import android.hardware.wifi.V1_0.IfaceType;
27import android.hardware.wifi.V1_0.RttBw;
28import android.hardware.wifi.V1_0.RttConfig;
29import android.hardware.wifi.V1_0.RttPeerType;
30import android.hardware.wifi.V1_0.RttPreamble;
31import android.hardware.wifi.V1_0.RttResponder;
32import android.hardware.wifi.V1_0.RttResult;
33import android.hardware.wifi.V1_0.RttType;
34import android.hardware.wifi.V1_0.StaBackgroundScanBucketEventReportSchemeMask;
35import android.hardware.wifi.V1_0.StaBackgroundScanBucketParameters;
36import android.hardware.wifi.V1_0.StaBackgroundScanParameters;
37import android.hardware.wifi.V1_0.StaRoamingConfig;
38import android.hardware.wifi.V1_0.StaRoamingState;
39import android.hardware.wifi.V1_0.StaScanData;
40import android.hardware.wifi.V1_0.StaScanDataFlagMask;
41import android.hardware.wifi.V1_0.StaScanResult;
42import android.hardware.wifi.V1_0.WifiBand;
43import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
44import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats;
45import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType;
46import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags;
47import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus;
48import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
49import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
50import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
51import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
52import android.hardware.wifi.V1_0.WifiInformationElement;
53import android.hardware.wifi.V1_0.WifiStatus;
54import android.hardware.wifi.V1_0.WifiStatusCode;
55import android.net.apf.ApfCapabilities;
56import android.net.wifi.RttManager;
57import android.net.wifi.RttManager.ResponderConfig;
58import android.net.wifi.ScanResult;
59import android.net.wifi.WifiInfo;
60import android.net.wifi.WifiLinkLayerStats;
61import android.net.wifi.WifiManager;
62import android.net.wifi.WifiScanner;
63import android.net.wifi.WifiSsid;
64import android.net.wifi.WifiWakeReasonAndCounts;
65import android.os.HandlerThread;
66import android.os.RemoteException;
67import android.util.Log;
68import android.util.MutableBoolean;
69import android.util.MutableInt;
70
71import com.android.internal.annotations.VisibleForTesting;
72import com.android.internal.util.ArrayUtils;
73import com.android.server.connectivity.KeepalivePacketData;
74import com.android.server.wifi.util.BitMask;
75import com.android.server.wifi.util.NativeUtil;
76
77import java.util.ArrayList;
78import java.util.Set;
79
80/**
81 * Vendor HAL via HIDL
82 */
83public class WifiVendorHal {
84
85    private static final String TAG = "WifiVendorHal";
86
87    // Vendor HAL HIDL interface objects.
88    private IWifiChip mIWifiChip;
89    private IWifiStaIface mIWifiStaIface;
90    private IWifiApIface mIWifiApIface;
91    private IWifiRttController mIWifiRttController;
92    private final HalDeviceManager mHalDeviceManager;
93    private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
94    private final HandlerThread mWifiStateMachineHandlerThread;
95    private final IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback;
96    private final IWifiChipEventCallback mIWifiChipEventCallback;
97
98    public WifiVendorHal(HalDeviceManager halDeviceManager,
99                         HandlerThread wifiStateMachineHandlerThread) {
100        mHalDeviceManager = halDeviceManager;
101        mWifiStateMachineHandlerThread = wifiStateMachineHandlerThread;
102        mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener();
103        mIWifiStaIfaceEventCallback = new StaIfaceEventCallback();
104        mIWifiChipEventCallback = new ChipEventCallback();
105    }
106
107    // TODO(mplass): figure out where we need locking in hidl world. b/33383725
108    public static final Object sLock = new Object();
109
110    private void handleRemoteException(RemoteException e) {
111        kilroy();
112        Log.e(TAG, "RemoteException in HIDL call " + e);
113    }
114
115    private void noteHidlError(WifiStatus status, String culprit) {
116        kilroy();
117        Log.e(TAG, "Error in " + culprit + " code: " + status.code
118                + " (" + status.description + ")");
119    }
120
121    /**
122     * Initialize the Hal device manager and register for status callbacks.
123     *
124     * @return
125     */
126    public boolean initialize() {
127        mHalDeviceManager.initialize();
128        mHalDeviceManager.registerStatusListener(
129                mHalDeviceManagerStatusCallbacks, mWifiStateMachineHandlerThread.getLooper());
130        return true;
131    }
132
133    /**
134     * Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode
135     *
136     * @return true for success
137     */
138    public boolean startVendorHalAp() {
139        return startVendorHal(AP_MODE);
140    }
141
142    /**
143     * Bring up the HIDL Vendor HAL and configure for STA (Station) mode
144     *
145     * @return true for success
146     */
147    public boolean startVendorHalSta() {
148        return startVendorHal(STA_MODE);
149    }
150
151    public static final boolean STA_MODE = true;
152    public static final boolean AP_MODE = false;
153
154    /**
155     * Bring up the HIDL Vendor HAL and configure for STA mode or AP mode.
156     *
157     * @param isStaMode true to start HAL in STA mode, false to start in AP mode.
158     */
159    public boolean startVendorHal(boolean isStaMode) {
160        if (!mHalDeviceManager.start()) {
161            Log.e(TAG, "Failed to start the vendor HAL");
162            return false;
163        }
164        IWifiIface iface;
165        if (isStaMode) {
166            mIWifiStaIface = mHalDeviceManager.createStaIface(null, null);
167            if (mIWifiStaIface == null) {
168                Log.e(TAG, "Failed to create STA Iface. Vendor Hal start failed");
169                mHalDeviceManager.stop();
170                return false;
171            }
172            iface = (IWifiIface) mIWifiStaIface;
173            if (!registerStaIfaceCallback()) {
174                Log.e(TAG, "Failed to register sta iface callback");
175                mHalDeviceManager.stop();
176                return false;
177            }
178            mIWifiRttController = mHalDeviceManager.createRttController(iface);
179            if (mIWifiRttController == null) {
180                Log.e(TAG, "Failed to create RTT controller. Vendor Hal start failed");
181                stopVendorHal();
182                return false;
183            }
184            enableLinkLayerStats();
185        } else {
186            mIWifiApIface = mHalDeviceManager.createApIface(null, null);
187            if (mIWifiApIface == null) {
188                Log.e(TAG, "Failed to create AP Iface. Vendor Hal start failed");
189                stopVendorHal();
190                return false;
191            }
192            iface = (IWifiIface) mIWifiApIface;
193        }
194        mIWifiChip = mHalDeviceManager.getChip(iface);
195        if (mIWifiChip == null) {
196            Log.e(TAG, "Failed to get the chip created for the Iface. Vendor Hal start failed");
197            stopVendorHal();
198            return false;
199        }
200        if (!registerChipCallback()) {
201            Log.e(TAG, "Failed to register chip callback");
202            mHalDeviceManager.stop();
203            return false;
204        }
205        Log.i(TAG, "Vendor Hal started successfully");
206        return true;
207    }
208
209    /**
210     * Registers the sta iface callback.
211     */
212    private boolean registerStaIfaceCallback() {
213        synchronized (sLock) {
214            if (mIWifiStaIface == null || mIWifiStaIfaceEventCallback == null) return false;
215            try {
216                kilroy();
217                WifiStatus status =
218                        mIWifiStaIface.registerEventCallback(mIWifiStaIfaceEventCallback);
219                return (status.code == WifiStatusCode.SUCCESS);
220            } catch (RemoteException e) {
221                kilroy();
222                handleRemoteException(e);
223                return false;
224            }
225        }
226    }
227
228    /**
229     * Registers the sta iface callback.
230     */
231    private boolean registerChipCallback() {
232        synchronized (sLock) {
233            if (mIWifiChip == null || mIWifiChipEventCallback == null) return false;
234            try {
235                kilroy();
236                WifiStatus status = mIWifiChip.registerEventCallback(mIWifiChipEventCallback);
237                return (status.code == WifiStatusCode.SUCCESS);
238            } catch (RemoteException e) {
239                kilroy();
240                handleRemoteException(e);
241                return false;
242            }
243        }
244    }
245
246    /**
247     * Stops the HAL
248     */
249    public void stopVendorHal() {
250        mHalDeviceManager.stop();
251        Log.i(TAG, "Vendor Hal stopped");
252    }
253
254    /**
255     * Tests whether the HAL is running or not
256     */
257    public boolean isHalStarted() {
258        return (mIWifiStaIface != null || mIWifiApIface != null);
259    }
260
261    /**
262     * Gets the scan capabilities
263     *
264     * @param capabilities object to be filled in
265     * @return true for success. false for failure
266     */
267    public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) {
268        synchronized (sLock) {
269            if (mIWifiStaIface == null) return false;
270            try {
271                MutableBoolean ok = new MutableBoolean(false);
272                WifiNative.ScanCapabilities out = capabilities;
273                mIWifiStaIface.getBackgroundScanCapabilities((status, cap) -> {
274                            kilroy();
275                            if (status.code != WifiStatusCode.SUCCESS) return;
276                            out.max_scan_cache_size = cap.maxCacheSize;
277                            out.max_ap_cache_per_scan = cap.maxApCachePerScan;
278                            out.max_scan_buckets = cap.maxBuckets;
279                            out.max_rssi_sample_size = 0;
280                            out.max_scan_reporting_threshold = cap.maxReportingThreshold;
281                            out.max_hotlist_bssids = 0;
282                            out.max_significant_wifi_change_aps = 0;
283                            out.max_bssid_history_entries = 0;
284                            out.max_number_epno_networks = 0;
285                            out.max_number_epno_networks_by_ssid = 0;
286                            out.max_number_of_white_listed_ssid = 0;
287                            ok.value = true;
288                        }
289                );
290                return ok.value;
291            } catch (RemoteException e) {
292                handleRemoteException(e);
293                return false;
294            }
295        }
296    }
297
298    /**
299     * Holds the current background scan state, to implement pause and restart
300     */
301    @VisibleForTesting
302    class CurrentBackgroundScan {
303        public int cmdId;
304        public StaBackgroundScanParameters param;
305        public WifiNative.ScanEventHandler eventHandler = null;
306        public boolean paused = false;
307        public WifiScanner.ScanData[] latestScanResults = null;
308
309        CurrentBackgroundScan(int id, WifiNative.ScanSettings settings) {
310            cmdId = id;
311            param = new StaBackgroundScanParameters();
312            param.basePeriodInMs = settings.base_period_ms;
313            param.maxApPerScan = settings.max_ap_per_scan;
314            param.reportThresholdPercent = settings.report_threshold_percent;
315            param.reportThresholdNumScans = settings.report_threshold_num_scans;
316            if (settings.buckets != null) {
317                for (WifiNative.BucketSettings bs : settings.buckets) {
318                    param.buckets.add(makeStaBackgroundScanBucketParametersFromBucketSettings(bs));
319                }
320            }
321        }
322    }
323
324    /**
325     * Makes the Hal flavor of WifiNative.BucketSettings
326     * @param bs WifiNative.BucketSettings
327     * @return Hal flavor of bs
328     * @throws IllegalArgumentException if band value is not recognized
329     */
330    private StaBackgroundScanBucketParameters
331            makeStaBackgroundScanBucketParametersFromBucketSettings(WifiNative.BucketSettings bs) {
332        StaBackgroundScanBucketParameters pa = new StaBackgroundScanBucketParameters();
333        pa.band = makeWifiBandFromFrameworkBand(bs.band);
334        if (bs.channels != null) {
335            for (WifiNative.ChannelSettings cs : bs.channels) {
336                pa.frequencies.add(cs.frequency);
337            }
338        }
339        pa.periodInMs = bs.period_ms;
340        pa.eventReportScheme = makeReportSchemeFromBucketSettingsReportEvents(bs.report_events);
341        pa.exponentialMaxPeriodInMs = bs.max_period_ms;
342        // Although HAL API allows configurable base value for the truncated
343        // exponential back off scan. Native API and above support only
344        // truncated binary exponential back off scan.
345        // Hard code value of base to 2 here.
346        pa.exponentialBase = 2;
347        pa.exponentialStepCount = bs.step_count;
348        return pa;
349    }
350
351    /**
352     * Makes the Hal flavor of WifiScanner's band indication
353     * @param frameworkBand one of WifiScanner.WIFI_BAND_*
354     * @return A WifiBand value
355     * @throws IllegalArgumentException if frameworkBand is not recognized
356     */
357    private int makeWifiBandFromFrameworkBand(int frameworkBand) {
358        switch (frameworkBand) {
359            case WifiScanner.WIFI_BAND_UNSPECIFIED:
360                return WifiBand.BAND_UNSPECIFIED;
361            case WifiScanner.WIFI_BAND_24_GHZ:
362                return WifiBand.BAND_24GHZ;
363            case WifiScanner.WIFI_BAND_5_GHZ:
364                return WifiBand.BAND_5GHZ;
365            case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
366                return WifiBand.BAND_5GHZ_DFS;
367            case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS:
368                return WifiBand.BAND_5GHZ_WITH_DFS;
369            case WifiScanner.WIFI_BAND_BOTH:
370                return WifiBand.BAND_24GHZ_5GHZ;
371            case WifiScanner.WIFI_BAND_BOTH_WITH_DFS:
372                return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS;
373            default:
374                throw new IllegalArgumentException("bad band " + frameworkBand);
375        }
376    }
377
378    /**
379     * Makes the Hal flavor of WifiScanner's report event mask
380     *
381     * @param reportUnderscoreEvents is logical OR of WifiScanner.REPORT_EVENT_* values
382     * @return Corresponding StaBackgroundScanBucketEventReportSchemeMask value
383     * @throws IllegalArgumentException if a mask bit is not recognized
384     */
385    private int makeReportSchemeFromBucketSettingsReportEvents(int reportUnderscoreEvents) {
386        int ans = 0;
387        BitMask in = new BitMask(reportUnderscoreEvents);
388        if (in.testAndClear(WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)) {
389            ans |= StaBackgroundScanBucketEventReportSchemeMask.EACH_SCAN;
390        }
391        if (in.testAndClear(WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)) {
392            ans |= StaBackgroundScanBucketEventReportSchemeMask.FULL_RESULTS;
393        }
394        if (in.testAndClear(WifiScanner.REPORT_EVENT_NO_BATCH)) {
395            ans |= StaBackgroundScanBucketEventReportSchemeMask.NO_BATCH;
396        }
397        if (in.value != 0) throw new IllegalArgumentException("bad " + reportUnderscoreEvents);
398        return ans;
399    }
400
401    private int mLastScanCmdId; // For assigning cmdIds to scans
402
403    @VisibleForTesting
404    CurrentBackgroundScan mScan = null;
405
406    /**
407     * Starts a background scan
408     *
409     * Any ongoing scan will be stopped first
410     *
411     * @param settings to control the scan
412     * @param eventHandler to call with the results
413     * @return true for success
414     */
415    public boolean startScan(WifiNative.ScanSettings settings,
416                             WifiNative.ScanEventHandler eventHandler) {
417        WifiStatus status;
418        kilroy();
419        if (eventHandler == null) return false;
420        synchronized (sLock) {
421            if (mIWifiStaIface == null) return false;
422            try {
423                if (mScan != null && !mScan.paused) {
424                    status = mIWifiStaIface.stopBackgroundScan(mScan.cmdId);
425                    if (status.code != WifiStatusCode.SUCCESS) {
426                        kilroy();
427                    }
428                    mScan = null;
429                }
430                mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits
431                CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings);
432                status = mIWifiStaIface.startBackgroundScan(scan.cmdId, scan.param);
433                if (status.code != WifiStatusCode.SUCCESS) return false;
434                kilroy();
435                scan.eventHandler = eventHandler;
436                mScan = scan;
437                return true;
438            } catch (RemoteException e) {
439                handleRemoteException(e);
440                return false;
441            }
442        }
443    }
444
445
446    /**
447     * Stops any ongoing backgound scan
448     */
449    public void stopScan() {
450        WifiStatus status;
451        synchronized (sLock) {
452            if (mIWifiStaIface == null) return;
453            try {
454                if (mScan != null) {
455                    mIWifiStaIface.stopBackgroundScan(mScan.cmdId);
456                    mScan = null;
457                }
458            } catch (RemoteException e) {
459                handleRemoteException(e);
460            }
461        }
462    }
463
464    /**
465     * Pauses an ongoing backgound scan
466     */
467    public void pauseScan() {
468        WifiStatus status;
469        kilroy();
470        synchronized (sLock) {
471            try {
472                if (mIWifiStaIface == null) return;
473                if (mScan != null && !mScan.paused) {
474                    status = mIWifiStaIface.stopBackgroundScan(mScan.cmdId);
475                    if (status.code != WifiStatusCode.SUCCESS) return;
476                    kilroy();
477                    mScan.paused = true;
478                }
479            } catch (RemoteException e) {
480                handleRemoteException(e);
481            }
482        }
483    }
484
485    /**
486     * Restarts a paused scan
487     */
488    public void restartScan() {
489        WifiStatus status;
490        kilroy();
491        synchronized (sLock) {
492            if (mIWifiStaIface == null) return;
493            try {
494                if (mScan != null && mScan.paused) {
495                    status = mIWifiStaIface.startBackgroundScan(mScan.cmdId, mScan.param);
496                    if (status.code != WifiStatusCode.SUCCESS) return;
497                    kilroy();
498                    mScan.paused = false;
499                }
500            } catch (RemoteException e) {
501                handleRemoteException(e);
502            }
503        }
504    }
505
506    /**
507     * Gets the latest scan results received from the HIDL interface callback.
508     * TODO(b/35754840): This hop to fetch scan results after callback is unnecessary. Refactor
509     * WifiScanner to use the scan results from the callback.
510     */
511    public WifiScanner.ScanData[] getScanResults() {
512        kilroy();
513        synchronized (sLock) {
514            if (mIWifiStaIface == null) return null;
515            if (mScan == null) return null;
516            return mScan.latestScanResults;
517        }
518    }
519
520    /**
521     * Get the link layer statistics
522     *
523     * Note - we always enable link layer stats on a STA interface.
524     *
525     * @return the statistics, or null if unable to do so
526     */
527    public WifiLinkLayerStats getWifiLinkLayerStats() {
528        kilroy();
529        synchronized (sLock) {
530            try {
531                if (mIWifiStaIface == null) return null;
532                kilroy();
533                WifiLinkLayerStats out = new WifiLinkLayerStats();
534                MutableBoolean ok = new MutableBoolean(false);
535                kilroy();
536                mIWifiStaIface.getLinkLayerStats((status, stats) -> {
537                            kilroy();
538                            if (status.code != WifiStatusCode.SUCCESS) return;
539                            out.status = 0; // TODO
540                            out.SSID = null; // TODO
541                            out.BSSID = null; // TODO
542                            out.beacon_rx = stats.iface.beaconRx;
543                            out.rssi_mgmt = stats.iface.avgRssiMgmt;
544                        /* WME Best Effort Access Category */
545                            out.rxmpdu_be = stats.iface.wmeBePktStats.rxMpdu;
546                            out.txmpdu_be = stats.iface.wmeBePktStats.txMpdu;
547                            out.lostmpdu_be = stats.iface.wmeBePktStats.lostMpdu;
548                            out.retries_be = stats.iface.wmeBePktStats.retries;
549                        /* WME Background Access Category */
550                            out.rxmpdu_bk = stats.iface.wmeBkPktStats.rxMpdu;
551                            out.txmpdu_bk = stats.iface.wmeBkPktStats.txMpdu;
552                            out.lostmpdu_bk = stats.iface.wmeBkPktStats.lostMpdu;
553                            out.retries_bk = stats.iface.wmeBkPktStats.retries;
554                        /* WME Video Access Category */
555                            out.rxmpdu_vi = stats.iface.wmeViPktStats.rxMpdu;
556                            out.txmpdu_vi = stats.iface.wmeViPktStats.txMpdu;
557                            out.lostmpdu_vi = stats.iface.wmeViPktStats.lostMpdu;
558                            out.retries_vi = stats.iface.wmeViPktStats.retries;
559                        /* WME Voice Access Category */
560                            out.rxmpdu_vo = stats.iface.wmeVoPktStats.rxMpdu;
561                            out.txmpdu_vo = stats.iface.wmeVoPktStats.txMpdu;
562                            out.lostmpdu_vo = stats.iface.wmeVoPktStats.lostMpdu;
563                            out.retries_vo = stats.iface.wmeVoPktStats.retries;
564                            out.on_time = stats.radio.onTimeInMs;
565                            out.tx_time = stats.radio.txTimeInMs;
566                            out.tx_time_per_level = new int[stats.radio.txTimeInMsPerLevel.size()];
567                            for (int i = 0; i < out.tx_time_per_level.length; i++) {
568                                out.tx_time_per_level[i] = stats.radio.txTimeInMsPerLevel.get(i);
569                            }
570                            out.rx_time = stats.radio.rxTimeInMs;
571                            out.on_time_scan = stats.radio.onTimeInMsForScan;
572                            kilroy();
573                            ok.value = true;
574                        }
575                );
576                return ok.value ? out : null;
577            } catch (RemoteException e) {
578                kilroy();
579                handleRemoteException(e);
580                return null;
581            }
582        }
583    }
584
585    @VisibleForTesting
586    boolean mLinkLayerStatsDebug = false;  // Passed to Hal
587
588    /**
589     * Enables the linkLayerStats in the Hal.
590     *
591     * This is called unconditionally whenever we create a STA interface.
592     *
593     */
594    private void enableLinkLayerStats() {
595        synchronized (sLock) {
596            try {
597                kilroy();
598                WifiStatus status;
599                status = mIWifiStaIface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug);
600                if (status.code != WifiStatusCode.SUCCESS) {
601                    kilroy();
602                    Log.e(TAG, "unable to enable link layer stats collection");
603                }
604            } catch (RemoteException e) {
605                kilroy();
606                handleRemoteException(e);
607            }
608        }
609    }
610
611    /**
612     * Translation table used by getSupportedFeatureSet for translating IWifiStaIface caps
613     */
614    private static final int[][] sFeatureCapabilityTranslation = {
615            {WifiManager.WIFI_FEATURE_INFRA_5G,
616                    IWifiStaIface.StaIfaceCapabilityMask.STA_5G
617            },
618            {WifiManager.WIFI_FEATURE_PASSPOINT,
619                    IWifiStaIface.StaIfaceCapabilityMask.HOTSPOT
620            },
621            {WifiManager.WIFI_FEATURE_SCANNER,
622                    IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN,
623            },
624            {WifiManager.WIFI_FEATURE_PNO,
625                    IWifiStaIface.StaIfaceCapabilityMask.PNO
626            },
627            {WifiManager.WIFI_FEATURE_TDLS,
628                    IWifiStaIface.StaIfaceCapabilityMask.TDLS
629            },
630            {WifiManager.WIFI_FEATURE_TDLS_OFFCHANNEL,
631                    IWifiStaIface.StaIfaceCapabilityMask.TDLS_OFFCHANNEL
632            },
633            {WifiManager.WIFI_FEATURE_LINK_LAYER_STATS,
634                    IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
635            },
636            {WifiManager.WIFI_FEATURE_RSSI_MONITOR,
637                    IWifiStaIface.StaIfaceCapabilityMask.RSSI_MONITOR
638            },
639            {WifiManager.WIFI_FEATURE_MKEEP_ALIVE,
640                    IWifiStaIface.StaIfaceCapabilityMask.KEEP_ALIVE
641            },
642            {WifiManager.WIFI_FEATURE_CONFIG_NDO,
643                    IWifiStaIface.StaIfaceCapabilityMask.ND_OFFLOAD
644            },
645            {WifiManager.WIFI_FEATURE_CONTROL_ROAMING,
646                    IWifiStaIface.StaIfaceCapabilityMask.CONTROL_ROAMING
647            },
648            {WifiManager.WIFI_FEATURE_IE_WHITELIST,
649                    IWifiStaIface.StaIfaceCapabilityMask.PROBE_IE_WHITELIST
650            },
651            {WifiManager.WIFI_FEATURE_SCAN_RAND,
652                    IWifiStaIface.StaIfaceCapabilityMask.SCAN_RAND
653            },
654    };
655
656    /**
657     * Feature bit mask translation for STAs
658     *
659     * @param capabilities bitmask defined IWifiStaIface.StaIfaceCapabilityMask
660     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
661     */
662    @VisibleForTesting
663    int wifiFeatureMaskFromStaCapabilities(int capabilities) {
664        int features = 0;
665        for (int i = 0; i < sFeatureCapabilityTranslation.length; i++) {
666            if ((capabilities & sFeatureCapabilityTranslation[i][1]) != 0) {
667                features |= sFeatureCapabilityTranslation[i][0];
668            }
669        }
670        return features;
671    }
672
673    /**
674     * Get the supported features
675     * <p>
676     * Note that not all the WifiManager.WIFI_FEATURE_* bits are supplied through
677     * this call. //TODO(b/34900537) fix this
678     *
679     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
680     */
681    public int getSupportedFeatureSet() {
682        int featureSet = 0;
683        try {
684            final MutableInt feat = new MutableInt(0);
685            synchronized (sLock) {
686                if (mIWifiStaIface != null) {
687                    mIWifiStaIface.getCapabilities((status, capabilities) -> {
688                        if (status.code != WifiStatusCode.SUCCESS) return;
689                        feat.value = wifiFeatureMaskFromStaCapabilities(capabilities);
690                    });
691                }
692            }
693            featureSet = feat.value;
694        } catch (RemoteException e) {
695            handleRemoteException(e);
696            return 0;
697        }
698
699        Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes();
700        if (supportedIfaceTypes.contains(IfaceType.STA)) {
701            featureSet |= WifiManager.WIFI_FEATURE_INFRA;
702        }
703        if (supportedIfaceTypes.contains(IfaceType.AP)) {
704            featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT;
705        }
706        if (supportedIfaceTypes.contains(IfaceType.P2P)) {
707            featureSet |= WifiManager.WIFI_FEATURE_P2P;
708        }
709        if (supportedIfaceTypes.contains(IfaceType.NAN)) {
710            featureSet |= WifiManager.WIFI_FEATURE_AWARE;
711        }
712
713        return featureSet;
714    }
715
716    /* RTT related commands/events */
717
718    /**
719     * RTT (Round Trip Time) measurement capabilities of the device.
720     */
721    public RttManager.RttCapabilities getRttCapabilities() {
722        kilroy();
723        class AnswerBox {
724            public RttManager.RttCapabilities value = null;
725        }
726        synchronized (sLock) {
727            if (mIWifiRttController == null) return null;
728            try {
729                AnswerBox box = new AnswerBox();
730                mIWifiRttController.getCapabilities((status, capabilities) -> {
731                    if (status.code != WifiStatusCode.SUCCESS) return;
732                    RttManager.RttCapabilities ans = new RttManager.RttCapabilities();
733                    ans.oneSidedRttSupported = capabilities.rttOneSidedSupported;
734                    ans.twoSided11McRttSupported = capabilities.rttFtmSupported;
735                    ans.lciSupported = capabilities.lciSupported;
736                    ans.lcrSupported = capabilities.lcrSupported;
737                    ans.preambleSupported = frameworkPreambleFromHalPreamble(
738                            capabilities.preambleSupport);
739                    ans.bwSupported = frameworkBwFromHalBw(capabilities.bwSupport);
740                    ans.responderSupported = capabilities.responderSupported;
741                    ans.secureRttSupported = false;
742                    ans.mcVersion = ((int) capabilities.mcVersion) & 0xff;
743                    kilroy();
744                    box.value = ans;
745                });
746                return box.value;
747            } catch (RemoteException e) {
748                handleRemoteException(e);
749                return null;
750            }
751        }
752    }
753
754    private int mRttCmdIdNext = 1;              // used to generate new command ids
755    private int mRttCmdId;                      // id of currently active request
756    private RttEventCallback mRttEventCallback; // currently active RTT callback
757
758    /**
759     * Receives a callback from the Hal and passes it along to our client using RttEventHandler
760     */
761    private class RttEventCallback extends IWifiRttControllerEventCallback.Stub {
762        WifiNative.RttEventHandler mRttEventHandler;
763        int mRttCmdId;
764
765        RttEventCallback(int cmdId, WifiNative.RttEventHandler rttEventHandler) {
766            kilroy();
767            mRttCmdId = cmdId;
768            mRttEventHandler = rttEventHandler;
769        }
770
771        @Override
772        public void onResults(int cmdId, java.util.ArrayList<RttResult> results) {
773            kilroy();
774            synchronized (sLock) {
775                kilroy();
776                if (cmdId != mRttCmdId || mRttEventHandler == null) return;
777                RttManager.RttResult[] rtt = new RttManager.RttResult[results.size()];
778                for (int i = 0; i < rtt.length; i++) {
779                    kilroy();
780                    rtt[i] = frameworkRttResultFromHalRttResult(results.get(i));
781                }
782                mRttEventHandler.onRttResults(rtt);
783            }
784        }
785    }
786
787    /**
788     * Converts a Hal RttResult to a RttManager.RttResult
789     */
790    @VisibleForTesting
791    static RttManager.RttResult frameworkRttResultFromHalRttResult(RttResult result) {
792        RttManager.RttResult ans = new RttManager.RttResult();
793        ans.bssid = NativeUtil.macAddressFromByteArray(result.addr);
794        ans.burstNumber = result.burstNum;
795        ans.measurementFrameNumber = result.measurementNumber;
796        ans.successMeasurementFrameNumber = result.successNumber;
797        ans.frameNumberPerBurstPeer = result.numberPerBurstPeer;
798        ans.status = result.status; //TODO(b/34901744) - don't assume identity translation
799        ans.retryAfterDuration = result.retryAfterDuration;
800        ans.measurementType = result.type;
801        ans.rssi = result.rssi;
802        ans.rssiSpread = result.rssiSpread;
803        //TODO(b/35138520) Fix HAL and framework to use the same units
804        ans.txRate = result.txRate.bitRateInKbps;
805        ans.rxRate = result.rxRate.bitRateInKbps;
806        ans.rtt = result.rtt;
807        ans.rttStandardDeviation = result.rttSd;
808        ans.rttSpread = result.rttSpread;
809        //TODO(b/35138520) These divide-by-10s were in the legacy Hal
810        ans.distance = result.distanceInMm / 10; // Convert cm to mm
811        ans.distanceStandardDeviation = result.distanceSdInMm / 10; // Convert cm to mm
812        ans.distanceSpread = result.distanceSpreadInMm / 10;
813
814        ans.ts = result.timeStampInUs;
815        ans.burstDuration = result.burstDurationInMs;
816        ans.negotiatedBurstNum = result.negotiatedBurstNum;
817        ans.LCI = ieFromHal(result.lci);
818        ans.LCR = ieFromHal(result.lcr);
819        ans.secure = false; // Not present in HIDL HAL
820        return ans;
821    }
822
823    /**
824     * Convert a Hal WifiInformationElement to its RttManager equivalent
825     */
826    @VisibleForTesting
827    static RttManager.WifiInformationElement ieFromHal(
828            android.hardware.wifi.V1_0.WifiInformationElement ie) {
829        if (ie == null) return null;
830        RttManager.WifiInformationElement ans = new RttManager.WifiInformationElement();
831        ans.id = ie.id;
832        ans.data = NativeUtil.byteArrayFromArrayList(ie.data);
833        return ans;
834    }
835
836    @VisibleForTesting
837    static RttConfig halRttConfigFromFrameworkRttParams(RttManager.RttParams params) {
838        RttConfig rttConfig = new RttConfig();
839        if (params.bssid != null) {
840            byte[] addr = NativeUtil.macAddressToByteArray(params.bssid);
841            for (int i = 0; i < rttConfig.addr.length; i++) {
842                rttConfig.addr[i] = addr[i];
843            }
844        }
845        rttConfig.type = halRttTypeFromFrameworkRttType(params.requestType);
846        rttConfig.peer = halPeerFromFrameworkPeer(params.deviceType);
847        rttConfig.channel.width = halChannelWidthFromFrameworkChannelWidth(params.channelWidth);
848        rttConfig.channel.centerFreq = params.frequency;
849        rttConfig.channel.centerFreq0 = params.centerFreq0;
850        rttConfig.channel.centerFreq1 = params.centerFreq1;
851        rttConfig.burstPeriod = params.interval; // In 100ms units, 0 means no specific
852        rttConfig.numBurst = params.numberBurst;
853        rttConfig.numFramesPerBurst = params.numSamplesPerBurst;
854        rttConfig.numRetriesPerRttFrame = params.numRetriesPerMeasurementFrame;
855        rttConfig.numRetriesPerFtmr = params.numRetriesPerFTMR;
856        rttConfig.mustRequestLci = params.LCIRequest;
857        rttConfig.mustRequestLcr = params.LCRRequest;
858        rttConfig.burstDuration = params.burstTimeout;
859        rttConfig.preamble = halPreambleFromFrameworkPreamble(params.preamble);
860        rttConfig.bw = halBwFromFrameworkBw(params.bandwidth);
861        return rttConfig;
862    }
863
864    @VisibleForTesting
865    static int halRttTypeFromFrameworkRttType(int frameworkRttType) {
866        switch (frameworkRttType) {
867            case RttManager.RTT_TYPE_ONE_SIDED:
868                return RttType.ONE_SIDED;
869            case RttManager.RTT_TYPE_TWO_SIDED:
870                return RttType.TWO_SIDED;
871            default:
872                throw new IllegalArgumentException("bad " + frameworkRttType);
873        }
874    }
875
876    @VisibleForTesting
877    static int frameworkRttTypeFromHalRttType(int halType) {
878        switch (halType) {
879            case RttType.ONE_SIDED:
880                return RttManager.RTT_TYPE_ONE_SIDED;
881            case RttType.TWO_SIDED:
882                return RttManager.RTT_TYPE_TWO_SIDED;
883            default:
884                throw new IllegalArgumentException("bad " + halType);
885        }
886    }
887
888    @VisibleForTesting
889    static int halPeerFromFrameworkPeer(int frameworkPeer) {
890        switch (frameworkPeer) {
891            case RttManager.RTT_PEER_TYPE_AP:
892                return RttPeerType.AP;
893            case RttManager.RTT_PEER_TYPE_STA:
894                return RttPeerType.STA;
895            case RttManager.RTT_PEER_P2P_GO:
896                return RttPeerType.P2P_GO;
897            case RttManager.RTT_PEER_P2P_CLIENT:
898                return RttPeerType.P2P_CLIENT;
899            case RttManager.RTT_PEER_NAN:
900                return RttPeerType.NAN;
901            default:
902                throw new IllegalArgumentException("bad " + frameworkPeer);
903        }
904    }
905
906    @VisibleForTesting
907    static int frameworkPeerFromHalPeer(int halPeer) {
908        switch (halPeer) {
909            case RttPeerType.AP:
910                return RttManager.RTT_PEER_TYPE_AP;
911            case RttPeerType.STA:
912                return RttManager.RTT_PEER_TYPE_STA;
913            case RttPeerType.P2P_GO:
914                return RttManager.RTT_PEER_P2P_GO;
915            case RttPeerType.P2P_CLIENT:
916                return RttManager.RTT_PEER_P2P_CLIENT;
917            case RttPeerType.NAN:
918                return RttManager.RTT_PEER_NAN;
919            default:
920                throw new IllegalArgumentException("bad " + halPeer);
921
922        }
923    }
924
925    @VisibleForTesting
926    static int halChannelWidthFromFrameworkChannelWidth(int frameworkChannelWidth) {
927        switch (frameworkChannelWidth) {
928            case ScanResult.CHANNEL_WIDTH_20MHZ:
929                return WifiChannelWidthInMhz.WIDTH_20;
930            case ScanResult.CHANNEL_WIDTH_40MHZ:
931                return WifiChannelWidthInMhz.WIDTH_40;
932            case ScanResult.CHANNEL_WIDTH_80MHZ:
933                return WifiChannelWidthInMhz.WIDTH_80;
934            case ScanResult.CHANNEL_WIDTH_160MHZ:
935                return WifiChannelWidthInMhz.WIDTH_160;
936            case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
937                return WifiChannelWidthInMhz.WIDTH_80P80;
938            default:
939                throw new IllegalArgumentException("bad " + frameworkChannelWidth);
940        }
941    }
942
943    @VisibleForTesting
944    static int frameworkChannelWidthFromHalChannelWidth(int halChannelWidth) {
945        switch (halChannelWidth) {
946            case WifiChannelWidthInMhz.WIDTH_20:
947                return ScanResult.CHANNEL_WIDTH_20MHZ;
948            case WifiChannelWidthInMhz.WIDTH_40:
949                return ScanResult.CHANNEL_WIDTH_40MHZ;
950            case WifiChannelWidthInMhz.WIDTH_80:
951                return ScanResult.CHANNEL_WIDTH_80MHZ;
952            case WifiChannelWidthInMhz.WIDTH_160:
953                return ScanResult.CHANNEL_WIDTH_160MHZ;
954            case WifiChannelWidthInMhz.WIDTH_80P80:
955                return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
956            default:
957                throw new IllegalArgumentException("bad " + halChannelWidth);
958        }
959    }
960
961    @VisibleForTesting
962    static int halPreambleFromFrameworkPreamble(int rttManagerPreamble) {
963        BitMask checkoff = new BitMask(rttManagerPreamble);
964        int flags = 0;
965        if (checkoff.testAndClear(RttManager.PREAMBLE_LEGACY)) {
966            flags |= RttPreamble.LEGACY;
967        }
968        if (checkoff.testAndClear(RttManager.PREAMBLE_HT)) {
969            flags |= RttPreamble.HT;
970        }
971        if (checkoff.testAndClear(RttManager.PREAMBLE_VHT)) {
972            flags |= RttPreamble.VHT;
973        }
974        if (checkoff.value != 0) {
975            throw new IllegalArgumentException("bad " + rttManagerPreamble);
976        }
977        return flags;
978    }
979
980    @VisibleForTesting
981    static int frameworkPreambleFromHalPreamble(int halPreamble) {
982        BitMask checkoff = new BitMask(halPreamble);
983        int flags = 0;
984        if (checkoff.testAndClear(RttPreamble.LEGACY)) {
985            flags |= RttManager.PREAMBLE_LEGACY;
986        }
987        if (checkoff.testAndClear(RttPreamble.HT)) {
988            flags |= RttManager.PREAMBLE_HT;
989        }
990        if (checkoff.testAndClear(RttPreamble.VHT)) {
991            flags |= RttManager.PREAMBLE_VHT;
992        }
993        if (checkoff.value != 0) {
994            throw new IllegalArgumentException("bad " + halPreamble);
995        }
996        return flags;
997    }
998
999    @VisibleForTesting
1000    static int halBwFromFrameworkBw(int rttManagerBandwidth) {
1001        BitMask checkoff = new BitMask(rttManagerBandwidth);
1002        int flags = 0;
1003        if (checkoff.testAndClear(RttManager.RTT_BW_5_SUPPORT)) {
1004            flags |= RttBw.BW_5MHZ;
1005        }
1006        if (checkoff.testAndClear(RttManager.RTT_BW_10_SUPPORT)) {
1007            flags |= RttBw.BW_10MHZ;
1008        }
1009        if (checkoff.testAndClear(RttManager.RTT_BW_20_SUPPORT)) {
1010            flags |= RttBw.BW_20MHZ;
1011        }
1012        if (checkoff.testAndClear(RttManager.RTT_BW_40_SUPPORT)) {
1013            flags |= RttBw.BW_40MHZ;
1014        }
1015        if (checkoff.testAndClear(RttManager.RTT_BW_80_SUPPORT)) {
1016            flags |= RttBw.BW_80MHZ;
1017        }
1018        if (checkoff.testAndClear(RttManager.RTT_BW_160_SUPPORT)) {
1019            flags |= RttBw.BW_160MHZ;
1020        }
1021        if (checkoff.value != 0) {
1022            throw new IllegalArgumentException("bad " + rttManagerBandwidth);
1023        }
1024        return flags;
1025    }
1026
1027    @VisibleForTesting
1028    static int frameworkBwFromHalBw(int rttBw) {
1029        BitMask checkoff = new BitMask(rttBw);
1030        int flags = 0;
1031        if (checkoff.testAndClear(RttBw.BW_5MHZ)) {
1032            flags |= RttManager.RTT_BW_5_SUPPORT;
1033        }
1034        if (checkoff.testAndClear(RttBw.BW_10MHZ)) {
1035            flags |= RttManager.RTT_BW_10_SUPPORT;
1036        }
1037        if (checkoff.testAndClear(RttBw.BW_20MHZ)) {
1038            flags |= RttManager.RTT_BW_20_SUPPORT;
1039        }
1040        if (checkoff.testAndClear(RttBw.BW_40MHZ)) {
1041            flags |= RttManager.RTT_BW_40_SUPPORT;
1042        }
1043        if (checkoff.testAndClear(RttBw.BW_80MHZ)) {
1044            flags |= RttManager.RTT_BW_80_SUPPORT;
1045        }
1046        if (checkoff.testAndClear(RttBw.BW_160MHZ)) {
1047            flags |= RttManager.RTT_BW_160_SUPPORT;
1048        }
1049        if (checkoff.value != 0) {
1050            throw new IllegalArgumentException("bad " + rttBw);
1051        }
1052        return flags;
1053    }
1054
1055    @VisibleForTesting
1056    static ArrayList<RttConfig> halRttConfigArrayFromFrameworkRttParamsArray(
1057            RttManager.RttParams[] params) {
1058        final int length = params.length;
1059        ArrayList<RttConfig> config = new ArrayList<RttConfig>(length);
1060        for (int i = 0; i < length; i++) {
1061            config.add(halRttConfigFromFrameworkRttParams(params[i]));
1062        }
1063        return config;
1064    }
1065
1066    /**
1067     * Starts a new rtt request
1068     *
1069     * @param params
1070     * @param handler
1071     * @return success indication
1072     */
1073    public boolean requestRtt(RttManager.RttParams[] params, WifiNative.RttEventHandler handler) {
1074        kilroy();
1075        ArrayList<RttConfig> rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params);
1076        synchronized (sLock) {
1077            if (mIWifiRttController == null) return false;
1078            if (mRttCmdId != 0) return false;
1079            mRttCmdId = mRttCmdIdNext++;
1080            if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1;
1081            try {
1082                mRttEventCallback = new RttEventCallback(mRttCmdId, handler);
1083                WifiStatus status = mIWifiRttController.rangeRequest(mRttCmdId, rttConfigs);
1084                if (status.code == WifiStatusCode.SUCCESS) {
1085                    kilroy();
1086                    status = mIWifiRttController.registerEventCallback(mRttEventCallback);
1087                }
1088                if (status.code == WifiStatusCode.SUCCESS) {
1089                    kilroy();
1090                    return true;
1091                }
1092                noteHidlError(status, "requestRtt");
1093                mRttCmdId = 0;
1094                return false;
1095            } catch (RemoteException e) {
1096                handleRemoteException(e);
1097                return false;
1098            }
1099        }
1100    }
1101
1102    /**
1103     * Cancels an outstanding rtt request
1104     *
1105     * @param params
1106     * @return true if there was an outstanding request and it was successfully cancelled
1107     */
1108    public boolean cancelRtt(RttManager.RttParams[] params) {
1109        kilroy();
1110        ArrayList<RttConfig> rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params);
1111        synchronized (sLock) {
1112            if (mIWifiRttController == null) return false;
1113            if (mRttCmdId == 0) return false;
1114            ArrayList<byte[/* 6 */]> addrs = new ArrayList<byte[]>(rttConfigs.size());
1115            for (RttConfig x : rttConfigs) addrs.add(x.addr);
1116            try {
1117                WifiStatus status = mIWifiRttController.rangeCancel(mRttCmdId, addrs);
1118                mRttCmdId = 0;
1119                if (status.code != WifiStatusCode.SUCCESS) return false;
1120                kilroy();
1121                return true;
1122            } catch (RemoteException e) {
1123                handleRemoteException(e);
1124                return false;
1125            }
1126        }
1127    }
1128
1129    private int mRttResponderCmdId = 0;
1130
1131    /**
1132     * Get RTT responder information e.g. WiFi channel to enable responder on.
1133     * @return info Instance of |RttResponder|, or null for error.
1134     */
1135    private RttResponder getRttResponder() {
1136        kilroy();
1137        class AnswerBox {
1138            public RttResponder value = null;
1139        }
1140        synchronized (sLock) {
1141            if (mIWifiRttController == null) return null;
1142            AnswerBox answer = new AnswerBox();
1143            try {
1144                mIWifiRttController.getResponderInfo((status, info) -> {
1145                    if (status.code != WifiStatusCode.SUCCESS) return;
1146                    kilroy();
1147                    answer.value = info;
1148                });
1149                return answer.value;
1150            } catch (RemoteException e) {
1151                handleRemoteException(e);
1152                return null;
1153            }
1154        }
1155    }
1156
1157    /**
1158     * Convert Hal RttResponder to a framework ResponderConfig
1159     * @param info Instance of |RttResponder|
1160     * @return framework version of same
1161     */
1162    private ResponderConfig frameworkResponderConfigFromHalRttResponder(RttResponder info) {
1163        ResponderConfig config = new ResponderConfig();
1164        config.frequency = info.channel.centerFreq;
1165        config.centerFreq0 = info.channel.centerFreq0;
1166        config.centerFreq1 = info.channel.centerFreq1;
1167        config.channelWidth = frameworkChannelWidthFromHalChannelWidth(info.channel.width);
1168        config.preamble = frameworkPreambleFromHalPreamble(info.preamble);
1169        return config;
1170    }
1171
1172    /**
1173     * Enables RTT responder role on the device.
1174     *
1175     * @return {@link ResponderConfig} if the responder role is successfully enabled,
1176     * {@code null} otherwise.
1177     */
1178    public ResponderConfig enableRttResponder(int timeoutSeconds) {
1179        kilroy();
1180        RttResponder info = getRttResponder();
1181        synchronized (sLock) {
1182            if (mIWifiRttController == null) return null;
1183            if (mRttResponderCmdId != 0) {
1184                Log.e(TAG, "responder mode already enabled - this shouldn't happen");
1185                return null;
1186            }
1187            ResponderConfig config = null;
1188            int id = mRttCmdIdNext++;
1189            if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1;
1190            try {
1191                WifiStatus status = mIWifiRttController.enableResponder(
1192                        /* cmdId */id,
1193                        /* WifiChannelInfo channelHint */null,
1194                        timeoutSeconds, info);
1195                if (status.code == WifiStatusCode.SUCCESS) {
1196                    mRttResponderCmdId = id;
1197                    config = frameworkResponderConfigFromHalRttResponder(info);
1198                    Log.d(TAG, "enabling rtt " + mRttResponderCmdId);
1199                } else {
1200                    noteHidlError(status, "enableRttResponder");
1201                }
1202                return config;
1203            } catch (RemoteException e) {
1204                handleRemoteException(e);
1205                return null;
1206            }
1207        }
1208    }
1209
1210    /**
1211     * Disables RTT responder role.
1212     *
1213     * @return {@code true} if responder role is successfully disabled,
1214     * {@code false} otherwise.
1215     */
1216    public boolean disableRttResponder() {
1217        kilroy();
1218        synchronized (sLock) {
1219            if (mIWifiRttController == null) return false;
1220            if (mRttResponderCmdId == 0) return false;
1221            try {
1222                WifiStatus status = mIWifiRttController.disableResponder(mRttResponderCmdId);
1223                mRttResponderCmdId = 0;
1224                if (status.code != WifiStatusCode.SUCCESS) return false;
1225                kilroy();
1226                return true;
1227            } catch (RemoteException e) {
1228                handleRemoteException(e);
1229                return false;
1230            }
1231        }
1232    }
1233
1234    /**
1235     * Set the MAC OUI during scanning.
1236     *
1237     * An OUI {Organizationally Unique Identifier} is a 24-bit number that
1238     * uniquely identifies a vendor or manufacturer.
1239     *
1240     * @param oui
1241     * @return true for success
1242     */
1243    public boolean setScanningMacOui(byte[] oui) {
1244        kilroy();
1245        if (oui == null) return false;
1246        kilroy();
1247        if (oui.length != 3) return false;
1248        kilroy();
1249        synchronized (sLock) {
1250            try {
1251                if (mIWifiStaIface == null) return false;
1252                WifiStatus status = mIWifiStaIface.setScanningMacOui(oui);
1253                if (status.code != WifiStatusCode.SUCCESS) return false;
1254                kilroy();
1255                return true;
1256            } catch (RemoteException e) {
1257                handleRemoteException(e);
1258                return false;
1259            }
1260        }
1261    }
1262
1263    /**
1264     * Query the list of valid frequencies for the provided band.
1265     *
1266     * The result depends on the on the country code that has been set.
1267     *
1268     * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1269     * @return frequencies vector of valid frequencies (MHz), or null for error.
1270     * @throws IllegalArgumentException if band is not recognized.
1271     */
1272    public int[] getChannelsForBand(int band) {
1273        kilroy();
1274        class AnswerBox {
1275            public int[] value = null;
1276        }
1277        synchronized (sLock) {
1278            try {
1279                AnswerBox box = new AnswerBox();
1280                int hb = makeWifiBandFromFrameworkBand(band);
1281                if (mIWifiStaIface != null) {
1282                    mIWifiStaIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
1283                        if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
1284                            kilroy();
1285                            mChannelsForBandSupport = false;
1286                        }
1287                        if (status.code != WifiStatusCode.SUCCESS) return;
1288                        mChannelsForBandSupport = true;
1289                        kilroy();
1290                        box.value = intArrayFromArrayList(frequencies);
1291                    });
1292                } else if (mIWifiApIface != null) {
1293                    mIWifiApIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
1294                        if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
1295                            kilroy();
1296                            mChannelsForBandSupport = false;
1297                        }
1298                        if (status.code != WifiStatusCode.SUCCESS) return;
1299                        mChannelsForBandSupport = true;
1300                        kilroy();
1301                        box.value = intArrayFromArrayList(frequencies);
1302                    });
1303                }
1304                return box.value;
1305            } catch (RemoteException e) {
1306                handleRemoteException(e);
1307                return null;
1308            }
1309        }
1310    }
1311
1312    private int[] intArrayFromArrayList(ArrayList<Integer> in) {
1313        int[] ans = new int[in.size()];
1314        int i = 0;
1315        for (Integer e : in) ans[i++] = e;
1316        return ans;
1317    }
1318
1319    /**
1320     * This holder is null until we know whether or not there is frequency-for-band support.
1321     *
1322     * Set as a side-effect of getChannelsForBand.
1323     */
1324    @VisibleForTesting
1325    Boolean mChannelsForBandSupport = null;
1326
1327    /**
1328     * Indicates whether getChannelsForBand is supported.
1329     *
1330     * @return true if it is.
1331     */
1332    public boolean isGetChannelsForBandSupported() {
1333        if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
1334        getChannelsForBand(WifiBand.BAND_24GHZ);
1335        if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
1336        return false;
1337    }
1338
1339    /**
1340     * Set DFS - actually, this is always on.
1341     *
1342     * @param dfsOn
1343     * @return success indication
1344     */
1345    public boolean setDfsFlag(boolean dfsOn) {
1346        return dfsOn;
1347    }
1348
1349    /**
1350     * Get the APF (Android Packet Filter) capabilities of the device
1351     */
1352    public ApfCapabilities getApfCapabilities() {
1353        class AnswerBox {
1354            public ApfCapabilities value = sNoApfCapabilities;
1355        }
1356        synchronized (sLock) {
1357            try {
1358                if (mIWifiStaIface == null) return sNoApfCapabilities;
1359                AnswerBox box = new AnswerBox();
1360                mIWifiStaIface.getApfPacketFilterCapabilities((status, capabilities) -> {
1361                    if (status.code != WifiStatusCode.SUCCESS) return;
1362                    box.value = new ApfCapabilities(
1363                        /* apfVersionSupported */   capabilities.version,
1364                        /* maximumApfProgramSize */ capabilities.maxLength,
1365                        /* apfPacketFormat */       android.system.OsConstants.ARPHRD_ETHER);
1366                });
1367                return box.value;
1368            } catch (RemoteException e) {
1369                handleRemoteException(e);
1370                return sNoApfCapabilities;
1371            }
1372        }
1373    }
1374
1375    private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0);
1376
1377    /**
1378     * Installs an APF program on this iface, replacing any existing program.
1379     *
1380     * @param filter is the android packet filter program
1381     * @return true for success
1382     */
1383    public boolean installPacketFilter(byte[] filter) {
1384        kilroy();
1385        int cmdId = 0; //TODO(b/34901818) We only aspire to support one program at a time
1386        if (filter == null) return false;
1387        // Copy the program before taking the lock.
1388        ArrayList<Byte> program = NativeUtil.byteArrayToArrayList(filter);
1389        synchronized (sLock) {
1390            try {
1391                if (mIWifiStaIface == null) return false;
1392                WifiStatus status = mIWifiStaIface.installApfPacketFilter(cmdId, program);
1393                if (status.code != WifiStatusCode.SUCCESS) return false;
1394                kilroy();
1395                return true;
1396            } catch (RemoteException e) {
1397                handleRemoteException(e);
1398                return false;
1399            }
1400        }
1401    }
1402
1403    /**
1404     * Set country code for this AP iface.
1405     *
1406     * @param countryCode - two-letter country code (as ISO 3166)
1407     * @return true for success
1408     */
1409    public boolean setCountryCodeHal(String countryCode) {
1410        kilroy();
1411        if (countryCode == null) return false;
1412        if (countryCode.length() != 2) return false;
1413        byte[] code;
1414        try {
1415            code = NativeUtil.stringToByteArray(countryCode);
1416        } catch (IllegalArgumentException e) {
1417            kilroy();
1418            return false;
1419        }
1420        synchronized (sLock) {
1421            try {
1422                if (mIWifiApIface == null) return false;
1423                kilroy();
1424                WifiStatus status = mIWifiApIface.setCountryCode(code);
1425                if (status.code != WifiStatusCode.SUCCESS) return false;
1426                kilroy();
1427                return true;
1428            } catch (RemoteException e) {
1429                handleRemoteException(e);
1430                return false;
1431            }
1432        }
1433    }
1434
1435    /**
1436     * to be implemented TODO(b/34901821)
1437     */
1438    public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) {
1439        kilroy();
1440        throw new UnsupportedOperationException();
1441    }
1442
1443    /**
1444     * Control debug data collection
1445     *
1446     * @param verboseLevel       0 to 3, inclusive. 0 stops logging.
1447     * @param flags              Ignored.
1448     * @param maxIntervalInSec   Maximum interval between reports; ignore if 0.
1449     * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0.
1450     * @param ringName           Name of the ring for which data collection is to start.
1451     * @return true for success
1452     */
1453    public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec,
1454                                          int minDataSizeInBytes, String ringName) {
1455        kilroy();
1456        synchronized (sLock) {
1457            try {
1458                if (mIWifiChip == null) return false;
1459                kilroy();
1460                // note - flags are not used
1461                WifiStatus status = mIWifiChip.startLoggingToDebugRingBuffer(
1462                        ringName,
1463                        verboseLevel,
1464                        maxIntervalInSec,
1465                        minDataSizeInBytes
1466                );
1467                return status.code == WifiStatusCode.SUCCESS;
1468            } catch (RemoteException e) {
1469                kilroy();
1470                handleRemoteException(e);
1471                return false;
1472            }
1473        }
1474    }
1475
1476    /**
1477     * Pointlessly fail
1478     *
1479     * @return -1
1480     */
1481    public int getSupportedLoggerFeatureSet() {
1482        return -1;
1483    }
1484
1485    /**
1486     * to be implemented TODO(b/34901821)
1487     */
1488    public boolean resetLogHandler() {
1489        kilroy();
1490        throw new UnsupportedOperationException();
1491    }
1492
1493    private String mDriverDescription; // Cached value filled by requestChipDebugInfo()
1494
1495    /**
1496     * Vendor-provided wifi driver version string
1497     */
1498    public String getDriverVersion() {
1499        synchronized (sLock) {
1500            if (mDriverDescription == null) requestChipDebugInfo();
1501            return mDriverDescription;
1502        }
1503    }
1504
1505    private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo()
1506
1507    /**
1508     * Vendor-provided wifi firmware version string
1509     */
1510    public String getFirmwareVersion() {
1511        synchronized (sLock) {
1512            if (mFirmwareDescription == null) requestChipDebugInfo();
1513            return mFirmwareDescription;
1514        }
1515    }
1516
1517    /**
1518     * Refreshes our idea of the driver and firmware versions
1519     */
1520    private void requestChipDebugInfo() {
1521        mDriverDescription = null;
1522        mFirmwareDescription = null;
1523        try {
1524            if (mIWifiChip == null) return;
1525            mIWifiChip.requestChipDebugInfo((status, chipDebugInfo) -> {
1526                if (status.code != WifiStatusCode.SUCCESS) return;
1527                mDriverDescription = chipDebugInfo.driverDescription;
1528                mFirmwareDescription = chipDebugInfo.firmwareDescription;
1529            });
1530        } catch (RemoteException e) {
1531            handleRemoteException(e);
1532            return;
1533        }
1534        Log.e(TAG, "Driver: " + mDriverDescription + " Firmware: " + mFirmwareDescription);
1535    }
1536
1537    /**
1538     * Creates RingBufferStatus from the Hal version
1539     */
1540    private static WifiNative.RingBufferStatus ringBufferStatus(WifiDebugRingBufferStatus h) {
1541        WifiNative.RingBufferStatus ans = new WifiNative.RingBufferStatus();
1542        ans.name = h.ringName;
1543        ans.flag = frameworkRingBufferFlagsFromHal(h.flags);
1544        ans.ringBufferId = h.ringId;
1545        ans.ringBufferByteSize = h.sizeInBytes;
1546        ans.verboseLevel = h.verboseLevel;
1547        // Remaining fields are unavailable
1548        //  writtenBytes;
1549        //  readBytes;
1550        //  writtenRecords;
1551        return ans;
1552    }
1553
1554    /**
1555     * Translates a hal wifiDebugRingBufferFlag to the WifiNative version
1556     */
1557    private static int frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag) {
1558        BitMask checkoff = new BitMask(wifiDebugRingBufferFlag);
1559        int flags = 0;
1560        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES)) {
1561            flags |= WifiNative.RingBufferStatus.HAS_BINARY_ENTRIES;
1562        }
1563        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES)) {
1564            flags |= WifiNative.RingBufferStatus.HAS_ASCII_ENTRIES;
1565        }
1566        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES)) {
1567            flags |= WifiNative.RingBufferStatus.HAS_PER_PACKET_ENTRIES;
1568        }
1569        if (checkoff.value != 0) {
1570            throw new IllegalArgumentException("Unknown WifiDebugRingBufferFlag " + checkoff.value);
1571        }
1572        return flags;
1573    }
1574
1575    /**
1576     * Creates array of RingBufferStatus from the Hal version
1577     */
1578    private static WifiNative.RingBufferStatus[] makeRingBufferStatusArray(
1579            ArrayList<WifiDebugRingBufferStatus> ringBuffers) {
1580        WifiNative.RingBufferStatus[] ans = new WifiNative.RingBufferStatus[ringBuffers.size()];
1581        int i = 0;
1582        for (WifiDebugRingBufferStatus b : ringBuffers) {
1583            ans[i++] = ringBufferStatus(b);
1584        }
1585        return ans;
1586    }
1587
1588    /**
1589     * API to get the status of all ring buffers supported by driver
1590     */
1591    public WifiNative.RingBufferStatus[] getRingBufferStatus() {
1592        kilroy();
1593        class AnswerBox {
1594            public WifiNative.RingBufferStatus[] value = null;
1595        }
1596        AnswerBox ans = new AnswerBox();
1597        synchronized (sLock) {
1598            if (mIWifiChip == null) return null;
1599            try {
1600                kilroy();
1601                mIWifiChip.getDebugRingBuffersStatus((status, ringBuffers) -> {
1602                    kilroy();
1603                    if (status.code != WifiStatusCode.SUCCESS) return;
1604                    ans.value = makeRingBufferStatusArray(ringBuffers);
1605                });
1606            } catch (RemoteException e) {
1607                kilroy();
1608                handleRemoteException(e);
1609                return null;
1610            }
1611        }
1612        return ans.value;
1613    }
1614
1615    /**
1616     * indicates to driver that all
1617     * the data has to be uploaded urgently
1618     */
1619    public boolean getRingBufferData(String ringName) {
1620        kilroy();
1621        synchronized (sLock) {
1622            try {
1623                if (mIWifiChip == null) return false;
1624                kilroy();
1625                WifiStatus status = mIWifiChip.forceDumpToDebugRingBuffer(ringName);
1626                return status.code == WifiStatusCode.SUCCESS;
1627            } catch (RemoteException e) {
1628                handleRemoteException(e);
1629                return false;
1630            }
1631        }
1632    }
1633
1634    /**
1635     * Request vendor debug info from the firmware
1636     */
1637    public byte[] getFwMemoryDump() {
1638        kilroy();
1639        class AnswerBox {
1640            public byte[] value;
1641        }
1642        AnswerBox ans = new AnswerBox();
1643        synchronized (sLock) {
1644            if (mIWifiChip == null) return (null);
1645            try {
1646                kilroy();
1647                mIWifiChip.requestFirmwareDebugDump((status, blob) -> {
1648                    kilroy();
1649                    if (status.code != WifiStatusCode.SUCCESS) return;
1650                    kilroy();
1651                    ans.value = NativeUtil.byteArrayFromArrayList(blob);
1652                });
1653            } catch (RemoteException e) {
1654                kilroy();
1655                handleRemoteException(e);
1656                return null;
1657            }
1658        }
1659        return ans.value;
1660    }
1661
1662    /**
1663     * Request vendor debug info from the driver
1664     */
1665    public byte[] getDriverStateDump() {
1666        kilroy();
1667        class AnswerBox {
1668            public byte[] value;
1669        }
1670        AnswerBox ans = new AnswerBox();
1671        synchronized (sLock) {
1672            if (mIWifiChip == null) return (null);
1673            try {
1674                kilroy();
1675                mIWifiChip.requestDriverDebugDump((status, blob) -> {
1676                    kilroy();
1677                    if (status.code != WifiStatusCode.SUCCESS) return;
1678                    kilroy();
1679                    ans.value = NativeUtil.byteArrayFromArrayList(blob);
1680                });
1681            } catch (RemoteException e) {
1682                kilroy();
1683                handleRemoteException(e);
1684                return null;
1685            }
1686        }
1687        return ans.value;
1688    }
1689
1690    /**
1691     * Start packet fate monitoring
1692     *
1693     * Once started, monitoring remains active until HAL is unloaded.
1694     *
1695     * @return true for success
1696     */
1697    public boolean startPktFateMonitoring() {
1698        kilroy();
1699        synchronized (sLock) {
1700            if (mIWifiStaIface == null) return false;
1701            try {
1702                kilroy();
1703                WifiStatus status = mIWifiStaIface.startDebugPacketFateMonitoring();
1704                return status.code == WifiStatusCode.SUCCESS;
1705            } catch (RemoteException e) {
1706                kilroy();
1707                handleRemoteException(e);
1708                return false;
1709            }
1710        }
1711    }
1712
1713    private byte halToFrameworkPktFateFrameType(int type) {
1714        switch (type) {
1715            case WifiDebugPacketFateFrameType.UNKNOWN:
1716                return WifiLoggerHal.FRAME_TYPE_UNKNOWN;
1717            case WifiDebugPacketFateFrameType.ETHERNET_II:
1718                return WifiLoggerHal.FRAME_TYPE_ETHERNET_II;
1719            case WifiDebugPacketFateFrameType.MGMT_80211:
1720                return WifiLoggerHal.FRAME_TYPE_80211_MGMT;
1721            default:
1722                throw new IllegalArgumentException("bad " + type);
1723        }
1724    }
1725
1726    private byte halToFrameworkRxPktFate(int type) {
1727        switch (type) {
1728            case WifiDebugRxPacketFate.SUCCESS:
1729                return WifiLoggerHal.RX_PKT_FATE_SUCCESS;
1730            case WifiDebugRxPacketFate.FW_QUEUED:
1731                return WifiLoggerHal.RX_PKT_FATE_FW_QUEUED;
1732            case WifiDebugRxPacketFate.FW_DROP_FILTER:
1733                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER;
1734            case WifiDebugRxPacketFate.FW_DROP_INVALID:
1735                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID;
1736            case WifiDebugRxPacketFate.FW_DROP_NOBUFS:
1737                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS;
1738            case WifiDebugRxPacketFate.FW_DROP_OTHER:
1739                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER;
1740            case WifiDebugRxPacketFate.DRV_QUEUED:
1741                return WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED;
1742            case WifiDebugRxPacketFate.DRV_DROP_FILTER:
1743                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER;
1744            case WifiDebugRxPacketFate.DRV_DROP_INVALID:
1745                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID;
1746            case WifiDebugRxPacketFate.DRV_DROP_NOBUFS:
1747                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS;
1748            case WifiDebugRxPacketFate.DRV_DROP_OTHER:
1749                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER;
1750            default:
1751                throw new IllegalArgumentException("bad " + type);
1752        }
1753    }
1754
1755    private byte halToFrameworkTxPktFate(int type) {
1756        switch (type) {
1757            case WifiDebugTxPacketFate.ACKED:
1758                return WifiLoggerHal.TX_PKT_FATE_ACKED;
1759            case WifiDebugTxPacketFate.SENT:
1760                return WifiLoggerHal.TX_PKT_FATE_SENT;
1761            case WifiDebugTxPacketFate.FW_QUEUED:
1762                return WifiLoggerHal.TX_PKT_FATE_FW_QUEUED;
1763            case WifiDebugTxPacketFate.FW_DROP_INVALID:
1764                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID;
1765            case WifiDebugTxPacketFate.FW_DROP_NOBUFS:
1766                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS;
1767            case WifiDebugTxPacketFate.FW_DROP_OTHER:
1768                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER;
1769            case WifiDebugTxPacketFate.DRV_QUEUED:
1770                return WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED;
1771            case WifiDebugTxPacketFate.DRV_DROP_INVALID:
1772                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID;
1773            case WifiDebugTxPacketFate.DRV_DROP_NOBUFS:
1774                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS;
1775            case WifiDebugTxPacketFate.DRV_DROP_OTHER:
1776                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER;
1777            default:
1778                throw new IllegalArgumentException("bad " + type);
1779        }
1780    }
1781
1782    /**
1783     * Retrieve fates of outbound packets
1784     *
1785     * Reports the outbound frames for the most recent association (space allowing).
1786     *
1787     * @param reportBufs
1788     * @return true for success
1789     */
1790    public boolean getTxPktFates(WifiNative.TxFateReport[] reportBufs) {
1791        kilroy();
1792        if (ArrayUtils.isEmpty(reportBufs)) return false;
1793        synchronized (sLock) {
1794            if (mIWifiStaIface == null) return false;
1795            try {
1796                kilroy();
1797                MutableBoolean ok = new MutableBoolean(false);
1798                mIWifiStaIface.getDebugTxPacketFates((status, fates) -> {
1799                            kilroy();
1800                            if (status.code != WifiStatusCode.SUCCESS) return;
1801                            int i = 0;
1802                            for (WifiDebugTxPacketFateReport fate : fates) {
1803                                kilroy();
1804                                if (i >= reportBufs.length) break;
1805                                byte code = halToFrameworkTxPktFate(fate.fate);
1806                                long us = fate.frameInfo.driverTimestampUsec;
1807                                byte type =
1808                                        halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
1809                                byte[] frame =
1810                                        NativeUtil.byteArrayFromArrayList(
1811                                                fate.frameInfo.frameContent);
1812                                reportBufs[i++] =
1813                                        new WifiNative.TxFateReport(code, us, type, frame);
1814                            }
1815                            ok.value = true;
1816                        }
1817                );
1818                return ok.value;
1819            } catch (RemoteException e) {
1820                kilroy();
1821                handleRemoteException(e);
1822                return false;
1823            }
1824        }
1825    }
1826
1827    /**
1828     * Retrieve fates of inbound packets
1829     *
1830     * Reports the inbound frames for the most recent association (space allowing).
1831     *
1832     * @param reportBufs
1833     * @return true for success
1834     */
1835    public boolean getRxPktFates(WifiNative.RxFateReport[] reportBufs) {
1836        kilroy();
1837        if (ArrayUtils.isEmpty(reportBufs)) return false;
1838        synchronized (sLock) {
1839            if (mIWifiStaIface == null) return false;
1840            try {
1841                kilroy();
1842                MutableBoolean ok = new MutableBoolean(false);
1843                mIWifiStaIface.getDebugRxPacketFates((status, fates) -> {
1844                            kilroy();
1845                            if (status.code != WifiStatusCode.SUCCESS) return;
1846                            int i = 0;
1847                            for (WifiDebugRxPacketFateReport fate : fates) {
1848                                kilroy();
1849                                if (i >= reportBufs.length) break;
1850                                byte code = halToFrameworkRxPktFate(fate.fate);
1851                                long us = fate.frameInfo.driverTimestampUsec;
1852                                byte type =
1853                                        halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
1854                                byte[] frame =
1855                                        NativeUtil.byteArrayFromArrayList(
1856                                                fate.frameInfo.frameContent);
1857                                reportBufs[i++] =
1858                                        new WifiNative.RxFateReport(code, us, type, frame);
1859                            }
1860                            ok.value = true;
1861                        }
1862                );
1863                return ok.value;
1864            } catch (RemoteException e) {
1865                kilroy();
1866                handleRemoteException(e);
1867                return false;
1868            }
1869        }
1870    }
1871
1872    /**
1873     * Start sending the specified keep alive packets periodically.
1874     * @param slot
1875     * @param srcMac
1876     * @param keepAlivePacket
1877     * @param periodInMs
1878     * @return 0 for success, -1 for error
1879     */
1880    public int startSendingOffloadedPacket(
1881            int slot, byte[] srcMac, KeepalivePacketData keepAlivePacket, int periodInMs) {
1882        Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " periodInMs=" + periodInMs);
1883
1884        ArrayList<Byte> data = NativeUtil.byteArrayToArrayList(keepAlivePacket.data);
1885        short protocol = (short) (keepAlivePacket.protocol);
1886
1887        synchronized (sLock) {
1888            if (mIWifiStaIface == null) return -1;
1889            try {
1890                WifiStatus status = mIWifiStaIface.startSendingKeepAlivePackets(
1891                        slot,
1892                        data,
1893                        protocol,
1894                        srcMac,
1895                        keepAlivePacket.dstMac,
1896                        periodInMs);
1897                if (status.code != WifiStatusCode.SUCCESS) return -1;
1898                return 0;
1899            } catch (RemoteException e) {
1900                kilroy();
1901                handleRemoteException(e);
1902                return -1;
1903            }
1904        }
1905    }
1906
1907    /**
1908     * Stop sending the specified keep alive packets.
1909     *
1910     * @param slot id - same as startSendingOffloadedPacket call.
1911     * @return 0 for success, -1 for error
1912     */
1913    public int stopSendingOffloadedPacket(int slot) {
1914        Log.d(TAG, "stopSendingOffloadedPacket " + slot);
1915
1916        synchronized (sLock) {
1917            if (mIWifiStaIface == null) return -1;
1918            try {
1919                WifiStatus wifiStatus = mIWifiStaIface.stopSendingKeepAlivePackets(slot);
1920                if (wifiStatus.code != WifiStatusCode.SUCCESS) return -1;
1921                kilroy();
1922                return 0;
1923            } catch (RemoteException e) {
1924                handleRemoteException(e);
1925                return -1;
1926            }
1927        }
1928    }
1929
1930    /**
1931     * A fixed cmdId for our RssiMonitoring (we only do one at a time)
1932     */
1933    @VisibleForTesting
1934    static final int sRssiMonCmdId = 7551;
1935
1936    /**
1937     * Our client's handler
1938     */
1939    private WifiNative.WifiRssiEventHandler mWifiRssiEventHandler;
1940
1941    /**
1942     * Start RSSI monitoring on the currently connected access point.
1943     *
1944     * @param maxRssi          Maximum RSSI threshold.
1945     * @param minRssi          Minimum RSSI threshold.
1946     * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
1947     * @return 0 for success, -1 for failure
1948     */
1949    public int startRssiMonitoring(byte maxRssi, byte minRssi,
1950                                   WifiNative.WifiRssiEventHandler rssiEventHandler) {
1951        kilroy();
1952        if (maxRssi <= minRssi) return -1;
1953        if (rssiEventHandler == null) return -1;
1954        synchronized (sLock) {
1955            if (mIWifiStaIface == null) return -1;
1956            try {
1957                mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
1958                WifiStatus status;
1959                status = mIWifiStaIface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi);
1960                if (status.code != WifiStatusCode.SUCCESS) return -1;
1961                mWifiRssiEventHandler = rssiEventHandler;
1962                kilroy();
1963                return 0;
1964            } catch (RemoteException e) {
1965                handleRemoteException(e);
1966                return -1;
1967            }
1968        }
1969    }
1970
1971    /**
1972     * Stop RSSI monitoring
1973     *
1974     * @return 0 for success, -1 for failure
1975     */
1976    public int stopRssiMonitoring() {
1977        kilroy();
1978        synchronized (sLock) {
1979            mWifiRssiEventHandler = null;
1980            if (mIWifiStaIface == null) return -1;
1981            try {
1982                mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
1983                WifiStatus status = mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
1984                if (status.code != WifiStatusCode.SUCCESS) return -1;
1985                kilroy();
1986                return 0;
1987            } catch (RemoteException e) {
1988                handleRemoteException(e);
1989                return -1;
1990            }
1991        }
1992    }
1993
1994    //TODO - belongs in NativeUtil
1995    private static int[] intsFromArrayList(ArrayList<Integer> a) {
1996        if (a == null) return null;
1997        int[] b = new int[a.size()];
1998        int i = 0;
1999        for (Integer e : a) b[i++] = e;
2000        return b;
2001    }
2002
2003    /**
2004     * Translates from Hal version of wake reason stats to the framework version of same
2005     *
2006     * @param h - Hal version of wake reason stats
2007     * @return framework version of same
2008     */
2009    private static WifiWakeReasonAndCounts halToFrameworkWakeReasons(
2010            WifiDebugHostWakeReasonStats h) {
2011        if (h == null) return null;
2012        WifiWakeReasonAndCounts ans = new WifiWakeReasonAndCounts();
2013        ans.totalCmdEventWake = h.totalCmdEventWakeCnt;
2014        ans.totalDriverFwLocalWake = h.totalDriverFwLocalWakeCnt;
2015        ans.totalRxDataWake = h.totalRxPacketWakeCnt;
2016        ans.rxUnicast = h.rxPktWakeDetails.rxUnicastCnt;
2017        ans.rxMulticast = h.rxPktWakeDetails.rxMulticastCnt;
2018        ans.rxBroadcast = h.rxPktWakeDetails.rxBroadcastCnt;
2019        ans.icmp = h.rxIcmpPkWakeDetails.icmpPkt;
2020        ans.icmp6 = h.rxIcmpPkWakeDetails.icmp6Pkt;
2021        ans.icmp6Ra = h.rxIcmpPkWakeDetails.icmp6Ra;
2022        ans.icmp6Na = h.rxIcmpPkWakeDetails.icmp6Na;
2023        ans.icmp6Ns = h.rxIcmpPkWakeDetails.icmp6Ns;
2024        ans.ipv4RxMulticast = h.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt;
2025        ans.ipv6Multicast = h.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt;
2026        ans.otherRxMulticast = h.rxMulticastPkWakeDetails.otherRxMulticastAddrCnt;
2027        ans.cmdEventWakeCntArray = intsFromArrayList(h.cmdEventWakeCntPerType);
2028        ans.driverFWLocalWakeCntArray = intsFromArrayList(h.driverFwLocalWakeCntPerType);
2029        return ans;
2030    }
2031
2032    /**
2033     * Fetch the host wakeup reasons stats from wlan driver.
2034     *
2035     * @return the |WifiWakeReasonAndCounts| from the wlan driver, or null on failure.
2036     */
2037    public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
2038        kilroy();
2039        class AnswerBox {
2040            public WifiDebugHostWakeReasonStats value = null;
2041        }
2042        AnswerBox ans = new AnswerBox();
2043        synchronized (sLock) {
2044            if (mIWifiChip == null) return null;
2045            try {
2046                kilroy();
2047                mIWifiChip.getDebugHostWakeReasonStats((status, stats) -> {
2048                    kilroy();
2049                    if (status.code == WifiStatusCode.SUCCESS) {
2050                        ans.value = stats;
2051                    }
2052                });
2053                kilroy();
2054                return halToFrameworkWakeReasons(ans.value);
2055            } catch (RemoteException e) {
2056                kilroy();
2057                handleRemoteException(e);
2058                return null;
2059            }
2060        }
2061    }
2062
2063    /**
2064     * Enable/Disable Neighbour discovery offload functionality in the firmware.
2065     *
2066     * @param enabled true to enable, false to disable.
2067     */
2068    public boolean configureNeighborDiscoveryOffload(boolean enabled) {
2069        kilroy();
2070        synchronized (sLock) {
2071            if (mIWifiStaIface == null) return false;
2072            kilroy();
2073            try {
2074                kilroy();
2075                WifiStatus wifiStatus = mIWifiStaIface.enableNdOffload(enabled);
2076                if (wifiStatus.code != WifiStatusCode.SUCCESS) {
2077                    kilroy();
2078                    noteHidlError(wifiStatus, "configureNeighborDiscoveryOffload");
2079                    return false;
2080                }
2081            } catch (RemoteException e) {
2082                kilroy();
2083                handleRemoteException(e);
2084                return false;
2085            }
2086        }
2087        return true;
2088    }
2089
2090    // Firmware roaming control.
2091
2092    /**
2093     * Query the firmware roaming capabilities.
2094     *
2095     * @param capabilities object to be filled in
2096     * @return true for success; false for failure
2097     */
2098    public boolean getRoamingCapabilities(WifiNative.RoamingCapabilities capabilities) {
2099        kilroy();
2100        synchronized (sLock) {
2101            kilroy();
2102            try {
2103                kilroy();
2104                if (!isHalStarted()) return false;
2105                MutableBoolean ok = new MutableBoolean(false);
2106                WifiNative.RoamingCapabilities out = capabilities;
2107                mIWifiStaIface.getRoamingCapabilities((status, cap) -> {
2108                    kilroy();
2109                    if (status.code != WifiStatusCode.SUCCESS) return;
2110                    out.maxBlacklistSize = cap.maxBlacklistSize;
2111                    out.maxWhitelistSize = cap.maxWhitelistSize;
2112                    ok.value = true;
2113                });
2114                return ok.value;
2115            } catch (RemoteException e) {
2116                kilroy();
2117                handleRemoteException(e);
2118                return false;
2119            }
2120        }
2121    }
2122
2123    /**
2124     * Enable/disable firmware roaming.
2125     *
2126     * @param state the intended roaming state
2127     * @return SUCCESS, FAILURE, or BUSY
2128     */
2129    public int enableFirmwareRoaming(int state) {
2130        kilroy();
2131        synchronized (sLock) {
2132            if (mIWifiStaIface == null) return WifiStatusCode.ERROR_NOT_STARTED;
2133            kilroy();
2134            try {
2135                kilroy();
2136                byte val;
2137                switch (state) {
2138                    case WifiNative.DISABLE_FIRMWARE_ROAMING:
2139                        val = StaRoamingState.DISABLED;
2140                        break;
2141                    case WifiNative.ENABLE_FIRMWARE_ROAMING:
2142                        val = StaRoamingState.ENABLED;
2143                        break;
2144                    default:
2145                        Log.e(TAG, "enableFirmwareRoaming invalid argument " + state);
2146                        return WifiStatusCode.ERROR_INVALID_ARGS;
2147                }
2148
2149                kilroy();
2150                WifiStatus status = mIWifiStaIface.setRoamingState(val);
2151                Log.d(TAG, "setRoamingState returned " + status.code);
2152                return status.code;
2153            } catch (RemoteException e) {
2154                kilroy();
2155                handleRemoteException(e);
2156                return WifiStatusCode.ERROR_UNKNOWN;
2157            }
2158        }
2159    }
2160
2161    /**
2162     * Set firmware roaming configurations.
2163     *
2164     * @param config new roaming configuration object
2165     * @return true for success; false for failure
2166     */
2167    public boolean configureRoaming(WifiNative.RoamingConfig config) {
2168        kilroy();
2169        synchronized (sLock) {
2170            if (mIWifiStaIface == null) return false;
2171            kilroy();
2172            try {
2173                kilroy();
2174                StaRoamingConfig roamingConfig = new StaRoamingConfig();
2175
2176                // parse the blacklist BSSIDs if any
2177                if (config.blacklistBssids != null) {
2178                    kilroy();
2179                    for (String bssid : config.blacklistBssids) {
2180                        byte[] mac = NativeUtil.macAddressToByteArray(bssid);
2181                        roamingConfig.bssidBlacklist.add(mac);
2182                    }
2183                }
2184
2185                // parse the whitelist SSIDs if any
2186                if (config.whitelistSsids != null) {
2187                    kilroy();
2188                    for (String ssidStr : config.whitelistSsids) {
2189                        String unquotedSsidStr = WifiInfo.removeDoubleQuotes(ssidStr);
2190
2191                        int len = unquotedSsidStr.length();
2192                        if (len > 32) {
2193                            Log.e(TAG, "configureRoaming: skip invalid SSID " + unquotedSsidStr);
2194                            continue;
2195                        }
2196                        byte[] ssid = new byte[len];
2197                        for (int i = 0; i < len; i++) {
2198                            ssid[i] = (byte) unquotedSsidStr.charAt(i);
2199                        }
2200                        roamingConfig.ssidWhitelist.add(ssid);
2201                    }
2202                }
2203
2204                kilroy();
2205                WifiStatus status = mIWifiStaIface.configureRoaming(roamingConfig);
2206                if (status.code != WifiStatusCode.SUCCESS) {
2207                    kilroy();
2208                    noteHidlError(status, "configureRoaming");
2209                    return false;
2210                }
2211            } catch (RemoteException e) {
2212                kilroy();
2213                handleRemoteException(e);
2214                return false;
2215            }
2216            kilroy();
2217            return true;
2218        }
2219    }
2220
2221    StackTraceElement[] mTrace;
2222
2223    private void kilroy() {
2224        Thread cur = Thread.currentThread();
2225        mTrace = cur.getStackTrace();
2226        StackTraceElement s = mTrace[3];
2227        String name = s.getMethodName();
2228        if (name.contains("lambda$")) {
2229            // Try to find a friendlier method name
2230            String myFile = s.getFileName();
2231            if (myFile != null) {
2232                for (int i = 4; i < mTrace.length; i++) {
2233                    if (myFile.equals(mTrace[i].getFileName())) {
2234                        name = mTrace[i].getMethodName();
2235                        break;
2236                    }
2237                }
2238            }
2239        }
2240        Log.e(TAG, "th " + cur.getId() + " line " + s.getLineNumber() + " " + name);
2241    }
2242
2243    // This creates a blob of IE elements from the array received.
2244    // TODO: This ugly conversion can be removed if we put IE elements in ScanResult.
2245    private static byte[] hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies) {
2246        if (ies == null || ies.isEmpty()) return new byte[0];
2247        ArrayList<Byte> ieBlob = new ArrayList<>();
2248        for (WifiInformationElement ie : ies) {
2249            ieBlob.add(ie.id);
2250            ieBlob.addAll(ie.data);
2251        }
2252        return NativeUtil.byteArrayFromArrayList(ieBlob);
2253    }
2254
2255    // This is only filling up the fields of Scan Result used by Gscan clients.
2256    private static ScanResult hidlToFrameworkScanResult(StaScanResult scanResult) {
2257        if (scanResult == null) return null;
2258        ScanResult frameworkScanResult = new ScanResult();
2259        frameworkScanResult.SSID = NativeUtil.encodeSsid(scanResult.ssid);
2260        frameworkScanResult.wifiSsid =
2261                WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(scanResult.ssid));
2262        frameworkScanResult.BSSID = NativeUtil.macAddressFromByteArray(scanResult.bssid);
2263        frameworkScanResult.level = scanResult.rssi;
2264        frameworkScanResult.frequency = scanResult.frequency;
2265        frameworkScanResult.timestamp = scanResult.timeStampInUs;
2266        frameworkScanResult.bytes = hidlIeArrayToFrameworkIeBlob(scanResult.informationElements);
2267        return frameworkScanResult;
2268    }
2269
2270    private static ScanResult[] hidlToFrameworkScanResults(ArrayList<StaScanResult> scanResults) {
2271        if (scanResults == null || scanResults.isEmpty()) return new ScanResult[0];
2272        ScanResult[] frameworkScanResults = new ScanResult[scanResults.size()];
2273        int i = 0;
2274        for (StaScanResult scanResult : scanResults) {
2275            frameworkScanResults[i++] = hidlToFrameworkScanResult(scanResult);
2276        }
2277        return frameworkScanResults;
2278    }
2279
2280    /**
2281     * This just returns whether the scan was interrupted or not.
2282     */
2283    private static int hidlToFrameworkScanDataFlags(int flag) {
2284        if (flag == StaScanDataFlagMask.INTERRUPTED) {
2285            return 1;
2286        } else {
2287            return 0;
2288        }
2289    }
2290
2291    private static WifiScanner.ScanData[] hidlToFrameworkScanDatas(
2292            int cmdId, ArrayList<StaScanData> scanDatas) {
2293        if (scanDatas == null || scanDatas.isEmpty()) return new WifiScanner.ScanData[0];
2294        WifiScanner.ScanData[] frameworkScanDatas = new WifiScanner.ScanData[scanDatas.size()];
2295        int i = 0;
2296        for (StaScanData scanData : scanDatas) {
2297            int flags = hidlToFrameworkScanDataFlags(scanData.flags);
2298            ScanResult[] frameworkScanResults = hidlToFrameworkScanResults(scanData.results);
2299            frameworkScanDatas[i++] =
2300                    new WifiScanner.ScanData(cmdId, flags, scanData.bucketsScanned, false,
2301                            frameworkScanResults);
2302        }
2303        return frameworkScanDatas;
2304    }
2305
2306    /**
2307     * Callback for events on the STA interface.
2308     */
2309    private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub {
2310        @Override
2311        public void onBackgroundScanFailure(int cmdId) {
2312            kilroy();
2313            Log.d(TAG, "onBackgroundScanFailure " + cmdId);
2314            synchronized (sLock) {
2315                if (mScan != null && cmdId == mScan.cmdId) {
2316                    mScan.eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
2317                }
2318            }
2319        }
2320
2321        @Override
2322        public void onBackgroundFullScanResult(
2323                int cmdId, StaScanResult result) {
2324            kilroy();
2325            Log.d(TAG, "onBackgroundFullScanResult " + cmdId);
2326            synchronized (sLock) {
2327                if (mScan != null && cmdId == mScan.cmdId) {
2328                    mScan.eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), 0);
2329                }
2330            }
2331        }
2332
2333        @Override
2334        public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
2335            kilroy();
2336            Log.d(TAG, "onBackgroundScanResults " + cmdId);
2337            // WifiScanner currently uses the results callback to fetch the scan results.
2338            // So, simulate that by sending out the notification and then caching the results
2339            // locally. This will then be returned to WifiScanner via getScanResults.
2340            synchronized (sLock) {
2341                if (mScan != null && cmdId == mScan.cmdId) {
2342                    mScan.eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
2343                    mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas);
2344                }
2345            }
2346        }
2347
2348        @Override
2349        public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
2350            Log.d(TAG, "onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
2351            WifiNative.WifiRssiEventHandler handler;
2352            synchronized (sLock) {
2353                handler = mWifiRssiEventHandler;
2354                if (mWifiRssiEventHandler == null) return;
2355                if (cmdId != sRssiMonCmdId) return;
2356                kilroy();
2357            }
2358            handler.onRssiThresholdBreached((byte) currRssi);
2359        }
2360    }
2361
2362    /**
2363     * Callback for events on the STA interface.
2364     */
2365    private class ChipEventCallback extends IWifiChipEventCallback.Stub {
2366        @Override
2367        public void onChipReconfigured(int modeId) {
2368            kilroy();
2369            Log.d(TAG, "onChipReconfigured " + modeId);
2370        }
2371
2372        @Override
2373        public void onChipReconfigureFailure(WifiStatus status) {
2374            kilroy();
2375            Log.d(TAG, "onChipReconfigureFailure " + status);
2376        }
2377
2378        public void onIfaceAdded(int type, String name) {
2379            kilroy();
2380            Log.d(TAG, "onIfaceAdded " + type + ", name: " + name);
2381        }
2382
2383        @Override
2384        public void onIfaceRemoved(int type, String name) {
2385            kilroy();
2386            Log.d(TAG, "onIfaceRemoved " + type + ", name: " + name);
2387        }
2388
2389        @Override
2390        public void onDebugRingBufferDataAvailable(
2391                WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) {
2392            kilroy();
2393            Log.d(TAG, "onDebugRingBufferDataAvailable " + status);
2394        }
2395
2396        @Override
2397        public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) {
2398            kilroy();
2399            Log.d(TAG, "onDebugErrorAlert " + errorCode);
2400        }
2401    }
2402
2403    /**
2404     * Hal Device Manager callbacks.
2405     */
2406    public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener {
2407        @Override
2408        public void onStatusChanged() {
2409            boolean isReady = mHalDeviceManager.isReady();
2410            boolean isStarted = mHalDeviceManager.isStarted();
2411
2412            Log.i(TAG, "Device Manager onStatusChanged. isReady(): " + isReady
2413                    + ", isStarted(): " + isStarted);
2414            // Reset all our cached handles.
2415            if (!isReady || !isStarted) {
2416                kilroy();
2417                mIWifiChip = null;
2418                mIWifiStaIface = null;
2419                mIWifiApIface = null;
2420                mIWifiRttController = null;
2421                mDriverDescription = null;
2422                mFirmwareDescription = null;
2423            }
2424        }
2425    }
2426}
2427