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