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