• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server.wifi;
18 
19 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
20 
21 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP;
22 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP_BRIDGE;
23 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_STA;
24 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_NATIVE_SUPPORTED_FEATURES;
25 
26 import android.annotation.IntDef;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.net.MacAddress;
30 import android.net.TrafficStats;
31 import android.net.apf.ApfCapabilities;
32 import android.net.wifi.CoexUnsafeChannel;
33 import android.net.wifi.ScanResult;
34 import android.net.wifi.SecurityParams;
35 import android.net.wifi.SoftApConfiguration;
36 import android.net.wifi.WifiAnnotations;
37 import android.net.wifi.WifiAvailableChannel;
38 import android.net.wifi.WifiConfiguration;
39 import android.net.wifi.WifiContext;
40 import android.net.wifi.WifiManager;
41 import android.net.wifi.WifiScanner;
42 import android.net.wifi.WifiSsid;
43 import android.net.wifi.nl80211.DeviceWiphyCapabilities;
44 import android.net.wifi.nl80211.NativeScanResult;
45 import android.net.wifi.nl80211.NativeWifiClient;
46 import android.net.wifi.nl80211.RadioChainInfo;
47 import android.net.wifi.nl80211.WifiNl80211Manager;
48 import android.os.Bundle;
49 import android.os.Handler;
50 import android.os.SystemClock;
51 import android.os.WorkSource;
52 import android.text.TextUtils;
53 import android.util.ArraySet;
54 import android.util.Log;
55 import android.util.SparseArray;
56 
57 import com.android.internal.annotations.Immutable;
58 import com.android.internal.util.HexDump;
59 import com.android.modules.utils.build.SdkLevel;
60 import com.android.server.wifi.SupplicantStaIfaceHal.QosPolicyStatus;
61 import com.android.server.wifi.hotspot2.NetworkDetail;
62 import com.android.server.wifi.util.FrameParser;
63 import com.android.server.wifi.util.InformationElementUtil;
64 import com.android.server.wifi.util.NativeUtil;
65 import com.android.server.wifi.util.NetdWrapper;
66 import com.android.server.wifi.util.NetdWrapper.NetdEventObserver;
67 import com.android.wifi.resources.R;
68 
69 import java.io.PrintWriter;
70 import java.io.StringWriter;
71 import java.lang.annotation.Retention;
72 import java.lang.annotation.RetentionPolicy;
73 import java.nio.ByteBuffer;
74 import java.nio.ByteOrder;
75 import java.text.SimpleDateFormat;
76 import java.util.ArrayList;
77 import java.util.Arrays;
78 import java.util.Date;
79 import java.util.HashMap;
80 import java.util.HashSet;
81 import java.util.Iterator;
82 import java.util.List;
83 import java.util.Map;
84 import java.util.Objects;
85 import java.util.Random;
86 import java.util.Set;
87 import java.util.TimeZone;
88 
89 /**
90  * Native calls for bring up/shut down of the supplicant daemon and for
91  * sending requests to the supplicant daemon
92  *
93  * {@hide}
94  */
95 public class WifiNative {
96     private static final String TAG = "WifiNative";
97 
98     private final SupplicantStaIfaceHal mSupplicantStaIfaceHal;
99     private final HostapdHal mHostapdHal;
100     private final WifiVendorHal mWifiVendorHal;
101     private final WifiNl80211Manager mWifiCondManager;
102     private final WifiMonitor mWifiMonitor;
103     private final PropertyService mPropertyService;
104     private final WifiMetrics mWifiMetrics;
105     private final Handler mHandler;
106     private final Random mRandom;
107     private final BuildProperties mBuildProperties;
108     private final WifiInjector mWifiInjector;
109     private final WifiContext mContext;
110     private NetdWrapper mNetdWrapper;
111     private boolean mVerboseLoggingEnabled = false;
112     private boolean mIsEnhancedOpenSupported = false;
113     private final List<CoexUnsafeChannel> mCachedCoexUnsafeChannels = new ArrayList<>();
114     private int mCachedCoexRestrictions;
115     private CountryCodeChangeListenerInternal mCountryCodeChangeListener;
116     private boolean mUseFakeScanDetails;
117     private final ArrayList<ScanDetail> mFakeScanDetails = new ArrayList<>();
118     private long mCachedFeatureSet;
119 
WifiNative(WifiVendorHal vendorHal, SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, WifiNl80211Manager condManager, WifiMonitor wifiMonitor, PropertyService propertyService, WifiMetrics wifiMetrics, Handler handler, Random random, BuildProperties buildProperties, WifiInjector wifiInjector)120     public WifiNative(WifiVendorHal vendorHal,
121                       SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal,
122                       WifiNl80211Manager condManager, WifiMonitor wifiMonitor,
123                       PropertyService propertyService, WifiMetrics wifiMetrics,
124                       Handler handler, Random random, BuildProperties buildProperties,
125                       WifiInjector wifiInjector) {
126         mWifiVendorHal = vendorHal;
127         mSupplicantStaIfaceHal = staIfaceHal;
128         mHostapdHal = hostapdHal;
129         mWifiCondManager = condManager;
130         mWifiMonitor = wifiMonitor;
131         mPropertyService = propertyService;
132         mWifiMetrics = wifiMetrics;
133         mHandler = handler;
134         mRandom = random;
135         mBuildProperties = buildProperties;
136         mWifiInjector = wifiInjector;
137         mContext = wifiInjector.getContext();
138     }
139 
140     /**
141      * Enable verbose logging for all sub modules.
142      */
enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)143     public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) {
144         Log.d(TAG, "enableVerboseLogging " + verboseEnabled + " hal " + halVerboseEnabled);
145         mVerboseLoggingEnabled = verboseEnabled;
146         mWifiCondManager.enableVerboseLogging(verboseEnabled);
147         mSupplicantStaIfaceHal.enableVerboseLogging(verboseEnabled, halVerboseEnabled);
148         mHostapdHal.enableVerboseLogging(verboseEnabled, halVerboseEnabled);
149         mWifiVendorHal.enableVerboseLogging(verboseEnabled, halVerboseEnabled);
150         mIfaceMgr.enableVerboseLogging(verboseEnabled);
151     }
152 
153     /**
154      * Callbacks for SoftAp interface.
155      */
156     public class SoftApHalCallbackFromWificond implements WifiNl80211Manager.SoftApCallback {
157         // placeholder for now - provide a shell so that clients don't use a
158         // WifiNl80211Manager-specific API.
159         private String mIfaceName;
160         private SoftApHalCallback mSoftApHalCallback;
161 
SoftApHalCallbackFromWificond(String ifaceName, SoftApHalCallback softApHalCallback)162         SoftApHalCallbackFromWificond(String ifaceName,
163                 SoftApHalCallback softApHalCallback) {
164             mIfaceName = ifaceName;
165             mSoftApHalCallback = softApHalCallback;
166         }
167 
168         @Override
onFailure()169         public void onFailure() {
170             mSoftApHalCallback.onFailure();
171         }
172 
173         @Override
onSoftApChannelSwitched(int frequency, int bandwidth)174         public void onSoftApChannelSwitched(int frequency, int bandwidth) {
175             mSoftApHalCallback.onInfoChanged(mIfaceName, frequency, bandwidth,
176                     ScanResult.WIFI_STANDARD_UNKNOWN, null);
177         }
178 
179         @Override
onConnectedClientsChanged(NativeWifiClient client, boolean isConnected)180         public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected) {
181             mSoftApHalCallback.onConnectedClientsChanged(mIfaceName,
182                     client.getMacAddress(), isConnected);
183         }
184     }
185 
186     private static class CountryCodeChangeListenerInternal implements
187             WifiNl80211Manager.CountryCodeChangedListener {
188         private WifiCountryCode.ChangeListener mListener;
189 
setChangeListener(@onNull WifiCountryCode.ChangeListener listener)190         public void setChangeListener(@NonNull WifiCountryCode.ChangeListener listener) {
191             mListener = listener;
192         }
193 
onSetCountryCodeSucceeded(String country)194         public void onSetCountryCodeSucceeded(String country) {
195             Log.d(TAG, "onSetCountryCodeSucceeded: " + country);
196             if (mListener != null) {
197                 mListener.onSetCountryCodeSucceeded(country);
198             }
199         }
200 
201         @Override
onCountryCodeChanged(String country)202         public void onCountryCodeChanged(String country) {
203             Log.d(TAG, "onCountryCodeChanged: " + country);
204             if (mListener != null) {
205                 mListener.onDriverCountryCodeChanged(country);
206             }
207         }
208     }
209 
210     /**
211      * Callbacks for SoftAp instance.
212      */
213     public interface SoftApHalCallback {
214         /**
215          * Invoked when there is a fatal failure and the SoftAp is shutdown.
216          */
onFailure()217         void onFailure();
218 
219         /**
220          * Invoked when there is a fatal happen in specific instance only.
221          */
onInstanceFailure(String instanceName)222         default void onInstanceFailure(String instanceName) {}
223 
224         /**
225          * Invoked when a channel switch event happens - i.e. the SoftAp is moved to a different
226          * channel. Also called on initial registration.
227          *
228          * @param apIfaceInstance The identity of the ap instance.
229          * @param frequency The new frequency of the SoftAp. A value of 0 is invalid and is an
230          *                     indication that the SoftAp is not enabled.
231          * @param bandwidth The new bandwidth of the SoftAp.
232          * @param generation The new generation of the SoftAp.
233          */
onInfoChanged(String apIfaceInstance, int frequency, int bandwidth, int generation, MacAddress apIfaceInstanceMacAddress)234         void onInfoChanged(String apIfaceInstance, int frequency, int bandwidth,
235                 int generation, MacAddress apIfaceInstanceMacAddress);
236         /**
237          * Invoked when there is a change in the associated station (STA).
238          *
239          * @param apIfaceInstance The identity of the ap instance.
240          * @param clientAddress Macaddress of the client.
241          * @param isConnected Indication as to whether the client is connected (true), or
242          *                    disconnected (false).
243          */
onConnectedClientsChanged(String apIfaceInstance, MacAddress clientAddress, boolean isConnected)244         void onConnectedClientsChanged(String apIfaceInstance, MacAddress clientAddress,
245                 boolean isConnected);
246     }
247 
248     /********************************************************
249      * Interface management related methods.
250      ********************************************************/
251     /**
252      * Meta-info about every iface that is active.
253      */
254     private static class Iface {
255         /** Type of ifaces possible */
256         public static final int IFACE_TYPE_AP = 0;
257         public static final int IFACE_TYPE_STA_FOR_CONNECTIVITY = 1;
258         public static final int IFACE_TYPE_STA_FOR_SCAN = 2;
259 
260         @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA_FOR_CONNECTIVITY, IFACE_TYPE_STA_FOR_SCAN})
261         @Retention(RetentionPolicy.SOURCE)
262         public @interface IfaceType{}
263 
264         /** Identifier allocated for the interface */
265         public final int id;
266         /** Type of the iface: STA (for Connectivity or Scan) or AP */
267         public @IfaceType int type;
268         /** Name of the interface */
269         public String name;
270         /** Is the interface up? This is used to mask up/down notifications to external clients. */
271         public boolean isUp;
272         /** External iface destroyed listener for the iface */
273         public InterfaceCallback externalListener;
274         /** Network observer registered for this interface */
275         public NetworkObserverInternal networkObserver;
276         /** Interface feature set / capabilities */
277         public long featureSet;
278         public DeviceWiphyCapabilities phyCapabilities;
279 
Iface(int id, @Iface.IfaceType int type)280         Iface(int id, @Iface.IfaceType int type) {
281             this.id = id;
282             this.type = type;
283         }
284 
285         @Override
toString()286         public String toString() {
287             StringBuffer sb = new StringBuffer();
288             String typeString;
289             switch(type) {
290                 case IFACE_TYPE_STA_FOR_CONNECTIVITY:
291                     typeString = "STA_CONNECTIVITY";
292                     break;
293                 case IFACE_TYPE_STA_FOR_SCAN:
294                     typeString = "STA_SCAN";
295                     break;
296                 case IFACE_TYPE_AP:
297                     typeString = "AP";
298                     break;
299                 default:
300                     typeString = "<UNKNOWN>";
301                     break;
302             }
303             sb.append("Iface:")
304                 .append("{")
305                 .append("Name=").append(name)
306                 .append(",")
307                 .append("Id=").append(id)
308                 .append(",")
309                 .append("Type=").append(typeString)
310                 .append("}");
311             return sb.toString();
312         }
313     }
314 
315     /**
316      * Iface Management entity. This class maintains list of all the active ifaces.
317      */
318     private static class IfaceManager {
319         /** Integer to allocate for the next iface being created */
320         private int mNextId;
321         /** Map of the id to the iface structure */
322         private HashMap<Integer, Iface> mIfaces = new HashMap<>();
323         private boolean mVerboseLoggingEnabled = false;
324 
enableVerboseLogging(boolean enable)325         public void enableVerboseLogging(boolean enable) {
326             mVerboseLoggingEnabled = enable;
327         }
328 
329         /** Allocate a new iface for the given type */
allocateIface(@face.IfaceType int type)330         private Iface allocateIface(@Iface.IfaceType int type) {
331             if (mVerboseLoggingEnabled) {
332                 Log.d(TAG, "IfaceManager#allocateIface: type=" + type + ", pre-map=" + mIfaces);
333             }
334             Iface iface = new Iface(mNextId, type);
335             mIfaces.put(mNextId, iface);
336             mNextId++;
337             return iface;
338         }
339 
340         /** Remove the iface using the provided id */
removeIface(int id)341         private Iface removeIface(int id) {
342             if (mVerboseLoggingEnabled) {
343                 Log.d(TAG, "IfaceManager#removeIface: id=" + id + ", pre-map=" + mIfaces);
344             }
345             return mIfaces.remove(id);
346         }
347 
348         /** Lookup the iface using the provided id */
getIface(int id)349         private Iface getIface(int id) {
350             return mIfaces.get(id);
351         }
352 
353         /** Lookup the iface using the provided name */
getIface(@onNull String ifaceName)354         private Iface getIface(@NonNull String ifaceName) {
355             for (Iface iface : mIfaces.values()) {
356                 if (TextUtils.equals(iface.name, ifaceName)) {
357                     return iface;
358                 }
359             }
360             return null;
361         }
362 
363         /** Iterator to use for deleting all the ifaces while performing teardown on each of them */
getIfaceIdIter()364         private Iterator<Integer> getIfaceIdIter() {
365             return mIfaces.keySet().iterator();
366         }
367 
368         /** Checks if there are any iface active. */
hasAnyIface()369         private boolean hasAnyIface() {
370             return !mIfaces.isEmpty();
371         }
372 
373         /** Checks if there are any iface of the given type active. */
hasAnyIfaceOfType(@face.IfaceType int type)374         private boolean hasAnyIfaceOfType(@Iface.IfaceType int type) {
375             for (Iface iface : mIfaces.values()) {
376                 if (iface.type == type) {
377                     return true;
378                 }
379             }
380             return false;
381         }
382 
383         /** Checks if there are any STA (for connectivity) iface active. */
hasAnyStaIfaceForConnectivity()384         private boolean hasAnyStaIfaceForConnectivity() {
385             return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY);
386         }
387 
388         /** Checks if there are any STA (for scan) iface active. */
hasAnyStaIfaceForScan()389         private boolean hasAnyStaIfaceForScan() {
390             return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_SCAN);
391         }
392 
393         /** Checks if there are any AP iface active. */
hasAnyApIface()394         private boolean hasAnyApIface() {
395             return hasAnyIfaceOfType(Iface.IFACE_TYPE_AP);
396         }
397 
findAllStaIfaceNames()398         private @NonNull Set<String> findAllStaIfaceNames() {
399             Set<String> ifaceNames = new ArraySet<>();
400             for (Iface iface : mIfaces.values()) {
401                 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
402                         || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
403                     ifaceNames.add(iface.name);
404                 }
405             }
406             return ifaceNames;
407         }
408 
findAllApIfaceNames()409         private @NonNull Set<String> findAllApIfaceNames() {
410             Set<String> ifaceNames = new ArraySet<>();
411             for (Iface iface : mIfaces.values()) {
412                 if (iface.type == Iface.IFACE_TYPE_AP) {
413                     ifaceNames.add(iface.name);
414                 }
415             }
416             return ifaceNames;
417         }
418 
419         /** Removes the existing iface that does not match the provided id. */
removeExistingIface(int newIfaceId)420         public Iface removeExistingIface(int newIfaceId) {
421             if (mVerboseLoggingEnabled) {
422                 Log.d(TAG, "IfaceManager#removeExistingIface: newIfaceId=" + newIfaceId
423                         + ", pre-map=" + mIfaces);
424             }
425             Iface removedIface = null;
426             // The number of ifaces in the database could be 1 existing & 1 new at the max.
427             if (mIfaces.size() > 2) {
428                 Log.wtf(TAG, "More than 1 existing interface found");
429             }
430             Iterator<Map.Entry<Integer, Iface>> iter = mIfaces.entrySet().iterator();
431             while (iter.hasNext()) {
432                 Map.Entry<Integer, Iface> entry = iter.next();
433                 if (entry.getKey() != newIfaceId) {
434                     removedIface = entry.getValue();
435                     iter.remove();
436                 }
437             }
438             return removedIface;
439         }
440 
441         @Override
toString()442         public String toString() {
443             return mIfaces.toString();
444         }
445     }
446 
447     private class NormalScanEventCallback implements WifiNl80211Manager.ScanEventCallback {
448         private String mIfaceName;
449 
NormalScanEventCallback(String ifaceName)450         NormalScanEventCallback(String ifaceName) {
451             mIfaceName = ifaceName;
452         }
453 
454         @Override
onScanResultReady()455         public void onScanResultReady() {
456             Log.d(TAG, "Scan result ready event");
457             mWifiMonitor.broadcastScanResultEvent(mIfaceName);
458         }
459 
460         @Override
onScanFailed()461         public void onScanFailed() {
462             Log.d(TAG, "Scan failed event");
463             mWifiMonitor.broadcastScanFailedEvent(mIfaceName);
464         }
465     }
466 
467     private class PnoScanEventCallback implements WifiNl80211Manager.ScanEventCallback {
468         private String mIfaceName;
469 
PnoScanEventCallback(String ifaceName)470         PnoScanEventCallback(String ifaceName) {
471             mIfaceName = ifaceName;
472         }
473 
474         @Override
onScanResultReady()475         public void onScanResultReady() {
476             Log.d(TAG, "Pno scan result event");
477             mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName);
478             mWifiMetrics.incrementPnoFoundNetworkEventCount();
479         }
480 
481         @Override
onScanFailed()482         public void onScanFailed() {
483             Log.d(TAG, "Pno Scan failed event");
484             mWifiMetrics.incrementPnoScanFailedCount();
485         }
486     }
487 
488     private final Object mLock = new Object();
489     private final IfaceManager mIfaceMgr = new IfaceManager();
490     private HashSet<StatusListener> mStatusListeners = new HashSet<>();
491 
492     /** Helper method invoked to start supplicant if there were no ifaces */
startHal()493     private boolean startHal() {
494         synchronized (mLock) {
495             if (!mIfaceMgr.hasAnyIface()) {
496                 if (mWifiVendorHal.isVendorHalSupported()) {
497                     if (!mWifiVendorHal.startVendorHal()) {
498                         Log.e(TAG, "Failed to start vendor HAL");
499                         return false;
500                     }
501                     if (SdkLevel.isAtLeastS()) {
502                         mWifiVendorHal.setCoexUnsafeChannels(
503                                 mCachedCoexUnsafeChannels, mCachedCoexRestrictions);
504                     }
505                 } else {
506                     Log.i(TAG, "Vendor Hal not supported, ignoring start.");
507                 }
508             }
509             registerWificondListenerIfNecessary();
510             return true;
511         }
512     }
513 
514     /** Helper method invoked to stop HAL if there are no more ifaces */
stopHalAndWificondIfNecessary()515     private void stopHalAndWificondIfNecessary() {
516         synchronized (mLock) {
517             if (!mIfaceMgr.hasAnyIface()) {
518                 if (!mWifiCondManager.tearDownInterfaces()) {
519                     Log.e(TAG, "Failed to teardown ifaces from wificond");
520                 }
521                 if (mWifiVendorHal.isVendorHalSupported()) {
522                     mWifiVendorHal.stopVendorHal();
523                 } else {
524                     Log.i(TAG, "Vendor Hal not supported, ignoring stop.");
525                 }
526             }
527         }
528     }
529 
530     /**
531      * Helper method invoked to setup wificond related callback/listener.
532      */
registerWificondListenerIfNecessary()533     private void registerWificondListenerIfNecessary() {
534         if (mCountryCodeChangeListener == null && SdkLevel.isAtLeastS()) {
535             // The country code listener is a new API in S.
536             mCountryCodeChangeListener = new CountryCodeChangeListenerInternal();
537             mWifiCondManager.registerCountryCodeChangedListener(Runnable::run,
538                     mCountryCodeChangeListener);
539         }
540     }
541 
542     private static final int CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS = 100;
543     private static final int CONNECT_TO_SUPPLICANT_RETRY_TIMES = 50;
544     /**
545      * This method is called to wait for establishing connection to wpa_supplicant.
546      *
547      * @return true if connection is established, false otherwise.
548      */
startAndWaitForSupplicantConnection()549     private boolean startAndWaitForSupplicantConnection() {
550         // Start initialization if not already started.
551         if (!mSupplicantStaIfaceHal.isInitializationStarted()
552                 && !mSupplicantStaIfaceHal.initialize()) {
553             return false;
554         }
555         if (!mSupplicantStaIfaceHal.startDaemon()) {
556             Log.e(TAG, "Failed to startup supplicant");
557             return false;
558         }
559         boolean connected = false;
560         int connectTries = 0;
561         while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) {
562             // Check if the initialization is complete.
563             connected = mSupplicantStaIfaceHal.isInitializationComplete();
564             if (connected) {
565                 break;
566             }
567             try {
568                 Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS);
569             } catch (InterruptedException ignore) {
570             }
571         }
572         return connected;
573     }
574 
575     /** Helper method invoked to start supplicant if there were no STA ifaces */
startSupplicant()576     private boolean startSupplicant() {
577         synchronized (mLock) {
578             if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) {
579                 if (!startAndWaitForSupplicantConnection()) {
580                     Log.e(TAG, "Failed to connect to supplicant");
581                     return false;
582                 }
583                 if (!mSupplicantStaIfaceHal.registerDeathHandler(
584                         new SupplicantDeathHandlerInternal())) {
585                     Log.e(TAG, "Failed to register supplicant death handler");
586                     return false;
587                 }
588             }
589             return true;
590         }
591     }
592 
593     /** Helper method invoked to stop supplicant if there are no more STA ifaces */
stopSupplicantIfNecessary()594     private void stopSupplicantIfNecessary() {
595         synchronized (mLock) {
596             if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) {
597                 if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) {
598                     Log.e(TAG, "Failed to deregister supplicant death handler");
599                 }
600                 mSupplicantStaIfaceHal.terminate();
601             }
602         }
603     }
604 
605     /** Helper method invoked to start hostapd if there were no AP ifaces */
startHostapd()606     private boolean startHostapd() {
607         synchronized (mLock) {
608             if (!mIfaceMgr.hasAnyApIface()) {
609                 if (!startAndWaitForHostapdConnection()) {
610                     Log.e(TAG, "Failed to connect to hostapd");
611                     return false;
612                 }
613                 if (!mHostapdHal.registerDeathHandler(
614                         new HostapdDeathHandlerInternal())) {
615                     Log.e(TAG, "Failed to register hostapd death handler");
616                     return false;
617                 }
618             }
619             return true;
620         }
621     }
622 
623     /** Helper method invoked to stop hostapd if there are no more AP ifaces */
stopHostapdIfNecessary()624     private void stopHostapdIfNecessary() {
625         synchronized (mLock) {
626             if (!mIfaceMgr.hasAnyApIface()) {
627                 if (!mHostapdHal.deregisterDeathHandler()) {
628                     Log.e(TAG, "Failed to deregister hostapd death handler");
629                 }
630                 mHostapdHal.terminate();
631             }
632         }
633     }
634 
635     /** Helper method to register a network observer and return it */
registerNetworkObserver(NetworkObserverInternal observer)636     private boolean registerNetworkObserver(NetworkObserverInternal observer) {
637         if (observer == null) return false;
638         mNetdWrapper.registerObserver(observer);
639         return true;
640     }
641 
642     /** Helper method to unregister a network observer */
unregisterNetworkObserver(NetworkObserverInternal observer)643     private boolean unregisterNetworkObserver(NetworkObserverInternal observer) {
644         if (observer == null) return false;
645         mNetdWrapper.unregisterObserver(observer);
646         return true;
647     }
648 
649     /**
650      * Helper method invoked to teardown client iface (for connectivity) and perform
651      * necessary cleanup
652      */
onClientInterfaceForConnectivityDestroyed(@onNull Iface iface)653     private void onClientInterfaceForConnectivityDestroyed(@NonNull Iface iface) {
654         synchronized (mLock) {
655             mWifiMonitor.stopMonitoring(iface.name);
656             if (!unregisterNetworkObserver(iface.networkObserver)) {
657                 Log.e(TAG, "Failed to unregister network observer on " + iface);
658             }
659             if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) {
660                 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface);
661             }
662             if (!mWifiCondManager.tearDownClientInterface(iface.name)) {
663                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
664             }
665             stopSupplicantIfNecessary();
666             stopHalAndWificondIfNecessary();
667         }
668     }
669 
670     /** Helper method invoked to teardown client iface (for scan) and perform necessary cleanup */
onClientInterfaceForScanDestroyed(@onNull Iface iface)671     private void onClientInterfaceForScanDestroyed(@NonNull Iface iface) {
672         synchronized (mLock) {
673             mWifiMonitor.stopMonitoring(iface.name);
674             if (!unregisterNetworkObserver(iface.networkObserver)) {
675                 Log.e(TAG, "Failed to unregister network observer on " + iface);
676             }
677             if (!mWifiCondManager.tearDownClientInterface(iface.name)) {
678                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
679             }
680             stopHalAndWificondIfNecessary();
681         }
682     }
683 
684     /** Helper method invoked to teardown softAp iface and perform necessary cleanup */
onSoftApInterfaceDestroyed(@onNull Iface iface)685     private void onSoftApInterfaceDestroyed(@NonNull Iface iface) {
686         synchronized (mLock) {
687             if (!unregisterNetworkObserver(iface.networkObserver)) {
688                 Log.e(TAG, "Failed to unregister network observer on " + iface);
689             }
690             if (!mHostapdHal.removeAccessPoint(iface.name)) {
691                 Log.e(TAG, "Failed to remove access point on " + iface);
692             }
693             if (!mWifiCondManager.tearDownSoftApInterface(iface.name)) {
694                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
695             }
696             stopHostapdIfNecessary();
697             stopHalAndWificondIfNecessary();
698         }
699     }
700 
701     /** Helper method invoked to teardown iface and perform necessary cleanup */
onInterfaceDestroyed(@onNull Iface iface)702     private void onInterfaceDestroyed(@NonNull Iface iface) {
703         synchronized (mLock) {
704             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) {
705                 onClientInterfaceForConnectivityDestroyed(iface);
706             } else if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
707                 onClientInterfaceForScanDestroyed(iface);
708             } else if (iface.type == Iface.IFACE_TYPE_AP) {
709                 onSoftApInterfaceDestroyed(iface);
710             }
711             // Invoke the external callback only if the iface was not destroyed because of vendor
712             // HAL crash. In case of vendor HAL crash, let the crash recovery destroy the mode
713             // managers.
714             if (mWifiVendorHal.isVendorHalReady()) {
715                 iface.externalListener.onDestroyed(iface.name);
716             }
717         }
718     }
719 
720     /**
721      * Callback to be invoked by HalDeviceManager when an interface is destroyed.
722      */
723     private class InterfaceDestoyedListenerInternal
724             implements HalDeviceManager.InterfaceDestroyedListener {
725         /** Identifier allocated for the interface */
726         private final int mInterfaceId;
727 
InterfaceDestoyedListenerInternal(int ifaceId)728         InterfaceDestoyedListenerInternal(int ifaceId) {
729             mInterfaceId = ifaceId;
730         }
731 
732         @Override
onDestroyed(@onNull String ifaceName)733         public void onDestroyed(@NonNull String ifaceName) {
734             synchronized (mLock) {
735                 final Iface iface = mIfaceMgr.removeIface(mInterfaceId);
736                 if (iface == null) {
737                     if (mVerboseLoggingEnabled) {
738                         Log.v(TAG, "Received iface destroyed notification on an invalid iface="
739                                 + ifaceName);
740                     }
741                     return;
742                 }
743                 onInterfaceDestroyed(iface);
744                 Log.i(TAG, "Successfully torn down " + iface);
745             }
746         }
747     }
748 
749     /**
750      * Helper method invoked to trigger the status changed callback after one of the native
751      * daemon's death.
752      */
onNativeDaemonDeath()753     private void onNativeDaemonDeath() {
754         synchronized (mLock) {
755             for (StatusListener listener : mStatusListeners) {
756                 listener.onStatusChanged(false);
757             }
758             for (StatusListener listener : mStatusListeners) {
759                 listener.onStatusChanged(true);
760             }
761         }
762     }
763 
764     /**
765      * Death handler for the Vendor HAL daemon.
766      */
767     private class VendorHalDeathHandlerInternal implements VendorHalDeathEventHandler {
768         @Override
onDeath()769         public void onDeath() {
770             synchronized (mLock) {
771                 Log.i(TAG, "Vendor HAL died. Cleaning up internal state.");
772                 onNativeDaemonDeath();
773                 mWifiMetrics.incrementNumHalCrashes();
774             }
775         }
776     }
777 
778     /**
779      * Death handler for the wificond daemon.
780      */
781     private class WificondDeathHandlerInternal implements Runnable {
782         @Override
run()783         public void run() {
784             synchronized (mLock) {
785                 Log.i(TAG, "wificond died. Cleaning up internal state.");
786                 onNativeDaemonDeath();
787                 mWifiMetrics.incrementNumWificondCrashes();
788             }
789         }
790     }
791 
792     /**
793      * Death handler for the supplicant daemon.
794      */
795     private class SupplicantDeathHandlerInternal implements SupplicantDeathEventHandler {
796         @Override
onDeath()797         public void onDeath() {
798             synchronized (mLock) {
799                 Log.i(TAG, "wpa_supplicant died. Cleaning up internal state.");
800                 onNativeDaemonDeath();
801                 mWifiMetrics.incrementNumSupplicantCrashes();
802             }
803         }
804     }
805 
806     /**
807      * Death handler for the hostapd daemon.
808      */
809     private class HostapdDeathHandlerInternal implements HostapdDeathEventHandler {
810         @Override
onDeath()811         public void onDeath() {
812             synchronized (mLock) {
813                 Log.i(TAG, "hostapd died. Cleaning up internal state.");
814                 onNativeDaemonDeath();
815                 mWifiMetrics.incrementNumHostapdCrashes();
816             }
817         }
818     }
819 
820     /** Helper method invoked to handle interface change. */
onInterfaceStateChanged(Iface iface, boolean isUp)821     private void onInterfaceStateChanged(Iface iface, boolean isUp) {
822         synchronized (mLock) {
823             // Mask multiple notifications with the same state.
824             if (isUp == iface.isUp) {
825                 if (mVerboseLoggingEnabled) {
826                     Log.v(TAG, "Interface status unchanged on " + iface + " from " + isUp
827                             + ", Ignoring...");
828                 }
829                 return;
830             }
831             Log.i(TAG, "Interface state changed on " + iface + ", isUp=" + isUp);
832             if (isUp) {
833                 iface.externalListener.onUp(iface.name);
834             } else {
835                 iface.externalListener.onDown(iface.name);
836                 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
837                         || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
838                     mWifiMetrics.incrementNumClientInterfaceDown();
839                 } else if (iface.type == Iface.IFACE_TYPE_AP) {
840                     mWifiMetrics.incrementNumSoftApInterfaceDown();
841                 }
842             }
843             iface.isUp = isUp;
844         }
845     }
846 
847     /**
848      * Network observer to use for all interface up/down notifications.
849      */
850     private class NetworkObserverInternal implements NetdEventObserver {
851         /** Identifier allocated for the interface */
852         private final int mInterfaceId;
853 
NetworkObserverInternal(int id)854         NetworkObserverInternal(int id) {
855             mInterfaceId = id;
856         }
857 
858         /**
859          * Note: We should ideally listen to
860          * {@link NetdEventObserver#interfaceStatusChanged(String, boolean)} here. But, that
861          * callback is not working currently (broken in netd). So, instead listen to link state
862          * change callbacks as triggers to query the real interface state. We should get rid of
863          * this workaround if we get the |interfaceStatusChanged| callback to work in netd.
864          * Also, this workaround will not detect an interface up event, if the link state is
865          * still down.
866          */
867         @Override
interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp)868         public void interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp) {
869             // This is invoked from the main system_server thread. Post to our handler.
870             mHandler.post(() -> {
871                 synchronized (mLock) {
872                     if (mVerboseLoggingEnabled) {
873                         Log.d(TAG, "interfaceLinkStateChanged: ifaceName=" + ifaceName
874                                 + ", mInterfaceId = " + mInterfaceId
875                                 + ", mIfaceMgr=" + mIfaceMgr.toString());
876                     }
877                     final Iface ifaceWithId = mIfaceMgr.getIface(mInterfaceId);
878                     if (ifaceWithId == null) {
879                         if (mVerboseLoggingEnabled) {
880                             Log.v(TAG, "Received iface link up/down notification on an invalid"
881                                     + " iface=" + mInterfaceId);
882                         }
883                         return;
884                     }
885                     final Iface ifaceWithName = mIfaceMgr.getIface(ifaceName);
886                     if (ifaceWithName == null || ifaceWithName != ifaceWithId) {
887                         if (mVerboseLoggingEnabled) {
888                             Log.v(TAG, "Received iface link up/down notification on an invalid"
889                                     + " iface=" + ifaceName);
890                         }
891                         return;
892                     }
893                     onInterfaceStateChanged(ifaceWithName, isInterfaceUp(ifaceName));
894                 }
895             });
896         }
897 
898         @Override
interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp)899         public void interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp) {
900             // unused currently. Look at note above.
901         }
902     }
903 
904     /**
905      * Radio mode change handler for the Vendor HAL daemon.
906      */
907     private class VendorHalRadioModeChangeHandlerInternal
908             implements VendorHalRadioModeChangeEventHandler {
909         @Override
onMcc(int band)910         public void onMcc(int band) {
911             synchronized (mLock) {
912                 Log.i(TAG, "Device is in MCC mode now");
913                 mWifiMetrics.incrementNumRadioModeChangeToMcc();
914             }
915         }
916         @Override
onScc(int band)917         public void onScc(int band) {
918             synchronized (mLock) {
919                 Log.i(TAG, "Device is in SCC mode now");
920                 mWifiMetrics.incrementNumRadioModeChangeToScc();
921             }
922         }
923         @Override
onSbs(int band)924         public void onSbs(int band) {
925             synchronized (mLock) {
926                 Log.i(TAG, "Device is in SBS mode now");
927                 mWifiMetrics.incrementNumRadioModeChangeToSbs();
928             }
929         }
930         @Override
onDbs()931         public void onDbs() {
932             synchronized (mLock) {
933                 Log.i(TAG, "Device is in DBS mode now");
934                 mWifiMetrics.incrementNumRadioModeChangeToDbs();
935             }
936         }
937     }
938 
939     // For devices that don't support the vendor HAL, we will not support any concurrency.
940     // So simulate the HalDeviceManager behavior by triggering the destroy listener for
941     // any active interface.
handleIfaceCreationWhenVendorHalNotSupported(@onNull Iface newIface)942     private String handleIfaceCreationWhenVendorHalNotSupported(@NonNull Iface newIface) {
943         synchronized (mLock) {
944             Iface existingIface = mIfaceMgr.removeExistingIface(newIface.id);
945             if (existingIface != null) {
946                 onInterfaceDestroyed(existingIface);
947                 Log.i(TAG, "Successfully torn down " + existingIface);
948             }
949             // Return the interface name directly from the system property.
950             return mPropertyService.getString("wifi.interface", "wlan0");
951         }
952     }
953 
954     /**
955      * Helper function to handle creation of STA iface.
956      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
957      * teardown any existing iface.
958      */
createStaIface(@onNull Iface iface, @NonNull WorkSource requestorWs)959     private String createStaIface(@NonNull Iface iface, @NonNull WorkSource requestorWs) {
960         synchronized (mLock) {
961             if (mWifiVendorHal.isVendorHalSupported()) {
962                 return mWifiVendorHal.createStaIface(
963                         new InterfaceDestoyedListenerInternal(iface.id), requestorWs);
964             } else {
965                 Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface.");
966                 return handleIfaceCreationWhenVendorHalNotSupported(iface);
967             }
968         }
969     }
970 
971     /**
972      * Helper function to handle creation of AP iface.
973      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
974      * teardown any existing iface.
975      */
createApIface(@onNull Iface iface, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged, @NonNull SoftApManager softApManager)976     private String createApIface(@NonNull Iface iface, @NonNull WorkSource requestorWs,
977             @SoftApConfiguration.BandType int band, boolean isBridged,
978             @NonNull SoftApManager softApManager) {
979         synchronized (mLock) {
980             if (mWifiVendorHal.isVendorHalSupported()) {
981                 return mWifiVendorHal.createApIface(
982                         new InterfaceDestoyedListenerInternal(iface.id), requestorWs,
983                         band, isBridged, softApManager);
984             } else {
985                 Log.i(TAG, "Vendor Hal not supported, ignoring createApIface.");
986                 return handleIfaceCreationWhenVendorHalNotSupported(iface);
987             }
988         }
989     }
990 
991     /**
992      * Get list of instance name from this bridged AP iface.
993      *
994      * @param ifaceName Name of the bridged interface.
995      * @return list of instance name when succeed, otherwise null.
996      */
997     @Nullable
getBridgedApInstances(@onNull String ifaceName)998     private List<String> getBridgedApInstances(@NonNull String ifaceName) {
999         synchronized (mLock) {
1000             if (mWifiVendorHal.isVendorHalSupported()) {
1001                 return mWifiVendorHal.getBridgedApInstances(ifaceName);
1002             } else {
1003                 Log.i(TAG, "Vendor Hal not supported, ignoring getBridgedApInstances.");
1004                 return null;
1005             }
1006         }
1007     }
1008 
1009     // For devices that don't support the vendor HAL, we will not support any concurrency.
1010     // So simulate the HalDeviceManager behavior by triggering the destroy listener for
1011     // the interface.
handleIfaceRemovalWhenVendorHalNotSupported(@onNull Iface iface)1012     private boolean handleIfaceRemovalWhenVendorHalNotSupported(@NonNull Iface iface) {
1013         synchronized (mLock) {
1014             mIfaceMgr.removeIface(iface.id);
1015             onInterfaceDestroyed(iface);
1016             Log.i(TAG, "Successfully torn down " + iface);
1017             return true;
1018         }
1019     }
1020 
1021     /**
1022      * Helper function to handle removal of STA iface.
1023      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
1024      * teardown any existing iface.
1025      */
removeStaIface(@onNull Iface iface)1026     private boolean removeStaIface(@NonNull Iface iface) {
1027         synchronized (mLock) {
1028             if (mWifiVendorHal.isVendorHalSupported()) {
1029                 return mWifiVendorHal.removeStaIface(iface.name);
1030             } else {
1031                 Log.i(TAG, "Vendor Hal not supported, ignoring removeStaIface.");
1032                 return handleIfaceRemovalWhenVendorHalNotSupported(iface);
1033             }
1034         }
1035     }
1036 
1037     /**
1038      * Helper function to handle removal of STA iface.
1039      */
removeApIface(@onNull Iface iface)1040     private boolean removeApIface(@NonNull Iface iface) {
1041         synchronized (mLock) {
1042             if (mWifiVendorHal.isVendorHalSupported()) {
1043                 return mWifiVendorHal.removeApIface(iface.name);
1044             } else {
1045                 Log.i(TAG, "Vendor Hal not supported, ignoring removeApIface.");
1046                 return handleIfaceRemovalWhenVendorHalNotSupported(iface);
1047             }
1048         }
1049     }
1050 
1051     /**
1052      * Helper function to remove specific instance in bridged AP iface.
1053      *
1054      * @param ifaceName Name of the iface.
1055      * @param apIfaceInstance The identity of the ap instance.
1056      * @return true if the operation succeeded, false if there is an error in Hal.
1057      */
removeIfaceInstanceFromBridgedApIface(@onNull String ifaceName, @NonNull String apIfaceInstance)1058     public boolean removeIfaceInstanceFromBridgedApIface(@NonNull String ifaceName,
1059             @NonNull String apIfaceInstance) {
1060         synchronized (mLock) {
1061             if (mWifiVendorHal.isVendorHalSupported()) {
1062                 return mWifiVendorHal.removeIfaceInstanceFromBridgedApIface(ifaceName,
1063                         apIfaceInstance);
1064             } else {
1065                 return false;
1066             }
1067         }
1068     }
1069 
1070     /**
1071      * Register listener for subsystem restart event
1072      *
1073      * @param listener SubsystemRestartListener listener object.
1074      */
registerSubsystemRestartListener( HalDeviceManager.SubsystemRestartListener listener)1075     public void registerSubsystemRestartListener(
1076             HalDeviceManager.SubsystemRestartListener listener) {
1077         if (listener != null) {
1078             mWifiVendorHal.registerSubsystemRestartListener(listener);
1079         }
1080     }
1081 
1082     /**
1083      * Initialize the native modules.
1084      *
1085      * @return true on success, false otherwise.
1086      */
initialize()1087     public boolean initialize() {
1088         synchronized (mLock) {
1089             if (!mWifiVendorHal.initialize(new VendorHalDeathHandlerInternal())) {
1090                 Log.e(TAG, "Failed to initialize vendor HAL");
1091                 return false;
1092             }
1093             mWifiCondManager.setOnServiceDeadCallback(new WificondDeathHandlerInternal());
1094             mWifiCondManager.tearDownInterfaces();
1095             mWifiVendorHal.registerRadioModeChangeHandler(
1096                     new VendorHalRadioModeChangeHandlerInternal());
1097             mNetdWrapper = mWifiInjector.makeNetdWrapper();
1098             return true;
1099         }
1100     }
1101 
1102     /**
1103      * Callback to notify when the status of one of the native daemons
1104      * (wificond, wpa_supplicant & vendor HAL) changes.
1105      */
1106     public interface StatusListener {
1107         /**
1108          * @param allReady Indicates if all the native daemons are ready for operation or not.
1109          */
onStatusChanged(boolean allReady)1110         void onStatusChanged(boolean allReady);
1111     }
1112 
1113     /**
1114      * Register a StatusListener to get notified about any status changes from the native daemons.
1115      *
1116      * It is safe to re-register the same callback object - duplicates are detected and only a
1117      * single copy kept.
1118      *
1119      * @param listener StatusListener listener object.
1120      */
registerStatusListener(@onNull StatusListener listener)1121     public void registerStatusListener(@NonNull StatusListener listener) {
1122         synchronized (mLock) {
1123             mStatusListeners.add(listener);
1124         }
1125     }
1126 
1127     /**
1128      * Callback to notify when the associated interface is destroyed, up or down.
1129      */
1130     public interface InterfaceCallback {
1131         /**
1132          * Interface destroyed by HalDeviceManager.
1133          *
1134          * @param ifaceName Name of the iface.
1135          */
onDestroyed(String ifaceName)1136         void onDestroyed(String ifaceName);
1137 
1138         /**
1139          * Interface is up.
1140          *
1141          * @param ifaceName Name of the iface.
1142          */
onUp(String ifaceName)1143         void onUp(String ifaceName);
1144 
1145         /**
1146          * Interface is down.
1147          *
1148          * @param ifaceName Name of the iface.
1149          */
onDown(String ifaceName)1150         void onDown(String ifaceName);
1151     }
1152 
initializeNwParamsForClientInterface(@onNull String ifaceName)1153     private void initializeNwParamsForClientInterface(@NonNull String ifaceName) {
1154         try {
1155             // A runtime crash or shutting down AP mode can leave
1156             // IP addresses configured, and this affects
1157             // connectivity when supplicant starts up.
1158             // Ensure we have no IP addresses before a supplicant start.
1159             mNetdWrapper.clearInterfaceAddresses(ifaceName);
1160 
1161             // Set privacy extensions
1162             mNetdWrapper.setInterfaceIpv6PrivacyExtensions(ifaceName, true);
1163 
1164             // IPv6 is enabled only as long as access point is connected since:
1165             // - IPv6 addresses and routes stick around after disconnection
1166             // - kernel is unaware when connected and fails to start IPv6 negotiation
1167             // - kernel can start autoconfiguration when 802.1x is not complete
1168             mNetdWrapper.disableIpv6(ifaceName);
1169         } catch (IllegalStateException e) {
1170             Log.e(TAG, "Unable to change interface settings", e);
1171         }
1172     }
1173 
1174     /**
1175      * Setup an interface for client mode (for connectivity) operations.
1176      *
1177      * This method configures an interface in STA mode in all the native daemons
1178      * (wificond, wpa_supplicant & vendor HAL).
1179      *
1180      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1181      * @param requestorWs Requestor worksource.
1182      * @return Returns the name of the allocated interface, will be null on failure.
1183      */
setupInterfaceForClientInConnectivityMode( @onNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs)1184     public String setupInterfaceForClientInConnectivityMode(
1185             @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs) {
1186         synchronized (mLock) {
1187             if (!startHal()) {
1188                 Log.e(TAG, "Failed to start Hal");
1189                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1190                 return null;
1191             }
1192             if (!startSupplicant()) {
1193                 Log.e(TAG, "Failed to start supplicant");
1194                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1195                 return null;
1196             }
1197             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY);
1198             if (iface == null) {
1199                 Log.e(TAG, "Failed to allocate new STA iface");
1200                 return null;
1201             }
1202             iface.externalListener = interfaceCallback;
1203             iface.name = createStaIface(iface, requestorWs);
1204             if (TextUtils.isEmpty(iface.name)) {
1205                 Log.e(TAG, "Failed to create STA iface in vendor HAL");
1206                 mIfaceMgr.removeIface(iface.id);
1207                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1208                 return null;
1209             }
1210             if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
1211                     new NormalScanEventCallback(iface.name),
1212                     new PnoScanEventCallback(iface.name))) {
1213                 Log.e(TAG, "Failed to setup iface in wificond on " + iface);
1214                 teardownInterface(iface.name);
1215                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
1216                 return null;
1217             }
1218             if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
1219                 Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
1220                 teardownInterface(iface.name);
1221                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1222                 return null;
1223             }
1224             if (mContext.getResources().getBoolean(
1225                     R.bool.config_wifiNetworkCentricQosPolicyFeatureEnabled)) {
1226                 if (!mSupplicantStaIfaceHal.setNetworkCentricQosPolicyFeatureEnabled(
1227                         iface.name, true)) {
1228                     Log.e(TAG, "Failed to set QoS policy feature enabled for iface " + iface.name);
1229                     return null;
1230                 }
1231             }
1232             iface.networkObserver = new NetworkObserverInternal(iface.id);
1233             if (!registerNetworkObserver(iface.networkObserver)) {
1234                 Log.e(TAG, "Failed to register network observer on " + iface);
1235                 teardownInterface(iface.name);
1236                 return null;
1237             }
1238             mWifiMonitor.startMonitoring(iface.name);
1239             // Just to avoid any race conditions with interface state change callbacks,
1240             // update the interface state before we exit.
1241             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1242             mWifiVendorHal.enableLinkLayerStats(iface.name);
1243             initializeNwParamsForClientInterface(iface.name);
1244             Log.i(TAG, "Successfully setup " + iface);
1245 
1246             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1247             saveCompleteFeatureSetInConfigStoreIfNecessary(iface.featureSet);
1248             mIsEnhancedOpenSupported = (iface.featureSet & WIFI_FEATURE_OWE) != 0;
1249             return iface.name;
1250         }
1251     }
1252 
1253     /**
1254      * Setup an interface for client mode (for scan) operations.
1255      *
1256      * This method configures an interface in STA mode in the native daemons
1257      * (wificond, vendor HAL).
1258      *
1259      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1260      * @param requestorWs Requestor worksource.
1261      * @return Returns the name of the allocated interface, will be null on failure.
1262      */
setupInterfaceForClientInScanMode( @onNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs)1263     public String setupInterfaceForClientInScanMode(
1264             @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs) {
1265         synchronized (mLock) {
1266             if (!startHal()) {
1267                 Log.e(TAG, "Failed to start Hal");
1268                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1269                 return null;
1270             }
1271             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
1272             if (iface == null) {
1273                 Log.e(TAG, "Failed to allocate new STA iface");
1274                 return null;
1275             }
1276             iface.externalListener = interfaceCallback;
1277             iface.name = createStaIface(iface, requestorWs);
1278             if (TextUtils.isEmpty(iface.name)) {
1279                 Log.e(TAG, "Failed to create iface in vendor HAL");
1280                 mIfaceMgr.removeIface(iface.id);
1281                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1282                 return null;
1283             }
1284             if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
1285                     new NormalScanEventCallback(iface.name),
1286                     new PnoScanEventCallback(iface.name))) {
1287                 Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
1288                 teardownInterface(iface.name);
1289                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
1290                 return null;
1291             }
1292             iface.networkObserver = new NetworkObserverInternal(iface.id);
1293             if (!registerNetworkObserver(iface.networkObserver)) {
1294                 Log.e(TAG, "Failed to register network observer for iface=" + iface.name);
1295                 teardownInterface(iface.name);
1296                 return null;
1297             }
1298             mWifiMonitor.startMonitoring(iface.name);
1299             // Just to avoid any race conditions with interface state change callbacks,
1300             // update the interface state before we exit.
1301             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1302             mWifiVendorHal.enableLinkLayerStats(iface.name);
1303             Log.i(TAG, "Successfully setup " + iface);
1304 
1305             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1306             return iface.name;
1307         }
1308     }
1309 
1310     /**
1311      * Setup an interface for Soft AP mode operations.
1312      *
1313      * This method configures an interface in AP mode in all the native daemons
1314      * (wificond, wpa_supplicant & vendor HAL).
1315      *
1316      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1317      * @param requestorWs Requestor worksource.
1318      * @param isBridged Whether or not AP interface is a bridge interface.
1319      * @param softApManager SoftApManager of the request.
1320      * @return Returns the name of the allocated interface, will be null on failure.
1321      */
setupInterfaceForSoftApMode( @onNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged, @NonNull SoftApManager softApManager)1322     public String setupInterfaceForSoftApMode(
1323             @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs,
1324             @SoftApConfiguration.BandType int band, boolean isBridged,
1325             @NonNull SoftApManager softApManager) {
1326         synchronized (mLock) {
1327             if (!startHal()) {
1328                 Log.e(TAG, "Failed to start Hal");
1329                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
1330                 return null;
1331             }
1332             if (!startHostapd()) {
1333                 Log.e(TAG, "Failed to start hostapd");
1334                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1335                 return null;
1336             }
1337             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP);
1338             if (iface == null) {
1339                 Log.e(TAG, "Failed to allocate new AP iface");
1340                 return null;
1341             }
1342             iface.externalListener = interfaceCallback;
1343             iface.name = createApIface(iface, requestorWs, band, isBridged, softApManager);
1344             if (TextUtils.isEmpty(iface.name)) {
1345                 Log.e(TAG, "Failed to create AP iface in vendor HAL");
1346                 mIfaceMgr.removeIface(iface.id);
1347                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
1348                 return null;
1349             }
1350             String ifaceInstanceName = iface.name;
1351             if (isBridged) {
1352                 List<String> instances = getBridgedApInstances(iface.name);
1353                 if (instances == null || instances.size() == 0) {
1354                     Log.e(TAG, "Failed to get bridged AP instances" + iface.name);
1355                     teardownInterface(iface.name);
1356                     mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
1357                     return null;
1358                 }
1359                 // Always select first instance as wificond interface.
1360                 ifaceInstanceName = instances.get(0);
1361             }
1362             if (!mWifiCondManager.setupInterfaceForSoftApMode(ifaceInstanceName)) {
1363                 Log.e(TAG, "Failed to setup iface in wificond on " + iface);
1364                 teardownInterface(iface.name);
1365                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond();
1366                 return null;
1367             }
1368             iface.networkObserver = new NetworkObserverInternal(iface.id);
1369             if (!registerNetworkObserver(iface.networkObserver)) {
1370                 Log.e(TAG, "Failed to register network observer on " + iface);
1371                 teardownInterface(iface.name);
1372                 return null;
1373             }
1374             // Just to avoid any race conditions with interface state change callbacks,
1375             // update the interface state before we exit.
1376             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1377             Log.i(TAG, "Successfully setup " + iface);
1378 
1379             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1380             return iface.name;
1381         }
1382     }
1383 
1384     /**
1385      * Switches an existing Client mode interface from connectivity
1386      * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY} to scan mode
1387      * {@link Iface#IFACE_TYPE_STA_FOR_SCAN}.
1388      *
1389      * @param ifaceName Name of the interface.
1390      * @param requestorWs Requestor worksource.
1391      * @return true if the operation succeeded, false if there is an error or the iface is already
1392      * in scan mode.
1393      */
switchClientInterfaceToScanMode(@onNull String ifaceName, @NonNull WorkSource requestorWs)1394     public boolean switchClientInterfaceToScanMode(@NonNull String ifaceName,
1395             @NonNull WorkSource requestorWs) {
1396         synchronized (mLock) {
1397             final Iface iface = mIfaceMgr.getIface(ifaceName);
1398             if (iface == null) {
1399                 Log.e(TAG, "Trying to switch to scan mode on an invalid iface=" + ifaceName);
1400                 return false;
1401             }
1402             if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
1403                 Log.e(TAG, "Already in scan mode on iface=" + ifaceName);
1404                 return true;
1405             }
1406             if (mWifiVendorHal.isVendorHalSupported()
1407                     && !mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, requestorWs)) {
1408                 Log.e(TAG, "Failed to replace requestor ws on " + iface);
1409                 teardownInterface(iface.name);
1410                 return false;
1411             }
1412             if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) {
1413                 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface);
1414                 teardownInterface(iface.name);
1415                 return false;
1416             }
1417             iface.type = Iface.IFACE_TYPE_STA_FOR_SCAN;
1418             stopSupplicantIfNecessary();
1419             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1420             iface.phyCapabilities = null;
1421             Log.i(TAG, "Successfully switched to scan mode on iface=" + iface);
1422             return true;
1423         }
1424     }
1425 
1426     /**
1427      * Switches an existing Client mode interface from scan mode
1428      * {@link Iface#IFACE_TYPE_STA_FOR_SCAN} to connectivity mode
1429      * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY}.
1430      *
1431      * @param ifaceName Name of the interface.
1432      * @param requestorWs Requestor worksource.
1433      * @return true if the operation succeeded, false if there is an error or the iface is already
1434      * in scan mode.
1435      */
switchClientInterfaceToConnectivityMode(@onNull String ifaceName, @NonNull WorkSource requestorWs)1436     public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName,
1437             @NonNull WorkSource requestorWs) {
1438         synchronized (mLock) {
1439             final Iface iface = mIfaceMgr.getIface(ifaceName);
1440             if (iface == null) {
1441                 Log.e(TAG, "Trying to switch to connectivity mode on an invalid iface="
1442                         + ifaceName);
1443                 return false;
1444             }
1445             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) {
1446                 Log.e(TAG, "Already in connectivity mode on iface=" + ifaceName);
1447                 return true;
1448             }
1449             if (mWifiVendorHal.isVendorHalSupported()
1450                     && !mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, requestorWs)) {
1451                 Log.e(TAG, "Failed to replace requestor ws on " + iface);
1452                 teardownInterface(iface.name);
1453                 return false;
1454             }
1455             if (!startSupplicant()) {
1456                 Log.e(TAG, "Failed to start supplicant");
1457                 teardownInterface(iface.name);
1458                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1459                 return false;
1460             }
1461             if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
1462                 Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
1463                 teardownInterface(iface.name);
1464                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1465                 return false;
1466             }
1467             if (mContext.getResources().getBoolean(
1468                     R.bool.config_wifiNetworkCentricQosPolicyFeatureEnabled)) {
1469                 if (!mSupplicantStaIfaceHal.setNetworkCentricQosPolicyFeatureEnabled(
1470                         iface.name, true)) {
1471                     Log.e(TAG, "Failed to set QoS policy feature enabled for iface " + iface.name);
1472                     return false;
1473                 }
1474             }
1475             iface.type = Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY;
1476             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1477             saveCompleteFeatureSetInConfigStoreIfNecessary(iface.featureSet);
1478             mIsEnhancedOpenSupported = (iface.featureSet & WIFI_FEATURE_OWE) != 0;
1479             Log.i(TAG, "Successfully switched to connectivity mode on iface=" + iface);
1480             return true;
1481         }
1482     }
1483 
1484     /**
1485      * Change the requestor WorkSource for a given STA iface.
1486      * @return true if the operation succeeded, false otherwise.
1487      */
replaceStaIfaceRequestorWs(@onNull String ifaceName, WorkSource newWorkSource)1488     public boolean replaceStaIfaceRequestorWs(@NonNull String ifaceName, WorkSource newWorkSource) {
1489         final Iface iface = mIfaceMgr.getIface(ifaceName);
1490         if (iface == null) {
1491             Log.e(TAG, "Called replaceStaIfaceRequestorWs() on an invalid iface=" + ifaceName);
1492             return false;
1493         }
1494         if (!mWifiVendorHal.isVendorHalSupported()) {
1495             // if vendor HAL isn't supported, return true since there's nothing to do.
1496             return true;
1497         }
1498         if (!mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, newWorkSource)) {
1499             Log.e(TAG, "Failed to replace requestor ws on " + iface);
1500             teardownInterface(iface.name);
1501             return false;
1502         }
1503         return true;
1504     }
1505 
1506     /**
1507      *
1508      * Check if the interface is up or down.
1509      *
1510      * @param ifaceName Name of the interface.
1511      * @return true if iface is up, false if it's down or on error.
1512      */
isInterfaceUp(@onNull String ifaceName)1513     public boolean isInterfaceUp(@NonNull String ifaceName) {
1514         synchronized (mLock) {
1515             final Iface iface = mIfaceMgr.getIface(ifaceName);
1516             if (iface == null) {
1517                 Log.e(TAG, "Trying to get iface state on invalid iface=" + ifaceName);
1518                 return false;
1519             }
1520             try {
1521                 return mNetdWrapper.isInterfaceUp(ifaceName);
1522             } catch (IllegalStateException e) {
1523                 Log.e(TAG, "Unable to get interface config", e);
1524                 return false;
1525             }
1526         }
1527     }
1528 
1529     /**
1530      * Teardown an interface in Client/AP mode.
1531      *
1532      * This method tears down the associated interface from all the native daemons
1533      * (wificond, wpa_supplicant & vendor HAL).
1534      * Also, brings down the HAL, supplicant or hostapd as necessary.
1535      *
1536      * @param ifaceName Name of the interface.
1537      */
teardownInterface(@onNull String ifaceName)1538     public void teardownInterface(@NonNull String ifaceName) {
1539         synchronized (mLock) {
1540             final Iface iface = mIfaceMgr.getIface(ifaceName);
1541             if (iface == null) {
1542                 Log.e(TAG, "Trying to teardown an invalid iface=" + ifaceName);
1543                 return;
1544             }
1545             // Trigger the iface removal from HAL. The rest of the cleanup will be triggered
1546             // from the interface destroyed callback.
1547             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
1548                     || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
1549                 if (!removeStaIface(iface)) {
1550                     Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName);
1551                     return;
1552                 }
1553             } else if (iface.type == Iface.IFACE_TYPE_AP) {
1554                 if (!removeApIface(iface)) {
1555                     Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName);
1556                     return;
1557                 }
1558             }
1559             Log.i(TAG, "Successfully initiated teardown for iface=" + ifaceName);
1560         }
1561     }
1562 
1563     /**
1564      * Teardown all the active interfaces.
1565      *
1566      * This method tears down the associated interfaces from all the native daemons
1567      * (wificond, wpa_supplicant & vendor HAL).
1568      * Also, brings down the HAL, supplicant or hostapd as necessary.
1569      */
teardownAllInterfaces()1570     public void teardownAllInterfaces() {
1571         synchronized (mLock) {
1572             Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter();
1573             while (ifaceIdIter.hasNext()) {
1574                 Iface iface = mIfaceMgr.getIface(ifaceIdIter.next());
1575                 ifaceIdIter.remove();
1576                 onInterfaceDestroyed(iface);
1577                 Log.i(TAG, "Successfully torn down " + iface);
1578             }
1579             Log.i(TAG, "Successfully torn down all ifaces");
1580         }
1581     }
1582 
1583     /**
1584      * Get names of all the client interfaces.
1585      *
1586      * @return List of interface name of all active client interfaces.
1587      */
getClientInterfaceNames()1588     public Set<String> getClientInterfaceNames() {
1589         synchronized (mLock) {
1590             return mIfaceMgr.findAllStaIfaceNames();
1591         }
1592     }
1593 
1594     /**
1595      * Get names of all the client interfaces.
1596      *
1597      * @return List of interface name of all active client interfaces.
1598      */
getSoftApInterfaceNames()1599     public Set<String> getSoftApInterfaceNames() {
1600         synchronized (mLock) {
1601             return mIfaceMgr.findAllApIfaceNames();
1602         }
1603     }
1604 
1605     /********************************************************
1606      * Wificond operations
1607      ********************************************************/
1608 
1609     /**
1610      * Request signal polling to wificond.
1611      *
1612      * @param ifaceName Name of the interface.
1613      * Returns an SignalPollResult object.
1614      * Returns null on failure.
1615      */
signalPoll(@onNull String ifaceName)1616     public WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String ifaceName) {
1617         return mWifiCondManager.signalPoll(ifaceName);
1618     }
1619 
1620     /**
1621      * Query the list of valid frequencies for the provided band.
1622      * The result depends on the on the country code that has been set.
1623      *
1624      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1625      * The following bands are supported {@link WifiAnnotations.WifiBandBasic}:
1626      * WifiScanner.WIFI_BAND_24_GHZ
1627      * WifiScanner.WIFI_BAND_5_GHZ
1628      * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
1629      * WifiScanner.WIFI_BAND_6_GHZ
1630      * WifiScanner.WIFI_BAND_60_GHZ
1631      * @return frequencies vector of valid frequencies (MHz), or null for error.
1632      * @throws IllegalArgumentException if band is not recognized.
1633      */
getChannelsForBand(@ifiAnnotations.WifiBandBasic int band)1634     public int [] getChannelsForBand(@WifiAnnotations.WifiBandBasic int band) {
1635         if (!SdkLevel.isAtLeastS() && band == WifiScanner.WIFI_BAND_60_GHZ) {
1636             // 60 GHz band is new in Android S, return empty array on older SDK versions
1637             return new int[0];
1638         }
1639         return mWifiCondManager.getChannelsMhzForBand(band);
1640     }
1641 
1642     /**
1643      * Start a scan using wificond for the given parameters.
1644      * @param ifaceName Name of the interface.
1645      * @param scanType Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY},
1646      * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}.
1647      * @param freqs list of frequencies to scan for, if null scan all supported channels.
1648      * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
1649      * @param enable6GhzRnr whether Reduced Neighbor Report should be enabled for 6Ghz scanning.
1650      * @return Returns true on success.
1651      */
scan( @onNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs, List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr)1652     public boolean scan(
1653             @NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs,
1654             List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr) {
1655         List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>();
1656         for (String hiddenNetworkSsid : hiddenNetworkSSIDs) {
1657             try {
1658                 hiddenNetworkSsidsArrays.add(
1659                         NativeUtil.byteArrayFromArrayList(
1660                                 NativeUtil.decodeSsid(hiddenNetworkSsid)));
1661             } catch (IllegalArgumentException e) {
1662                 Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e);
1663                 continue;
1664             }
1665         }
1666         // enable6GhzRnr is a new parameter first introduced in Android S.
1667         if (SdkLevel.isAtLeastS()) {
1668             Bundle extraScanningParams = new Bundle();
1669             extraScanningParams.putBoolean(WifiNl80211Manager.SCANNING_PARAM_ENABLE_6GHZ_RNR,
1670                     enable6GhzRnr);
1671             return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays,
1672                     extraScanningParams);
1673         } else {
1674             return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays);
1675         }
1676     }
1677 
1678     /**
1679      * Fetch the latest scan result from kernel via wificond.
1680      * @param ifaceName Name of the interface.
1681      * @return Returns an ArrayList of ScanDetail.
1682      * Returns an empty ArrayList on failure.
1683      */
getScanResults(@onNull String ifaceName)1684     public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
1685         if (mUseFakeScanDetails) {
1686             synchronized (mFakeScanDetails) {
1687                 ArrayList<ScanDetail> copyList = new ArrayList<>();
1688                 for (ScanDetail sd: mFakeScanDetails) {
1689                     ScanDetail copy = new ScanDetail(sd);
1690                     copy.getScanResult().ifaceName = ifaceName;
1691                     // otherwise the fake will be too old
1692                     copy.getScanResult().timestamp = SystemClock.elapsedRealtime() * 1000;
1693                     copyList.add(copy);
1694                 }
1695                 return copyList;
1696             }
1697         }
1698         return convertNativeScanResults(ifaceName, mWifiCondManager.getScanResults(
1699                 ifaceName, WifiNl80211Manager.SCAN_TYPE_SINGLE_SCAN));
1700     }
1701 
1702     /**
1703      * Start faking scan results - using information provided via
1704      * {@link #addFakeScanDetail(ScanDetail)}. Stop with {@link #stopFakingScanDetails()}.
1705      */
startFakingScanDetails()1706     public void startFakingScanDetails() {
1707         if (mBuildProperties.isUserBuild()) {
1708             Log.wtf(TAG, "Can't fake scan results in a user build!");
1709             return;
1710         }
1711         Log.d(TAG, "Starting faking scan results - " + mFakeScanDetails);
1712         mUseFakeScanDetails = true;
1713     }
1714 
1715     /**
1716      * Add fake scan result. Fakes are not used until activated via
1717      * {@link #startFakingScanDetails()}.
1718      * @param fakeScanDetail
1719      */
addFakeScanDetail(@onNull ScanDetail fakeScanDetail)1720     public void addFakeScanDetail(@NonNull ScanDetail fakeScanDetail) {
1721         synchronized (mFakeScanDetails) {
1722             mFakeScanDetails.add(fakeScanDetail);
1723         }
1724     }
1725 
1726     /**
1727      * Reset the fake scan result list updated via {@link #addFakeScanDetail(ScanDetail)} .}
1728      */
resetFakeScanDetails()1729     public void resetFakeScanDetails() {
1730         synchronized (mFakeScanDetails) {
1731             mFakeScanDetails.clear();
1732         }
1733     }
1734 
1735     /**
1736      * Stop faking scan results. Started with {@link #startFakingScanDetails()}.
1737      */
stopFakingScanDetails()1738     public void stopFakingScanDetails() {
1739         mUseFakeScanDetails = false;
1740     }
1741 
1742     /**
1743      * Fetch the latest scan result from kernel via wificond.
1744      * @param ifaceName Name of the interface.
1745      * @return Returns an ArrayList of ScanDetail.
1746      * Returns an empty ArrayList on failure.
1747      */
getPnoScanResults(@onNull String ifaceName)1748     public ArrayList<ScanDetail> getPnoScanResults(@NonNull String ifaceName) {
1749         return convertNativeScanResults(ifaceName, mWifiCondManager.getScanResults(ifaceName,
1750                 WifiNl80211Manager.SCAN_TYPE_PNO_SCAN));
1751     }
1752 
1753     /**
1754      * Get the max number of SSIDs that the driver supports per scan.
1755      * @param ifaceName Name of the interface.
1756      */
getMaxSsidsPerScan(@onNull String ifaceName)1757     public int getMaxSsidsPerScan(@NonNull String ifaceName) {
1758         if (SdkLevel.isAtLeastT()) {
1759             return mWifiCondManager.getMaxSsidsPerScan(ifaceName);
1760         } else {
1761             return -1;
1762         }
1763     }
1764 
convertNativeScanResults(@onNull String ifaceName, List<NativeScanResult> nativeResults)1765     private ArrayList<ScanDetail> convertNativeScanResults(@NonNull String ifaceName,
1766             List<NativeScanResult> nativeResults) {
1767         ArrayList<ScanDetail> results = new ArrayList<>();
1768         for (NativeScanResult result : nativeResults) {
1769             WifiSsid wifiSsid = WifiSsid.fromBytes(result.getSsid());
1770             MacAddress bssidMac = result.getBssid();
1771             if (bssidMac == null) {
1772                 Log.e(TAG, "Invalid MAC (BSSID) for SSID " + wifiSsid);
1773                 continue;
1774             }
1775             String bssid = bssidMac.toString();
1776             ScanResult.InformationElement[] ies =
1777                     InformationElementUtil.parseInformationElements(result.getInformationElements());
1778             InformationElementUtil.Capabilities capabilities =
1779                     new InformationElementUtil.Capabilities();
1780             capabilities.from(ies, result.getCapabilities(), mIsEnhancedOpenSupported,
1781                               result.getFrequencyMhz());
1782             String flags = capabilities.generateCapabilitiesString();
1783             NetworkDetail networkDetail;
1784             try {
1785                 networkDetail = new NetworkDetail(bssid, ies, null, result.getFrequencyMhz());
1786             } catch (IllegalArgumentException e) {
1787                 Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
1788                 continue;
1789             }
1790 
1791             ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
1792                     result.getSignalMbm() / 100, result.getFrequencyMhz(), result.getTsf(), ies,
1793                     null, result.getInformationElements());
1794             ScanResult scanResult = scanDetail.getScanResult();
1795             scanResult.setWifiStandard(wifiModeToWifiStandard(networkDetail.getWifiMode()));
1796             scanResult.ifaceName = ifaceName;
1797 
1798             // Fill up the radio chain info.
1799             scanResult.radioChainInfos =
1800                     new ScanResult.RadioChainInfo[result.getRadioChainInfos().size()];
1801             int idx = 0;
1802             for (RadioChainInfo nativeRadioChainInfo : result.getRadioChainInfos()) {
1803                 scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo();
1804                 scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.getChainId();
1805                 scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.getLevelDbm();
1806                 idx++;
1807             }
1808 
1809             // Fill MLO Attributes
1810             scanResult.setApMldMacAddress(networkDetail.getMldMacAddress());
1811             scanResult.setApMloLinkId(networkDetail.getMloLinkId());
1812             scanResult.setAffiliatedMloLinks(networkDetail.getAffiliatedMloLinks());
1813 
1814             results.add(scanDetail);
1815         }
1816         if (mVerboseLoggingEnabled) {
1817             Log.d(TAG, "get " + results.size() + " scan results from wificond");
1818         }
1819 
1820         return results;
1821     }
1822 
1823     @WifiAnnotations.WifiStandard
wifiModeToWifiStandard(int wifiMode)1824     private static int wifiModeToWifiStandard(int wifiMode) {
1825         switch (wifiMode) {
1826             case InformationElementUtil.WifiMode.MODE_11A:
1827             case InformationElementUtil.WifiMode.MODE_11B:
1828             case InformationElementUtil.WifiMode.MODE_11G:
1829                 return ScanResult.WIFI_STANDARD_LEGACY;
1830             case InformationElementUtil.WifiMode.MODE_11N:
1831                 return ScanResult.WIFI_STANDARD_11N;
1832             case InformationElementUtil.WifiMode.MODE_11AC:
1833                 return ScanResult.WIFI_STANDARD_11AC;
1834             case InformationElementUtil.WifiMode.MODE_11AX:
1835                 return ScanResult.WIFI_STANDARD_11AX;
1836             case InformationElementUtil.WifiMode.MODE_11BE:
1837                 return ScanResult.WIFI_STANDARD_11BE;
1838             case InformationElementUtil.WifiMode.MODE_UNDEFINED:
1839             default:
1840                 return ScanResult.WIFI_STANDARD_UNKNOWN;
1841         }
1842     }
1843 
1844     /**
1845      * Start PNO scan.
1846      * @param ifaceName Name of the interface.
1847      * @param pnoSettings Pno scan configuration.
1848      * @return true on success.
1849      */
startPnoScan(@onNull String ifaceName, PnoSettings pnoSettings)1850     public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings) {
1851         return mWifiCondManager.startPnoScan(ifaceName, pnoSettings.toNativePnoSettings(),
1852                 Runnable::run,
1853                 new WifiNl80211Manager.PnoScanRequestCallback() {
1854                     @Override
1855                     public void onPnoRequestSucceeded() {
1856                         mWifiMetrics.incrementPnoScanStartAttemptCount();
1857                     }
1858 
1859                     @Override
1860                     public void onPnoRequestFailed() {
1861                         mWifiMetrics.incrementPnoScanStartAttemptCount();
1862                         mWifiMetrics.incrementPnoScanFailedCount();
1863                     }
1864                 });
1865     }
1866 
1867     /**
1868      * Stop PNO scan.
1869      * @param ifaceName Name of the interface.
1870      * @return true on success.
1871      */
1872     public boolean stopPnoScan(@NonNull String ifaceName) {
1873         return mWifiCondManager.stopPnoScan(ifaceName);
1874     }
1875 
1876     /**
1877      * Sends an arbitrary 802.11 management frame on the current channel.
1878      *
1879      * @param ifaceName Name of the interface.
1880      * @param frame Bytes of the 802.11 management frame to be sent, including the header, but not
1881      *              including the frame check sequence (FCS).
1882      * @param callback A callback triggered when the transmitted frame is ACKed or the transmission
1883      *                 fails.
1884      * @param mcs The MCS index that the frame will be sent at. If mcs < 0, the driver will select
1885      *            the rate automatically. If the device does not support sending the frame at a
1886      *            specified MCS rate, the transmission will be aborted and
1887      *            {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called
1888      *            with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}.
1889      */
1890     public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame,
1891             @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) {
1892         mWifiCondManager.sendMgmtFrame(ifaceName, frame, mcs, Runnable::run, callback);
1893     }
1894 
1895     /**
1896      * Sends a probe request to the AP and waits for a response in order to determine whether
1897      * there is connectivity between the device and AP.
1898      *
1899      * @param ifaceName Name of the interface.
1900      * @param receiverMac the MAC address of the AP that the probe request will be sent to.
1901      * @param callback callback triggered when the probe was ACKed by the AP, or when
1902      *                an error occurs after the link probe was started.
1903      * @param mcs The MCS index that this probe will be sent at. If mcs < 0, the driver will select
1904      *            the rate automatically. If the device does not support sending the frame at a
1905      *            specified MCS rate, the transmission will be aborted and
1906      *            {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called
1907      *            with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}.
1908      */
1909     public void probeLink(@NonNull String ifaceName, @NonNull MacAddress receiverMac,
1910             @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) {
1911         if (callback == null) {
1912             Log.e(TAG, "callback cannot be null!");
1913             return;
1914         }
1915 
1916         if (receiverMac == null) {
1917             Log.e(TAG, "Receiver MAC address cannot be null!");
1918             callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
1919             return;
1920         }
1921 
1922         String senderMacStr = getMacAddress(ifaceName);
1923         if (senderMacStr == null) {
1924             Log.e(TAG, "Failed to get this device's MAC Address");
1925             callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
1926             return;
1927         }
1928 
1929         byte[] frame = buildProbeRequestFrame(
1930                 receiverMac.toByteArray(),
1931                 NativeUtil.macAddressToByteArray(senderMacStr));
1932         sendMgmtFrame(ifaceName, frame, callback, mcs);
1933     }
1934 
1935     // header = 24 bytes, minimal body = 2 bytes, no FCS (will be added by driver)
1936     private static final int BASIC_PROBE_REQUEST_FRAME_SIZE = 24 + 2;
1937 
1938     private byte[] buildProbeRequestFrame(byte[] receiverMac, byte[] transmitterMac) {
1939         ByteBuffer frame = ByteBuffer.allocate(BASIC_PROBE_REQUEST_FRAME_SIZE);
1940         // ByteBuffer is big endian by default, switch to little endian
1941         frame.order(ByteOrder.LITTLE_ENDIAN);
1942 
1943         // Protocol version = 0, Type = management, Subtype = Probe Request
1944         frame.put((byte) 0x40);
1945 
1946         // no flags set
1947         frame.put((byte) 0x00);
1948 
1949         // duration = 60 microseconds. Note: this is little endian
1950         // Note: driver should calculate the duration and replace it before sending, putting a
1951         // reasonable default value here just in case.
1952         frame.putShort((short) 0x3c);
1953 
1954         // receiver/destination MAC address byte array
1955         frame.put(receiverMac);
1956         // sender MAC address byte array
1957         frame.put(transmitterMac);
1958         // BSSID (same as receiver address since we are sending to the AP)
1959         frame.put(receiverMac);
1960 
1961         // Generate random sequence number, fragment number = 0
1962         // Note: driver should replace the sequence number with the correct number that is
1963         // incremented from the last used sequence number. Putting a random sequence number as a
1964         // default here just in case.
1965         // bit 0 is least significant bit, bit 15 is most significant bit
1966         // bits [0, 7] go in byte 0
1967         // bits [8, 15] go in byte 1
1968         // bits [0, 3] represent the fragment number (which is 0)
1969         // bits [4, 15] represent the sequence number (which is random)
1970         // clear bits [0, 3] to set fragment number = 0
1971         short sequenceAndFragmentNumber = (short) (mRandom.nextInt() & 0xfff0);
1972         frame.putShort(sequenceAndFragmentNumber);
1973 
1974         // NL80211 rejects frames with an empty body, so we just need to put a placeholder
1975         // information element.
1976         // Tag for SSID
1977         frame.put((byte) 0x00);
1978         // Represents broadcast SSID. Not accurate, but works as placeholder.
1979         frame.put((byte) 0x00);
1980 
1981         return frame.array();
1982     }
1983 
1984     private static final int CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS = 100;
1985     private static final int CONNECT_TO_HOSTAPD_RETRY_TIMES = 50;
1986     /**
1987      * This method is called to wait for establishing connection to hostapd.
1988      *
1989      * @return true if connection is established, false otherwise.
1990      */
1991     private boolean startAndWaitForHostapdConnection() {
1992         // Start initialization if not already started.
1993         if (!mHostapdHal.isInitializationStarted()
1994                 && !mHostapdHal.initialize()) {
1995             return false;
1996         }
1997         if (!mHostapdHal.startDaemon()) {
1998             Log.e(TAG, "Failed to startup hostapd");
1999             return false;
2000         }
2001         boolean connected = false;
2002         int connectTries = 0;
2003         while (!connected && connectTries++ < CONNECT_TO_HOSTAPD_RETRY_TIMES) {
2004             // Check if the initialization is complete.
2005             connected = mHostapdHal.isInitializationComplete();
2006             if (connected) {
2007                 break;
2008             }
2009             try {
2010                 Thread.sleep(CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS);
2011             } catch (InterruptedException ignore) {
2012             }
2013         }
2014         return connected;
2015     }
2016 
2017     /**
2018      * Start Soft AP operation using the provided configuration.
2019      *
2020      * @param ifaceName Name of the interface.
2021      * @param config Configuration to use for the soft ap created.
2022      * @param isMetered Indicates the network is metered or not.
2023      * @param callback Callback for AP events.
2024      * @return true on success, false otherwise.
2025      */
2026     public boolean startSoftAp(
2027             @NonNull String ifaceName, SoftApConfiguration config, boolean isMetered,
2028             SoftApHalCallback callback) {
2029         if (mHostapdHal.isApInfoCallbackSupported()) {
2030             if (!mHostapdHal.registerApCallback(ifaceName, callback)) {
2031                 Log.e(TAG, "Failed to register ap hal event callback");
2032                 return false;
2033             }
2034         } else {
2035             SoftApHalCallbackFromWificond softApHalCallbackFromWificond =
2036                     new SoftApHalCallbackFromWificond(ifaceName, callback);
2037             if (!mWifiCondManager.registerApCallback(ifaceName,
2038                     Runnable::run, softApHalCallbackFromWificond)) {
2039                 Log.e(TAG, "Failed to register ap hal event callback from wificond");
2040                 return false;
2041             }
2042         }
2043 
2044         if (!mHostapdHal.addAccessPoint(ifaceName, config, isMetered, callback::onFailure)) {
2045             Log.e(TAG, "Failed to add acccess point");
2046             mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
2047             return false;
2048         }
2049 
2050         return true;
2051     }
2052 
2053     /**
2054      * Force a softap client disconnect with specific reason code.
2055      *
2056      * @param ifaceName Name of the interface.
2057      * @param client Mac address to force disconnect in clients of the SoftAp.
2058      * @param reasonCode One of disconnect reason code which defined in {@link ApConfigUtil}.
2059      * @return true on success, false otherwise.
2060      */
2061     public boolean forceClientDisconnect(@NonNull String ifaceName,
2062             @NonNull MacAddress client, int reasonCode) {
2063         return mHostapdHal.forceClientDisconnect(ifaceName, client, reasonCode);
2064     }
2065 
2066     /**
2067      * Set MAC address of the given interface
2068      * @param interfaceName Name of the interface
2069      * @param mac Mac address to change into
2070      * @return true on success
2071      */
2072     public boolean setStaMacAddress(String interfaceName, MacAddress mac) {
2073         // TODO(b/72459123): Suppress interface down/up events from this call
2074         // Trigger an explicit disconnect to avoid losing the disconnect event reason (if currently
2075         // connected) from supplicant if the interface is brought down for MAC address change.
2076         disconnect(interfaceName);
2077         return mWifiVendorHal.setStaMacAddress(interfaceName, mac);
2078     }
2079 
2080     /**
2081      * Set MAC address of the given interface
2082      * @param interfaceName Name of the interface
2083      * @param mac Mac address to change into
2084      * @return true on success
2085      */
2086     public boolean setApMacAddress(String interfaceName, MacAddress mac) {
2087         return mWifiVendorHal.setApMacAddress(interfaceName, mac);
2088     }
2089 
2090     /**
2091      * Returns true if Hal version supports setMacAddress, otherwise false.
2092      *
2093      * @param interfaceName Name of the interface
2094      */
2095     public boolean isStaSetMacAddressSupported(@NonNull String interfaceName) {
2096         return mWifiVendorHal.isStaSetMacAddressSupported(interfaceName);
2097     }
2098 
2099     /**
2100      * Returns true if Hal version supports setMacAddress, otherwise false.
2101      *
2102      * @param interfaceName Name of the interface
2103      */
2104     public boolean isApSetMacAddressSupported(@NonNull String interfaceName) {
2105         return mWifiVendorHal.isApSetMacAddressSupported(interfaceName);
2106     }
2107 
2108     /**
2109      * Get the factory MAC address of the given interface
2110      * @param interfaceName Name of the interface.
2111      * @return factory MAC address, or null on a failed call or if feature is unavailable.
2112      */
2113     public MacAddress getStaFactoryMacAddress(@NonNull String interfaceName) {
2114         return mWifiVendorHal.getStaFactoryMacAddress(interfaceName);
2115     }
2116 
2117     /**
2118      * Get the factory MAC address of the given interface
2119      * @param interfaceName Name of the interface.
2120      * @return factory MAC address, or null on a failed call or if feature is unavailable.
2121      */
2122     public MacAddress getApFactoryMacAddress(@NonNull String interfaceName) {
2123         return mWifiVendorHal.getApFactoryMacAddress(interfaceName);
2124     }
2125 
2126     /**
2127      * Reset MAC address to factory MAC address on the given interface
2128      *
2129      * @param interfaceName Name of the interface
2130      * @return true for success
2131      */
2132     public boolean resetApMacToFactoryMacAddress(@NonNull String interfaceName) {
2133         return mWifiVendorHal.resetApMacToFactoryMacAddress(interfaceName);
2134     }
2135 
2136     /**
2137      * Set the unsafe channels and restrictions to avoid for coex.
2138      * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid
2139      * @param restrictions Bitmask of WifiManager.COEX_RESTRICTION_ flags
2140      */
2141     public void setCoexUnsafeChannels(
2142             @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) {
2143         mCachedCoexUnsafeChannels.clear();
2144         mCachedCoexUnsafeChannels.addAll(unsafeChannels);
2145         mCachedCoexRestrictions = restrictions;
2146         mWifiVendorHal.setCoexUnsafeChannels(mCachedCoexUnsafeChannels, mCachedCoexRestrictions);
2147     }
2148 
2149     /********************************************************
2150      * Hostapd operations
2151      ********************************************************/
2152 
2153     /**
2154      * Callback to notify hostapd death.
2155      */
2156     public interface HostapdDeathEventHandler {
2157         /**
2158          * Invoked when the supplicant dies.
2159          */
2160         void onDeath();
2161     }
2162 
2163     /********************************************************
2164      * Supplicant operations
2165      ********************************************************/
2166 
2167     /**
2168      * Callback to notify supplicant death.
2169      */
2170     public interface SupplicantDeathEventHandler {
2171         /**
2172          * Invoked when the supplicant dies.
2173          */
2174         void onDeath();
2175     }
2176 
2177     /**
2178      * Trigger a reconnection if the iface is disconnected.
2179      *
2180      * @param ifaceName Name of the interface.
2181      * @return true if request is sent successfully, false otherwise.
2182      */
2183     public boolean reconnect(@NonNull String ifaceName) {
2184         return mSupplicantStaIfaceHal.reconnect(ifaceName);
2185     }
2186 
2187     /**
2188      * Trigger a reassociation even if the iface is currently connected.
2189      *
2190      * @param ifaceName Name of the interface.
2191      * @return true if request is sent successfully, false otherwise.
2192      */
2193     public boolean reassociate(@NonNull String ifaceName) {
2194         return mSupplicantStaIfaceHal.reassociate(ifaceName);
2195     }
2196 
2197     /**
2198      * Trigger a disconnection from the currently connected network.
2199      *
2200      * @param ifaceName Name of the interface.
2201      * @return true if request is sent successfully, false otherwise.
2202      */
2203     public boolean disconnect(@NonNull String ifaceName) {
2204         return mSupplicantStaIfaceHal.disconnect(ifaceName);
2205     }
2206 
2207     /**
2208      * Makes a callback to HIDL to getMacAddress from supplicant
2209      *
2210      * @param ifaceName Name of the interface.
2211      * @return string containing the MAC address, or null on a failed call
2212      */
2213     public String getMacAddress(@NonNull String ifaceName) {
2214         return mSupplicantStaIfaceHal.getMacAddress(ifaceName);
2215     }
2216 
2217     public static final int RX_FILTER_TYPE_V4_MULTICAST = 0;
2218     public static final int RX_FILTER_TYPE_V6_MULTICAST = 1;
2219     /**
2220      * Start filtering out Multicast V4 packets
2221      * @param ifaceName Name of the interface.
2222      * @return {@code true} if the operation succeeded, {@code false} otherwise
2223      *
2224      * Multicast filtering rules work as follows:
2225      *
2226      * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
2227      * a power optimized mode (typically when screen goes off).
2228      *
2229      * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
2230      * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
2231      *
2232      * DRIVER RXFILTER-ADD Num
2233      *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
2234      *
2235      * and DRIVER RXFILTER-START
2236      * In order to stop the usage of these rules, we do
2237      *
2238      * DRIVER RXFILTER-STOP
2239      * DRIVER RXFILTER-REMOVE Num
2240      *   where Num is as described for RXFILTER-ADD
2241      *
2242      * The  SETSUSPENDOPT driver command overrides the filtering rules
2243      */
2244     public boolean startFilteringMulticastV4Packets(@NonNull String ifaceName) {
2245         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
2246                 && mSupplicantStaIfaceHal.removeRxFilter(
2247                         ifaceName, RX_FILTER_TYPE_V4_MULTICAST)
2248                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
2249     }
2250 
2251     /**
2252      * Stop filtering out Multicast V4 packets.
2253      * @param ifaceName Name of the interface.
2254      * @return {@code true} if the operation succeeded, {@code false} otherwise
2255      */
2256     public boolean stopFilteringMulticastV4Packets(@NonNull String ifaceName) {
2257         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
2258                 && mSupplicantStaIfaceHal.addRxFilter(
2259                         ifaceName, RX_FILTER_TYPE_V4_MULTICAST)
2260                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
2261     }
2262 
2263     /**
2264      * Start filtering out Multicast V6 packets
2265      * @param ifaceName Name of the interface.
2266      * @return {@code true} if the operation succeeded, {@code false} otherwise
2267      */
2268     public boolean startFilteringMulticastV6Packets(@NonNull String ifaceName) {
2269         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
2270                 && mSupplicantStaIfaceHal.removeRxFilter(
2271                         ifaceName, RX_FILTER_TYPE_V6_MULTICAST)
2272                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
2273     }
2274 
2275     /**
2276      * Stop filtering out Multicast V6 packets.
2277      * @param ifaceName Name of the interface.
2278      * @return {@code true} if the operation succeeded, {@code false} otherwise
2279      */
2280     public boolean stopFilteringMulticastV6Packets(@NonNull String ifaceName) {
2281         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
2282                 && mSupplicantStaIfaceHal.addRxFilter(
2283                         ifaceName, RX_FILTER_TYPE_V6_MULTICAST)
2284                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
2285     }
2286 
2287     public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED  = 0;
2288     public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1;
2289     public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE    = 2;
2290     /**
2291      * Sets the bluetooth coexistence mode.
2292      *
2293      * @param ifaceName Name of the interface.
2294      * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
2295      *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
2296      *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
2297      * @return Whether the mode was successfully set.
2298      */
2299     public boolean setBluetoothCoexistenceMode(@NonNull String ifaceName, int mode) {
2300         return mSupplicantStaIfaceHal.setBtCoexistenceMode(ifaceName, mode);
2301     }
2302 
2303     /**
2304      * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
2305      * some of the low-level scan parameters used by the driver are changed to
2306      * reduce interference with A2DP streaming.
2307      *
2308      * @param ifaceName Name of the interface.
2309      * @param setCoexScanMode whether to enable or disable this mode
2310      * @return {@code true} if the command succeeded, {@code false} otherwise.
2311      */
2312     public boolean setBluetoothCoexistenceScanMode(
2313             @NonNull String ifaceName, boolean setCoexScanMode) {
2314         return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled(
2315                 ifaceName, setCoexScanMode);
2316     }
2317 
2318     /**
2319      * Enable or disable suspend mode optimizations.
2320      *
2321      * @param ifaceName Name of the interface.
2322      * @param enabled true to enable, false otherwise.
2323      * @return true if request is sent successfully, false otherwise.
2324      */
2325     public boolean setSuspendOptimizations(@NonNull String ifaceName, boolean enabled) {
2326         return mSupplicantStaIfaceHal.setSuspendModeEnabled(ifaceName, enabled);
2327     }
2328 
2329     /**
2330      * Set country code for STA interface
2331      *
2332      * @param ifaceName Name of the STA interface.
2333      * @param countryCode 2 byte ASCII string. For ex: US, CA.
2334      * @return true if request is sent successfully, false otherwise.
2335      */
2336     public boolean setStaCountryCode(@NonNull String ifaceName, String countryCode) {
2337         if (mSupplicantStaIfaceHal.setCountryCode(ifaceName, countryCode)) {
2338             if (mCountryCodeChangeListener != null) {
2339                 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode);
2340             }
2341             return true;
2342         }
2343         return false;
2344     }
2345 
2346     /**
2347      * Flush all previously configured HLPs.
2348      *
2349      * @return true if request is sent successfully, false otherwise.
2350      */
2351     public boolean flushAllHlp(@NonNull String ifaceName) {
2352         return mSupplicantStaIfaceHal.flushAllHlp(ifaceName);
2353     }
2354 
2355     /**
2356      * Set FILS HLP packet.
2357      *
2358      * @param dst Destination MAC address.
2359      * @param hlpPacket Hlp Packet data in hex.
2360      * @return true if request is sent successfully, false otherwise.
2361      */
2362     public boolean addHlpReq(@NonNull String ifaceName, MacAddress dst, byte [] hlpPacket) {
2363         return mSupplicantStaIfaceHal.addHlpReq(ifaceName, dst.toByteArray(), hlpPacket);
2364     }
2365 
2366     /**
2367      * Initiate TDLS discover and setup or teardown with the specified peer.
2368      *
2369      * @param ifaceName Name of the interface.
2370      * @param macAddr MAC Address of the peer.
2371      * @param enable true to start discovery and setup, false to teardown.
2372      */
2373     public void startTdls(@NonNull String ifaceName, String macAddr, boolean enable) {
2374         if (enable) {
2375             mSupplicantStaIfaceHal.initiateTdlsDiscover(ifaceName, macAddr);
2376             mSupplicantStaIfaceHal.initiateTdlsSetup(ifaceName, macAddr);
2377         } else {
2378             mSupplicantStaIfaceHal.initiateTdlsTeardown(ifaceName, macAddr);
2379         }
2380     }
2381 
2382     /**
2383      * Start WPS pin display operation with the specified peer.
2384      *
2385      * @param ifaceName Name of the interface.
2386      * @param bssid BSSID of the peer.
2387      * @return true if request is sent successfully, false otherwise.
2388      */
2389     public boolean startWpsPbc(@NonNull String ifaceName, String bssid) {
2390         return mSupplicantStaIfaceHal.startWpsPbc(ifaceName, bssid);
2391     }
2392 
2393     /**
2394      * Start WPS pin keypad operation with the specified pin.
2395      *
2396      * @param ifaceName Name of the interface.
2397      * @param pin Pin to be used.
2398      * @return true if request is sent successfully, false otherwise.
2399      */
2400     public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
2401         return mSupplicantStaIfaceHal.startWpsPinKeypad(ifaceName, pin);
2402     }
2403 
2404     /**
2405      * Start WPS pin display operation with the specified peer.
2406      *
2407      * @param ifaceName Name of the interface.
2408      * @param bssid BSSID of the peer.
2409      * @return new pin generated on success, null otherwise.
2410      */
2411     public String startWpsPinDisplay(@NonNull String ifaceName, String bssid) {
2412         return mSupplicantStaIfaceHal.startWpsPinDisplay(ifaceName, bssid);
2413     }
2414 
2415     /**
2416      * Sets whether to use external sim for SIM/USIM processing.
2417      *
2418      * @param ifaceName Name of the interface.
2419      * @param external true to enable, false otherwise.
2420      * @return true if request is sent successfully, false otherwise.
2421      */
2422     public boolean setExternalSim(@NonNull String ifaceName, boolean external) {
2423         return mSupplicantStaIfaceHal.setExternalSim(ifaceName, external);
2424     }
2425 
2426     /**
2427      * Sim auth response types.
2428      */
2429     public static final String SIM_AUTH_RESP_TYPE_GSM_AUTH = "GSM-AUTH";
2430     public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTH = "UMTS-AUTH";
2431     public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTS = "UMTS-AUTS";
2432 
2433     /**
2434      * EAP-SIM Error Codes
2435      */
2436     public static final int EAP_SIM_NOT_SUBSCRIBED = 1031;
2437     public static final int EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED = 16385;
2438 
2439     /**
2440      * Send the sim auth response for the currently configured network.
2441      *
2442      * @param ifaceName Name of the interface.
2443      * @param type |GSM-AUTH|, |UMTS-AUTH| or |UMTS-AUTS|.
2444      * @param response Response params.
2445      * @return true if succeeds, false otherwise.
2446      */
2447     public boolean simAuthResponse(
2448             @NonNull String ifaceName, String type, String response) {
2449         if (SIM_AUTH_RESP_TYPE_GSM_AUTH.equals(type)) {
2450             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse(
2451                     ifaceName, response);
2452         } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTH.equals(type)) {
2453             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse(
2454                     ifaceName, response);
2455         } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTS.equals(type)) {
2456             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse(
2457                     ifaceName, response);
2458         } else {
2459             return false;
2460         }
2461     }
2462 
2463     /**
2464      * Send the eap sim gsm auth failure for the currently configured network.
2465      *
2466      * @param ifaceName Name of the interface.
2467      * @return true if succeeds, false otherwise.
2468      */
2469     public boolean simAuthFailedResponse(@NonNull String ifaceName) {
2470         return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure(ifaceName);
2471     }
2472 
2473     /**
2474      * Send the eap sim umts auth failure for the currently configured network.
2475      *
2476      * @param ifaceName Name of the interface.
2477      * @return true if succeeds, false otherwise.
2478      */
2479     public boolean umtsAuthFailedResponse(@NonNull String ifaceName) {
2480         return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure(ifaceName);
2481     }
2482 
2483     /**
2484      * Send the eap identity response for the currently configured network.
2485      *
2486      * @param ifaceName Name of the interface.
2487      * @param unencryptedResponse String to send.
2488      * @param encryptedResponse String to send.
2489      * @return true if succeeds, false otherwise.
2490      */
2491     public boolean simIdentityResponse(@NonNull String ifaceName, String unencryptedResponse,
2492                                        String encryptedResponse) {
2493         return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(ifaceName,
2494                 unencryptedResponse, encryptedResponse);
2495     }
2496 
2497     /**
2498      * This get anonymous identity from supplicant and returns it as a string.
2499      *
2500      * @param ifaceName Name of the interface.
2501      * @return anonymous identity string if succeeds, null otherwise.
2502      */
2503     public String getEapAnonymousIdentity(@NonNull String ifaceName) {
2504         String anonymousIdentity = mSupplicantStaIfaceHal
2505                 .getCurrentNetworkEapAnonymousIdentity(ifaceName);
2506 
2507         if (TextUtils.isEmpty(anonymousIdentity)) {
2508             return anonymousIdentity;
2509         }
2510 
2511         int indexOfDecoration = anonymousIdentity.lastIndexOf('!');
2512         if (indexOfDecoration >= 0) {
2513             if (anonymousIdentity.substring(indexOfDecoration).length() < 2) {
2514                 // Invalid identity, shouldn't happen
2515                 Log.e(TAG, "Unexpected anonymous identity: " + anonymousIdentity);
2516                 return null;
2517             }
2518             // Truncate RFC 7542 decorated prefix, if exists. Keep only the anonymous identity or
2519             // pseudonym.
2520             anonymousIdentity = anonymousIdentity.substring(indexOfDecoration + 1);
2521         }
2522 
2523         return anonymousIdentity;
2524     }
2525 
2526     /**
2527      * Start WPS pin registrar operation with the specified peer and pin.
2528      *
2529      * @param ifaceName Name of the interface.
2530      * @param bssid BSSID of the peer.
2531      * @param pin Pin to be used.
2532      * @return true if request is sent successfully, false otherwise.
2533      */
2534     public boolean startWpsRegistrar(@NonNull String ifaceName, String bssid, String pin) {
2535         return mSupplicantStaIfaceHal.startWpsRegistrar(ifaceName, bssid, pin);
2536     }
2537 
2538     /**
2539      * Cancels any ongoing WPS requests.
2540      *
2541      * @param ifaceName Name of the interface.
2542      * @return true if request is sent successfully, false otherwise.
2543      */
2544     public boolean cancelWps(@NonNull String ifaceName) {
2545         return mSupplicantStaIfaceHal.cancelWps(ifaceName);
2546     }
2547 
2548     /**
2549      * Set WPS device name.
2550      *
2551      * @param ifaceName Name of the interface.
2552      * @param name String to be set.
2553      * @return true if request is sent successfully, false otherwise.
2554      */
2555     public boolean setDeviceName(@NonNull String ifaceName, String name) {
2556         return mSupplicantStaIfaceHal.setWpsDeviceName(ifaceName, name);
2557     }
2558 
2559     /**
2560      * Set WPS device type.
2561      *
2562      * @param ifaceName Name of the interface.
2563      * @param type Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
2564      * @return true if request is sent successfully, false otherwise.
2565      */
2566     public boolean setDeviceType(@NonNull String ifaceName, String type) {
2567         return mSupplicantStaIfaceHal.setWpsDeviceType(ifaceName, type);
2568     }
2569 
2570     /**
2571      * Set WPS config methods
2572      *
2573      * @param cfg List of config methods.
2574      * @return true if request is sent successfully, false otherwise.
2575      */
2576     public boolean setConfigMethods(@NonNull String ifaceName, String cfg) {
2577         return mSupplicantStaIfaceHal.setWpsConfigMethods(ifaceName, cfg);
2578     }
2579 
2580     /**
2581      * Set WPS manufacturer.
2582      *
2583      * @param ifaceName Name of the interface.
2584      * @param value String to be set.
2585      * @return true if request is sent successfully, false otherwise.
2586      */
2587     public boolean setManufacturer(@NonNull String ifaceName, String value) {
2588         return mSupplicantStaIfaceHal.setWpsManufacturer(ifaceName, value);
2589     }
2590 
2591     /**
2592      * Set WPS model name.
2593      *
2594      * @param ifaceName Name of the interface.
2595      * @param value String to be set.
2596      * @return true if request is sent successfully, false otherwise.
2597      */
2598     public boolean setModelName(@NonNull String ifaceName, String value) {
2599         return mSupplicantStaIfaceHal.setWpsModelName(ifaceName, value);
2600     }
2601 
2602     /**
2603      * Set WPS model number.
2604      *
2605      * @param ifaceName Name of the interface.
2606      * @param value String to be set.
2607      * @return true if request is sent successfully, false otherwise.
2608      */
2609     public boolean setModelNumber(@NonNull String ifaceName, String value) {
2610         return mSupplicantStaIfaceHal.setWpsModelNumber(ifaceName, value);
2611     }
2612 
2613     /**
2614      * Set WPS serial number.
2615      *
2616      * @param ifaceName Name of the interface.
2617      * @param value String to be set.
2618      * @return true if request is sent successfully, false otherwise.
2619      */
2620     public boolean setSerialNumber(@NonNull String ifaceName, String value) {
2621         return mSupplicantStaIfaceHal.setWpsSerialNumber(ifaceName, value);
2622     }
2623 
2624     /**
2625      * Enable or disable power save mode.
2626      *
2627      * @param ifaceName Name of the interface.
2628      * @param enabled true to enable, false to disable.
2629      */
2630     public void setPowerSave(@NonNull String ifaceName, boolean enabled) {
2631         mSupplicantStaIfaceHal.setPowerSave(ifaceName, enabled);
2632     }
2633 
2634     /**
2635      * Enable or disable low latency mode.
2636      *
2637      * @param enabled true to enable, false to disable.
2638      * @return true on success, false on failure
2639      */
2640     public boolean setLowLatencyMode(boolean enabled) {
2641         return mWifiVendorHal.setLowLatencyMode(enabled);
2642     }
2643 
2644     /**
2645      * Set concurrency priority between P2P & STA operations.
2646      *
2647      * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
2648      *                            false otherwise.
2649      * @return true if request is sent successfully, false otherwise.
2650      */
2651     public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
2652         return mSupplicantStaIfaceHal.setConcurrencyPriority(isStaHigherPriority);
2653     }
2654 
2655     /**
2656      * Enable/Disable auto reconnect functionality in wpa_supplicant.
2657      *
2658      * @param ifaceName Name of the interface.
2659      * @param enable true to enable auto reconnecting, false to disable.
2660      * @return true if request is sent successfully, false otherwise.
2661      */
2662     public boolean enableStaAutoReconnect(@NonNull String ifaceName, boolean enable) {
2663         return mSupplicantStaIfaceHal.enableAutoReconnect(ifaceName, enable);
2664     }
2665 
2666     /**
2667      * Add the provided network configuration to wpa_supplicant and initiate connection to it.
2668      * This method does the following:
2669      * 1. Abort any ongoing scan to unblock the connection request.
2670      * 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect).
2671      * 3. Add a new network to wpa_supplicant.
2672      * 4. Save the provided configuration to wpa_supplicant.
2673      * 5. Select the new network in wpa_supplicant.
2674      * 6. Triggers reconnect command to wpa_supplicant.
2675      *
2676      * @param ifaceName Name of the interface.
2677      * @param configuration WifiConfiguration parameters for the provided network.
2678      * @return {@code true} if it succeeds, {@code false} otherwise
2679      */
2680     public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
2681         // Abort ongoing scan before connect() to unblock connection request.
2682         mWifiCondManager.abortScan(ifaceName);
2683         return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
2684     }
2685 
2686     /**
2687      * Initiates roaming to the already configured network in wpa_supplicant. If the network
2688      * configuration provided does not match the already configured network, then this triggers
2689      * a new connection attempt (instead of roam).
2690      * 1. Abort any ongoing scan to unblock the roam request.
2691      * 2. First check if we're attempting to connect to the same network as we currently have
2692      * configured.
2693      * 3. Set the new bssid for the network in wpa_supplicant.
2694      * 4. Triggers reassociate command to wpa_supplicant.
2695      *
2696      * @param ifaceName Name of the interface.
2697      * @param configuration WifiConfiguration parameters for the provided network.
2698      * @return {@code true} if it succeeds, {@code false} otherwise
2699      */
2700     public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
2701         // Abort ongoing scan before connect() to unblock roaming request.
2702         mWifiCondManager.abortScan(ifaceName);
2703         return mSupplicantStaIfaceHal.roamToNetwork(ifaceName, configuration);
2704     }
2705 
2706     /**
2707      * Remove all the networks.
2708      *
2709      * @param ifaceName Name of the interface.
2710      * @return {@code true} if it succeeds, {@code false} otherwise
2711      */
2712     public boolean removeAllNetworks(@NonNull String ifaceName) {
2713         return mSupplicantStaIfaceHal.removeAllNetworks(ifaceName);
2714     }
2715 
2716     /**
2717      * Disable the currently configured network in supplicant
2718      *
2719      * @param ifaceName Name of the interface.
2720      */
2721     public boolean disableNetwork(@NonNull String ifaceName) {
2722         return mSupplicantStaIfaceHal.disableCurrentNetwork(ifaceName);
2723     }
2724 
2725     /**
2726      * Set the BSSID for the currently configured network in wpa_supplicant.
2727      *
2728      * @param ifaceName Name of the interface.
2729      * @return true if successful, false otherwise.
2730      */
2731     public boolean setNetworkBSSID(@NonNull String ifaceName, String bssid) {
2732         return mSupplicantStaIfaceHal.setCurrentNetworkBssid(ifaceName, bssid);
2733     }
2734 
2735     /**
2736      * Initiate ANQP query.
2737      *
2738      * @param ifaceName Name of the interface.
2739      * @param bssid BSSID of the AP to be queried
2740      * @param anqpIds Set of anqp IDs.
2741      * @param hs20Subtypes Set of HS20 subtypes.
2742      * @return true on success, false otherwise.
2743      */
2744     public boolean requestAnqp(
2745             @NonNull String ifaceName, String bssid, Set<Integer> anqpIds,
2746             Set<Integer> hs20Subtypes) {
2747         if (bssid == null || ((anqpIds == null || anqpIds.isEmpty())
2748                 && (hs20Subtypes == null || hs20Subtypes.isEmpty()))) {
2749             Log.e(TAG, "Invalid arguments for ANQP request.");
2750             return false;
2751         }
2752         ArrayList<Short> anqpIdList = new ArrayList<>();
2753         for (Integer anqpId : anqpIds) {
2754             anqpIdList.add(anqpId.shortValue());
2755         }
2756         ArrayList<Integer> hs20SubtypeList = new ArrayList<>();
2757         hs20SubtypeList.addAll(hs20Subtypes);
2758         return mSupplicantStaIfaceHal.initiateAnqpQuery(
2759                 ifaceName, bssid, anqpIdList, hs20SubtypeList);
2760     }
2761 
2762     /**
2763      * Request a passpoint icon file |filename| from the specified AP |bssid|.
2764      *
2765      * @param ifaceName Name of the interface.
2766      * @param bssid BSSID of the AP
2767      * @param fileName name of the icon file
2768      * @return true if request is sent successfully, false otherwise
2769      */
2770     public boolean requestIcon(@NonNull String ifaceName, String  bssid, String fileName) {
2771         if (bssid == null || fileName == null) {
2772             Log.e(TAG, "Invalid arguments for Icon request.");
2773             return false;
2774         }
2775         return mSupplicantStaIfaceHal.initiateHs20IconQuery(ifaceName, bssid, fileName);
2776     }
2777 
2778     /**
2779      * Initiate Venue URL ANQP query.
2780      *
2781      * @param ifaceName Name of the interface.
2782      * @param bssid BSSID of the AP to be queried
2783      * @return true on success, false otherwise.
2784      */
2785     public boolean requestVenueUrlAnqp(
2786             @NonNull String ifaceName, String bssid) {
2787         if (bssid == null) {
2788             Log.e(TAG, "Invalid arguments for Venue URL ANQP request.");
2789             return false;
2790         }
2791         return mSupplicantStaIfaceHal.initiateVenueUrlAnqpQuery(ifaceName, bssid);
2792     }
2793 
2794     /**
2795      * Get the currently configured network's WPS NFC token.
2796      *
2797      * @param ifaceName Name of the interface.
2798      * @return Hex string corresponding to the WPS NFC token.
2799      */
2800     public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
2801         return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken(ifaceName);
2802     }
2803 
2804     /**
2805      * Clean HAL cached data for |networkId|.
2806      *
2807      * @param networkId network id of the network to be removed from supplicant.
2808      */
2809     public void removeNetworkCachedData(int networkId) {
2810         mSupplicantStaIfaceHal.removeNetworkCachedData(networkId);
2811     }
2812 
2813     /** Clear HAL cached data for |networkId| if MAC address is changed.
2814      *
2815      * @param networkId network id of the network to be checked.
2816      * @param curMacAddress current MAC address
2817      */
2818     public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) {
2819         mSupplicantStaIfaceHal.removeNetworkCachedDataIfNeeded(networkId, curMacAddress);
2820     }
2821 
2822     /*
2823      * DPP
2824      */
2825 
2826     /**
2827      * Adds a DPP peer URI to the URI list.
2828      *
2829      * @param ifaceName Interface name
2830      * @param uri Bootstrap (URI) string (e.g. DPP:....)
2831      * @return ID, or -1 for failure
2832      */
2833     public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) {
2834         return mSupplicantStaIfaceHal.addDppPeerUri(ifaceName, uri);
2835     }
2836 
2837     /**
2838      * Removes a DPP URI to the URI list given an ID.
2839      *
2840      * @param ifaceName Interface name
2841      * @param bootstrapId Bootstrap (URI) ID
2842      * @return true when operation is successful, or false for failure
2843      */
2844     public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId)  {
2845         return mSupplicantStaIfaceHal.removeDppUri(ifaceName, bootstrapId);
2846     }
2847 
2848     /**
2849      * Stops/aborts DPP Initiator request
2850      *
2851      * @param ifaceName Interface name
2852      * @return true when operation is successful, or false for failure
2853      */
2854     public boolean stopDppInitiator(@NonNull String ifaceName)  {
2855         return mSupplicantStaIfaceHal.stopDppInitiator(ifaceName);
2856     }
2857 
2858     /**
2859      * Starts DPP Configurator-Initiator request
2860      *
2861      * @param ifaceName Interface name
2862      * @param peerBootstrapId Peer's bootstrap (URI) ID
2863      * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none
2864      * @param ssid SSID of the selected network
2865      * @param password Password of the selected network, or
2866      * @param psk PSK of the selected network in hexadecimal representation
2867      * @param netRole The network role of the enrollee (STA or AP)
2868      * @param securityAkm Security AKM to use: PSK, SAE
2869      * @return true when operation is successful, or false for failure
2870      */
2871     public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId,
2872             int ownBootstrapId, @NonNull String ssid, String password, String psk,
2873             int netRole, int securityAkm, byte[] privEcKey)  {
2874         return mSupplicantStaIfaceHal.startDppConfiguratorInitiator(ifaceName, peerBootstrapId,
2875                 ownBootstrapId, ssid, password, psk, netRole, securityAkm, privEcKey);
2876     }
2877 
2878     /**
2879      * Starts DPP Enrollee-Initiator request
2880      *
2881      * @param ifaceName Interface name
2882      * @param peerBootstrapId Peer's bootstrap (URI) ID
2883      * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none
2884      * @return true when operation is successful, or false for failure
2885      */
2886     public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId,
2887             int ownBootstrapId)  {
2888         return mSupplicantStaIfaceHal.startDppEnrolleeInitiator(ifaceName, peerBootstrapId,
2889                 ownBootstrapId);
2890     }
2891 
2892     /**
2893      * Callback to notify about DPP success, failure and progress events.
2894      */
2895     public interface DppEventCallback {
2896         /**
2897          * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
2898          * peer DPP configurator.
2899          *
2900          * @param newWifiConfiguration New Wi-Fi configuration received from the configurator
2901          */
2902         void onSuccessConfigReceived(WifiConfiguration newWifiConfiguration);
2903 
2904         /**
2905          * DPP Success event.
2906          *
2907          * @param dppStatusCode Status code of the success event.
2908          */
2909         void onSuccess(int dppStatusCode);
2910 
2911         /**
2912          * DPP Progress event.
2913          *
2914          * @param dppStatusCode Status code of the progress event.
2915          */
2916         void onProgress(int dppStatusCode);
2917 
2918         /**
2919          * DPP Failure event.
2920          *
2921          * @param dppStatusCode Status code of the failure event.
2922          * @param ssid SSID of the network the Enrollee tried to connect to.
2923          * @param channelList List of channels the Enrollee scanned for the network.
2924          * @param bandList List of bands the Enrollee supports.
2925          */
2926         void onFailure(int dppStatusCode, String ssid, String channelList, int[] bandList);
2927 
2928         /**
2929          * DPP Configurator Private keys update.
2930          *
2931          * @param key Configurator's private EC key.
2932          */
2933         void onDppConfiguratorKeyUpdate(byte[] key);
2934     }
2935 
2936     /**
2937      * Class to get generated bootstrap info for DPP responder operation.
2938      */
2939     public static class DppBootstrapQrCodeInfo {
2940         public int bootstrapId;
2941         public int listenChannel;
2942         public String uri = new String();
2943         DppBootstrapQrCodeInfo() {
2944             bootstrapId = -1;
2945             listenChannel = -1;
2946         }
2947     }
2948 
2949     /**
2950      * Generate DPP bootstrap Information:Bootstrap ID, DPP URI and the listen channel.
2951      *
2952      * @param ifaceName Interface name
2953      * @param deviceInfo Device specific info to attach in DPP URI.
2954      * @param dppCurve Elliptic curve cryptography type used to generate DPP
2955      *                 public/private key pair.
2956      * @return ID, or -1 for failure
2957      */
2958     public DppBootstrapQrCodeInfo generateDppBootstrapInfoForResponder(@NonNull String ifaceName,
2959             String deviceInfo, int dppCurve) {
2960         return mSupplicantStaIfaceHal.generateDppBootstrapInfoForResponder(ifaceName,
2961                 getMacAddress(ifaceName), deviceInfo, dppCurve);
2962     }
2963 
2964     /**
2965      * start DPP Enrollee responder mode.
2966      *
2967      * @param ifaceName Interface name
2968      * @param listenChannel Listen channel to wait for DPP authentication request.
2969      * @return ID, or -1 for failure
2970      */
2971     public boolean startDppEnrolleeResponder(@NonNull String ifaceName, int listenChannel) {
2972         return mSupplicantStaIfaceHal.startDppEnrolleeResponder(ifaceName, listenChannel);
2973     }
2974 
2975     /**
2976      * Stops/aborts DPP Responder request
2977      *
2978      * @param ifaceName Interface name
2979      * @param ownBootstrapId Bootstrap (URI) ID
2980      * @return true when operation is successful, or false for failure
2981      */
2982     public boolean stopDppResponder(@NonNull String ifaceName, int ownBootstrapId)  {
2983         return mSupplicantStaIfaceHal.stopDppResponder(ifaceName, ownBootstrapId);
2984     }
2985 
2986 
2987     /**
2988      * Registers DPP event callbacks.
2989      *
2990      * @param dppEventCallback Callback object.
2991      */
2992     public void registerDppEventCallback(DppEventCallback dppEventCallback) {
2993         mSupplicantStaIfaceHal.registerDppCallback(dppEventCallback);
2994     }
2995 
2996     /********************************************************
2997      * Vendor HAL operations
2998      ********************************************************/
2999     /**
3000      * Callback to notify vendor HAL death.
3001      */
3002     public interface VendorHalDeathEventHandler {
3003         /**
3004          * Invoked when the vendor HAL dies.
3005          */
3006         void onDeath();
3007     }
3008 
3009     /**
3010      * Callback to notify when vendor HAL detects that a change in radio mode.
3011      */
3012     public interface VendorHalRadioModeChangeEventHandler {
3013         /**
3014          * Invoked when the vendor HAL detects a change to MCC mode.
3015          * MCC (Multi channel concurrency) = Multiple interfaces are active on the same band,
3016          * different channels, same radios.
3017          *
3018          * @param band Band on which MCC is detected (specified by one of the
3019          *             WifiScanner.WIFI_BAND_* constants)
3020          */
3021         void onMcc(int band);
3022         /**
3023          * Invoked when the vendor HAL detects a change to SCC mode.
3024          * SCC (Single channel concurrency) = Multiple interfaces are active on the same band, same
3025          * channels, same radios.
3026          *
3027          * @param band Band on which SCC is detected (specified by one of the
3028          *             WifiScanner.WIFI_BAND_* constants)
3029          */
3030         void onScc(int band);
3031         /**
3032          * Invoked when the vendor HAL detects a change to SBS mode.
3033          * SBS (Single Band Simultaneous) = Multiple interfaces are active on the same band,
3034          * different channels, different radios.
3035          *
3036          * @param band Band on which SBS is detected (specified by one of the
3037          *             WifiScanner.WIFI_BAND_* constants)
3038          */
3039         void onSbs(int band);
3040         /**
3041          * Invoked when the vendor HAL detects a change to DBS mode.
3042          * DBS (Dual Band Simultaneous) = Multiple interfaces are active on the different bands,
3043          * different channels, different radios.
3044          */
3045         void onDbs();
3046     }
3047 
3048     /**
3049      * Tests whether the HAL is running or not
3050      */
3051     public boolean isHalStarted() {
3052         return mWifiVendorHal.isHalStarted();
3053     }
3054 
3055     /**
3056      * Tests whether the HAL is supported or not
3057      */
3058     public boolean isHalSupported() {
3059         return mWifiVendorHal.isVendorHalSupported();
3060     }
3061 
3062     // TODO: Change variable names to camel style.
3063     public static class ScanCapabilities {
3064         public int  max_scan_cache_size;
3065         public int  max_scan_buckets;
3066         public int  max_ap_cache_per_scan;
3067         public int  max_rssi_sample_size;
3068         public int  max_scan_reporting_threshold;
3069     }
3070 
3071     /**
3072      * Gets the scan capabilities
3073      *
3074      * @param ifaceName Name of the interface.
3075      * @param capabilities object to be filled in
3076      * @return true for success. false for failure
3077      */
3078     public boolean getBgScanCapabilities(
3079             @NonNull String ifaceName, ScanCapabilities capabilities) {
3080         return mWifiVendorHal.getBgScanCapabilities(ifaceName, capabilities);
3081     }
3082 
3083     public static class ChannelSettings {
3084         public int frequency;
3085         public int dwell_time_ms;
3086         public boolean passive;
3087     }
3088 
3089     public static class BucketSettings {
3090         public int bucket;
3091         public int band;
3092         public int period_ms;
3093         public int max_period_ms;
3094         public int step_count;
3095         public int report_events;
3096         public int num_channels;
3097         public ChannelSettings[] channels;
3098     }
3099 
3100     /**
3101      * Network parameters for hidden networks to be scanned for.
3102      */
3103     public static class HiddenNetwork {
3104         public String ssid;
3105 
3106         @Override
3107         public boolean equals(Object otherObj) {
3108             if (this == otherObj) {
3109                 return true;
3110             } else if (otherObj == null || getClass() != otherObj.getClass()) {
3111                 return false;
3112             }
3113             HiddenNetwork other = (HiddenNetwork) otherObj;
3114             return Objects.equals(ssid, other.ssid);
3115         }
3116 
3117         @Override
3118         public int hashCode() {
3119             return Objects.hash(ssid);
3120         }
3121     }
3122 
3123     public static class ScanSettings {
3124         /**
3125          * Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY},
3126          * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}.
3127          */
3128         @WifiAnnotations.ScanType
3129         public int scanType;
3130         public int base_period_ms;
3131         public int max_ap_per_scan;
3132         public int report_threshold_percent;
3133         public int report_threshold_num_scans;
3134         public int num_buckets;
3135         public boolean enable6GhzRnr;
3136         /* Not used for bg scans. Only works for single scans. */
3137         public HiddenNetwork[] hiddenNetworks;
3138         public BucketSettings[] buckets;
3139     }
3140 
3141     /**
3142      * Network parameters to start PNO scan.
3143      */
3144     public static class PnoNetwork {
3145         public String ssid;
3146         public byte flags;
3147         public byte auth_bit_field;
3148         public int[] frequencies;
3149 
3150         @Override
3151         public boolean equals(Object otherObj) {
3152             if (this == otherObj) {
3153                 return true;
3154             } else if (otherObj == null || getClass() != otherObj.getClass()) {
3155                 return false;
3156             }
3157             PnoNetwork other = (PnoNetwork) otherObj;
3158             return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags)
3159                     && (auth_bit_field == other.auth_bit_field))
3160                     && Arrays.equals(frequencies, other.frequencies);
3161         }
3162 
3163         @Override
3164         public int hashCode() {
3165             return Objects.hash(ssid, flags, auth_bit_field, frequencies);
3166         }
3167 
3168         android.net.wifi.nl80211.PnoNetwork toNativePnoNetwork() {
3169             android.net.wifi.nl80211.PnoNetwork nativePnoNetwork =
3170                     new android.net.wifi.nl80211.PnoNetwork();
3171             nativePnoNetwork.setHidden(
3172                     (flags & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0);
3173             try {
3174                 nativePnoNetwork.setSsid(
3175                         NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid)));
3176             } catch (IllegalArgumentException e) {
3177                 Log.e(TAG, "Illegal argument " + ssid, e);
3178                 return null;
3179             }
3180             nativePnoNetwork.setFrequenciesMhz(frequencies);
3181             return nativePnoNetwork;
3182         }
3183     }
3184 
3185     /**
3186      * Parameters to start PNO scan. This holds the list of networks which are going to used for
3187      * PNO scan.
3188      */
3189     public static class PnoSettings {
3190         public int min5GHzRssi;
3191         public int min24GHzRssi;
3192         public int min6GHzRssi;
3193         public int periodInMs;
3194         public boolean isConnected;
3195         public PnoNetwork[] networkList;
3196 
3197         android.net.wifi.nl80211.PnoSettings toNativePnoSettings() {
3198             android.net.wifi.nl80211.PnoSettings nativePnoSettings =
3199                     new android.net.wifi.nl80211.PnoSettings();
3200             nativePnoSettings.setIntervalMillis(periodInMs);
3201             nativePnoSettings.setMin2gRssiDbm(min24GHzRssi);
3202             nativePnoSettings.setMin5gRssiDbm(min5GHzRssi);
3203             nativePnoSettings.setMin6gRssiDbm(min6GHzRssi);
3204 
3205             List<android.net.wifi.nl80211.PnoNetwork> pnoNetworks = new ArrayList<>();
3206             if (networkList != null) {
3207                 for (PnoNetwork network : networkList) {
3208                     android.net.wifi.nl80211.PnoNetwork nativeNetwork =
3209                             network.toNativePnoNetwork();
3210                     if (nativeNetwork != null) {
3211                         pnoNetworks.add(nativeNetwork);
3212                     }
3213                 }
3214             }
3215             nativePnoSettings.setPnoNetworks(pnoNetworks);
3216             return nativePnoSettings;
3217         }
3218     }
3219 
3220     public static interface ScanEventHandler {
3221         /**
3222          * Called for each AP as it is found with the entire contents of the beacon/probe response.
3223          * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified.
3224          */
3225         void onFullScanResult(ScanResult fullScanResult, int bucketsScanned);
3226         /**
3227          * Callback on an event during a gscan scan.
3228          * See WifiNative.WIFI_SCAN_* for possible values.
3229          */
3230         void onScanStatus(int event);
3231         /**
3232          * Called with the current cached scan results when gscan is paused.
3233          */
3234         void onScanPaused(WifiScanner.ScanData[] data);
3235         /**
3236          * Called with the current cached scan results when gscan is resumed.
3237          */
3238         void onScanRestarted();
3239     }
3240 
3241     /**
3242      * Handler to notify the occurrence of various events during PNO scan.
3243      */
3244     public interface PnoEventHandler {
3245         /**
3246          * Callback to notify when one of the shortlisted networks is found during PNO scan.
3247          * @param results List of Scan results received.
3248          */
3249         void onPnoNetworkFound(ScanResult[] results);
3250 
3251         /**
3252          * Callback to notify when the PNO scan schedule fails.
3253          */
3254         void onPnoScanFailed();
3255     }
3256 
3257     public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
3258     public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
3259     public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
3260     public static final int WIFI_SCAN_FAILED = 3;
3261 
3262     /**
3263      * Starts a background scan.
3264      * Any ongoing scan will be stopped first
3265      *
3266      * @param ifaceName Name of the interface.
3267      * @param settings     to control the scan
3268      * @param eventHandler to call with the results
3269      * @return true for success
3270      */
3271     public boolean startBgScan(
3272             @NonNull String ifaceName, ScanSettings settings, ScanEventHandler eventHandler) {
3273         return mWifiVendorHal.startBgScan(ifaceName, settings, eventHandler);
3274     }
3275 
3276     /**
3277      * Stops any ongoing backgound scan
3278      * @param ifaceName Name of the interface.
3279      */
3280     public void stopBgScan(@NonNull String ifaceName) {
3281         mWifiVendorHal.stopBgScan(ifaceName);
3282     }
3283 
3284     /**
3285      * Pauses an ongoing backgound scan
3286      * @param ifaceName Name of the interface.
3287      */
3288     public void pauseBgScan(@NonNull String ifaceName) {
3289         mWifiVendorHal.pauseBgScan(ifaceName);
3290     }
3291 
3292     /**
3293      * Restarts a paused scan
3294      * @param ifaceName Name of the interface.
3295      */
3296     public void restartBgScan(@NonNull String ifaceName) {
3297         mWifiVendorHal.restartBgScan(ifaceName);
3298     }
3299 
3300     /**
3301      * Gets the latest scan results received.
3302      * @param ifaceName Name of the interface.
3303      */
3304     public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) {
3305         return mWifiVendorHal.getBgScanResults(ifaceName);
3306     }
3307 
3308     /**
3309      * Gets the latest link layer stats
3310      * @param ifaceName Name of the interface.
3311      */
3312     public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) {
3313         return mWifiVendorHal.getWifiLinkLayerStats(ifaceName);
3314     }
3315 
3316     /**
3317      * Gets the usable channels
3318      * @param band one of the {@code WifiScanner#WIFI_BAND_*} constants.
3319      * @param mode bitmask of {@code WifiAvailablechannel#OP_MODE_*} constants.
3320      * @param filter bitmask of filters (regulatory, coex, concurrency).
3321      *
3322      * @return list of channels
3323      */
3324     public List<WifiAvailableChannel> getUsableChannels(
3325             @WifiScanner.WifiBand int band,
3326             @WifiAvailableChannel.OpMode int mode,
3327             @WifiAvailableChannel.Filter int filter) {
3328         return mWifiVendorHal.getUsableChannels(band, mode, filter);
3329     }
3330     /**
3331      * Returns whether the device supports the requested
3332      * {@link HalDeviceManager.HdmIfaceTypeForCreation} combo.
3333      */
3334     public boolean canDeviceSupportCreateTypeCombo(SparseArray<Integer> combo) {
3335         synchronized (mLock) {
3336             return mWifiVendorHal.canDeviceSupportCreateTypeCombo(combo);
3337         }
3338     }
3339 
3340     /**
3341      * Returns whether STA + AP concurrency is supported or not.
3342      */
3343     public boolean isStaApConcurrencySupported() {
3344         synchronized (mLock) {
3345             return mWifiVendorHal.canDeviceSupportCreateTypeCombo(
3346                     new SparseArray<Integer>() {{
3347                             put(HDM_CREATE_IFACE_STA, 1);
3348                             put(HDM_CREATE_IFACE_AP, 1);
3349                     }});
3350         }
3351     }
3352 
3353     /**
3354      * Returns whether STA + STA concurrency is supported or not.
3355      */
3356     public boolean isStaStaConcurrencySupported() {
3357         synchronized (mLock) {
3358             return mWifiVendorHal.canDeviceSupportCreateTypeCombo(
3359                     new SparseArray<Integer>() {{
3360                             put(HDM_CREATE_IFACE_STA, 2);
3361                     }});
3362         }
3363     }
3364 
3365     /**
3366      * Returns whether a new AP iface can be created or not.
3367      */
3368     public boolean isItPossibleToCreateApIface(@NonNull WorkSource requestorWs) {
3369         synchronized (mLock) {
3370             if (!isHalStarted()) {
3371                 return canDeviceSupportCreateTypeCombo(
3372                         new SparseArray<Integer>() {{
3373                             put(HDM_CREATE_IFACE_AP, 1);
3374                         }});
3375             }
3376             return mWifiVendorHal.isItPossibleToCreateApIface(requestorWs);
3377         }
3378     }
3379 
3380     /**
3381      * Returns whether a new AP iface can be created or not.
3382      */
3383     public boolean isItPossibleToCreateBridgedApIface(@NonNull WorkSource requestorWs) {
3384         synchronized (mLock) {
3385             if (!isHalStarted()) {
3386                 return canDeviceSupportCreateTypeCombo(
3387                         new SparseArray<Integer>() {{
3388                             put(HDM_CREATE_IFACE_AP_BRIDGE, 1);
3389                         }});
3390             }
3391             return mWifiVendorHal.isItPossibleToCreateBridgedApIface(requestorWs);
3392         }
3393     }
3394 
3395     /**
3396      * Returns whether creating a single AP does not require destroying an existing iface, but
3397      * creating a bridged AP does.
3398      */
3399     public boolean shouldDowngradeToSingleApForConcurrency(@NonNull WorkSource requestorWs) {
3400         synchronized (mLock) {
3401             if (!mWifiVendorHal.isHalStarted()) {
3402                 return false;
3403             }
3404             return !mWifiVendorHal.canDeviceSupportAdditionalIface(HDM_CREATE_IFACE_AP_BRIDGE,
3405                     requestorWs)
3406                     && mWifiVendorHal.canDeviceSupportAdditionalIface(HDM_CREATE_IFACE_AP,
3407                     requestorWs);
3408         }
3409     }
3410 
3411     /**
3412      * Returns whether a new STA iface can be created or not.
3413      */
3414     public boolean isItPossibleToCreateStaIface(@NonNull WorkSource requestorWs) {
3415         synchronized (mLock) {
3416             if (!isHalStarted()) {
3417                 return canDeviceSupportCreateTypeCombo(
3418                         new SparseArray<Integer>() {{
3419                             put(HDM_CREATE_IFACE_STA, 1);
3420                         }});
3421             }
3422             return mWifiVendorHal.isItPossibleToCreateStaIface(requestorWs);
3423         }
3424     }
3425 
3426     /**
3427      * Set primary connection when multiple STA ifaces are active.
3428      *
3429      * @param ifaceName Name of the interface.
3430      * @return true for success
3431      */
3432     public boolean setMultiStaPrimaryConnection(@NonNull String ifaceName) {
3433         synchronized (mLock) {
3434             return mWifiVendorHal.setMultiStaPrimaryConnection(ifaceName);
3435         }
3436     }
3437 
3438     /**
3439      * Multi STA use case flags.
3440      */
3441     public static final int DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0;
3442     public static final int DUAL_STA_NON_TRANSIENT_UNBIASED = 1;
3443 
3444     @IntDef({DUAL_STA_TRANSIENT_PREFER_PRIMARY, DUAL_STA_NON_TRANSIENT_UNBIASED})
3445     @Retention(RetentionPolicy.SOURCE)
3446     public @interface MultiStaUseCase{}
3447 
3448     /**
3449      * Set use-case when multiple STA ifaces are active.
3450      *
3451      * @param useCase one of the use cases.
3452      * @return true for success
3453      */
3454     public boolean setMultiStaUseCase(@MultiStaUseCase int useCase) {
3455         synchronized (mLock) {
3456             return mWifiVendorHal.setMultiStaUseCase(useCase);
3457         }
3458     }
3459 
3460     /**
3461      * Get the supported features
3462      *
3463      * @param ifaceName Name of the interface.
3464      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
3465      */
3466     public long getSupportedFeatureSet(String ifaceName) {
3467         synchronized (mLock) {
3468             long featureSet = 0;
3469             // First get the complete feature set stored in config store when supplicant was
3470             // started
3471             featureSet = getCompleteFeatureSetFromConfigStore();
3472             // Include the feature set saved in interface class. This is to make sure that
3473             // framework is returning the feature set for SoftAp only products and multi-chip
3474             // products.
3475             if (ifaceName != null) {
3476                 Iface iface = mIfaceMgr.getIface(ifaceName);
3477                 if (iface != null) {
3478                     featureSet |= iface.featureSet;
3479                 }
3480             }
3481             return featureSet;
3482         }
3483     }
3484 
3485     /**
3486      * Get the supported features
3487      *
3488      * @param ifaceName Name of the interface.
3489      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
3490      */
3491     private long getSupportedFeatureSetInternal(@NonNull String ifaceName) {
3492         long featureSet = mSupplicantStaIfaceHal.getAdvancedCapabilities(ifaceName)
3493                 | mWifiVendorHal.getSupportedFeatureSet(ifaceName)
3494                 | mSupplicantStaIfaceHal.getWpaDriverFeatureSet(ifaceName);
3495         if (SdkLevel.isAtLeastT()) {
3496             if (((featureSet & WifiManager.WIFI_FEATURE_DPP) != 0)
3497                     && mContext.getResources().getBoolean(R.bool.config_wifiDppAkmSupported)) {
3498                 // Set if DPP is filled by supplicant and DPP AKM is enabled by overlay.
3499                 featureSet |= WifiManager.WIFI_FEATURE_DPP_AKM;
3500                 Log.v(TAG, ": DPP AKM supported");
3501             }
3502         }
3503         return featureSet;
3504     }
3505 
3506     /**
3507      * Class to retrieve connection capability parameters after association
3508      */
3509     public static class ConnectionCapabilities {
3510         public @WifiAnnotations.WifiStandard int wifiStandard;
3511         public int channelBandwidth;
3512         public int maxNumberTxSpatialStreams;
3513         public int maxNumberRxSpatialStreams;
3514         public boolean is11bMode;
3515         ConnectionCapabilities() {
3516             wifiStandard = ScanResult.WIFI_STANDARD_UNKNOWN;
3517             channelBandwidth = ScanResult.CHANNEL_WIDTH_20MHZ;
3518             maxNumberTxSpatialStreams = 1;
3519             maxNumberRxSpatialStreams = 1;
3520             is11bMode = false;
3521         }
3522     }
3523 
3524     /**
3525      * Returns connection capabilities of the current network
3526      *
3527      * @param ifaceName Name of the interface.
3528      * @return connection capabilities of the current network
3529      */
3530     public ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) {
3531         return mSupplicantStaIfaceHal.getConnectionCapabilities(ifaceName);
3532     }
3533 
3534     /**
3535      * Class to represent a connection MLO Link
3536      */
3537     public static class ConnectionMloLink {
3538         public int linkId;
3539         public MacAddress staMacAddress;
3540 
3541         ConnectionMloLink() {
3542             // Nothing for now
3543         };
3544     }
3545 
3546     /**
3547      * Class to represent the MLO links info for a connection that is collected after association
3548      */
3549     public static class ConnectionMloLinksInfo {
3550         public ConnectionMloLink[] links;
3551 
3552         ConnectionMloLinksInfo() {
3553             // Nothing for now
3554         }
3555     }
3556 
3557     /**
3558      * Returns connection MLO Links Info.
3559      *
3560      * @param ifaceName Name of the interface.
3561      * @return connection MLO Links Info
3562      */
3563     public ConnectionMloLinksInfo getConnectionMloLinksInfo(@NonNull String ifaceName) {
3564         return mSupplicantStaIfaceHal.getConnectionMloLinksInfo(ifaceName);
3565     }
3566 
3567     /**
3568      * Get the APF (Android Packet Filter) capabilities of the device
3569      * @param ifaceName Name of the interface.
3570      */
3571     public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) {
3572         return mWifiVendorHal.getApfCapabilities(ifaceName);
3573     }
3574 
3575     /**
3576      * Installs an APF program on this iface, replacing any existing program.
3577      *
3578      * @param ifaceName Name of the interface
3579      * @param filter is the android packet filter program
3580      * @return true for success
3581      */
3582     public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) {
3583         return mWifiVendorHal.installPacketFilter(ifaceName, filter);
3584     }
3585 
3586     /**
3587      * Reads the APF program and data buffer for this iface.
3588      *
3589      * @param ifaceName Name of the interface
3590      * @return the buffer returned by the driver, or null in case of an error
3591      */
3592     public byte[] readPacketFilter(@NonNull String ifaceName) {
3593         return mWifiVendorHal.readPacketFilter(ifaceName);
3594     }
3595 
3596     /**
3597      * Set country code for this AP iface.
3598      * @param ifaceName Name of the AP interface.
3599      * @param countryCode - two-letter country code (as ISO 3166)
3600      * @return true for success
3601      */
3602     public boolean setApCountryCode(@NonNull String ifaceName, String countryCode) {
3603         if (mWifiVendorHal.setApCountryCode(ifaceName, countryCode)) {
3604             if (mCountryCodeChangeListener != null) {
3605                 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode);
3606             }
3607             return true;
3608         }
3609         return false;
3610     }
3611 
3612     /**
3613      * Set country code for this chip
3614      * @param countryCode - two-letter country code (as ISO 3166)
3615      * @return true for success
3616      */
3617     public boolean setChipCountryCode(String countryCode) {
3618         if (mWifiVendorHal.setChipCountryCode(countryCode)) {
3619             if (mCountryCodeChangeListener != null) {
3620                 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode);
3621             }
3622             return true;
3623         }
3624         return false;
3625     }
3626 
3627     //---------------------------------------------------------------------------------
3628     /* Wifi Logger commands/events */
3629     public static interface WifiLoggerEventHandler {
3630         void onRingBufferData(RingBufferStatus status, byte[] buffer);
3631         void onWifiAlert(int errorCode, byte[] buffer);
3632     }
3633 
3634     /**
3635      * Registers the logger callback and enables alerts.
3636      * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
3637      *
3638      * @param handler Callback to be invoked.
3639      * @return true on success, false otherwise.
3640      */
3641     public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
3642         return mWifiVendorHal.setLoggingEventHandler(handler);
3643     }
3644 
3645     /**
3646      * Control debug data collection
3647      *
3648      * @param verboseLevel 0 to 3, inclusive. 0 stops logging.
3649      * @param flags        Ignored.
3650      * @param maxInterval  Maximum interval between reports; ignore if 0.
3651      * @param minDataSize  Minimum data size in buffer for report; ignore if 0.
3652      * @param ringName     Name of the ring for which data collection is to start.
3653      * @return true for success, false otherwise.
3654      */
3655     public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
3656             int minDataSize, String ringName){
3657         return mWifiVendorHal.startLoggingRingBuffer(
3658                 verboseLevel, flags, maxInterval, minDataSize, ringName);
3659     }
3660 
3661     /**
3662      * Logger features exposed.
3663      * This is a no-op now, will always return -1.
3664      *
3665      * @return true on success, false otherwise.
3666      */
3667     public int getSupportedLoggerFeatureSet() {
3668         return mWifiVendorHal.getSupportedLoggerFeatureSet();
3669     }
3670 
3671     /**
3672      * Stops all logging and resets the logger callback.
3673      * This stops both the alerts and ring buffer data collection.
3674      * @return true on success, false otherwise.
3675      */
3676     public boolean resetLogHandler() {
3677         return mWifiVendorHal.resetLogHandler();
3678     }
3679 
3680     /**
3681      * Vendor-provided wifi driver version string
3682      *
3683      * @return String returned from the HAL.
3684      */
3685     public String getDriverVersion() {
3686         return mWifiVendorHal.getDriverVersion();
3687     }
3688 
3689     /**
3690      * Vendor-provided wifi firmware version string
3691      *
3692      * @return String returned from the HAL.
3693      */
3694     public String getFirmwareVersion() {
3695         return mWifiVendorHal.getFirmwareVersion();
3696     }
3697 
3698     public static class RingBufferStatus{
3699         String name;
3700         int flag;
3701         int ringBufferId;
3702         int ringBufferByteSize;
3703         int verboseLevel;
3704         int writtenBytes;
3705         int readBytes;
3706         int writtenRecords;
3707 
3708         // Bit masks for interpreting |flag|
3709         public static final int HAS_BINARY_ENTRIES = (1 << 0);
3710         public static final int HAS_ASCII_ENTRIES = (1 << 1);
3711         public static final int HAS_PER_PACKET_ENTRIES = (1 << 2);
3712 
3713         @Override
3714         public String toString() {
3715             return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
3716                     " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
3717                     " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
3718                     " writtenRecords: " + writtenRecords;
3719         }
3720     }
3721 
3722     /**
3723      * API to get the status of all ring buffers supported by driver
3724      */
3725     public RingBufferStatus[] getRingBufferStatus() {
3726         return mWifiVendorHal.getRingBufferStatus();
3727     }
3728 
3729     /**
3730      * Indicates to driver that all the data has to be uploaded urgently
3731      *
3732      * @param ringName Name of the ring buffer requested.
3733      * @return true on success, false otherwise.
3734      */
3735     public boolean getRingBufferData(String ringName) {
3736         return mWifiVendorHal.getRingBufferData(ringName);
3737     }
3738 
3739     /**
3740      * Request hal to flush ring buffers to files
3741      *
3742      * @return true on success, false otherwise.
3743      */
3744     public boolean flushRingBufferData() {
3745         return mWifiVendorHal.flushRingBufferData();
3746     }
3747 
3748     /**
3749      * Request vendor debug info from the firmware
3750      *
3751      * @return Raw data obtained from the HAL.
3752      */
3753     public byte[] getFwMemoryDump() {
3754         return mWifiVendorHal.getFwMemoryDump();
3755     }
3756 
3757     /**
3758      * Request vendor debug info from the driver
3759      *
3760      * @return Raw data obtained from the HAL.
3761      */
3762     public byte[] getDriverStateDump() {
3763         return mWifiVendorHal.getDriverStateDump();
3764     }
3765 
3766     /**
3767      * Dump information about the internal state
3768      *
3769      * @param pw PrintWriter to write dump to
3770      */
3771     protected void dump(PrintWriter pw) {
3772         mHostapdHal.dump(pw);
3773     }
3774 
3775     //---------------------------------------------------------------------------------
3776     /* Packet fate API */
3777 
3778     @Immutable
3779     abstract static class FateReport {
3780         final static int USEC_PER_MSEC = 1000;
3781         // The driver timestamp is a 32-bit counter, in microseconds. This field holds the
3782         // maximal value of a driver timestamp in milliseconds.
3783         final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000);
3784         final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
3785 
3786         final byte mFate;
3787         final long mDriverTimestampUSec;
3788         final byte mFrameType;
3789         final byte[] mFrameBytes;
3790         final long mEstimatedWallclockMSec;
3791 
3792         FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3793             mFate = fate;
3794             mDriverTimestampUSec = driverTimestampUSec;
3795             mEstimatedWallclockMSec =
3796                     convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec);
3797             mFrameType = frameType;
3798             mFrameBytes = frameBytes;
3799         }
3800 
3801         public String toTableRowString() {
3802             StringWriter sw = new StringWriter();
3803             PrintWriter pw = new PrintWriter(sw);
3804             FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
3805             dateFormatter.setTimeZone(TimeZone.getDefault());
3806             pw.format("%-15s  %12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3807                     mDriverTimestampUSec,
3808                     dateFormatter.format(new Date(mEstimatedWallclockMSec)),
3809                     directionToString(), fateToString(), parser.mMostSpecificProtocolString,
3810                     parser.mTypeString, parser.mResultString);
3811             return sw.toString();
3812         }
3813 
3814         public String toVerboseStringWithPiiAllowed() {
3815             StringWriter sw = new StringWriter();
3816             PrintWriter pw = new PrintWriter(sw);
3817             FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
3818             pw.format("Frame direction: %s\n", directionToString());
3819             pw.format("Frame timestamp: %d\n", mDriverTimestampUSec);
3820             pw.format("Frame fate: %s\n", fateToString());
3821             pw.format("Frame type: %s\n", frameTypeToString(mFrameType));
3822             pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString);
3823             pw.format("Frame protocol type: %s\n", parser.mTypeString);
3824             pw.format("Frame length: %d\n", mFrameBytes.length);
3825             pw.append("Frame bytes");
3826             pw.append(HexDump.dumpHexString(mFrameBytes));  // potentially contains PII
3827             pw.append("\n");
3828             return sw.toString();
3829         }
3830 
3831         /* Returns a header to match the output of toTableRowString(). */
3832         public static String getTableHeader() {
3833             StringWriter sw = new StringWriter();
3834             PrintWriter pw = new PrintWriter(sw);
3835             pw.format("\n%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3836                     "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result");
3837             pw.format("%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3838                     "---------", "--------", "---------", "----", "--------", "----", "------");
3839             return sw.toString();
3840         }
3841 
3842         protected abstract String directionToString();
3843 
3844         protected abstract String fateToString();
3845 
3846         private static String frameTypeToString(byte frameType) {
3847             switch (frameType) {
3848                 case WifiLoggerHal.FRAME_TYPE_UNKNOWN:
3849                     return "unknown";
3850                 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II:
3851                     return "data";
3852                 case WifiLoggerHal.FRAME_TYPE_80211_MGMT:
3853                     return "802.11 management";
3854                 default:
3855                     return Byte.toString(frameType);
3856             }
3857         }
3858 
3859         /**
3860          * Converts a driver timestamp to a wallclock time, based on the current
3861          * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of
3862          * microseconds, with the same base as BOOTTIME.
3863          */
3864         private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) {
3865             final long wallclockMillisNow = System.currentTimeMillis();
3866             final long boottimeMillisNow = SystemClock.elapsedRealtime();
3867             final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC;
3868 
3869             long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC;
3870             if (boottimeTimestampMillis < driverTimestampMillis) {
3871                 // The 32-bit microsecond count has wrapped between the time that the driver
3872                 // recorded the packet, and the call to this function. Adjust the BOOTTIME
3873                 // timestamp, to compensate.
3874                 //
3875                 // Note that overflow is not a concern here, since the result is less than
3876                 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above,
3877                 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since
3878                 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit
3879                 // within a long.
3880                 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC;
3881             }
3882 
3883             final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis;
3884             return wallclockMillisNow - millisSincePacketTimestamp;
3885         }
3886     }
3887 
3888     /**
3889      * Represents the fate information for one outbound packet.
3890      */
3891     @Immutable
3892     public static final class TxFateReport extends FateReport {
3893         TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3894             super(fate, driverTimestampUSec, frameType, frameBytes);
3895         }
3896 
3897         @Override
3898         protected String directionToString() {
3899             return "TX";
3900         }
3901 
3902         @Override
3903         protected String fateToString() {
3904             switch (mFate) {
3905                 case WifiLoggerHal.TX_PKT_FATE_ACKED:
3906                     return "acked";
3907                 case WifiLoggerHal.TX_PKT_FATE_SENT:
3908                     return "sent";
3909                 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED:
3910                     return "firmware queued";
3911                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID:
3912                     return "firmware dropped (invalid frame)";
3913                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS:
3914                     return "firmware dropped (no bufs)";
3915                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER:
3916                     return "firmware dropped (other)";
3917                 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED:
3918                     return "driver queued";
3919                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID:
3920                     return "driver dropped (invalid frame)";
3921                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS:
3922                     return "driver dropped (no bufs)";
3923                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER:
3924                     return "driver dropped (other)";
3925                 default:
3926                     return Byte.toString(mFate);
3927             }
3928         }
3929     }
3930 
3931     /**
3932      * Represents the fate information for one inbound packet.
3933      */
3934     @Immutable
3935     public static final class RxFateReport extends FateReport {
3936         RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3937             super(fate, driverTimestampUSec, frameType, frameBytes);
3938         }
3939 
3940         @Override
3941         protected String directionToString() {
3942             return "RX";
3943         }
3944 
3945         @Override
3946         protected String fateToString() {
3947             switch (mFate) {
3948                 case WifiLoggerHal.RX_PKT_FATE_SUCCESS:
3949                     return "success";
3950                 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED:
3951                     return "firmware queued";
3952                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER:
3953                     return "firmware dropped (filter)";
3954                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID:
3955                     return "firmware dropped (invalid frame)";
3956                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS:
3957                     return "firmware dropped (no bufs)";
3958                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER:
3959                     return "firmware dropped (other)";
3960                 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED:
3961                     return "driver queued";
3962                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER:
3963                     return "driver dropped (filter)";
3964                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID:
3965                     return "driver dropped (invalid frame)";
3966                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS:
3967                     return "driver dropped (no bufs)";
3968                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER:
3969                     return "driver dropped (other)";
3970                 default:
3971                     return Byte.toString(mFate);
3972             }
3973         }
3974     }
3975 
3976     /**
3977      * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started.
3978      *
3979      * @param ifaceName Name of the interface.
3980      * @return true for success, false otherwise.
3981      */
3982     public boolean startPktFateMonitoring(@NonNull String ifaceName) {
3983         return mWifiVendorHal.startPktFateMonitoring(ifaceName);
3984     }
3985 
3986     /**
3987      * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started.
3988      *
3989      * @param ifaceName Name of the interface.
3990      * @return TxFateReport list on success, empty list on failure. Never returns null.
3991      */
3992     @NonNull
3993     public List<TxFateReport> getTxPktFates(@NonNull String ifaceName) {
3994         return mWifiVendorHal.getTxPktFates(ifaceName);
3995     }
3996 
3997     /**
3998      * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started.
3999      * @param ifaceName Name of the interface.
4000      * @return RxFateReport list on success, empty list on failure. Never returns null.
4001      */
4002     @NonNull
4003     public List<RxFateReport> getRxPktFates(@NonNull String ifaceName) {
4004         return mWifiVendorHal.getRxPktFates(ifaceName);
4005     }
4006 
4007     /**
4008      * Get the tx packet counts for the interface.
4009      *
4010      * @param ifaceName Name of the interface.
4011      * @return tx packet counts
4012      */
4013     public long getTxPackets(@NonNull String ifaceName) {
4014         return TrafficStats.getTxPackets(ifaceName);
4015     }
4016 
4017     /**
4018      * Get the rx packet counts for the interface.
4019      *
4020      * @param ifaceName Name of the interface
4021      * @return rx packet counts
4022      */
4023     public long getRxPackets(@NonNull String ifaceName) {
4024         return TrafficStats.getRxPackets(ifaceName);
4025     }
4026 
4027     /**
4028      * Start sending the specified keep alive packets periodically.
4029      *
4030      * @param ifaceName Name of the interface.
4031      * @param slot Integer used to identify each request.
4032      * @param dstMac Destination MAC Address
4033      * @param packet Raw packet contents to send.
4034      * @param protocol The ethernet protocol type
4035      * @param period Period to use for sending these packets.
4036      * @return 0 for success, -1 for error
4037      */
4038     public int startSendingOffloadedPacket(@NonNull String ifaceName, int slot,
4039             byte[] dstMac, byte[] packet, int protocol, int period) {
4040         byte[] srcMac = NativeUtil.macAddressToByteArray(getMacAddress(ifaceName));
4041         return mWifiVendorHal.startSendingOffloadedPacket(
4042                 ifaceName, slot, srcMac, dstMac, packet, protocol, period);
4043     }
4044 
4045     /**
4046      * Stop sending the specified keep alive packets.
4047      *
4048      * @param ifaceName Name of the interface.
4049      * @param slot id - same as startSendingOffloadedPacket call.
4050      * @return 0 for success, -1 for error
4051      */
4052     public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) {
4053         return mWifiVendorHal.stopSendingOffloadedPacket(ifaceName, slot);
4054     }
4055 
4056     public static interface WifiRssiEventHandler {
4057         void onRssiThresholdBreached(byte curRssi);
4058     }
4059 
4060     /**
4061      * Start RSSI monitoring on the currently connected access point.
4062      *
4063      * @param ifaceName        Name of the interface.
4064      * @param maxRssi          Maximum RSSI threshold.
4065      * @param minRssi          Minimum RSSI threshold.
4066      * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
4067      * @return 0 for success, -1 for failure
4068      */
4069     public int startRssiMonitoring(
4070             @NonNull String ifaceName, byte maxRssi, byte minRssi,
4071             WifiRssiEventHandler rssiEventHandler) {
4072         return mWifiVendorHal.startRssiMonitoring(
4073                 ifaceName, maxRssi, minRssi, rssiEventHandler);
4074     }
4075 
4076     /**
4077      * Stop RSSI monitoring on the currently connected access point.
4078      *
4079      * @param ifaceName Name of the interface.
4080      * @return 0 for success, -1 for failure
4081      */
4082     public int stopRssiMonitoring(@NonNull String ifaceName) {
4083         return mWifiVendorHal.stopRssiMonitoring(ifaceName);
4084     }
4085 
4086     /**
4087      * Fetch the host wakeup reasons stats from wlan driver.
4088      *
4089      * @return the |WlanWakeReasonAndCounts| object retrieved from the wlan driver.
4090      */
4091     public WlanWakeReasonAndCounts getWlanWakeReasonCount() {
4092         return mWifiVendorHal.getWlanWakeReasonCount();
4093     }
4094 
4095     /**
4096      * Enable/Disable Neighbour discovery offload functionality in the firmware.
4097      *
4098      * @param ifaceName Name of the interface.
4099      * @param enabled true to enable, false to disable.
4100      * @return true for success, false otherwise.
4101      */
4102     public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) {
4103         return mWifiVendorHal.configureNeighborDiscoveryOffload(ifaceName, enabled);
4104     }
4105 
4106     // Firmware roaming control.
4107 
4108     /**
4109      * Class to retrieve firmware roaming capability parameters.
4110      */
4111     public static class RoamingCapabilities {
4112         public int maxBlocklistSize;
4113         public int maxAllowlistSize;
4114     }
4115 
4116     /**
4117      * Query the firmware roaming capabilities.
4118      * @param ifaceName Name of the interface.
4119      * @return capabilities object on success, null otherwise.
4120      */
4121     @Nullable
4122     public RoamingCapabilities getRoamingCapabilities(@NonNull String ifaceName) {
4123         return mWifiVendorHal.getRoamingCapabilities(ifaceName);
4124     }
4125 
4126     /**
4127      * Macros for controlling firmware roaming.
4128      */
4129     public static final int DISABLE_FIRMWARE_ROAMING = 0;
4130     public static final int ENABLE_FIRMWARE_ROAMING = 1;
4131 
4132     @IntDef({ENABLE_FIRMWARE_ROAMING, DISABLE_FIRMWARE_ROAMING})
4133     @Retention(RetentionPolicy.SOURCE)
4134     public @interface RoamingEnableState {}
4135 
4136     /**
4137      * Indicates success for enableFirmwareRoaming
4138      */
4139     public static final int SET_FIRMWARE_ROAMING_SUCCESS = 0;
4140 
4141     /**
4142      * Indicates failure for enableFirmwareRoaming
4143      */
4144     public static final int SET_FIRMWARE_ROAMING_FAILURE = 1;
4145 
4146     /**
4147      * Indicates temporary failure for enableFirmwareRoaming - try again later
4148      */
4149     public static final int SET_FIRMWARE_ROAMING_BUSY = 2;
4150 
4151     @IntDef({SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE, SET_FIRMWARE_ROAMING_BUSY})
4152     @Retention(RetentionPolicy.SOURCE)
4153     public @interface RoamingEnableStatus {}
4154 
4155     /**
4156      * Enable/disable firmware roaming.
4157      *
4158      * @param ifaceName Name of the interface.
4159      * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE,
4160      *         or SET_FIRMWARE_ROAMING_BUSY
4161      */
4162     public @RoamingEnableStatus int enableFirmwareRoaming(@NonNull String ifaceName,
4163             @RoamingEnableState int state) {
4164         return mWifiVendorHal.enableFirmwareRoaming(ifaceName, state);
4165     }
4166 
4167     /**
4168      * Class for specifying the roaming configurations.
4169      */
4170     public static class RoamingConfig {
4171         public ArrayList<String> blocklistBssids;
4172         public ArrayList<String> allowlistSsids;
4173     }
4174 
4175     /**
4176      * Set firmware roaming configurations.
4177      * @param ifaceName Name of the interface.
4178      */
4179     public boolean configureRoaming(@NonNull String ifaceName, RoamingConfig config) {
4180         return mWifiVendorHal.configureRoaming(ifaceName, config);
4181     }
4182 
4183     /**
4184      * Reset firmware roaming configuration.
4185      * @param ifaceName Name of the interface.
4186      */
4187     public boolean resetRoamingConfiguration(@NonNull String ifaceName) {
4188         // Pass in an empty RoamingConfig object which translates to zero size
4189         // blacklist and whitelist to reset the firmware roaming configuration.
4190         return mWifiVendorHal.configureRoaming(ifaceName, new RoamingConfig());
4191     }
4192 
4193     /**
4194      * Select one of the pre-configured transmit power level scenarios or reset it back to normal.
4195      * Primarily used for meeting SAR requirements.
4196      *
4197      * @param sarInfo The collection of inputs used to select the SAR scenario.
4198      * @return true for success; false for failure or if the HAL version does not support this API.
4199      */
4200     public boolean selectTxPowerScenario(SarInfo sarInfo) {
4201         return mWifiVendorHal.selectTxPowerScenario(sarInfo);
4202     }
4203 
4204     /**
4205      * Set MBO cellular data status
4206      *
4207      * @param ifaceName Name of the interface.
4208      * @param available cellular data status,
4209      *        true means cellular data available, false otherwise.
4210      */
4211     public void setMboCellularDataStatus(@NonNull String ifaceName, boolean available) {
4212         mSupplicantStaIfaceHal.setMboCellularDataStatus(ifaceName, available);
4213     }
4214 
4215     /**
4216      * Query of support of Wi-Fi standard
4217      *
4218      * @param ifaceName name of the interface to check support on
4219      * @param standard the wifi standard to check on
4220      * @return true if the wifi standard is supported on this interface, false otherwise.
4221      */
4222     public boolean isWifiStandardSupported(@NonNull String ifaceName,
4223             @WifiAnnotations.WifiStandard int standard) {
4224         synchronized (mLock) {
4225             Iface iface = mIfaceMgr.getIface(ifaceName);
4226             if (iface == null || iface.phyCapabilities == null) {
4227                 return false;
4228             }
4229             return iface.phyCapabilities.isWifiStandardSupported(standard);
4230         }
4231     }
4232 
4233     /**
4234      * Get the Wiphy capabilities of a device for a given interface
4235      * If the interface is not associated with one,
4236      * it will be read from the device through wificond
4237      *
4238      * @param ifaceName name of the interface
4239      * @return the device capabilities for this interface
4240      */
4241     public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) {
4242         synchronized (mLock) {
4243             Iface iface = mIfaceMgr.getIface(ifaceName);
4244             if (iface == null) {
4245                 Log.e(TAG, "Failed to get device capabilities, interface not found: " + ifaceName);
4246                 return null;
4247             }
4248             if (iface.phyCapabilities == null) {
4249                 iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities(ifaceName);
4250             }
4251             return iface.phyCapabilities;
4252         }
4253     }
4254 
4255     /**
4256      * Set the Wiphy capabilities of a device for a given interface
4257      *
4258      * @param ifaceName name of the interface
4259      * @param capabilities the wiphy capabilities to set for this interface
4260      */
4261     public void setDeviceWiphyCapabilities(@NonNull String ifaceName,
4262             DeviceWiphyCapabilities capabilities) {
4263         synchronized (mLock) {
4264             Iface iface = mIfaceMgr.getIface(ifaceName);
4265             if (iface == null) {
4266                 Log.e(TAG, "Failed to set device capabilities, interface not found: " + ifaceName);
4267                 return;
4268             }
4269             iface.phyCapabilities = capabilities;
4270         }
4271     }
4272 
4273     /**
4274      * Notify scan mode state to driver to save power in scan-only mode.
4275      *
4276      * @param ifaceName Name of the interface.
4277      * @param enable whether is in scan-only mode
4278      * @return true for success
4279      */
4280     public boolean setScanMode(String ifaceName, boolean enable) {
4281         return mWifiVendorHal.setScanMode(ifaceName, enable);
4282     }
4283 
4284     /** updates linked networks of the |networkId| in supplicant if it's the current network,
4285      * if the current configured network matches |networkId|.
4286      *
4287      * @param ifaceName Name of the interface.
4288      * @param networkId network id of the network to be updated from supplicant.
4289      * @param linkedNetworks Map of config profile key and config for linking.
4290      */
4291     public boolean updateLinkedNetworks(@NonNull String ifaceName, int networkId,
4292             Map<String, WifiConfiguration> linkedNetworks) {
4293         return mSupplicantStaIfaceHal.updateLinkedNetworks(ifaceName, networkId, linkedNetworks);
4294     }
4295 
4296     /**
4297      * Start Subsystem Restart
4298      * @return true on success
4299      */
4300     public boolean startSubsystemRestart() {
4301         return mWifiVendorHal.startSubsystemRestart();
4302     }
4303 
4304     /**
4305      * Register the provided listener for country code event.
4306      *
4307      * @param listener listener for country code changed events.
4308      */
4309     public void registerCountryCodeEventListener(WifiCountryCode.ChangeListener listener) {
4310         registerWificondListenerIfNecessary();
4311         if (mCountryCodeChangeListener != null) {
4312             mCountryCodeChangeListener.setChangeListener(listener);
4313         }
4314     }
4315 
4316     /**
4317      * Gets the security params of the current network associated with this interface
4318      *
4319      * @param ifaceName Name of the interface
4320      * @return Security params of the current network associated with the interface
4321      */
4322     public SecurityParams getCurrentNetworkSecurityParams(@NonNull String ifaceName) {
4323         return mSupplicantStaIfaceHal.getCurrentNetworkSecurityParams(ifaceName);
4324     }
4325 
4326     /**
4327      * Sends a QoS policy response.
4328      *
4329      * @param ifaceName Name of the interface.
4330      * @param qosPolicyRequestId Dialog token to identify the request.
4331      * @param morePolicies Flag to indicate more QoS policies can be accommodated.
4332      * @param qosPolicyStatusList List of framework QosPolicyStatus objects.
4333      * @return true if response is sent successfully, false otherwise.
4334      */
4335     public boolean sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId,
4336             boolean morePolicies, @NonNull List<QosPolicyStatus> qosPolicyStatusList) {
4337         return mSupplicantStaIfaceHal.sendQosPolicyResponse(ifaceName, qosPolicyRequestId,
4338                 morePolicies, qosPolicyStatusList);
4339     }
4340 
4341     /**
4342      * Indicates the removal of all active QoS policies configured by the AP.
4343      *
4344      * @param ifaceName Name of the interface.
4345      */
4346     public boolean removeAllQosPolicies(String ifaceName) {
4347         return mSupplicantStaIfaceHal.removeAllQosPolicies(ifaceName);
4348     }
4349 
4350     /**
4351      * Generate DPP credential for network access
4352      *
4353      * @param ifaceName Name of the interface.
4354      * @param ssid ssid of the network
4355      * @param privEcKey Private EC Key for DPP Configurator
4356      * Returns true when operation is successful. On error, false is returned.
4357      */
4358     public boolean generateSelfDppConfiguration(@NonNull String ifaceName, @NonNull String ssid,
4359             byte[] privEcKey) {
4360         return mSupplicantStaIfaceHal.generateSelfDppConfiguration(ifaceName, ssid, privEcKey);
4361     }
4362 
4363     /**
4364      * This set anonymous identity to supplicant.
4365      *
4366      * @param ifaceName Name of the interface.
4367      * @param anonymousIdentity the anonymouns identity.
4368      * @return true if succeeds, false otherwise.
4369      */
4370     public boolean setEapAnonymousIdentity(@NonNull String ifaceName, String anonymousIdentity) {
4371         if (null == anonymousIdentity) {
4372             Log.e(TAG, "Cannot set null anonymous identity.");
4373             return false;
4374         }
4375         return mSupplicantStaIfaceHal.setEapAnonymousIdentity(ifaceName, anonymousIdentity);
4376     }
4377 
4378     /**
4379      * Notify wificond daemon of country code have changed.
4380      */
4381     public void countryCodeChanged(String countryCode) {
4382         if (SdkLevel.isAtLeastT()) {
4383             try {
4384                 mWifiCondManager.notifyCountryCodeChanged(countryCode);
4385             } catch (RuntimeException re) {
4386                 Log.e(TAG, "Fail to notify wificond country code changed to " + countryCode
4387                         + "because exception happened:" + re);
4388             }
4389         }
4390     }
4391 
4392     /**
4393      * Save the complete list of features retrieved from WiFi HAL and Supplicant HAL in
4394      * config store.
4395      */
4396     private void saveCompleteFeatureSetInConfigStoreIfNecessary(long featureSet) {
4397         long cachedFeatureSet = getCompleteFeatureSetFromConfigStore();
4398         if (cachedFeatureSet != featureSet) {
4399             mCachedFeatureSet = featureSet;
4400             mWifiInjector.getSettingsConfigStore()
4401                     .put(WIFI_NATIVE_SUPPORTED_FEATURES, mCachedFeatureSet);
4402             Log.i(TAG, "Supported features is updated in config store: " + mCachedFeatureSet);
4403         }
4404     }
4405 
4406     /**
4407      * Get the feature set from cache/config store
4408      */
4409     private long getCompleteFeatureSetFromConfigStore() {
4410         if (mCachedFeatureSet == 0) {
4411             mCachedFeatureSet = mWifiInjector.getSettingsConfigStore()
4412                     .get(WIFI_NATIVE_SUPPORTED_FEATURES);
4413         }
4414         return mCachedFeatureSet;
4415     }
4416 
4417     /**
4418      * Returns whether or not the hostapd HAL supports reporting single instance died event.
4419      */
4420     public boolean isSoftApInstanceDiedHandlerSupported() {
4421         return mHostapdHal.isSoftApInstanceDiedHandlerSupported();
4422     }
4423 }
4424