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