1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.net.InterfaceConfiguration;
23import android.net.MacAddress;
24import android.net.TrafficStats;
25import android.net.apf.ApfCapabilities;
26import android.net.wifi.RttManager;
27import android.net.wifi.RttManager.ResponderConfig;
28import android.net.wifi.ScanResult;
29import android.net.wifi.WifiConfiguration;
30import android.net.wifi.WifiScanner;
31import android.net.wifi.WifiWakeReasonAndCounts;
32import android.os.INetworkManagementService;
33import android.os.RemoteException;
34import android.os.SystemClock;
35import android.text.TextUtils;
36import android.util.Log;
37import android.util.SparseArray;
38
39import com.android.internal.annotations.Immutable;
40import com.android.internal.util.HexDump;
41import com.android.server.net.BaseNetworkObserver;
42import com.android.server.wifi.util.FrameParser;
43import com.android.server.wifi.util.NativeUtil;
44
45import java.io.PrintWriter;
46import java.io.StringWriter;
47import java.lang.annotation.Retention;
48import java.lang.annotation.RetentionPolicy;
49import java.nio.ByteBuffer;
50import java.nio.CharBuffer;
51import java.nio.charset.CharacterCodingException;
52import java.nio.charset.CharsetDecoder;
53import java.nio.charset.StandardCharsets;
54import java.text.SimpleDateFormat;
55import java.util.ArrayList;
56import java.util.Date;
57import java.util.HashMap;
58import java.util.HashSet;
59import java.util.Iterator;
60import java.util.Map;
61import java.util.Objects;
62import java.util.Set;
63import java.util.TimeZone;
64
65/**
66 * Native calls for bring up/shut down of the supplicant daemon and for
67 * sending requests to the supplicant daemon
68 *
69 * {@hide}
70 */
71public class WifiNative {
72    private static final String TAG = "WifiNative";
73    private final SupplicantStaIfaceHal mSupplicantStaIfaceHal;
74    private final HostapdHal mHostapdHal;
75    private final WifiVendorHal mWifiVendorHal;
76    private final WificondControl mWificondControl;
77    private final WifiMonitor mWifiMonitor;
78    private final INetworkManagementService mNwManagementService;
79    private final PropertyService mPropertyService;
80    private final WifiMetrics mWifiMetrics;
81    private boolean mVerboseLoggingEnabled = false;
82
83    public WifiNative(WifiVendorHal vendorHal,
84                      SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal,
85                      WificondControl condControl, WifiMonitor wifiMonitor,
86                      INetworkManagementService nwService,
87                      PropertyService propertyService, WifiMetrics wifiMetrics) {
88        mWifiVendorHal = vendorHal;
89        mSupplicantStaIfaceHal = staIfaceHal;
90        mHostapdHal = hostapdHal;
91        mWificondControl = condControl;
92        mWifiMonitor = wifiMonitor;
93        mNwManagementService = nwService;
94        mPropertyService = propertyService;
95        mWifiMetrics = wifiMetrics;
96    }
97
98    /**
99     * Enable verbose logging for all sub modules.
100     */
101    public void enableVerboseLogging(int verbose) {
102        mVerboseLoggingEnabled = verbose > 0 ? true : false;
103        mWificondControl.enableVerboseLogging(mVerboseLoggingEnabled);
104        mSupplicantStaIfaceHal.enableVerboseLogging(mVerboseLoggingEnabled);
105        mWifiVendorHal.enableVerboseLogging(mVerboseLoggingEnabled);
106    }
107
108    /********************************************************
109     * Interface management related methods.
110     ********************************************************/
111    /**
112     * Meta-info about every iface that is active.
113     */
114    private static class Iface {
115        /** Type of ifaces possible */
116        public static final int IFACE_TYPE_AP = 0;
117        public static final int IFACE_TYPE_STA = 1;
118
119        @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA})
120        @Retention(RetentionPolicy.SOURCE)
121        public @interface IfaceType{}
122
123        /** Identifier allocated for the interface */
124        public final int id;
125        /** Type of the iface: STA or AP */
126        public final @IfaceType int type;
127        /** Name of the interface */
128        public String name;
129        /** Is the interface up? This is used to mask up/down notifications to external clients. */
130        public boolean isUp;
131        /** External iface destroyed listener for the iface */
132        public InterfaceCallback externalListener;
133        /** Network observer registered for this interface */
134        public NetworkObserverInternal networkObserver;
135
136        Iface(int id, @Iface.IfaceType int type) {
137            this.id = id;
138            this.type = type;
139        }
140
141        @Override
142        public String toString() {
143            StringBuffer sb = new StringBuffer();
144            sb.append("Iface:")
145                .append("{")
146                .append("Name=").append(name)
147                .append(",")
148                .append("Id=").append(id)
149                .append(",")
150                .append("Type=").append(type == IFACE_TYPE_STA ? "STA" : "AP")
151                .append("}");
152            return sb.toString();
153        }
154    }
155
156    /**
157     * Iface Management entity. This class maintains list of all the active ifaces.
158     */
159    private static class IfaceManager {
160        /** Integer to allocate for the next iface being created */
161        private int mNextId;
162        /** Map of the id to the iface structure */
163        private HashMap<Integer, Iface> mIfaces = new HashMap<>();
164
165        /** Allocate a new iface for the given type */
166        private Iface allocateIface(@Iface.IfaceType  int type) {
167            Iface iface = new Iface(mNextId, type);
168            mIfaces.put(mNextId, iface);
169            mNextId++;
170            return iface;
171        }
172
173        /** Remove the iface using the provided id */
174        private Iface removeIface(int id) {
175            return mIfaces.remove(id);
176        }
177
178        /** Lookup the iface using the provided id */
179        private Iface getIface(int id) {
180            return mIfaces.get(id);
181        }
182
183        /** Lookup the iface using the provided name */
184        private Iface getIface(@NonNull String ifaceName) {
185            for (Iface iface : mIfaces.values()) {
186                if (TextUtils.equals(iface.name, ifaceName)) {
187                    return iface;
188                }
189            }
190            return null;
191        }
192
193        /** Iterator to use for deleting all the ifaces while performing teardown on each of them */
194        private Iterator<Integer> getIfaceIdIter() {
195            return mIfaces.keySet().iterator();
196        }
197
198        /** Checks if there are any iface active. */
199        private boolean hasAnyIface() {
200            return !mIfaces.isEmpty();
201        }
202
203        /** Checks if there are any iface of the given type active. */
204        private boolean hasAnyIfaceOfType(@Iface.IfaceType int type) {
205            for (Iface iface : mIfaces.values()) {
206                if (iface.type == type) {
207                    return true;
208                }
209            }
210            return false;
211        }
212
213        /** Checks if there are any iface of the given type active. */
214        private Iface findAnyIfaceOfType(@Iface.IfaceType int type) {
215            for (Iface iface : mIfaces.values()) {
216                if (iface.type == type) {
217                    return iface;
218                }
219            }
220            return null;
221        }
222
223        /** Checks if there are any STA iface active. */
224        private boolean hasAnyStaIface() {
225            return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA);
226        }
227
228        /** Checks if there are any AP iface active. */
229        private boolean hasAnyApIface() {
230            return hasAnyIfaceOfType(Iface.IFACE_TYPE_AP);
231        }
232
233        private String findAnyStaIfaceName() {
234            Iface iface = findAnyIfaceOfType(Iface.IFACE_TYPE_STA);
235            if (iface == null) {
236                return null;
237            }
238            return iface.name;
239        }
240
241        private String findAnyApIfaceName() {
242            Iface iface = findAnyIfaceOfType(Iface.IFACE_TYPE_AP);
243            if (iface == null) {
244                return null;
245            }
246            return iface.name;
247        }
248
249        /** Removes the existing iface that does not match the provided id. */
250        public Iface removeExistingIface(int newIfaceId) {
251            Iface removedIface = null;
252            // The number of ifaces in the database could be 1 existing & 1 new at the max.
253            if (mIfaces.size() > 2) {
254                Log.wtf(TAG, "More than 1 existing interface found");
255            }
256            Iterator<Map.Entry<Integer, Iface>> iter = mIfaces.entrySet().iterator();
257            while (iter.hasNext()) {
258                Map.Entry<Integer, Iface> entry = iter.next();
259                if (entry.getKey() != newIfaceId) {
260                    removedIface = entry.getValue();
261                    iter.remove();
262                }
263            }
264            return removedIface;
265        }
266    }
267
268    private Object mLock = new Object();
269    private final IfaceManager mIfaceMgr = new IfaceManager();
270    private HashSet<StatusListener> mStatusListeners = new HashSet<>();
271
272    /** Helper method invoked to start supplicant if there were no ifaces */
273    private boolean startHal() {
274        synchronized (mLock) {
275            if (!mIfaceMgr.hasAnyIface()) {
276                if (mWifiVendorHal.isVendorHalSupported()) {
277                    if (!mWifiVendorHal.startVendorHal()) {
278                        Log.e(TAG, "Failed to start vendor HAL");
279                        return false;
280                    }
281                } else {
282                    Log.i(TAG, "Vendor Hal not supported, ignoring start.");
283                }
284            }
285            return true;
286        }
287    }
288
289    /** Helper method invoked to stop HAL if there are no more ifaces */
290    private void stopHalAndWificondIfNecessary() {
291        synchronized (mLock) {
292            if (!mIfaceMgr.hasAnyIface()) {
293                if (!mWificondControl.tearDownInterfaces()) {
294                    Log.e(TAG, "Failed to teardown ifaces from wificond");
295                }
296                if (mWifiVendorHal.isVendorHalSupported()) {
297                    mWifiVendorHal.stopVendorHal();
298                } else {
299                    Log.i(TAG, "Vendor Hal not supported, ignoring stop.");
300                }
301            }
302        }
303    }
304
305    private static final int CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS = 100;
306    private static final int CONNECT_TO_SUPPLICANT_RETRY_TIMES = 50;
307    /**
308     * This method is called to wait for establishing connection to wpa_supplicant.
309     *
310     * @return true if connection is established, false otherwise.
311     */
312    private boolean waitForSupplicantConnection() {
313        // Start initialization if not already started.
314        if (!mSupplicantStaIfaceHal.isInitializationStarted()
315                && !mSupplicantStaIfaceHal.initialize()) {
316            return false;
317        }
318        boolean connected = false;
319        int connectTries = 0;
320        while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) {
321            // Check if the initialization is complete.
322            connected = mSupplicantStaIfaceHal.isInitializationComplete();
323            if (connected) {
324                break;
325            }
326            try {
327                Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS);
328            } catch (InterruptedException ignore) {
329            }
330        }
331        return connected;
332    }
333
334    /** Helper method invoked to start supplicant if there were no STA ifaces */
335    private boolean startSupplicant() {
336        synchronized (mLock) {
337            if (!mIfaceMgr.hasAnyStaIface()) {
338                if (!mWificondControl.enableSupplicant()) {
339                    Log.e(TAG, "Failed to enable supplicant");
340                    return false;
341                }
342                if (!waitForSupplicantConnection()) {
343                    Log.e(TAG, "Failed to connect to supplicant");
344                    return false;
345                }
346                if (!mSupplicantStaIfaceHal.registerDeathHandler(
347                        new SupplicantDeathHandlerInternal())) {
348                    Log.e(TAG, "Failed to register supplicant death handler");
349                    return false;
350                }
351            }
352            return true;
353        }
354    }
355
356    /** Helper method invoked to stop supplicant if there are no more STA ifaces */
357    private void stopSupplicantIfNecessary() {
358        synchronized (mLock) {
359            if (!mIfaceMgr.hasAnyStaIface()) {
360                if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) {
361                    Log.e(TAG, "Failed to deregister supplicant death handler");
362                }
363                if (!mWificondControl.disableSupplicant()) {
364                    Log.e(TAG, "Failed to disable supplicant");
365                }
366            }
367        }
368    }
369
370    /** Helper method to register a network observer and return it */
371    private boolean registerNetworkObserver(NetworkObserverInternal observer) {
372        if (observer == null) return false;
373        try {
374            mNwManagementService.registerObserver(observer);
375        } catch (RemoteException e) {
376            return false;
377        }
378        return true;
379    }
380
381    /** Helper method to unregister a network observer */
382    private boolean unregisterNetworkObserver(NetworkObserverInternal observer) {
383        if (observer == null) return false;
384        try {
385            mNwManagementService.unregisterObserver(observer);
386        } catch (RemoteException e) {
387            return false;
388        }
389        return true;
390    }
391
392    /** Helper method invoked to teardown client iface and perform necessary cleanup */
393    private void onClientInterfaceDestroyed(@NonNull Iface iface) {
394        synchronized (mLock) {
395            mWifiMonitor.stopMonitoring(iface.name);
396            if (!unregisterNetworkObserver(iface.networkObserver)) {
397                Log.e(TAG, "Failed to unregister network observer on " + iface);
398            }
399            if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) {
400                Log.e(TAG, "Failed to teardown iface in supplicant on " + iface);
401            }
402            if (!mWificondControl.tearDownClientInterface(iface.name)) {
403                Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
404            }
405            stopSupplicantIfNecessary();
406            stopHalAndWificondIfNecessary();
407        }
408    }
409
410    /** Helper method invoked to teardown softAp iface and perform necessary cleanup */
411    private void onSoftApInterfaceDestroyed(@NonNull Iface iface) {
412        synchronized (mLock) {
413            if (!unregisterNetworkObserver(iface.networkObserver)) {
414                Log.e(TAG, "Failed to unregister network observer on " + iface);
415            }
416            if (!mHostapdHal.removeAccessPoint(iface.name)) {
417                Log.e(TAG, "Failed to remove access point on " + iface);
418            }
419            if (!mHostapdHal.deregisterDeathHandler()) {
420                Log.e(TAG, "Failed to deregister supplicant death handler");
421            }
422            // TODO(b/71513606): Move this to a global operation.
423            if (!mWificondControl.stopHostapd(iface.name)) {
424                Log.e(TAG, "Failed to stop hostapd on " + iface);
425            }
426            if (!mWificondControl.tearDownSoftApInterface(iface.name)) {
427                Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
428            }
429            stopHalAndWificondIfNecessary();
430        }
431    }
432
433    /** Helper method invoked to teardown iface and perform necessary cleanup */
434    private void onInterfaceDestroyed(@NonNull Iface iface) {
435        synchronized (mLock) {
436            if (iface.type == Iface.IFACE_TYPE_STA) {
437                onClientInterfaceDestroyed(iface);
438            } else if (iface.type == Iface.IFACE_TYPE_AP) {
439                onSoftApInterfaceDestroyed(iface);
440            }
441            // Invoke the external callback.
442            iface.externalListener.onDestroyed(iface.name);
443        }
444    }
445
446    /**
447     * Callback to be invoked by HalDeviceManager when an interface is destroyed.
448     */
449    private class InterfaceDestoyedListenerInternal
450            implements HalDeviceManager.InterfaceDestroyedListener {
451        /** Identifier allocated for the interface */
452        private final int mInterfaceId;
453
454        InterfaceDestoyedListenerInternal(int ifaceId) {
455            mInterfaceId = ifaceId;
456        }
457
458        @Override
459        public void onDestroyed(@NonNull String ifaceName) {
460            synchronized (mLock) {
461                final Iface iface = mIfaceMgr.removeIface(mInterfaceId);
462                if (iface == null) {
463                    if (mVerboseLoggingEnabled) {
464                        Log.v(TAG, "Received iface destroyed notification on an invalid iface="
465                                + ifaceName);
466                    }
467                    return;
468                }
469                onInterfaceDestroyed(iface);
470                Log.i(TAG, "Successfully torn down " + iface);
471            }
472        }
473    }
474
475    /**
476     * Helper method invoked to trigger the status changed callback after one of the native
477     * daemon's death.
478     */
479    private void onNativeDaemonDeath() {
480        synchronized (mLock) {
481            for (StatusListener listener : mStatusListeners) {
482                listener.onStatusChanged(false);
483            }
484            for (StatusListener listener : mStatusListeners) {
485                listener.onStatusChanged(true);
486            }
487        }
488    }
489
490    /**
491     * Death handler for the Vendor HAL daemon.
492     */
493    private class VendorHalDeathHandlerInternal implements VendorHalDeathEventHandler {
494        @Override
495        public void onDeath() {
496            synchronized (mLock) {
497                Log.i(TAG, "Vendor HAL died. Cleaning up internal state.");
498                onNativeDaemonDeath();
499                mWifiMetrics.incrementNumHalCrashes();
500            }
501        }
502    }
503
504    /**
505     * Death handler for the wificond daemon.
506     */
507    private class WificondDeathHandlerInternal implements WificondDeathEventHandler {
508        @Override
509        public void onDeath() {
510            synchronized (mLock) {
511                Log.i(TAG, "wificond died. Cleaning up internal state.");
512                onNativeDaemonDeath();
513                mWifiMetrics.incrementNumWificondCrashes();
514            }
515        }
516    }
517
518    /**
519     * Death handler for the supplicant daemon.
520     */
521    private class SupplicantDeathHandlerInternal implements SupplicantDeathEventHandler {
522        @Override
523        public void onDeath() {
524            synchronized (mLock) {
525                Log.i(TAG, "wpa_supplicant died. Cleaning up internal state.");
526                onNativeDaemonDeath();
527                mWifiMetrics.incrementNumSupplicantCrashes();
528            }
529        }
530    }
531
532    /**
533     * Death handler for the hostapd daemon.
534     */
535    private class HostapdDeathHandlerInternal implements HostapdDeathEventHandler {
536        @Override
537        public void onDeath() {
538            synchronized (mLock) {
539                Log.i(TAG, "hostapd died. Cleaning up internal state.");
540                onNativeDaemonDeath();
541                mWifiMetrics.incrementNumHostapdCrashes();
542            }
543        }
544    }
545
546    /** Helper method invoked to handle interface change. */
547    private void onInterfaceStateChanged(Iface iface, boolean isUp) {
548        synchronized (mLock) {
549            // Mask multiple notifications with the same state.
550            if (isUp == iface.isUp) {
551                if (mVerboseLoggingEnabled) {
552                    Log.v(TAG, "Interface status unchanged on " + iface + " from " + isUp
553                            + ", Ignoring...");
554                }
555                return;
556            }
557            Log.i(TAG, "Interface state changed on " + iface + ", isUp=" + isUp);
558            if (isUp) {
559                iface.externalListener.onUp(iface.name);
560            } else {
561                iface.externalListener.onDown(iface.name);
562                if (iface.type == Iface.IFACE_TYPE_STA) {
563                    mWifiMetrics.incrementNumClientInterfaceDown();
564                } else if (iface.type == Iface.IFACE_TYPE_AP) {
565                    mWifiMetrics.incrementNumSoftApInterfaceDown();
566                }
567            }
568            iface.isUp = isUp;
569        }
570    }
571
572    /**
573     * Network observer to use for all interface up/down notifications.
574     */
575    private class NetworkObserverInternal extends BaseNetworkObserver {
576        /** Identifier allocated for the interface */
577        private final int mInterfaceId;
578
579        NetworkObserverInternal(int id) {
580            mInterfaceId = id;
581        }
582
583        // TODO(b/76219766): We may need to listen for link state changes in SoftAp mode.
584        /**
585         * Note: We should ideally listen to
586         * {@link BaseNetworkObserver#interfaceStatusChanged(String, boolean)} here. But, that
587         * callback is not working currently (broken in netd). So, instead listen to link state
588         * change callbacks as triggers to query the real interface state. We should get rid of
589         * this workaround if we get the |interfaceStatusChanged| callback to work in netd.
590         * Also, this workaround will not detect an interface up event, if the link state is
591         * still down.
592         */
593        @Override
594        public void interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp) {
595            synchronized (mLock) {
596                final Iface ifaceWithId = mIfaceMgr.getIface(mInterfaceId);
597                if (ifaceWithId == null) {
598                    if (mVerboseLoggingEnabled) {
599                        Log.v(TAG, "Received iface link up/down notification on an invalid iface="
600                                + mInterfaceId);
601                    }
602                    return;
603                }
604                final Iface ifaceWithName = mIfaceMgr.getIface(ifaceName);
605                if (ifaceWithName == null || ifaceWithName != ifaceWithId) {
606                    if (mVerboseLoggingEnabled) {
607                        Log.v(TAG, "Received iface link up/down notification on an invalid iface="
608                                + ifaceName);
609                    }
610                    return;
611                }
612                onInterfaceStateChanged(ifaceWithName, isInterfaceUp(ifaceName));
613            }
614        }
615    }
616
617    /**
618     * Radio mode change handler for the Vendor HAL daemon.
619     */
620    private class VendorHalRadioModeChangeHandlerInternal
621            implements VendorHalRadioModeChangeEventHandler {
622        @Override
623        public void onMcc(int band) {
624            synchronized (mLock) {
625                Log.i(TAG, "Device is in MCC mode now");
626                mWifiMetrics.incrementNumRadioModeChangeToMcc();
627            }
628        }
629        @Override
630        public void onScc(int band) {
631            synchronized (mLock) {
632                Log.i(TAG, "Device is in SCC mode now");
633                mWifiMetrics.incrementNumRadioModeChangeToScc();
634            }
635        }
636        @Override
637        public void onSbs(int band) {
638            synchronized (mLock) {
639                Log.i(TAG, "Device is in SBS mode now");
640                mWifiMetrics.incrementNumRadioModeChangeToSbs();
641            }
642        }
643        @Override
644        public void onDbs() {
645            synchronized (mLock) {
646                Log.i(TAG, "Device is in DBS mode now");
647                mWifiMetrics.incrementNumRadioModeChangeToDbs();
648            }
649        }
650    }
651
652    // For devices that don't support the vendor HAL, we will not support any concurrency.
653    // So simulate the HalDeviceManager behavior by triggering the destroy listener for
654    // any active interface.
655    private String handleIfaceCreationWhenVendorHalNotSupported(@NonNull Iface newIface) {
656        synchronized (mLock) {
657            Iface existingIface = mIfaceMgr.removeExistingIface(newIface.id);
658            if (existingIface != null) {
659                onInterfaceDestroyed(existingIface);
660                Log.i(TAG, "Successfully torn down " + existingIface);
661            }
662            // Return the interface name directly from the system property.
663            return mPropertyService.getString("wifi.interface", "wlan0");
664        }
665    }
666
667    /**
668     * Helper function to handle creation of STA iface.
669     * For devices which do not the support the HAL, this will bypass HalDeviceManager &
670     * teardown any existing iface.
671     */
672    private String createStaIface(@NonNull Iface iface, boolean lowPrioritySta) {
673        synchronized (mLock) {
674            if (mWifiVendorHal.isVendorHalSupported()) {
675                return mWifiVendorHal.createStaIface(lowPrioritySta,
676                        new InterfaceDestoyedListenerInternal(iface.id));
677            } else {
678                Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface.");
679                return handleIfaceCreationWhenVendorHalNotSupported(iface);
680            }
681        }
682    }
683
684    /**
685     * Helper function to handle creation of AP iface.
686     * For devices which do not the support the HAL, this will bypass HalDeviceManager &
687     * teardown any existing iface.
688     */
689    private String createApIface(@NonNull Iface iface) {
690        synchronized (mLock) {
691            if (mWifiVendorHal.isVendorHalSupported()) {
692                return mWifiVendorHal.createApIface(
693                        new InterfaceDestoyedListenerInternal(iface.id));
694            } else {
695                Log.i(TAG, "Vendor Hal not supported, ignoring createApIface.");
696                return handleIfaceCreationWhenVendorHalNotSupported(iface);
697            }
698        }
699    }
700
701    // For devices that don't support the vendor HAL, we will not support any concurrency.
702    // So simulate the HalDeviceManager behavior by triggering the destroy listener for
703    // the interface.
704    private boolean handleIfaceRemovalWhenVendorHalNotSupported(@NonNull Iface iface) {
705        synchronized (mLock) {
706            mIfaceMgr.removeIface(iface.id);
707            onInterfaceDestroyed(iface);
708            Log.i(TAG, "Successfully torn down " + iface);
709            return true;
710        }
711    }
712
713    /**
714     * Helper function to handle removal of STA iface.
715     * For devices which do not the support the HAL, this will bypass HalDeviceManager &
716     * teardown any existing iface.
717     */
718    private boolean removeStaIface(@NonNull Iface iface) {
719        synchronized (mLock) {
720            if (mWifiVendorHal.isVendorHalSupported()) {
721                return mWifiVendorHal.removeStaIface(iface.name);
722            } else {
723                Log.i(TAG, "Vendor Hal not supported, ignoring removeStaIface.");
724                return handleIfaceRemovalWhenVendorHalNotSupported(iface);
725            }
726        }
727    }
728
729    /**
730     * Helper function to handle removal of STA iface.
731     */
732    private boolean removeApIface(@NonNull Iface iface) {
733        synchronized (mLock) {
734            if (mWifiVendorHal.isVendorHalSupported()) {
735                return mWifiVendorHal.removeApIface(iface.name);
736            } else {
737                Log.i(TAG, "Vendor Hal not supported, ignoring removeApIface.");
738                return handleIfaceRemovalWhenVendorHalNotSupported(iface);
739            }
740        }
741    }
742
743    /**
744     * Initialize the native modules.
745     *
746     * @return true on success, false otherwise.
747     */
748    public boolean initialize() {
749        synchronized (mLock) {
750            if (!mWifiVendorHal.initialize(new VendorHalDeathHandlerInternal())) {
751                Log.e(TAG, "Failed to initialize vendor HAL");
752                return false;
753            }
754            if (!mWificondControl.initialize(new WificondDeathHandlerInternal())) {
755                Log.e(TAG, "Failed to initialize wificond");
756                return false;
757            }
758            mWifiVendorHal.registerRadioModeChangeHandler(
759                    new VendorHalRadioModeChangeHandlerInternal());
760            return true;
761        }
762    }
763
764    /**
765     * Callback to notify when the status of one of the native daemons
766     * (wificond, wpa_supplicant & vendor HAL) changes.
767     */
768    public interface StatusListener {
769        /**
770         * @param allReady Indicates if all the native daemons are ready for operation or not.
771         */
772        void onStatusChanged(boolean allReady);
773    }
774
775    /**
776     * Register a StatusListener to get notified about any status changes from the native daemons.
777     *
778     * It is safe to re-register the same callback object - duplicates are detected and only a
779     * single copy kept.
780     *
781     * @param listener StatusListener listener object.
782     */
783    public void registerStatusListener(@NonNull StatusListener listener) {
784        mStatusListeners.add(listener);
785    }
786
787    /**
788     * Callback to notify when the associated interface is destroyed, up or down.
789     */
790    public interface InterfaceCallback {
791        /**
792         * Interface destroyed by HalDeviceManager.
793         *
794         * @param ifaceName Name of the iface.
795         */
796        void onDestroyed(String ifaceName);
797
798        /**
799         * Interface is up.
800         *
801         * @param ifaceName Name of the iface.
802         */
803        void onUp(String ifaceName);
804
805        /**
806         * Interface is down.
807         *
808         * @param ifaceName Name of the iface.
809         */
810        void onDown(String ifaceName);
811    }
812
813    private void initializeNwParamsForClientInterface(@NonNull String ifaceName) {
814        try {
815            // A runtime crash or shutting down AP mode can leave
816            // IP addresses configured, and this affects
817            // connectivity when supplicant starts up.
818            // Ensure we have no IP addresses before a supplicant start.
819            mNwManagementService.clearInterfaceAddresses(ifaceName);
820
821            // Set privacy extensions
822            mNwManagementService.setInterfaceIpv6PrivacyExtensions(ifaceName, true);
823
824            // IPv6 is enabled only as long as access point is connected since:
825            // - IPv6 addresses and routes stick around after disconnection
826            // - kernel is unaware when connected and fails to start IPv6 negotiation
827            // - kernel can start autoconfiguration when 802.1x is not complete
828            mNwManagementService.disableIpv6(ifaceName);
829        } catch (RemoteException re) {
830            Log.e(TAG, "Unable to change interface settings: " + re);
831        } catch (IllegalStateException ie) {
832            Log.e(TAG, "Unable to change interface settings: " + ie);
833        }
834    }
835
836    /**
837     * Setup an interface for Client mode operations.
838     *
839     * This method configures an interface in STA mode in all the native daemons
840     * (wificond, wpa_supplicant & vendor HAL).
841     *
842     * @param lowPrioritySta The requested STA has a low request priority (lower probability of
843     *                       getting created, higher probability of getting destroyed).
844     * @param interfaceCallback Associated callback for notifying status changes for the iface.
845     * @return Returns the name of the allocated interface, will be null on failure.
846     */
847    public String setupInterfaceForClientMode(boolean lowPrioritySta,
848            @NonNull InterfaceCallback interfaceCallback) {
849        synchronized (mLock) {
850            if (!startHal()) {
851                Log.e(TAG, "Failed to start Hal");
852                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
853                return null;
854            }
855            if (!startSupplicant()) {
856                Log.e(TAG, "Failed to start supplicant");
857                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
858                return null;
859            }
860            Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA);
861            if (iface == null) {
862                Log.e(TAG, "Failed to allocate new STA iface");
863                return null;
864            }
865            iface.externalListener = interfaceCallback;
866            iface.name = createStaIface(iface, lowPrioritySta);
867            if (TextUtils.isEmpty(iface.name)) {
868                Log.e(TAG, "Failed to create STA iface in vendor HAL");
869                mIfaceMgr.removeIface(iface.id);
870                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
871                return null;
872            }
873            if (mWificondControl.setupInterfaceForClientMode(iface.name) == null) {
874                Log.e(TAG, "Failed to setup iface in wificond on " + iface);
875                teardownInterface(iface.name);
876                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
877                return null;
878            }
879            if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
880                Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
881                teardownInterface(iface.name);
882                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
883                return null;
884            }
885            iface.networkObserver = new NetworkObserverInternal(iface.id);
886            if (!registerNetworkObserver(iface.networkObserver)) {
887                Log.e(TAG, "Failed to register network observer on " + iface);
888                teardownInterface(iface.name);
889                return null;
890            }
891            mWifiMonitor.startMonitoring(iface.name);
892            // Just to avoid any race conditions with interface state change callbacks,
893            // update the interface state before we exit.
894            onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
895            initializeNwParamsForClientInterface(iface.name);
896            Log.i(TAG, "Successfully setup " + iface);
897            return iface.name;
898        }
899    }
900
901    /**
902     * Setup an interface for Soft AP mode operations.
903     *
904     * This method configures an interface in AP mode in all the native daemons
905     * (wificond, wpa_supplicant & vendor HAL).
906     *
907     * @param interfaceCallback Associated callback for notifying status changes for the iface.
908     * @return Returns the name of the allocated interface, will be null on failure.
909     */
910    public String setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) {
911        synchronized (mLock) {
912            if (!startHal()) {
913                Log.e(TAG, "Failed to start Hal");
914                mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
915                return null;
916            }
917            Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP);
918            if (iface == null) {
919                Log.e(TAG, "Failed to allocate new AP iface");
920                return null;
921            }
922            iface.externalListener = interfaceCallback;
923            iface.name = createApIface(iface);
924            if (TextUtils.isEmpty(iface.name)) {
925                Log.e(TAG, "Failed to create AP iface in vendor HAL");
926                mIfaceMgr.removeIface(iface.id);
927                mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
928                return null;
929            }
930            if (mWificondControl.setupInterfaceForSoftApMode(iface.name) == null) {
931                Log.e(TAG, "Failed to setup iface in wificond on " + iface);
932                teardownInterface(iface.name);
933                mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond();
934                return null;
935            }
936            iface.networkObserver = new NetworkObserverInternal(iface.id);
937            if (!registerNetworkObserver(iface.networkObserver)) {
938                Log.e(TAG, "Failed to register network observer on " + iface);
939                teardownInterface(iface.name);
940                return null;
941            }
942            // Just to avoid any race conditions with interface state change callbacks,
943            // update the interface state before we exit.
944            onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
945            Log.i(TAG, "Successfully setup " + iface);
946            return iface.name;
947        }
948    }
949
950    /**
951     *
952     * Check if the interface is up or down.
953     *
954     * @param ifaceName Name of the interface.
955     * @return true if iface is up, false if it's down or on error.
956     */
957    public boolean isInterfaceUp(@NonNull String ifaceName) {
958        synchronized (mLock) {
959            final Iface iface = mIfaceMgr.getIface(ifaceName);
960            if (iface == null) {
961                Log.e(TAG, "Trying to get iface state on invalid iface=" + ifaceName);
962                return false;
963            }
964            InterfaceConfiguration config = null;
965            try {
966                config = mNwManagementService.getInterfaceConfig(ifaceName);
967            } catch (RemoteException e) {
968            }
969            if (config == null) {
970                return false;
971            }
972            return config.isUp();
973        }
974    }
975
976    /**
977     * Teardown an interface in Client/AP mode.
978     *
979     * This method tears down the associated interface from all the native daemons
980     * (wificond, wpa_supplicant & vendor HAL).
981     * Also, brings down the HAL, supplicant or hostapd as necessary.
982     *
983     * @param ifaceName Name of the interface.
984     */
985    public void teardownInterface(@NonNull String ifaceName) {
986        synchronized (mLock) {
987            final Iface iface = mIfaceMgr.getIface(ifaceName);
988            if (iface == null) {
989                Log.e(TAG, "Trying to teardown an invalid iface=" + ifaceName);
990                return;
991            }
992            // Trigger the iface removal from HAL. The rest of the cleanup will be triggered
993            // from the interface destroyed callback.
994            if (iface.type == Iface.IFACE_TYPE_STA) {
995                if (!removeStaIface(iface)) {
996                    Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName);
997                    return;
998                }
999            } else if (iface.type == Iface.IFACE_TYPE_AP) {
1000                if (!removeApIface(iface)) {
1001                    Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName);
1002                    return;
1003                }
1004            }
1005            Log.i(TAG, "Successfully initiated teardown for iface=" + ifaceName);
1006        }
1007    }
1008
1009    /**
1010     * Teardown all the active interfaces.
1011     *
1012     * This method tears down the associated interfaces from all the native daemons
1013     * (wificond, wpa_supplicant & vendor HAL).
1014     * Also, brings down the HAL, supplicant or hostapd as necessary.
1015     */
1016    public void teardownAllInterfaces() {
1017        synchronized (mLock) {
1018            Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter();
1019            while (ifaceIdIter.hasNext()) {
1020                Iface iface = mIfaceMgr.getIface(ifaceIdIter.next());
1021                ifaceIdIter.remove();
1022                onInterfaceDestroyed(iface);
1023                Log.i(TAG, "Successfully torn down " + iface);
1024            }
1025            Log.i(TAG, "Successfully torn down all ifaces");
1026        }
1027    }
1028
1029    /**
1030     * Get name of the client interface.
1031     *
1032     * This is mainly used by external modules that needs to perform some
1033     * client operations on the STA interface.
1034     *
1035     * TODO(b/70932231): This may need to be reworked once we start supporting STA + STA.
1036     *
1037     * @return Interface name of any active client interface, null if no active client interface
1038     * exist.
1039     * Return Values for the different scenarios are listed below:
1040     * a) When there are no client interfaces, returns null.
1041     * b) when there is 1 client interface, returns the name of that interface.
1042     * c) When there are 2 or more client interface, returns the name of any client interface.
1043     */
1044    public String getClientInterfaceName() {
1045        synchronized (mLock) {
1046            return mIfaceMgr.findAnyStaIfaceName();
1047        }
1048    }
1049
1050    /**
1051     * Get name of the softap interface.
1052     *
1053     * This is mainly used by external modules that needs to perform some
1054     * operations on the AP interface.
1055     *
1056     * TODO(b/70932231): This may need to be reworked once we start supporting AP + AP.
1057     *
1058     * @return Interface name of any active softap interface, null if no active softap interface
1059     * exist.
1060     * Return Values for the different scenarios are listed below:
1061     * a) When there are no softap interfaces, returns null.
1062     * b) when there is 1 softap interface, returns the name of that interface.
1063     * c) When there are 2 or more softap interface, returns the name of any softap interface.
1064     */
1065    public String getSoftApInterfaceName() {
1066        synchronized (mLock) {
1067            return mIfaceMgr.findAnyApIfaceName();
1068        }
1069    }
1070
1071    /********************************************************
1072     * Wificond operations
1073     ********************************************************/
1074    /**
1075     * Result of a signal poll.
1076     */
1077    public static class SignalPollResult {
1078        // RSSI value in dBM.
1079        public int currentRssi;
1080        //Transmission bit rate in Mbps.
1081        public int txBitrate;
1082        // Association frequency in MHz.
1083        public int associationFrequency;
1084    }
1085
1086    /**
1087     * WiFi interface transimission counters.
1088     */
1089    public static class TxPacketCounters {
1090        // Number of successfully transmitted packets.
1091        public int txSucceeded;
1092        // Number of tramsmission failures.
1093        public int txFailed;
1094    }
1095
1096    /**
1097     * Callback to notify wificond death.
1098     */
1099    public interface WificondDeathEventHandler {
1100        /**
1101         * Invoked when the wificond dies.
1102         */
1103        void onDeath();
1104    }
1105
1106    /**
1107     * Request signal polling to wificond.
1108     *
1109     * @param ifaceName Name of the interface.
1110     * Returns an SignalPollResult object.
1111     * Returns null on failure.
1112     */
1113    public SignalPollResult signalPoll(@NonNull String ifaceName) {
1114        return mWificondControl.signalPoll(ifaceName);
1115    }
1116
1117    /**
1118     * Fetch TX packet counters on current connection from wificond.
1119     * @param ifaceName Name of the interface.
1120     * Returns an TxPacketCounters object.
1121     * Returns null on failure.
1122     */
1123    public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
1124        return mWificondControl.getTxPacketCounters(ifaceName);
1125    }
1126
1127    /**
1128     * Query the list of valid frequencies for the provided band.
1129     * The result depends on the on the country code that has been set.
1130     *
1131     * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1132     * The following bands are supported:
1133     * WifiScanner.WIFI_BAND_24_GHZ
1134     * WifiScanner.WIFI_BAND_5_GHZ
1135     * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
1136     * @return frequencies vector of valid frequencies (MHz), or null for error.
1137     * @throws IllegalArgumentException if band is not recognized.
1138     */
1139    public int [] getChannelsForBand(int band) {
1140        return mWificondControl.getChannelsForBand(band);
1141    }
1142
1143    /**
1144     * Start a scan using wificond for the given parameters.
1145     * @param ifaceName Name of the interface.
1146     * @param scanType Type of scan to perform. One of {@link ScanSettings#SCAN_TYPE_LOW_LATENCY},
1147     * {@link ScanSettings#SCAN_TYPE_LOW_POWER} or {@link ScanSettings#SCAN_TYPE_HIGH_ACCURACY}.
1148     * @param freqs list of frequencies to scan for, if null scan all supported channels.
1149     * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
1150     * @return Returns true on success.
1151     */
1152    public boolean scan(
1153            @NonNull String ifaceName, int scanType, Set<Integer> freqs,
1154            Set<String> hiddenNetworkSSIDs) {
1155        return mWificondControl.scan(ifaceName, scanType, freqs, hiddenNetworkSSIDs);
1156    }
1157
1158    /**
1159     * Fetch the latest scan result from kernel via wificond.
1160     * @param ifaceName Name of the interface.
1161     * @return Returns an ArrayList of ScanDetail.
1162     * Returns an empty ArrayList on failure.
1163     */
1164    public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
1165        return mWificondControl.getScanResults(
1166                ifaceName, WificondControl.SCAN_TYPE_SINGLE_SCAN);
1167    }
1168
1169    /**
1170     * Fetch the latest scan result from kernel via wificond.
1171     * @param ifaceName Name of the interface.
1172     * @return Returns an ArrayList of ScanDetail.
1173     * Returns an empty ArrayList on failure.
1174     */
1175    public ArrayList<ScanDetail> getPnoScanResults(@NonNull String ifaceName) {
1176        return mWificondControl.getScanResults(ifaceName, WificondControl.SCAN_TYPE_PNO_SCAN);
1177    }
1178
1179    /**
1180     * Start PNO scan.
1181     * @param ifaceName Name of the interface.
1182     * @param pnoSettings Pno scan configuration.
1183     * @return true on success.
1184     */
1185    public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings) {
1186        return mWificondControl.startPnoScan(ifaceName, pnoSettings);
1187    }
1188
1189    /**
1190     * Stop PNO scan.
1191     * @param ifaceName Name of the interface.
1192     * @return true on success.
1193     */
1194    public boolean stopPnoScan(@NonNull String ifaceName) {
1195        return mWificondControl.stopPnoScan(ifaceName);
1196    }
1197
1198    /**
1199     * Callbacks for SoftAp interface.
1200     */
1201    public interface SoftApListener {
1202        /**
1203         * Invoked when the number of associated stations changes.
1204         */
1205        void onNumAssociatedStationsChanged(int numStations);
1206
1207        /**
1208         * Invoked when the channel switch event happens.
1209         */
1210        void onSoftApChannelSwitched(int frequency, int bandwidth);
1211    }
1212
1213    private static final int CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS = 100;
1214    private static final int CONNECT_TO_HOSTAPD_RETRY_TIMES = 50;
1215    /**
1216     * This method is called to wait for establishing connection to hostapd.
1217     *
1218     * @return true if connection is established, false otherwise.
1219     */
1220    private boolean waitForHostapdConnection() {
1221        // Start initialization if not already started.
1222        if (!mHostapdHal.isInitializationStarted()
1223                && !mHostapdHal.initialize()) {
1224            return false;
1225        }
1226        boolean connected = false;
1227        int connectTries = 0;
1228        while (!connected && connectTries++ < CONNECT_TO_HOSTAPD_RETRY_TIMES) {
1229            // Check if the initialization is complete.
1230            connected = mHostapdHal.isInitializationComplete();
1231            if (connected) {
1232                break;
1233            }
1234            try {
1235                Thread.sleep(CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS);
1236            } catch (InterruptedException ignore) {
1237            }
1238        }
1239        return connected;
1240    }
1241
1242    /**
1243     * Start Soft AP operation using the provided configuration.
1244     *
1245     * @param ifaceName Name of the interface.
1246     * @param config Configuration to use for the soft ap created.
1247     * @param listener Callback for AP events.
1248     * @return true on success, false otherwise.
1249     */
1250    public boolean startSoftAp(
1251            @NonNull String ifaceName, WifiConfiguration config, SoftApListener listener) {
1252        if (!mWificondControl.startHostapd(ifaceName, listener)) {
1253            Log.e(TAG, "Failed to start hostapd");
1254            mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1255            return false;
1256        }
1257        if (!waitForHostapdConnection()) {
1258            Log.e(TAG, "Failed to establish connection to hostapd");
1259            mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1260            return false;
1261        }
1262        if (!mHostapdHal.registerDeathHandler(new HostapdDeathHandlerInternal())) {
1263            Log.e(TAG, "Failed to register hostapd death handler");
1264            mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1265            return false;
1266        }
1267        if (!mHostapdHal.addAccessPoint(ifaceName, config)) {
1268            Log.e(TAG, "Failed to add acccess point");
1269            mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1270            return false;
1271        }
1272        return true;
1273    }
1274
1275    /**
1276     * Stop the ongoing Soft AP operation.
1277     *
1278     * @param ifaceName Name of the interface.
1279     * @return true on success, false otherwise.
1280     */
1281    public boolean stopSoftAp(@NonNull String ifaceName) {
1282        if (!mHostapdHal.removeAccessPoint(ifaceName)) {
1283            Log.e(TAG, "Failed to remove access point");
1284        }
1285        return mWificondControl.stopHostapd(ifaceName);
1286    }
1287
1288    /**
1289     * Set MAC address of the given interface
1290     * @param interfaceName Name of the interface
1291     * @param mac Mac address to change into
1292     * @return true on success
1293     */
1294    public boolean setMacAddress(String interfaceName, MacAddress mac) {
1295        // TODO(b/72459123): Suppress interface down/up events from this call
1296        return mWifiVendorHal.setMacAddress(interfaceName, mac);
1297    }
1298
1299    /********************************************************
1300     * Hostapd operations
1301     ********************************************************/
1302
1303    /**
1304     * Callback to notify hostapd death.
1305     */
1306    public interface HostapdDeathEventHandler {
1307        /**
1308         * Invoked when the supplicant dies.
1309         */
1310        void onDeath();
1311    }
1312
1313    /********************************************************
1314     * Supplicant operations
1315     ********************************************************/
1316
1317    /**
1318     * Callback to notify supplicant death.
1319     */
1320    public interface SupplicantDeathEventHandler {
1321        /**
1322         * Invoked when the supplicant dies.
1323         */
1324        void onDeath();
1325    }
1326
1327    /**
1328     * Set supplicant log level
1329     *
1330     * @param turnOnVerbose Whether to turn on verbose logging or not.
1331     */
1332    public void setSupplicantLogLevel(boolean turnOnVerbose) {
1333        mSupplicantStaIfaceHal.setLogLevel(turnOnVerbose);
1334    }
1335
1336    /**
1337     * Trigger a reconnection if the iface is disconnected.
1338     *
1339     * @param ifaceName Name of the interface.
1340     * @return true if request is sent successfully, false otherwise.
1341     */
1342    public boolean reconnect(@NonNull String ifaceName) {
1343        return mSupplicantStaIfaceHal.reconnect(ifaceName);
1344    }
1345
1346    /**
1347     * Trigger a reassociation even if the iface is currently connected.
1348     *
1349     * @param ifaceName Name of the interface.
1350     * @return true if request is sent successfully, false otherwise.
1351     */
1352    public boolean reassociate(@NonNull String ifaceName) {
1353        return mSupplicantStaIfaceHal.reassociate(ifaceName);
1354    }
1355
1356    /**
1357     * Trigger a disconnection from the currently connected network.
1358     *
1359     * @param ifaceName Name of the interface.
1360     * @return true if request is sent successfully, false otherwise.
1361     */
1362    public boolean disconnect(@NonNull String ifaceName) {
1363        return mSupplicantStaIfaceHal.disconnect(ifaceName);
1364    }
1365
1366    /**
1367     * Makes a callback to HIDL to getMacAddress from supplicant
1368     *
1369     * @param ifaceName Name of the interface.
1370     * @return string containing the MAC address, or null on a failed call
1371     */
1372    public String getMacAddress(@NonNull String ifaceName) {
1373        return mSupplicantStaIfaceHal.getMacAddress(ifaceName);
1374    }
1375
1376    public static final int RX_FILTER_TYPE_V4_MULTICAST = 0;
1377    public static final int RX_FILTER_TYPE_V6_MULTICAST = 1;
1378    /**
1379     * Start filtering out Multicast V4 packets
1380     * @param ifaceName Name of the interface.
1381     * @return {@code true} if the operation succeeded, {@code false} otherwise
1382     *
1383     * Multicast filtering rules work as follows:
1384     *
1385     * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
1386     * a power optimized mode (typically when screen goes off).
1387     *
1388     * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
1389     * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
1390     *
1391     * DRIVER RXFILTER-ADD Num
1392     *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
1393     *
1394     * and DRIVER RXFILTER-START
1395     * In order to stop the usage of these rules, we do
1396     *
1397     * DRIVER RXFILTER-STOP
1398     * DRIVER RXFILTER-REMOVE Num
1399     *   where Num is as described for RXFILTER-ADD
1400     *
1401     * The  SETSUSPENDOPT driver command overrides the filtering rules
1402     */
1403    public boolean startFilteringMulticastV4Packets(@NonNull String ifaceName) {
1404        return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
1405                && mSupplicantStaIfaceHal.removeRxFilter(
1406                        ifaceName, RX_FILTER_TYPE_V4_MULTICAST)
1407                && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
1408    }
1409
1410    /**
1411     * Stop filtering out Multicast V4 packets.
1412     * @param ifaceName Name of the interface.
1413     * @return {@code true} if the operation succeeded, {@code false} otherwise
1414     */
1415    public boolean stopFilteringMulticastV4Packets(@NonNull String ifaceName) {
1416        return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
1417                && mSupplicantStaIfaceHal.addRxFilter(
1418                        ifaceName, RX_FILTER_TYPE_V4_MULTICAST)
1419                && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
1420    }
1421
1422    /**
1423     * Start filtering out Multicast V6 packets
1424     * @param ifaceName Name of the interface.
1425     * @return {@code true} if the operation succeeded, {@code false} otherwise
1426     */
1427    public boolean startFilteringMulticastV6Packets(@NonNull String ifaceName) {
1428        return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
1429                && mSupplicantStaIfaceHal.removeRxFilter(
1430                        ifaceName, RX_FILTER_TYPE_V6_MULTICAST)
1431                && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
1432    }
1433
1434    /**
1435     * Stop filtering out Multicast V6 packets.
1436     * @param ifaceName Name of the interface.
1437     * @return {@code true} if the operation succeeded, {@code false} otherwise
1438     */
1439    public boolean stopFilteringMulticastV6Packets(@NonNull String ifaceName) {
1440        return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
1441                && mSupplicantStaIfaceHal.addRxFilter(
1442                        ifaceName, RX_FILTER_TYPE_V6_MULTICAST)
1443                && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
1444    }
1445
1446    public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED  = 0;
1447    public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1;
1448    public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE    = 2;
1449    /**
1450     * Sets the bluetooth coexistence mode.
1451     *
1452     * @param ifaceName Name of the interface.
1453     * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
1454     *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
1455     *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
1456     * @return Whether the mode was successfully set.
1457     */
1458    public boolean setBluetoothCoexistenceMode(@NonNull String ifaceName, int mode) {
1459        return mSupplicantStaIfaceHal.setBtCoexistenceMode(ifaceName, mode);
1460    }
1461
1462    /**
1463     * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
1464     * some of the low-level scan parameters used by the driver are changed to
1465     * reduce interference with A2DP streaming.
1466     *
1467     * @param ifaceName Name of the interface.
1468     * @param setCoexScanMode whether to enable or disable this mode
1469     * @return {@code true} if the command succeeded, {@code false} otherwise.
1470     */
1471    public boolean setBluetoothCoexistenceScanMode(
1472            @NonNull String ifaceName, boolean setCoexScanMode) {
1473        return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled(
1474                ifaceName, setCoexScanMode);
1475    }
1476
1477    /**
1478     * Enable or disable suspend mode optimizations.
1479     *
1480     * @param ifaceName Name of the interface.
1481     * @param enabled true to enable, false otherwise.
1482     * @return true if request is sent successfully, false otherwise.
1483     */
1484    public boolean setSuspendOptimizations(@NonNull String ifaceName, boolean enabled) {
1485        return mSupplicantStaIfaceHal.setSuspendModeEnabled(ifaceName, enabled);
1486    }
1487
1488    /**
1489     * Set country code.
1490     *
1491     * @param ifaceName Name of the interface.
1492     * @param countryCode 2 byte ASCII string. For ex: US, CA.
1493     * @return true if request is sent successfully, false otherwise.
1494     */
1495    public boolean setCountryCode(@NonNull String ifaceName, String countryCode) {
1496        return mSupplicantStaIfaceHal.setCountryCode(ifaceName, countryCode);
1497    }
1498
1499    /**
1500     * Initiate TDLS discover and setup or teardown with the specified peer.
1501     *
1502     * @param ifaceName Name of the interface.
1503     * @param macAddr MAC Address of the peer.
1504     * @param enable true to start discovery and setup, false to teardown.
1505     */
1506    public void startTdls(@NonNull String ifaceName, String macAddr, boolean enable) {
1507        if (enable) {
1508            mSupplicantStaIfaceHal.initiateTdlsDiscover(ifaceName, macAddr);
1509            mSupplicantStaIfaceHal.initiateTdlsSetup(ifaceName, macAddr);
1510        } else {
1511            mSupplicantStaIfaceHal.initiateTdlsTeardown(ifaceName, macAddr);
1512        }
1513    }
1514
1515    /**
1516     * Start WPS pin display operation with the specified peer.
1517     *
1518     * @param ifaceName Name of the interface.
1519     * @param bssid BSSID of the peer.
1520     * @return true if request is sent successfully, false otherwise.
1521     */
1522    public boolean startWpsPbc(@NonNull String ifaceName, String bssid) {
1523        return mSupplicantStaIfaceHal.startWpsPbc(ifaceName, bssid);
1524    }
1525
1526    /**
1527     * Start WPS pin keypad operation with the specified pin.
1528     *
1529     * @param ifaceName Name of the interface.
1530     * @param pin Pin to be used.
1531     * @return true if request is sent successfully, false otherwise.
1532     */
1533    public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
1534        return mSupplicantStaIfaceHal.startWpsPinKeypad(ifaceName, pin);
1535    }
1536
1537    /**
1538     * Start WPS pin display operation with the specified peer.
1539     *
1540     * @param ifaceName Name of the interface.
1541     * @param bssid BSSID of the peer.
1542     * @return new pin generated on success, null otherwise.
1543     */
1544    public String startWpsPinDisplay(@NonNull String ifaceName, String bssid) {
1545        return mSupplicantStaIfaceHal.startWpsPinDisplay(ifaceName, bssid);
1546    }
1547
1548    /**
1549     * Sets whether to use external sim for SIM/USIM processing.
1550     *
1551     * @param ifaceName Name of the interface.
1552     * @param external true to enable, false otherwise.
1553     * @return true if request is sent successfully, false otherwise.
1554     */
1555    public boolean setExternalSim(@NonNull String ifaceName, boolean external) {
1556        return mSupplicantStaIfaceHal.setExternalSim(ifaceName, external);
1557    }
1558
1559    /**
1560     * Sim auth response types.
1561     */
1562    public static final String SIM_AUTH_RESP_TYPE_GSM_AUTH = "GSM-AUTH";
1563    public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTH = "UMTS-AUTH";
1564    public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTS = "UMTS-AUTS";
1565
1566    /**
1567     * EAP-SIM Error Codes
1568     */
1569    public static final int EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED = 16385;
1570
1571    /**
1572     * Send the sim auth response for the currently configured network.
1573     *
1574     * @param ifaceName Name of the interface.
1575     * @param type |GSM-AUTH|, |UMTS-AUTH| or |UMTS-AUTS|.
1576     * @param response Response params.
1577     * @return true if succeeds, false otherwise.
1578     */
1579    public boolean simAuthResponse(
1580            @NonNull String ifaceName, int id, String type, String response) {
1581        if (SIM_AUTH_RESP_TYPE_GSM_AUTH.equals(type)) {
1582            return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse(
1583                    ifaceName, response);
1584        } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTH.equals(type)) {
1585            return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse(
1586                    ifaceName, response);
1587        } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTS.equals(type)) {
1588            return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse(
1589                    ifaceName, response);
1590        } else {
1591            return false;
1592        }
1593    }
1594
1595    /**
1596     * Send the eap sim gsm auth failure for the currently configured network.
1597     *
1598     * @param ifaceName Name of the interface.
1599     * @return true if succeeds, false otherwise.
1600     */
1601    public boolean simAuthFailedResponse(@NonNull String ifaceName, int id) {
1602        return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure(ifaceName);
1603    }
1604
1605    /**
1606     * Send the eap sim umts auth failure for the currently configured network.
1607     *
1608     * @param ifaceName Name of the interface.
1609     * @return true if succeeds, false otherwise.
1610     */
1611    public boolean umtsAuthFailedResponse(@NonNull String ifaceName, int id) {
1612        return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure(ifaceName);
1613    }
1614
1615    /**
1616     * Send the eap identity response for the currently configured network.
1617     *
1618     * @param ifaceName Name of the interface.
1619     * @param unencryptedResponse String to send.
1620     * @param encryptedResponse String to send.
1621     * @return true if succeeds, false otherwise.
1622     */
1623    public boolean simIdentityResponse(@NonNull String ifaceName, int id,
1624                                       String unencryptedResponse, String encryptedResponse) {
1625        return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(ifaceName,
1626                unencryptedResponse, encryptedResponse);
1627    }
1628
1629    /**
1630     * This get anonymous identity from supplicant and returns it as a string.
1631     *
1632     * @param ifaceName Name of the interface.
1633     * @return anonymous identity string if succeeds, null otherwise.
1634     */
1635    public String getEapAnonymousIdentity(@NonNull String ifaceName) {
1636        return mSupplicantStaIfaceHal.getCurrentNetworkEapAnonymousIdentity(ifaceName);
1637    }
1638
1639    /**
1640     * Start WPS pin registrar operation with the specified peer and pin.
1641     *
1642     * @param ifaceName Name of the interface.
1643     * @param bssid BSSID of the peer.
1644     * @param pin Pin to be used.
1645     * @return true if request is sent successfully, false otherwise.
1646     */
1647    public boolean startWpsRegistrar(@NonNull String ifaceName, String bssid, String pin) {
1648        return mSupplicantStaIfaceHal.startWpsRegistrar(ifaceName, bssid, pin);
1649    }
1650
1651    /**
1652     * Cancels any ongoing WPS requests.
1653     *
1654     * @param ifaceName Name of the interface.
1655     * @return true if request is sent successfully, false otherwise.
1656     */
1657    public boolean cancelWps(@NonNull String ifaceName) {
1658        return mSupplicantStaIfaceHal.cancelWps(ifaceName);
1659    }
1660
1661    /**
1662     * Set WPS device name.
1663     *
1664     * @param ifaceName Name of the interface.
1665     * @param name String to be set.
1666     * @return true if request is sent successfully, false otherwise.
1667     */
1668    public boolean setDeviceName(@NonNull String ifaceName, String name) {
1669        return mSupplicantStaIfaceHal.setWpsDeviceName(ifaceName, name);
1670    }
1671
1672    /**
1673     * Set WPS device type.
1674     *
1675     * @param ifaceName Name of the interface.
1676     * @param type Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
1677     * @return true if request is sent successfully, false otherwise.
1678     */
1679    public boolean setDeviceType(@NonNull String ifaceName, String type) {
1680        return mSupplicantStaIfaceHal.setWpsDeviceType(ifaceName, type);
1681    }
1682
1683    /**
1684     * Set WPS config methods
1685     *
1686     * @param cfg List of config methods.
1687     * @return true if request is sent successfully, false otherwise.
1688     */
1689    public boolean setConfigMethods(@NonNull String ifaceName, String cfg) {
1690        return mSupplicantStaIfaceHal.setWpsConfigMethods(ifaceName, cfg);
1691    }
1692
1693    /**
1694     * Set WPS manufacturer.
1695     *
1696     * @param ifaceName Name of the interface.
1697     * @param value String to be set.
1698     * @return true if request is sent successfully, false otherwise.
1699     */
1700    public boolean setManufacturer(@NonNull String ifaceName, String value) {
1701        return mSupplicantStaIfaceHal.setWpsManufacturer(ifaceName, value);
1702    }
1703
1704    /**
1705     * Set WPS model name.
1706     *
1707     * @param ifaceName Name of the interface.
1708     * @param value String to be set.
1709     * @return true if request is sent successfully, false otherwise.
1710     */
1711    public boolean setModelName(@NonNull String ifaceName, String value) {
1712        return mSupplicantStaIfaceHal.setWpsModelName(ifaceName, value);
1713    }
1714
1715    /**
1716     * Set WPS model number.
1717     *
1718     * @param ifaceName Name of the interface.
1719     * @param value String to be set.
1720     * @return true if request is sent successfully, false otherwise.
1721     */
1722    public boolean setModelNumber(@NonNull String ifaceName, String value) {
1723        return mSupplicantStaIfaceHal.setWpsModelNumber(ifaceName, value);
1724    }
1725
1726    /**
1727     * Set WPS serial number.
1728     *
1729     * @param ifaceName Name of the interface.
1730     * @param value String to be set.
1731     * @return true if request is sent successfully, false otherwise.
1732     */
1733    public boolean setSerialNumber(@NonNull String ifaceName, String value) {
1734        return mSupplicantStaIfaceHal.setWpsSerialNumber(ifaceName, value);
1735    }
1736
1737    /**
1738     * Enable or disable power save mode.
1739     *
1740     * @param ifaceName Name of the interface.
1741     * @param enabled true to enable, false to disable.
1742     */
1743    public void setPowerSave(@NonNull String ifaceName, boolean enabled) {
1744        mSupplicantStaIfaceHal.setPowerSave(ifaceName, enabled);
1745    }
1746
1747    /**
1748     * Set concurrency priority between P2P & STA operations.
1749     *
1750     * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
1751     *                            false otherwise.
1752     * @return true if request is sent successfully, false otherwise.
1753     */
1754    public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
1755        return mSupplicantStaIfaceHal.setConcurrencyPriority(isStaHigherPriority);
1756    }
1757
1758    /**
1759     * Enable/Disable auto reconnect functionality in wpa_supplicant.
1760     *
1761     * @param ifaceName Name of the interface.
1762     * @param enable true to enable auto reconnecting, false to disable.
1763     * @return true if request is sent successfully, false otherwise.
1764     */
1765    public boolean enableStaAutoReconnect(@NonNull String ifaceName, boolean enable) {
1766        return mSupplicantStaIfaceHal.enableAutoReconnect(ifaceName, enable);
1767    }
1768
1769    /**
1770     * Migrate all the configured networks from wpa_supplicant.
1771     *
1772     * @param ifaceName Name of the interface.
1773     * @param configs       Map of configuration key to configuration objects corresponding to all
1774     *                      the networks.
1775     * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf
1776     * @return Max priority of all the configs.
1777     */
1778    public boolean migrateNetworksFromSupplicant(
1779            @NonNull String ifaceName, Map<String, WifiConfiguration> configs,
1780            SparseArray<Map<String, String>> networkExtras) {
1781        return mSupplicantStaIfaceHal.loadNetworks(ifaceName, configs, networkExtras);
1782    }
1783
1784    /**
1785     * Add the provided network configuration to wpa_supplicant and initiate connection to it.
1786     * This method does the following:
1787     * 1. Abort any ongoing scan to unblock the connection request.
1788     * 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect).
1789     * 3. Add a new network to wpa_supplicant.
1790     * 4. Save the provided configuration to wpa_supplicant.
1791     * 5. Select the new network in wpa_supplicant.
1792     * 6. Triggers reconnect command to wpa_supplicant.
1793     *
1794     * @param ifaceName Name of the interface.
1795     * @param configuration WifiConfiguration parameters for the provided network.
1796     * @return {@code true} if it succeeds, {@code false} otherwise
1797     */
1798    public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
1799        // Abort ongoing scan before connect() to unblock connection request.
1800        mWificondControl.abortScan(ifaceName);
1801        return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
1802    }
1803
1804    /**
1805     * Initiates roaming to the already configured network in wpa_supplicant. If the network
1806     * configuration provided does not match the already configured network, then this triggers
1807     * a new connection attempt (instead of roam).
1808     * 1. Abort any ongoing scan to unblock the roam request.
1809     * 2. First check if we're attempting to connect to the same network as we currently have
1810     * configured.
1811     * 3. Set the new bssid for the network in wpa_supplicant.
1812     * 4. Triggers reassociate command to wpa_supplicant.
1813     *
1814     * @param ifaceName Name of the interface.
1815     * @param configuration WifiConfiguration parameters for the provided network.
1816     * @return {@code true} if it succeeds, {@code false} otherwise
1817     */
1818    public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
1819        // Abort ongoing scan before connect() to unblock roaming request.
1820        mWificondControl.abortScan(ifaceName);
1821        return mSupplicantStaIfaceHal.roamToNetwork(ifaceName, configuration);
1822    }
1823
1824    /**
1825     * Remove all the networks.
1826     *
1827     * @param ifaceName Name of the interface.
1828     * @return {@code true} if it succeeds, {@code false} otherwise
1829     */
1830    public boolean removeAllNetworks(@NonNull String ifaceName) {
1831        return mSupplicantStaIfaceHal.removeAllNetworks(ifaceName);
1832    }
1833
1834    /**
1835     * Set the BSSID for the currently configured network in wpa_supplicant.
1836     *
1837     * @param ifaceName Name of the interface.
1838     * @return true if successful, false otherwise.
1839     */
1840    public boolean setConfiguredNetworkBSSID(@NonNull String ifaceName, String bssid) {
1841        return mSupplicantStaIfaceHal.setCurrentNetworkBssid(ifaceName, bssid);
1842    }
1843
1844    /**
1845     * Initiate ANQP query.
1846     *
1847     * @param ifaceName Name of the interface.
1848     * @param bssid BSSID of the AP to be queried
1849     * @param anqpIds Set of anqp IDs.
1850     * @param hs20Subtypes Set of HS20 subtypes.
1851     * @return true on success, false otherwise.
1852     */
1853    public boolean requestAnqp(
1854            @NonNull String ifaceName, String bssid, Set<Integer> anqpIds,
1855            Set<Integer> hs20Subtypes) {
1856        if (bssid == null || ((anqpIds == null || anqpIds.isEmpty())
1857                && (hs20Subtypes == null || hs20Subtypes.isEmpty()))) {
1858            Log.e(TAG, "Invalid arguments for ANQP request.");
1859            return false;
1860        }
1861        ArrayList<Short> anqpIdList = new ArrayList<>();
1862        for (Integer anqpId : anqpIds) {
1863            anqpIdList.add(anqpId.shortValue());
1864        }
1865        ArrayList<Integer> hs20SubtypeList = new ArrayList<>();
1866        hs20SubtypeList.addAll(hs20Subtypes);
1867        return mSupplicantStaIfaceHal.initiateAnqpQuery(
1868                ifaceName, bssid, anqpIdList, hs20SubtypeList);
1869    }
1870
1871    /**
1872     * Request a passpoint icon file |filename| from the specified AP |bssid|.
1873     *
1874     * @param ifaceName Name of the interface.
1875     * @param bssid BSSID of the AP
1876     * @param fileName name of the icon file
1877     * @return true if request is sent successfully, false otherwise
1878     */
1879    public boolean requestIcon(@NonNull String ifaceName, String  bssid, String fileName) {
1880        if (bssid == null || fileName == null) {
1881            Log.e(TAG, "Invalid arguments for Icon request.");
1882            return false;
1883        }
1884        return mSupplicantStaIfaceHal.initiateHs20IconQuery(ifaceName, bssid, fileName);
1885    }
1886
1887    /**
1888     * Get the currently configured network's WPS NFC token.
1889     *
1890     * @param ifaceName Name of the interface.
1891     * @return Hex string corresponding to the WPS NFC token.
1892     */
1893    public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
1894        return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken(ifaceName);
1895    }
1896
1897    /** Remove the request |networkId| from supplicant if it's the current network,
1898     * if the current configured network matches |networkId|.
1899     *
1900     * @param ifaceName Name of the interface.
1901     * @param networkId network id of the network to be removed from supplicant.
1902     */
1903    public void removeNetworkIfCurrent(@NonNull String ifaceName, int networkId) {
1904        mSupplicantStaIfaceHal.removeNetworkIfCurrent(ifaceName, networkId);
1905    }
1906
1907    /********************************************************
1908     * Vendor HAL operations
1909     ********************************************************/
1910    /**
1911     * Callback to notify vendor HAL death.
1912     */
1913    public interface VendorHalDeathEventHandler {
1914        /**
1915         * Invoked when the vendor HAL dies.
1916         */
1917        void onDeath();
1918    }
1919
1920    /**
1921     * Callback to notify when vendor HAL detects that a change in radio mode.
1922     */
1923    public interface VendorHalRadioModeChangeEventHandler {
1924        /**
1925         * Invoked when the vendor HAL detects a change to MCC mode.
1926         * MCC (Multi channel concurrency) = Multiple interfaces are active on the same band,
1927         * different channels, same radios.
1928         *
1929         * @param band Band on which MCC is detected (specified by one of the
1930         *             WifiScanner.WIFI_BAND_* constants)
1931         */
1932        void onMcc(int band);
1933        /**
1934         * Invoked when the vendor HAL detects a change to SCC mode.
1935         * SCC (Single channel concurrency) = Multiple interfaces are active on the same band, same
1936         * channels, same radios.
1937         *
1938         * @param band Band on which SCC is detected (specified by one of the
1939         *             WifiScanner.WIFI_BAND_* constants)
1940         */
1941        void onScc(int band);
1942        /**
1943         * Invoked when the vendor HAL detects a change to SBS mode.
1944         * SBS (Single Band Simultaneous) = Multiple interfaces are active on the same band,
1945         * different channels, different radios.
1946         *
1947         * @param band Band on which SBS is detected (specified by one of the
1948         *             WifiScanner.WIFI_BAND_* constants)
1949         */
1950        void onSbs(int band);
1951        /**
1952         * Invoked when the vendor HAL detects a change to DBS mode.
1953         * DBS (Dual Band Simultaneous) = Multiple interfaces are active on the different bands,
1954         * different channels, different radios.
1955         */
1956        void onDbs();
1957    }
1958
1959    /**
1960     * Tests whether the HAL is running or not
1961     */
1962    public boolean isHalStarted() {
1963        return mWifiVendorHal.isHalStarted();
1964    }
1965
1966    // TODO: Change variable names to camel style.
1967    public static class ScanCapabilities {
1968        public int  max_scan_cache_size;
1969        public int  max_scan_buckets;
1970        public int  max_ap_cache_per_scan;
1971        public int  max_rssi_sample_size;
1972        public int  max_scan_reporting_threshold;
1973    }
1974
1975    /**
1976     * Gets the scan capabilities
1977     *
1978     * @param ifaceName Name of the interface.
1979     * @param capabilities object to be filled in
1980     * @return true for success. false for failure
1981     */
1982    public boolean getBgScanCapabilities(
1983            @NonNull String ifaceName, ScanCapabilities capabilities) {
1984        return mWifiVendorHal.getBgScanCapabilities(ifaceName, capabilities);
1985    }
1986
1987    public static class ChannelSettings {
1988        public int frequency;
1989        public int dwell_time_ms;
1990        public boolean passive;
1991    }
1992
1993    public static class BucketSettings {
1994        public int bucket;
1995        public int band;
1996        public int period_ms;
1997        public int max_period_ms;
1998        public int step_count;
1999        public int report_events;
2000        public int num_channels;
2001        public ChannelSettings[] channels;
2002    }
2003
2004    /**
2005     * Network parameters for hidden networks to be scanned for.
2006     */
2007    public static class HiddenNetwork {
2008        public String ssid;
2009
2010        @Override
2011        public boolean equals(Object otherObj) {
2012            if (this == otherObj) {
2013                return true;
2014            } else if (otherObj == null || getClass() != otherObj.getClass()) {
2015                return false;
2016            }
2017            HiddenNetwork other = (HiddenNetwork) otherObj;
2018            return Objects.equals(ssid, other.ssid);
2019        }
2020
2021        @Override
2022        public int hashCode() {
2023            return (ssid == null ? 0 : ssid.hashCode());
2024        }
2025    }
2026
2027    public static final int SCAN_TYPE_LOW_LATENCY = 0;
2028    public static final int SCAN_TYPE_LOW_POWER = 1;
2029    public static final int SCAN_TYPE_HIGH_ACCURACY = 2;
2030
2031    public static class ScanSettings {
2032        /**
2033         * Type of scan to perform. One of {@link ScanSettings#SCAN_TYPE_LOW_LATENCY},
2034         * {@link ScanSettings#SCAN_TYPE_LOW_POWER} or {@link ScanSettings#SCAN_TYPE_HIGH_ACCURACY}.
2035         */
2036        public int scanType;
2037        public int base_period_ms;
2038        public int max_ap_per_scan;
2039        public int report_threshold_percent;
2040        public int report_threshold_num_scans;
2041        public int num_buckets;
2042        /* Not used for bg scans. Only works for single scans. */
2043        public HiddenNetwork[] hiddenNetworks;
2044        public BucketSettings[] buckets;
2045    }
2046
2047    /**
2048     * Network parameters to start PNO scan.
2049     */
2050    public static class PnoNetwork {
2051        public String ssid;
2052        public byte flags;
2053        public byte auth_bit_field;
2054
2055        @Override
2056        public boolean equals(Object otherObj) {
2057            if (this == otherObj) {
2058                return true;
2059            } else if (otherObj == null || getClass() != otherObj.getClass()) {
2060                return false;
2061            }
2062            PnoNetwork other = (PnoNetwork) otherObj;
2063            return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags)
2064                    && (auth_bit_field == other.auth_bit_field));
2065        }
2066
2067        @Override
2068        public int hashCode() {
2069            int result = (ssid == null ? 0 : ssid.hashCode());
2070            result ^= ((int) flags * 31) + ((int) auth_bit_field << 8);
2071            return result;
2072        }
2073    }
2074
2075    /**
2076     * Parameters to start PNO scan. This holds the list of networks which are going to used for
2077     * PNO scan.
2078     */
2079    public static class PnoSettings {
2080        public int min5GHzRssi;
2081        public int min24GHzRssi;
2082        public int initialScoreMax;
2083        public int currentConnectionBonus;
2084        public int sameNetworkBonus;
2085        public int secureBonus;
2086        public int band5GHzBonus;
2087        public int periodInMs;
2088        public boolean isConnected;
2089        public PnoNetwork[] networkList;
2090    }
2091
2092    public static interface ScanEventHandler {
2093        /**
2094         * Called for each AP as it is found with the entire contents of the beacon/probe response.
2095         * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified.
2096         */
2097        void onFullScanResult(ScanResult fullScanResult, int bucketsScanned);
2098        /**
2099         * Callback on an event during a gscan scan.
2100         * See WifiNative.WIFI_SCAN_* for possible values.
2101         */
2102        void onScanStatus(int event);
2103        /**
2104         * Called with the current cached scan results when gscan is paused.
2105         */
2106        void onScanPaused(WifiScanner.ScanData[] data);
2107        /**
2108         * Called with the current cached scan results when gscan is resumed.
2109         */
2110        void onScanRestarted();
2111    }
2112
2113    /**
2114     * Handler to notify the occurrence of various events during PNO scan.
2115     */
2116    public interface PnoEventHandler {
2117        /**
2118         * Callback to notify when one of the shortlisted networks is found during PNO scan.
2119         * @param results List of Scan results received.
2120         */
2121        void onPnoNetworkFound(ScanResult[] results);
2122
2123        /**
2124         * Callback to notify when the PNO scan schedule fails.
2125         */
2126        void onPnoScanFailed();
2127    }
2128
2129    public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
2130    public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
2131    public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
2132    public static final int WIFI_SCAN_FAILED = 3;
2133
2134    /**
2135     * Starts a background scan.
2136     * Any ongoing scan will be stopped first
2137     *
2138     * @param ifaceName Name of the interface.
2139     * @param settings     to control the scan
2140     * @param eventHandler to call with the results
2141     * @return true for success
2142     */
2143    public boolean startBgScan(
2144            @NonNull String ifaceName, ScanSettings settings, ScanEventHandler eventHandler) {
2145        return mWifiVendorHal.startBgScan(ifaceName, settings, eventHandler);
2146    }
2147
2148    /**
2149     * Stops any ongoing backgound scan
2150     * @param ifaceName Name of the interface.
2151     */
2152    public void stopBgScan(@NonNull String ifaceName) {
2153        mWifiVendorHal.stopBgScan(ifaceName);
2154    }
2155
2156    /**
2157     * Pauses an ongoing backgound scan
2158     * @param ifaceName Name of the interface.
2159     */
2160    public void pauseBgScan(@NonNull String ifaceName) {
2161        mWifiVendorHal.pauseBgScan(ifaceName);
2162    }
2163
2164    /**
2165     * Restarts a paused scan
2166     * @param ifaceName Name of the interface.
2167     */
2168    public void restartBgScan(@NonNull String ifaceName) {
2169        mWifiVendorHal.restartBgScan(ifaceName);
2170    }
2171
2172    /**
2173     * Gets the latest scan results received.
2174     * @param ifaceName Name of the interface.
2175     */
2176    public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) {
2177        return mWifiVendorHal.getBgScanResults(ifaceName);
2178    }
2179
2180    /**
2181     * Gets the latest link layer stats
2182     * @param ifaceName Name of the interface.
2183     */
2184    public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) {
2185        return mWifiVendorHal.getWifiLinkLayerStats(ifaceName);
2186    }
2187
2188    /**
2189     * Get the supported features
2190     *
2191     * @param ifaceName Name of the interface.
2192     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
2193     */
2194    public int getSupportedFeatureSet(@NonNull String ifaceName) {
2195        return mWifiVendorHal.getSupportedFeatureSet(ifaceName);
2196    }
2197
2198    public static interface RttEventHandler {
2199        void onRttResults(RttManager.RttResult[] result);
2200    }
2201
2202    /**
2203     * Starts a new rtt request
2204     *
2205     * @param params RTT request params. Refer to {@link RttManager#RttParams}.
2206     * @param handler Callback to be invoked to notify any results.
2207     * @return true if the request was successful, false otherwise.
2208     */
2209    public boolean requestRtt(
2210            RttManager.RttParams[] params, RttEventHandler handler) {
2211        return mWifiVendorHal.requestRtt(params, handler);
2212    }
2213
2214    /**
2215     * Cancels an outstanding rtt request
2216     *
2217     * @param params RTT request params. Refer to {@link RttManager#RttParams}
2218     * @return true if there was an outstanding request and it was successfully cancelled
2219     */
2220    public boolean cancelRtt(RttManager.RttParams[] params) {
2221        return mWifiVendorHal.cancelRtt(params);
2222    }
2223
2224    /**
2225     * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder
2226     * role is successfully enabled, {@code null} otherwise.
2227     *
2228     * @param timeoutSeconds timeout to use for the responder.
2229     */
2230    @Nullable
2231    public ResponderConfig enableRttResponder(int timeoutSeconds) {
2232        return mWifiVendorHal.enableRttResponder(timeoutSeconds);
2233    }
2234
2235    /**
2236     * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled,
2237     * {@code false} otherwise.
2238     */
2239    public boolean disableRttResponder() {
2240        return mWifiVendorHal.disableRttResponder();
2241    }
2242
2243    /**
2244     * Set the MAC OUI during scanning.
2245     * An OUI {Organizationally Unique Identifier} is a 24-bit number that
2246     * uniquely identifies a vendor or manufacturer.
2247     *
2248     * @param ifaceName Name of the interface.
2249     * @param oui OUI to set.
2250     * @return true for success
2251     */
2252    public boolean setScanningMacOui(@NonNull String ifaceName, byte[] oui) {
2253        return mWifiVendorHal.setScanningMacOui(ifaceName, oui);
2254    }
2255
2256    /**
2257     * RTT (Round Trip Time) measurement capabilities of the device.
2258     */
2259    public RttManager.RttCapabilities getRttCapabilities() {
2260        return mWifiVendorHal.getRttCapabilities();
2261    }
2262
2263    /**
2264     * Get the APF (Android Packet Filter) capabilities of the device
2265     * @param ifaceName Name of the interface.
2266     */
2267    public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) {
2268        return mWifiVendorHal.getApfCapabilities(ifaceName);
2269    }
2270
2271    /**
2272     * Installs an APF program on this iface, replacing any existing program.
2273     *
2274     * @param ifaceName Name of the interface
2275     * @param filter is the android packet filter program
2276     * @return true for success
2277     */
2278    public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) {
2279        return mWifiVendorHal.installPacketFilter(ifaceName, filter);
2280    }
2281
2282    /**
2283     * Reads the APF program and data buffer for this iface.
2284     *
2285     * @param ifaceName Name of the interface
2286     * @return the buffer returned by the driver, or null in case of an error
2287     */
2288    public byte[] readPacketFilter(@NonNull String ifaceName) {
2289        return mWifiVendorHal.readPacketFilter(ifaceName);
2290    }
2291
2292    /**
2293     * Set country code for this AP iface.
2294     * @param ifaceName Name of the interface.
2295     * @param countryCode - two-letter country code (as ISO 3166)
2296     * @return true for success
2297     */
2298    public boolean setCountryCodeHal(@NonNull String ifaceName, String countryCode) {
2299        return mWifiVendorHal.setCountryCodeHal(ifaceName, countryCode);
2300    }
2301
2302    //---------------------------------------------------------------------------------
2303    /* Wifi Logger commands/events */
2304    public static interface WifiLoggerEventHandler {
2305        void onRingBufferData(RingBufferStatus status, byte[] buffer);
2306        void onWifiAlert(int errorCode, byte[] buffer);
2307    }
2308
2309    /**
2310     * Registers the logger callback and enables alerts.
2311     * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
2312     *
2313     * @param handler Callback to be invoked.
2314     * @return true on success, false otherwise.
2315     */
2316    public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
2317        return mWifiVendorHal.setLoggingEventHandler(handler);
2318    }
2319
2320    /**
2321     * Control debug data collection
2322     *
2323     * @param verboseLevel 0 to 3, inclusive. 0 stops logging.
2324     * @param flags        Ignored.
2325     * @param maxInterval  Maximum interval between reports; ignore if 0.
2326     * @param minDataSize  Minimum data size in buffer for report; ignore if 0.
2327     * @param ringName     Name of the ring for which data collection is to start.
2328     * @return true for success, false otherwise.
2329     */
2330    public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
2331            int minDataSize, String ringName){
2332        return mWifiVendorHal.startLoggingRingBuffer(
2333                verboseLevel, flags, maxInterval, minDataSize, ringName);
2334    }
2335
2336    /**
2337     * Logger features exposed.
2338     * This is a no-op now, will always return -1.
2339     *
2340     * @return true on success, false otherwise.
2341     */
2342    public int getSupportedLoggerFeatureSet() {
2343        return mWifiVendorHal.getSupportedLoggerFeatureSet();
2344    }
2345
2346    /**
2347     * Stops all logging and resets the logger callback.
2348     * This stops both the alerts and ring buffer data collection.
2349     * @return true on success, false otherwise.
2350     */
2351    public boolean resetLogHandler() {
2352        return mWifiVendorHal.resetLogHandler();
2353    }
2354
2355    /**
2356     * Vendor-provided wifi driver version string
2357     *
2358     * @return String returned from the HAL.
2359     */
2360    public String getDriverVersion() {
2361        return mWifiVendorHal.getDriverVersion();
2362    }
2363
2364    /**
2365     * Vendor-provided wifi firmware version string
2366     *
2367     * @return String returned from the HAL.
2368     */
2369    public String getFirmwareVersion() {
2370        return mWifiVendorHal.getFirmwareVersion();
2371    }
2372
2373    public static class RingBufferStatus{
2374        String name;
2375        int flag;
2376        int ringBufferId;
2377        int ringBufferByteSize;
2378        int verboseLevel;
2379        int writtenBytes;
2380        int readBytes;
2381        int writtenRecords;
2382
2383        // Bit masks for interpreting |flag|
2384        public static final int HAS_BINARY_ENTRIES = (1 << 0);
2385        public static final int HAS_ASCII_ENTRIES = (1 << 1);
2386        public static final int HAS_PER_PACKET_ENTRIES = (1 << 2);
2387
2388        @Override
2389        public String toString() {
2390            return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
2391                    " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
2392                    " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
2393                    " writtenRecords: " + writtenRecords;
2394        }
2395    }
2396
2397    /**
2398     * API to get the status of all ring buffers supported by driver
2399     */
2400    public RingBufferStatus[] getRingBufferStatus() {
2401        return mWifiVendorHal.getRingBufferStatus();
2402    }
2403
2404    /**
2405     * Indicates to driver that all the data has to be uploaded urgently
2406     *
2407     * @param ringName Name of the ring buffer requested.
2408     * @return true on success, false otherwise.
2409     */
2410    public boolean getRingBufferData(String ringName) {
2411        return mWifiVendorHal.getRingBufferData(ringName);
2412    }
2413
2414    /**
2415     * Request vendor debug info from the firmware
2416     *
2417     * @return Raw data obtained from the HAL.
2418     */
2419    public byte[] getFwMemoryDump() {
2420        return mWifiVendorHal.getFwMemoryDump();
2421    }
2422
2423    /**
2424     * Request vendor debug info from the driver
2425     *
2426     * @return Raw data obtained from the HAL.
2427     */
2428    public byte[] getDriverStateDump() {
2429        return mWifiVendorHal.getDriverStateDump();
2430    }
2431
2432    //---------------------------------------------------------------------------------
2433    /* Packet fate API */
2434
2435    @Immutable
2436    abstract static class FateReport {
2437        final static int USEC_PER_MSEC = 1000;
2438        // The driver timestamp is a 32-bit counter, in microseconds. This field holds the
2439        // maximal value of a driver timestamp in milliseconds.
2440        final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000);
2441        final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
2442
2443        final byte mFate;
2444        final long mDriverTimestampUSec;
2445        final byte mFrameType;
2446        final byte[] mFrameBytes;
2447        final long mEstimatedWallclockMSec;
2448
2449        FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
2450            mFate = fate;
2451            mDriverTimestampUSec = driverTimestampUSec;
2452            mEstimatedWallclockMSec =
2453                    convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec);
2454            mFrameType = frameType;
2455            mFrameBytes = frameBytes;
2456        }
2457
2458        public String toTableRowString() {
2459            StringWriter sw = new StringWriter();
2460            PrintWriter pw = new PrintWriter(sw);
2461            FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
2462            dateFormatter.setTimeZone(TimeZone.getDefault());
2463            pw.format("%-15s  %12s  %-9s  %-32s  %-12s  %-23s  %s\n",
2464                    mDriverTimestampUSec,
2465                    dateFormatter.format(new Date(mEstimatedWallclockMSec)),
2466                    directionToString(), fateToString(), parser.mMostSpecificProtocolString,
2467                    parser.mTypeString, parser.mResultString);
2468            return sw.toString();
2469        }
2470
2471        public String toVerboseStringWithPiiAllowed() {
2472            StringWriter sw = new StringWriter();
2473            PrintWriter pw = new PrintWriter(sw);
2474            FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
2475            pw.format("Frame direction: %s\n", directionToString());
2476            pw.format("Frame timestamp: %d\n", mDriverTimestampUSec);
2477            pw.format("Frame fate: %s\n", fateToString());
2478            pw.format("Frame type: %s\n", frameTypeToString(mFrameType));
2479            pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString);
2480            pw.format("Frame protocol type: %s\n", parser.mTypeString);
2481            pw.format("Frame length: %d\n", mFrameBytes.length);
2482            pw.append("Frame bytes");
2483            pw.append(HexDump.dumpHexString(mFrameBytes));  // potentially contains PII
2484            pw.append("\n");
2485            return sw.toString();
2486        }
2487
2488        /* Returns a header to match the output of toTableRowString(). */
2489        public static String getTableHeader() {
2490            StringWriter sw = new StringWriter();
2491            PrintWriter pw = new PrintWriter(sw);
2492            pw.format("\n%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
2493                    "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result");
2494            pw.format("%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
2495                    "---------", "--------", "---------", "----", "--------", "----", "------");
2496            return sw.toString();
2497        }
2498
2499        protected abstract String directionToString();
2500
2501        protected abstract String fateToString();
2502
2503        private static String frameTypeToString(byte frameType) {
2504            switch (frameType) {
2505                case WifiLoggerHal.FRAME_TYPE_UNKNOWN:
2506                    return "unknown";
2507                case WifiLoggerHal.FRAME_TYPE_ETHERNET_II:
2508                    return "data";
2509                case WifiLoggerHal.FRAME_TYPE_80211_MGMT:
2510                    return "802.11 management";
2511                default:
2512                    return Byte.toString(frameType);
2513            }
2514        }
2515
2516        /**
2517         * Converts a driver timestamp to a wallclock time, based on the current
2518         * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of
2519         * microseconds, with the same base as BOOTTIME.
2520         */
2521        private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) {
2522            final long wallclockMillisNow = System.currentTimeMillis();
2523            final long boottimeMillisNow = SystemClock.elapsedRealtime();
2524            final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC;
2525
2526            long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC;
2527            if (boottimeTimestampMillis < driverTimestampMillis) {
2528                // The 32-bit microsecond count has wrapped between the time that the driver
2529                // recorded the packet, and the call to this function. Adjust the BOOTTIME
2530                // timestamp, to compensate.
2531                //
2532                // Note that overflow is not a concern here, since the result is less than
2533                // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above,
2534                // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since
2535                // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit
2536                // within a long.
2537                boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC;
2538            }
2539
2540            final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis;
2541            return wallclockMillisNow - millisSincePacketTimestamp;
2542        }
2543    }
2544
2545    /**
2546     * Represents the fate information for one outbound packet.
2547     */
2548    @Immutable
2549    public static final class TxFateReport extends FateReport {
2550        TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
2551            super(fate, driverTimestampUSec, frameType, frameBytes);
2552        }
2553
2554        @Override
2555        protected String directionToString() {
2556            return "TX";
2557        }
2558
2559        @Override
2560        protected String fateToString() {
2561            switch (mFate) {
2562                case WifiLoggerHal.TX_PKT_FATE_ACKED:
2563                    return "acked";
2564                case WifiLoggerHal.TX_PKT_FATE_SENT:
2565                    return "sent";
2566                case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED:
2567                    return "firmware queued";
2568                case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID:
2569                    return "firmware dropped (invalid frame)";
2570                case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS:
2571                    return "firmware dropped (no bufs)";
2572                case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER:
2573                    return "firmware dropped (other)";
2574                case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED:
2575                    return "driver queued";
2576                case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID:
2577                    return "driver dropped (invalid frame)";
2578                case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS:
2579                    return "driver dropped (no bufs)";
2580                case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER:
2581                    return "driver dropped (other)";
2582                default:
2583                    return Byte.toString(mFate);
2584            }
2585        }
2586    }
2587
2588    /**
2589     * Represents the fate information for one inbound packet.
2590     */
2591    @Immutable
2592    public static final class RxFateReport extends FateReport {
2593        RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
2594            super(fate, driverTimestampUSec, frameType, frameBytes);
2595        }
2596
2597        @Override
2598        protected String directionToString() {
2599            return "RX";
2600        }
2601
2602        @Override
2603        protected String fateToString() {
2604            switch (mFate) {
2605                case WifiLoggerHal.RX_PKT_FATE_SUCCESS:
2606                    return "success";
2607                case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED:
2608                    return "firmware queued";
2609                case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER:
2610                    return "firmware dropped (filter)";
2611                case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID:
2612                    return "firmware dropped (invalid frame)";
2613                case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS:
2614                    return "firmware dropped (no bufs)";
2615                case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER:
2616                    return "firmware dropped (other)";
2617                case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED:
2618                    return "driver queued";
2619                case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER:
2620                    return "driver dropped (filter)";
2621                case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID:
2622                    return "driver dropped (invalid frame)";
2623                case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS:
2624                    return "driver dropped (no bufs)";
2625                case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER:
2626                    return "driver dropped (other)";
2627                default:
2628                    return Byte.toString(mFate);
2629            }
2630        }
2631    }
2632
2633    /**
2634     * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started.
2635     *
2636     * @param ifaceName Name of the interface.
2637     * @return true for success, false otherwise.
2638     */
2639    public boolean startPktFateMonitoring(@NonNull String ifaceName) {
2640        return mWifiVendorHal.startPktFateMonitoring(ifaceName);
2641    }
2642
2643    /**
2644     * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started.
2645     *
2646     * @param ifaceName Name of the interface.
2647     * @return true for success, false otherwise.
2648     */
2649    public boolean getTxPktFates(@NonNull String ifaceName, TxFateReport[] reportBufs) {
2650        return mWifiVendorHal.getTxPktFates(ifaceName, reportBufs);
2651    }
2652
2653    /**
2654     * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started.
2655     * @param ifaceName Name of the interface.
2656     */
2657    public boolean getRxPktFates(@NonNull String ifaceName, RxFateReport[] reportBufs) {
2658        return mWifiVendorHal.getRxPktFates(ifaceName, reportBufs);
2659    }
2660
2661    /**
2662     * Get the tx packet counts for the interface.
2663     *
2664     * @param ifaceName Name of the interface.
2665     * @return tx packet counts
2666     */
2667    public long getTxPackets(@NonNull String ifaceName) {
2668        return TrafficStats.getTxPackets(ifaceName);
2669    }
2670
2671    /**
2672     * Get the rx packet counts for the interface.
2673     *
2674     * @param ifaceName Name of the interface
2675     * @return rx packet counts
2676     */
2677    public long getRxPackets(@NonNull String ifaceName) {
2678        return TrafficStats.getRxPackets(ifaceName);
2679    }
2680
2681    /**
2682     * Start sending the specified keep alive packets periodically.
2683     *
2684     * @param ifaceName Name of the interface.
2685     * @param slot Integer used to identify each request.
2686     * @param dstMac Destination MAC Address
2687     * @param packet Raw packet contents to send.
2688     * @param protocol The ethernet protocol type
2689     * @param period Period to use for sending these packets.
2690     * @return 0 for success, -1 for error
2691     */
2692    public int startSendingOffloadedPacket(@NonNull String ifaceName, int slot,
2693            byte[] dstMac, byte[] packet, int protocol, int period) {
2694        byte[] srcMac = NativeUtil.macAddressToByteArray(getMacAddress(ifaceName));
2695        return mWifiVendorHal.startSendingOffloadedPacket(
2696                ifaceName, slot, srcMac, dstMac, packet, protocol, period);
2697    }
2698
2699    /**
2700     * Stop sending the specified keep alive packets.
2701     *
2702     * @param ifaceName Name of the interface.
2703     * @param slot id - same as startSendingOffloadedPacket call.
2704     * @return 0 for success, -1 for error
2705     */
2706    public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) {
2707        return mWifiVendorHal.stopSendingOffloadedPacket(ifaceName, slot);
2708    }
2709
2710    public static interface WifiRssiEventHandler {
2711        void onRssiThresholdBreached(byte curRssi);
2712    }
2713
2714    /**
2715     * Start RSSI monitoring on the currently connected access point.
2716     *
2717     * @param ifaceName        Name of the interface.
2718     * @param maxRssi          Maximum RSSI threshold.
2719     * @param minRssi          Minimum RSSI threshold.
2720     * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
2721     * @return 0 for success, -1 for failure
2722     */
2723    public int startRssiMonitoring(
2724            @NonNull String ifaceName, byte maxRssi, byte minRssi,
2725            WifiRssiEventHandler rssiEventHandler) {
2726        return mWifiVendorHal.startRssiMonitoring(
2727                ifaceName, maxRssi, minRssi, rssiEventHandler);
2728    }
2729
2730    /**
2731     * Stop RSSI monitoring on the currently connected access point.
2732     *
2733     * @param ifaceName Name of the interface.
2734     * @return 0 for success, -1 for failure
2735     */
2736    public int stopRssiMonitoring(@NonNull String ifaceName) {
2737        return mWifiVendorHal.stopRssiMonitoring(ifaceName);
2738    }
2739
2740    /**
2741     * Fetch the host wakeup reasons stats from wlan driver.
2742     *
2743     * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver.
2744     */
2745    public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
2746        return mWifiVendorHal.getWlanWakeReasonCount();
2747    }
2748
2749    /**
2750     * Enable/Disable Neighbour discovery offload functionality in the firmware.
2751     *
2752     * @param ifaceName Name of the interface.
2753     * @param enabled true to enable, false to disable.
2754     * @return true for success, false otherwise.
2755     */
2756    public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) {
2757        return mWifiVendorHal.configureNeighborDiscoveryOffload(ifaceName, enabled);
2758    }
2759
2760    // Firmware roaming control.
2761
2762    /**
2763     * Class to retrieve firmware roaming capability parameters.
2764     */
2765    public static class RoamingCapabilities {
2766        public int  maxBlacklistSize;
2767        public int  maxWhitelistSize;
2768    }
2769
2770    /**
2771     * Query the firmware roaming capabilities.
2772     * @param ifaceName Name of the interface.
2773     * @return true for success, false otherwise.
2774     */
2775    public boolean getRoamingCapabilities(
2776            @NonNull String ifaceName, RoamingCapabilities capabilities) {
2777        return mWifiVendorHal.getRoamingCapabilities(ifaceName, capabilities);
2778    }
2779
2780    /**
2781     * Macros for controlling firmware roaming.
2782     */
2783    public static final int DISABLE_FIRMWARE_ROAMING = 0;
2784    public static final int ENABLE_FIRMWARE_ROAMING = 1;
2785
2786    /**
2787     * Enable/disable firmware roaming.
2788     *
2789     * @param ifaceName Name of the interface.
2790     * @return error code returned from HAL.
2791     */
2792    public int enableFirmwareRoaming(@NonNull String ifaceName, int state) {
2793        return mWifiVendorHal.enableFirmwareRoaming(ifaceName, state);
2794    }
2795
2796    /**
2797     * Class for specifying the roaming configurations.
2798     */
2799    public static class RoamingConfig {
2800        public ArrayList<String> blacklistBssids;
2801        public ArrayList<String> whitelistSsids;
2802    }
2803
2804    /**
2805     * Set firmware roaming configurations.
2806     * @param ifaceName Name of the interface.
2807     */
2808    public boolean configureRoaming(@NonNull String ifaceName, RoamingConfig config) {
2809        return mWifiVendorHal.configureRoaming(ifaceName, config);
2810    }
2811
2812    /**
2813     * Reset firmware roaming configuration.
2814     * @param ifaceName Name of the interface.
2815     */
2816    public boolean resetRoamingConfiguration(@NonNull String ifaceName) {
2817        // Pass in an empty RoamingConfig object which translates to zero size
2818        // blacklist and whitelist to reset the firmware roaming configuration.
2819        return mWifiVendorHal.configureRoaming(ifaceName, new RoamingConfig());
2820    }
2821
2822    /**
2823     * Tx power level scenarios that can be selected.
2824     */
2825    public static final int TX_POWER_SCENARIO_NORMAL = 0;
2826    public static final int TX_POWER_SCENARIO_VOICE_CALL = 1;
2827
2828    /**
2829     * Select one of the pre-configured TX power level scenarios or reset it back to normal.
2830     * Primarily used for meeting SAR requirements during voice calls.
2831     *
2832     * @param scenario Should be one {@link #TX_POWER_SCENARIO_NORMAL} or
2833     *        {@link #TX_POWER_SCENARIO_VOICE_CALL}.
2834     * @return true for success; false for failure or if the HAL version does not support this API.
2835     */
2836    public boolean selectTxPowerScenario(int scenario) {
2837        return mWifiVendorHal.selectTxPowerScenario(scenario);
2838    }
2839
2840    /********************************************************
2841     * JNI operations
2842     ********************************************************/
2843    /* Register native functions */
2844    static {
2845        /* Native functions are defined in libwifi-service.so */
2846        System.loadLibrary("wifi-service");
2847        registerNatives();
2848    }
2849
2850    private static native int registerNatives();
2851    /* kernel logging support */
2852    private static native byte[] readKernelLogNative();
2853
2854    /**
2855     * Fetches the latest kernel logs.
2856     */
2857    public synchronized String readKernelLog() {
2858        byte[] bytes = readKernelLogNative();
2859        if (bytes != null) {
2860            CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
2861            try {
2862                CharBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
2863                return decoded.toString();
2864            } catch (CharacterCodingException cce) {
2865                return new String(bytes, StandardCharsets.ISO_8859_1);
2866            }
2867        } else {
2868            return "*** failed to read kernel log ***";
2869        }
2870    }
2871}
2872