• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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_DECORATED_IDENTITY;
20 import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP;
21 import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP_ENROLLEE_RESPONDER;
22 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA256;
23 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA384;
24 import static android.net.wifi.WifiManager.WIFI_FEATURE_MBO;
25 import static android.net.wifi.WifiManager.WIFI_FEATURE_OCE;
26 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
27 import static android.net.wifi.WifiManager.WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS;
28 import static android.net.wifi.WifiManager.WIFI_FEATURE_SAE_PK;
29 import static android.net.wifi.WifiManager.WIFI_FEATURE_SET_TLS_MINIMUM_VERSION;
30 import static android.net.wifi.WifiManager.WIFI_FEATURE_TLS_V1_3;
31 import static android.net.wifi.WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE;
32 import static android.net.wifi.WifiManager.WIFI_FEATURE_WAPI;
33 import static android.net.wifi.WifiManager.WIFI_FEATURE_WFD_R2;
34 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
35 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
36 
37 import android.annotation.NonNull;
38 import android.content.Context;
39 import android.hardware.wifi.V1_6.WifiChannelWidthInMhz;
40 import android.hardware.wifi.supplicant.BtCoexistenceMode;
41 import android.hardware.wifi.supplicant.ConnectionCapabilities;
42 import android.hardware.wifi.supplicant.DebugLevel;
43 import android.hardware.wifi.supplicant.DppAkm;
44 import android.hardware.wifi.supplicant.DppCurve;
45 import android.hardware.wifi.supplicant.DppNetRole;
46 import android.hardware.wifi.supplicant.DppResponderBootstrapInfo;
47 import android.hardware.wifi.supplicant.INonStandardCertCallback;
48 import android.hardware.wifi.supplicant.ISupplicant;
49 import android.hardware.wifi.supplicant.ISupplicantStaIface;
50 import android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback;
51 import android.hardware.wifi.supplicant.ISupplicantStaNetwork;
52 import android.hardware.wifi.supplicant.IfaceInfo;
53 import android.hardware.wifi.supplicant.IfaceType;
54 import android.hardware.wifi.supplicant.IpVersion;
55 import android.hardware.wifi.supplicant.KeyMgmtMask;
56 import android.hardware.wifi.supplicant.LegacyMode;
57 import android.hardware.wifi.supplicant.MloLinksInfo;
58 import android.hardware.wifi.supplicant.PortRange;
59 import android.hardware.wifi.supplicant.QosPolicyClassifierParams;
60 import android.hardware.wifi.supplicant.QosPolicyClassifierParamsMask;
61 import android.hardware.wifi.supplicant.QosPolicyData;
62 import android.hardware.wifi.supplicant.QosPolicyRequestType;
63 import android.hardware.wifi.supplicant.QosPolicyScsData;
64 import android.hardware.wifi.supplicant.QosPolicyScsRequestStatus;
65 import android.hardware.wifi.supplicant.QosPolicyScsRequestStatusCode;
66 import android.hardware.wifi.supplicant.QosPolicyStatus;
67 import android.hardware.wifi.supplicant.QosPolicyStatusCode;
68 import android.hardware.wifi.supplicant.RxFilterType;
69 import android.hardware.wifi.supplicant.SignalPollResult;
70 import android.hardware.wifi.supplicant.SupplicantStatusCode;
71 import android.hardware.wifi.supplicant.WifiTechnology;
72 import android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask;
73 import android.hardware.wifi.supplicant.WpsConfigMethods;
74 import android.net.DscpPolicy;
75 import android.net.MacAddress;
76 import android.net.NetworkAgent;
77 import android.net.wifi.QosPolicyParams;
78 import android.net.wifi.ScanResult;
79 import android.net.wifi.SecurityParams;
80 import android.net.wifi.WifiAnnotations;
81 import android.net.wifi.WifiConfiguration;
82 import android.net.wifi.WifiKeystore;
83 import android.net.wifi.WifiSsid;
84 import android.os.Handler;
85 import android.os.IBinder;
86 import android.os.IBinder.DeathRecipient;
87 import android.os.RemoteException;
88 import android.os.ServiceManager;
89 import android.os.ServiceSpecificException;
90 import android.text.TextUtils;
91 import android.util.Log;
92 import android.util.Pair;
93 
94 import com.android.internal.annotations.VisibleForTesting;
95 import com.android.modules.utils.build.SdkLevel;
96 import com.android.server.wifi.util.NativeUtil;
97 
98 import java.nio.ByteBuffer;
99 import java.nio.ByteOrder;
100 import java.util.ArrayList;
101 import java.util.HashMap;
102 import java.util.List;
103 import java.util.Map;
104 import java.util.NoSuchElementException;
105 import java.util.Objects;
106 import java.util.concurrent.CountDownLatch;
107 import java.util.concurrent.TimeUnit;
108 import java.util.regex.Matcher;
109 import java.util.regex.Pattern;
110 
111 /**
112  * HAL calls to set up/tear down the supplicant daemon and make requests
113  * related to station mode. Uses the AIDL supplicant interface.
114  * To maintain thread-safety, the locking protocol is that every non-static method (regardless of
115  * access level) acquires mLock.
116  */
117 public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal {
118     private static final String TAG = "SupplicantStaIfaceHalAidlImpl";
119     @VisibleForTesting
120     private static final String HAL_INSTANCE_NAME = ISupplicant.DESCRIPTOR + "/default";
121     @VisibleForTesting
122     public static final long WAIT_FOR_DEATH_TIMEOUT_MS = 50L;
123 
124     /**
125      * Regex pattern for extracting the wps device type bytes.
126      * Matches a strings like the following: "<categ>-<OUI>-<subcateg>";
127      */
128     private static final Pattern WPS_DEVICE_TYPE_PATTERN =
129             Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$");
130 
131     private final Object mLock = new Object();
132     private boolean mVerboseLoggingEnabled = false;
133     private boolean mVerboseHalLoggingEnabled = false;
134     private boolean mServiceDeclared = false;
135     private int mServiceVersion = -1;
136 
137     // Supplicant HAL interface objects
138     private ISupplicant mISupplicant = null;
139     private Map<String, ISupplicantStaIface> mISupplicantStaIfaces = new HashMap<>();
140     private Map<String, ISupplicantStaIfaceCallback>
141             mISupplicantStaIfaceCallbacks = new HashMap<>();
142     private Map<String, SupplicantStaNetworkHalAidlImpl>
143             mCurrentNetworkRemoteHandles = new HashMap<>();
144     private Map<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>();
145     private Map<String, WifiSsid> mCurrentNetworkFallbackSsids = new HashMap<>();
146     private Map<String, List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>>>
147             mLinkedNetworkLocalAndRemoteConfigs = new HashMap<>();
148     @VisibleForTesting
149     PmkCacheManager mPmkCacheManager;
150     private WifiNative.SupplicantDeathEventHandler mDeathEventHandler;
151     private SupplicantDeathRecipient mSupplicantDeathRecipient;
152     private final Context mContext;
153     private final WifiMonitor mWifiMonitor;
154     private final Handler mEventHandler;
155     private WifiNative.DppEventCallback mDppCallback = null;
156     private final Clock mClock;
157     private final WifiMetrics mWifiMetrics;
158     private final WifiGlobals mWifiGlobals;
159     private final SsidTranslator mSsidTranslator;
160     private final WifiInjector mWifiInjector;
161     private CountDownLatch mWaitForDeathLatch;
162     private INonStandardCertCallback mNonStandardCertCallback;
163     private SupplicantStaIfaceHal.QosScsResponseCallback mQosScsResponseCallback;
164 
165     private class SupplicantDeathRecipient implements DeathRecipient {
166         @Override
binderDied()167         public void binderDied() {
168         }
169 
170         @Override
binderDied(@onNull IBinder who)171         public void binderDied(@NonNull IBinder who) {
172             synchronized (mLock) {
173                 IBinder supplicantBinder = getServiceBinderMockable();
174                 Log.w(TAG, "ISupplicant binder died. who=" + who + ", service="
175                         + supplicantBinder);
176                 if (supplicantBinder == null) {
177                     Log.w(TAG, "Supplicant Death EventHandler called"
178                             + " when ISupplicant/binder service is already cleared");
179                 } else if (supplicantBinder != who) {
180                     Log.w(TAG, "Ignoring stale death recipient notification");
181                     return;
182                 }
183                 if (mWaitForDeathLatch != null) {
184                     mWaitForDeathLatch.countDown();
185                 }
186                 Log.w(TAG, "Handle supplicant death");
187                 supplicantServiceDiedHandler();
188             }
189         }
190     }
191 
SupplicantStaIfaceHalAidlImpl(Context context, WifiMonitor monitor, Handler handler, Clock clock, WifiMetrics wifiMetrics, WifiGlobals wifiGlobals, @NonNull SsidTranslator ssidTranslator, WifiInjector wifiInjector)192     public SupplicantStaIfaceHalAidlImpl(Context context, WifiMonitor monitor, Handler handler,
193             Clock clock, WifiMetrics wifiMetrics, WifiGlobals wifiGlobals,
194             @NonNull SsidTranslator ssidTranslator, WifiInjector wifiInjector) {
195         mContext = context;
196         mWifiMonitor = monitor;
197         mEventHandler = handler;
198         mClock = clock;
199         mWifiMetrics = wifiMetrics;
200         mWifiGlobals = wifiGlobals;
201         mSsidTranslator = ssidTranslator;
202         mSupplicantDeathRecipient = new SupplicantDeathRecipient();
203         mPmkCacheManager = new PmkCacheManager(mClock, mEventHandler);
204         mWifiInjector = wifiInjector;
205     }
206 
207     /**
208      * Enable/Disable verbose logging.
209      *
210      */
enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)211     public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) {
212         synchronized (mLock) {
213             mVerboseLoggingEnabled = verboseEnabled;
214             mVerboseHalLoggingEnabled = halVerboseEnabled;
215             setLogLevel(mVerboseHalLoggingEnabled);
216         }
217     }
218 
isVerboseLoggingEnabled()219     protected boolean isVerboseLoggingEnabled() {
220         synchronized (mLock) {
221             return mVerboseLoggingEnabled;
222         }
223     }
224 
225     /**
226      * Checks whether the ISupplicant service is declared, and therefore should be available.
227      *
228      * @return true if the ISupplicant service is declared
229      */
initialize()230     public boolean initialize() {
231         synchronized (mLock) {
232             if (mISupplicant != null) {
233                 Log.i(TAG, "Service is already initialized, skipping initialize method");
234                 return true;
235             }
236             if (mVerboseLoggingEnabled) {
237                 Log.i(TAG, "Checking for ISupplicant service.");
238             }
239             mISupplicantStaIfaces.clear();
240             mServiceDeclared = serviceDeclared();
241             return mServiceDeclared;
242         }
243     }
244 
getCurrentNetworkId(@onNull String ifaceName)245     protected int getCurrentNetworkId(@NonNull String ifaceName) {
246         synchronized (mLock) {
247             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
248             if (currentConfig == null) {
249                 return WifiConfiguration.INVALID_NETWORK_ID;
250             }
251             return currentConfig.networkId;
252         }
253     }
254 
255     /**
256      * Setup a STA interface for the specified iface name.
257      *
258      * @param ifaceName Name of the interface.
259      * @return true on success, false otherwise.
260      */
setupIface(@onNull String ifaceName)261     public boolean setupIface(@NonNull String ifaceName) {
262         synchronized (mLock) {
263             if (getStaIface(ifaceName) != null) {
264                 Log.e(TAG, "Iface " + ifaceName + " already exists.");
265                 return false;
266             }
267 
268             ISupplicantStaIface iface = addIface(ifaceName);
269             if (iface == null) {
270                 Log.e(TAG, "Unable to add iface " + ifaceName);
271                 return false;
272             }
273 
274             ISupplicantStaIfaceCallback callback = new SupplicantStaIfaceCallbackAidlImpl(
275                     SupplicantStaIfaceHalAidlImpl.this, ifaceName,
276                     new Object(), mContext, mWifiMonitor, mSsidTranslator);
277             if (registerCallback(iface, callback)) {
278                 mISupplicantStaIfaces.put(ifaceName, iface);
279                 // Keep callback in a store to avoid recycling by garbage collector
280                 mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
281                 return true;
282             } else {
283                 Log.e(TAG, "Unable to register callback for iface " + ifaceName);
284                 return false;
285             }
286         }
287     }
288 
289     /**
290      * Create a STA interface for the specified iface name.
291      *
292      * @param ifaceName Name of the interface.
293      * @return ISupplicantStaIface object on success, null otherwise.
294      */
addIface(@onNull String ifaceName)295     private ISupplicantStaIface addIface(@NonNull String ifaceName) {
296         synchronized (mLock) {
297             String methodStr = "addIface";
298             if (!checkSupplicantAndLogFailure(methodStr)) {
299                 return null;
300             }
301             try {
302                 return mISupplicant.addStaInterface(ifaceName);
303             } catch (RemoteException e) {
304                 handleRemoteException(e, methodStr);
305             } catch (ServiceSpecificException e) {
306                 handleServiceSpecificException(e, methodStr);
307             } catch (NoSuchElementException | IllegalArgumentException e) {
308                 Log.e(TAG, "Encountered exception at addIface: ", e);
309             }
310             return null;
311         }
312     }
313 
314     /**
315      * Teardown a STA interface for the specified iface name.
316      *
317      * @param ifaceName Name of the interface.
318      * @return true on success, false otherwise.
319      */
teardownIface(@onNull String ifaceName)320     public boolean teardownIface(@NonNull String ifaceName) {
321         synchronized (mLock) {
322             final String methodStr = "teardownIface";
323             if (checkStaIfaceAndLogFailure(ifaceName, methodStr) == null) {
324                 return false;
325             }
326             if (!checkSupplicantAndLogFailure(methodStr)) {
327                 return false;
328             }
329 
330             try {
331                 IfaceInfo ifaceInfo = new IfaceInfo();
332                 ifaceInfo.name = ifaceName;
333                 ifaceInfo.type = IfaceType.STA;
334                 mISupplicant.removeInterface(ifaceInfo);
335                 mISupplicantStaIfaces.remove(ifaceName);
336                 mISupplicantStaIfaceCallbacks.remove(ifaceName);
337                 return true;
338             } catch (RemoteException e) {
339                 handleRemoteException(e, methodStr);
340             } catch (ServiceSpecificException e) {
341                 handleServiceSpecificException(e, methodStr);
342             } catch (NoSuchElementException e) {
343                 Log.e(TAG, "Encountered exception at teardownIface: ", e);
344             }
345             return false;
346         }
347     }
348 
349     /**
350      * Registers a death notification for supplicant.
351      * @return Returns true on success.
352      */
registerDeathHandler(@onNull WifiNative.SupplicantDeathEventHandler handler)353     public boolean registerDeathHandler(@NonNull WifiNative.SupplicantDeathEventHandler handler) {
354         synchronized (mLock) {
355             if (mDeathEventHandler != null) {
356                 Log.e(TAG, "Death handler already present");
357             }
358             mDeathEventHandler = handler;
359             return true;
360         }
361     }
362 
363     /**
364      * Deregisters a death notification for supplicant.
365      * @return Returns true on success.
366      */
deregisterDeathHandler()367     public boolean deregisterDeathHandler() {
368         synchronized (mLock) {
369             if (mDeathEventHandler == null) {
370                 Log.e(TAG, "No Death handler present");
371             }
372             mDeathEventHandler = null;
373             return true;
374         }
375     }
376 
377     /**
378      * Signals whether initialization started successfully.
379      */
isInitializationStarted()380     public boolean isInitializationStarted() {
381         synchronized (mLock) {
382             return mServiceDeclared;
383         }
384     }
385 
386     /**
387      * Signals whether initialization completed successfully.
388      */
isInitializationComplete()389     public boolean isInitializationComplete() {
390         synchronized (mLock) {
391             return mISupplicant != null;
392         }
393     }
394 
395     /**
396      * Indicates whether the AIDL service is declared
397      */
serviceDeclared()398     public static boolean serviceDeclared() {
399         // Service Manager API ServiceManager#isDeclared supported after T.
400         if (!SdkLevel.isAtLeastT()) {
401             return false;
402         }
403         return ServiceManager.isDeclared(HAL_INSTANCE_NAME);
404     }
405 
406     /**
407      * Check that the service is running at least the expected version.
408      * Use to avoid the case where the framework is using a newer
409      * interface version than the service.
410      */
isServiceVersionAtLeast(int expectedVersion)411     protected boolean isServiceVersionAtLeast(int expectedVersion) {
412         return expectedVersion <= mServiceVersion;
413     }
414 
clearState()415     private void clearState() {
416         synchronized (mLock) {
417             Log.i(TAG, "Clearing internal state");
418             mISupplicant = null;
419             mISupplicantStaIfaces.clear();
420             mCurrentNetworkLocalConfigs.clear();
421             mCurrentNetworkRemoteHandles.clear();
422             mLinkedNetworkLocalAndRemoteConfigs.clear();
423             mNonStandardCertCallback = null;
424         }
425     }
426 
supplicantServiceDiedHandler()427     private void supplicantServiceDiedHandler() {
428         synchronized (mLock) {
429             clearState();
430             if (mDeathEventHandler != null) {
431                 mDeathEventHandler.onDeath();
432             }
433         }
434     }
435 
436     /**
437      * Start the supplicant daemon.
438      *
439      * @return true on success, false otherwise.
440      */
startDaemon()441     public boolean startDaemon() {
442         synchronized (mLock) {
443             final String methodStr = "startDaemon";
444             if (mISupplicant != null) {
445                 Log.i(TAG, "Service is already initialized, skipping " + methodStr);
446                 return true;
447             }
448 
449             clearState();
450             mISupplicant = getSupplicantMockable();
451             if (mISupplicant == null) {
452                 Log.e(TAG, "Unable to obtain ISupplicant binder.");
453                 return false;
454             }
455             Log.i(TAG, "Obtained ISupplicant binder.");
456             Log.i(TAG, "Local Version: " + ISupplicant.VERSION);
457 
458             try {
459                 getServiceVersion();
460                 Log.i(TAG, "Remote Version: " + mServiceVersion);
461                 IBinder serviceBinder = getServiceBinderMockable();
462                 if (serviceBinder == null) {
463                     return false;
464                 }
465                 mWaitForDeathLatch = null;
466                 serviceBinder.linkToDeath(mSupplicantDeathRecipient, /* flags= */  0);
467                 setLogLevel(mVerboseHalLoggingEnabled);
468                 registerNonStandardCertCallback();
469                 return true;
470             } catch (RemoteException e) {
471                 handleRemoteException(e, methodStr);
472                 return false;
473             }
474         }
475     }
476 
getServiceVersion()477     private void getServiceVersion() throws RemoteException {
478         synchronized (mLock) {
479             if (mISupplicant == null) return;
480             if (mServiceVersion == -1) {
481                 int serviceVersion = mISupplicant.getInterfaceVersion();
482                 mWifiInjector.getSettingsConfigStore().put(
483                         WifiSettingsConfigStore.SUPPLICANT_HAL_AIDL_SERVICE_VERSION,
484                         serviceVersion);
485                 mServiceVersion = serviceVersion;
486                 Log.i(TAG, "Remote service version was cached");
487             }
488         }
489     }
490 
491     /**
492      * Terminate the supplicant daemon & wait for its death.
493      */
terminate()494     public void terminate() {
495         synchronized (mLock) {
496             final String methodStr = "terminate";
497             if (!checkSupplicantAndLogFailure(methodStr)) {
498                 return;
499             }
500             Log.i(TAG, "Terminate supplicant service");
501             try {
502                 mWaitForDeathLatch = new CountDownLatch(1);
503                 mISupplicant.terminate();
504             } catch (RemoteException e) {
505                 handleRemoteException(e, methodStr);
506             }
507         }
508 
509         // Wait for death recipient to confirm the service death.
510         try {
511             if (!mWaitForDeathLatch.await(WAIT_FOR_DEATH_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
512                 Log.w(TAG, "Timed out waiting for confirmation of supplicant death");
513             } else {
514                 Log.d(TAG, "Got service death confirmation");
515             }
516         } catch (InterruptedException e) {
517             Log.w(TAG, "Failed to wait for supplicant death");
518         }
519     }
520 
521     /**
522      * Wrapper functions to access HAL objects, created to be mockable in unit tests
523      */
524     @VisibleForTesting
getSupplicantMockable()525     protected ISupplicant getSupplicantMockable() {
526         synchronized (mLock) {
527             try {
528                 if (SdkLevel.isAtLeastT()) {
529                     return ISupplicant.Stub.asInterface(
530                             ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME));
531                 } else {
532                     return null;
533                 }
534             } catch (Exception e) {
535                 Log.e(TAG, "Unable to get ISupplicant service, " + e);
536                 return null;
537             }
538         }
539     }
540 
541     @VisibleForTesting
getServiceBinderMockable()542     protected IBinder getServiceBinderMockable() {
543         synchronized (mLock) {
544             if (mISupplicant == null) {
545                 return null;
546             }
547             return mISupplicant.asBinder();
548         }
549     }
550 
551     /**
552      * Helper method to look up the specified iface.
553      */
getStaIface(@onNull String ifaceName)554     private ISupplicantStaIface getStaIface(@NonNull String ifaceName) {
555         synchronized (mLock) {
556             return mISupplicantStaIfaces.get(ifaceName);
557         }
558     }
559 
560     /**
561      * Helper method to look up the network object for the specified iface.
562      */
getCurrentNetworkRemoteHandle( @onNull String ifaceName)563     private SupplicantStaNetworkHalAidlImpl getCurrentNetworkRemoteHandle(
564             @NonNull String ifaceName) {
565         synchronized (mLock) {
566             return mCurrentNetworkRemoteHandles.get(ifaceName);
567         }
568     }
569 
570     /**
571      * Helper method to look up the network config for the specified iface.
572      */
getCurrentNetworkLocalConfig(@onNull String ifaceName)573     protected WifiConfiguration getCurrentNetworkLocalConfig(@NonNull String ifaceName) {
574         synchronized (mLock) {
575             return mCurrentNetworkLocalConfigs.get(ifaceName);
576         }
577     }
578 
579     /**
580      * Add a network configuration to wpa_supplicant.
581      *
582      * @param config Config corresponding to the network.
583      * @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects
584      * for the current network.
585      */
586     private Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>
addNetworkAndSaveConfig(@onNull String ifaceName, WifiConfiguration config)587             addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) {
588         synchronized (mLock) {
589             if (config == null) {
590                 Log.e(TAG, "Cannot add null network.");
591                 return null;
592             }
593             SupplicantStaNetworkHalAidlImpl network = addNetwork(ifaceName);
594             if (network == null) {
595                 Log.e(TAG, "Failed to add network.");
596                 return null;
597             }
598             boolean saveSuccess = false;
599             try {
600                 saveSuccess = network.saveWifiConfiguration(config);
601             } catch (IllegalArgumentException e) {
602                 Log.e(TAG, "Exception while saving config params: " + config, e);
603             }
604             if (!saveSuccess) {
605                 Log.e(TAG, "Failed to save variables for: " + config.getProfileKey());
606                 if (!removeAllNetworks(ifaceName)) {
607                     Log.e(TAG, "Failed to remove all networks on failure.");
608                 }
609                 return null;
610             }
611             return new Pair(network, new WifiConfiguration(config));
612         }
613     }
614 
615     /**
616      * Add the provided network configuration to wpa_supplicant and initiate connection to it.
617      * This method does the following:
618      * 1. If |config| is different to the current supplicant network, removes all supplicant
619      * networks and saves |config|.
620      * 2. Select the new network in wpa_supplicant.
621      *
622      * @param ifaceName Name of the interface.
623      * @param config WifiConfiguration parameters for the provided network.
624      * @return true if it succeeds, false otherwise
625      */
connectToNetwork(@onNull String ifaceName, @NonNull WifiConfiguration config)626     public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
627         return connectToNetwork(ifaceName, config, null);
628     }
629 
630     /**
631      * Connects to the fallback SSID (if any) of the current network upon a network not found
632      * notification.
633      */
connectToFallbackSsid(@onNull String ifaceName)634     public boolean connectToFallbackSsid(@NonNull String ifaceName) {
635         synchronized (mLock) {
636             WifiSsid fallbackSsid = mCurrentNetworkFallbackSsids.remove(ifaceName);
637             if (fallbackSsid == null) {
638                 return false;
639             }
640             Log.d(TAG, "connectToFallbackSsid " + fallbackSsid);
641             return connectToNetwork(
642                     ifaceName, getCurrentNetworkLocalConfig(ifaceName), fallbackSsid);
643         }
644     }
645 
646     /**
647      * Add the provided network configuration to wpa_supplicant and initiate connection to it.
648      * This method does the following:
649      * 1. If |config| is different to the current supplicant network, removes all supplicant
650      * networks and saves |config|.
651      * 2. Selects an SSID from the 2 possible original SSIDs derived from config.SSID to pass to
652      *    wpa_supplicant, and stores the unused one as fallback if the first one is not found.
653      * 3. Select the new network in wpa_supplicant.
654      *
655      * @param ifaceName Name of the interface.
656      * @param config WifiConfiguration parameters for the provided network.
657      * @param actualSsid The actual, untranslated SSID to send to supplicant. If this is null, then
658      *                   we will connect to either of the 2 possible original SSIDs based on the
659      *                   config's network selection BSSID or network selection candidate. If that
660      *                   SSID is not found, then we will immediately connect to the other one.
661      * @return true if it succeeds, false otherwise
662      */
connectToNetwork(@onNull String ifaceName, @NonNull WifiConfiguration config, WifiSsid actualSsid)663     private boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config,
664             WifiSsid actualSsid) {
665         synchronized (mLock) {
666             Log.d(TAG, "connectToNetwork " + config.getProfileKey() + ", actualSsid=" + actualSsid);
667             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
668             if (actualSsid == null && WifiConfigurationUtil.isSameNetwork(config, currentConfig)) {
669                 String networkSelectionBSSID = config.getNetworkSelectionStatus()
670                         .getNetworkSelectionBSSID();
671                 String networkSelectionBSSIDCurrent = currentConfig.getNetworkSelectionStatus()
672                         .getNetworkSelectionBSSID();
673                 if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
674                     Log.d(TAG, "Network is already saved, will not trigger remove and add.");
675                 } else {
676                     Log.d(TAG, "Network is already saved, but need to update BSSID.");
677                     if (!setCurrentNetworkBssid(
678                             ifaceName,
679                             config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
680                         Log.e(TAG, "Failed to set current network BSSID.");
681                         return false;
682                     }
683                     mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
684                 }
685             } else {
686                 mCurrentNetworkRemoteHandles.remove(ifaceName);
687                 mCurrentNetworkLocalConfigs.remove(ifaceName);
688                 mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
689                 mCurrentNetworkFallbackSsids.remove(ifaceName);
690                 if (!removeAllNetworks(ifaceName)) {
691                     Log.e(TAG, "Failed to remove existing networks");
692                     return false;
693                 }
694                 WifiConfiguration supplicantConfig = new WifiConfiguration(config);
695                 if (actualSsid != null) {
696                     supplicantConfig.SSID = actualSsid.toString();
697                 } else {
698                     if (config.SSID != null) {
699                         // No actual SSID supplied, so select from the network selection BSSID
700                         // or the latest candidate BSSID.
701                         WifiSsid configSsid = WifiSsid.fromString(config.SSID);
702                         WifiSsid supplicantSsid = mSsidTranslator.getOriginalSsid(config);
703                         if (supplicantSsid != null) {
704                             supplicantConfig.SSID = supplicantSsid.toString();
705                             List<WifiSsid> allPossibleSsids = mSsidTranslator
706                                     .getAllPossibleOriginalSsids(configSsid);
707                             WifiSsid selectedSsid = mSsidTranslator.getOriginalSsid(config);
708                             allPossibleSsids.remove(selectedSsid);
709                             if (!allPossibleSsids.isEmpty()) {
710                                 // Store the unused SSID to fallback on in
711                                 // connectToFallbackSsid(String) if the chosen SSID isn't found.
712                                 mCurrentNetworkFallbackSsids.put(
713                                         ifaceName, allPossibleSsids.get(0));
714                             }
715                             Log.d(TAG, "Selecting supplicant SSID " + supplicantSsid);
716                             supplicantConfig.SSID = supplicantSsid.toString();
717                         }
718                         // Set the actual translation of the original SSID in case the untranslated
719                         // SSID has an ambiguous encoding.
720                         mSsidTranslator.setTranslatedSsidForStaIface(configSsid, ifaceName);
721                     }
722                 }
723                 Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair =
724                         addNetworkAndSaveConfig(ifaceName, supplicantConfig);
725                 if (pair == null) {
726                     Log.e(TAG, "Failed to add/save network configuration: " + config
727                             .getProfileKey());
728                     return false;
729                 }
730                 mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
731                 mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
732             }
733 
734             SupplicantStaNetworkHalAidlImpl networkHandle =
735                     checkStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
736             if (networkHandle == null) {
737                 Log.e(TAG, "No valid remote network handle for network configuration: "
738                         + config.getProfileKey());
739                 return false;
740             }
741 
742             SecurityParams params = config.getNetworkSelectionStatus()
743                     .getCandidateSecurityParams();
744             if (params != null && !(params.isSecurityType(WifiConfiguration.SECURITY_TYPE_PSK)
745                     || params.isSecurityType(WifiConfiguration.SECURITY_TYPE_DPP))) {
746                 List<ArrayList<Byte>> pmkDataList = mPmkCacheManager.get(config.networkId);
747                 if (pmkDataList != null) {
748                     Log.i(TAG, "Set PMK cache for config id " + config.networkId);
749                     pmkDataList.forEach(pmkData -> {
750                         if (networkHandle.setPmkCache(NativeUtil.byteArrayFromArrayList(pmkData))) {
751                             mWifiMetrics.setConnectionPmkCache(ifaceName, true);
752                         }
753                     });
754                 }
755             }
756 
757             if (!networkHandle.select()) {
758                 Log.e(TAG, "Failed to select network configuration: " + config.getProfileKey());
759                 return false;
760             }
761             return true;
762         }
763     }
764 
765     /**
766      * Initiates roaming to the already configured network in wpa_supplicant. If the network
767      * configuration provided does not match the already configured network, then this triggers
768      * a new connection attempt (instead of roam).
769      * 1. First check if we're attempting to connect to a linked network, and select the existing
770      *    supplicant network if there is one.
771      * 2. Set the new bssid for the network in wpa_supplicant.
772      * 3. Trigger reassociate command to wpa_supplicant.
773      *
774      * @param ifaceName Name of the interface.
775      * @param config WifiConfiguration parameters for the provided network.
776      * @return {@code true} if it succeeds, {@code false} otherwise
777      */
roamToNetwork(@onNull String ifaceName, WifiConfiguration config)778     public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration config) {
779         synchronized (mLock) {
780             if (updateOnLinkedNetworkRoaming(ifaceName, config.networkId, true)) {
781                 SupplicantStaNetworkHalAidlImpl networkHandle =
782                         getCurrentNetworkRemoteHandle(ifaceName);
783                 if (networkHandle == null) {
784                     Log.e(TAG, "Roaming config matches a linked config, "
785                             + "but a linked network handle was not found.");
786                     return false;
787                 }
788                 return networkHandle.select();
789             }
790             if (getCurrentNetworkId(ifaceName) != config.networkId) {
791                 Log.w(TAG, "Cannot roam to a different network, initiate new connection. "
792                         + "Current network ID: " + getCurrentNetworkId(ifaceName));
793                 return connectToNetwork(ifaceName, config);
794             }
795             String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
796             Log.d(TAG, "roamToNetwork" + config.getProfileKey() + " (bssid " + bssid + ")");
797 
798             SupplicantStaNetworkHalAidlImpl networkHandle =
799                     checkStaNetworkAndLogFailure(ifaceName, "roamToNetwork");
800             if (networkHandle == null || !networkHandle.setBssid(bssid)) {
801                 Log.e(TAG, "Failed to set new bssid on network: " + config.getProfileKey());
802                 return false;
803             }
804             if (!reassociate(ifaceName)) {
805                 Log.e(TAG, "Failed to trigger reassociate");
806                 return false;
807             }
808             return true;
809         }
810     }
811 
812     /**
813      * Clean HAL cached data for |networkId| in the framework.
814      *
815      * @param networkId network id of the network to be removed from supplicant.
816      */
removeNetworkCachedData(int networkId)817     public void removeNetworkCachedData(int networkId) {
818         synchronized (mLock) {
819             Log.d(TAG, "Remove cached HAL data for config id " + networkId);
820             removePmkCacheEntry(networkId);
821         }
822     }
823 
824 
825     /**
826      * Clear HAL cached data if MAC address is changed.
827      *
828      * @param networkId network id of the network to be checked.
829      * @param curMacAddress current MAC address
830      */
removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress)831     public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) {
832         synchronized (mLock) {
833             mPmkCacheManager.remove(networkId, curMacAddress);
834         }
835     }
836 
837     /**
838      * Remove all networks from supplicant
839      *
840      * @param ifaceName Name of the interface.
841      */
removeAllNetworks(@onNull String ifaceName)842     public boolean removeAllNetworks(@NonNull String ifaceName) {
843         synchronized (mLock) {
844             int[] networks = listNetworks(ifaceName);
845             if (networks == null) {
846                 Log.e(TAG, "removeAllNetworks failed, got null networks");
847                 return false;
848             }
849             for (int id : networks) {
850                 if (!removeNetwork(ifaceName, id)) {
851                     Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
852                     return false;
853                 }
854             }
855             // Reset current network info.
856             mCurrentNetworkRemoteHandles.remove(ifaceName);
857             mCurrentNetworkLocalConfigs.remove(ifaceName);
858             mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
859             return true;
860         }
861     }
862 
863     /**
864      * Disable the current network in supplicant
865      *
866      * @param ifaceName Name of the interface.
867      */
disableCurrentNetwork(@onNull String ifaceName)868     public boolean disableCurrentNetwork(@NonNull String ifaceName) {
869         synchronized (mLock) {
870             SupplicantStaNetworkHalAidlImpl networkHandle =
871                     checkStaNetworkAndLogFailure(ifaceName, "disableCurrentNetwork");
872             if (networkHandle == null) {
873                 return false;
874             }
875             return networkHandle.disable();
876         }
877     }
878 
879     /**
880      * Set the currently configured network's bssid.
881      *
882      * @param ifaceName Name of the interface.
883      * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX"
884      * @return true if succeeds, false otherwise.
885      */
setCurrentNetworkBssid(@onNull String ifaceName, String bssidStr)886     public boolean setCurrentNetworkBssid(@NonNull String ifaceName, String bssidStr) {
887         synchronized (mLock) {
888             SupplicantStaNetworkHalAidlImpl networkHandle =
889                     checkStaNetworkAndLogFailure(ifaceName, "setCurrentNetworkBssid");
890             if (networkHandle == null) {
891                 return false;
892             }
893             return networkHandle.setBssid(bssidStr);
894         }
895     }
896 
897     /**
898      * Get the currently configured network's WPS NFC token.
899      *
900      * @param ifaceName Name of the interface.
901      * @return Hex string corresponding to the WPS NFC token.
902      */
getCurrentNetworkWpsNfcConfigurationToken(@onNull String ifaceName)903     public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
904         synchronized (mLock) {
905             SupplicantStaNetworkHalAidlImpl networkHandle =
906                     checkStaNetworkAndLogFailure(
907                             ifaceName, "getCurrentNetworkWpsNfcConfigurationToken");
908             if (networkHandle == null) {
909                 return null;
910             }
911             return networkHandle.getWpsNfcConfigurationToken();
912         }
913     }
914 
915     /**
916      * Get the eap anonymous identity for the currently configured network.
917      *
918      * @param ifaceName Name of the interface.
919      * @return anonymous identity string if succeeds, null otherwise.
920      */
getCurrentNetworkEapAnonymousIdentity(@onNull String ifaceName)921     public String getCurrentNetworkEapAnonymousIdentity(@NonNull String ifaceName) {
922         synchronized (mLock) {
923             SupplicantStaNetworkHalAidlImpl networkHandle =
924                     checkStaNetworkAndLogFailure(
925                             ifaceName, "getCurrentNetworkEapAnonymousIdentity");
926             if (networkHandle == null) {
927                 return null;
928             }
929             return networkHandle.fetchEapAnonymousIdentity();
930         }
931     }
932 
933     /**
934      * Send the eap identity response for the currently configured network.
935      *
936      * @param ifaceName Name of the interface.
937      * @param identity identity used for EAP-Identity
938      * @param encryptedIdentity encrypted identity used for EAP-AKA/EAP-SIM
939      * @return true if succeeds, false otherwise.
940      */
sendCurrentNetworkEapIdentityResponse( @onNull String ifaceName, @NonNull String identity, String encryptedIdentity)941     public boolean sendCurrentNetworkEapIdentityResponse(
942             @NonNull String ifaceName, @NonNull String identity, String encryptedIdentity) {
943         synchronized (mLock) {
944             SupplicantStaNetworkHalAidlImpl networkHandle =
945                     checkStaNetworkAndLogFailure(
946                             ifaceName, "sendCurrentNetworkEapIdentityResponse");
947             if (networkHandle == null) {
948                 return false;
949             }
950             return networkHandle.sendNetworkEapIdentityResponse(identity, encryptedIdentity);
951         }
952     }
953 
954     /**
955      * Send the eap sim gsm auth response for the currently configured network.
956      *
957      * @param ifaceName Name of the interface.
958      * @param paramsStr String to send.
959      * @return true if succeeds, false otherwise.
960      */
sendCurrentNetworkEapSimGsmAuthResponse( @onNull String ifaceName, String paramsStr)961     public boolean sendCurrentNetworkEapSimGsmAuthResponse(
962             @NonNull String ifaceName, String paramsStr) {
963         synchronized (mLock) {
964             SupplicantStaNetworkHalAidlImpl networkHandle =
965                     checkStaNetworkAndLogFailure(
966                             ifaceName, "sendCurrentNetworkEapSimGsmAuthResponse");
967             if (networkHandle == null) {
968                 return false;
969             }
970             return networkHandle.sendNetworkEapSimGsmAuthResponse(paramsStr);
971         }
972     }
973 
974     /**
975      * Send the eap sim gsm auth failure for the currently configured network.
976      *
977      * @param ifaceName Name of the interface.
978      * @return true if succeeds, false otherwise.
979      */
sendCurrentNetworkEapSimGsmAuthFailure(@onNull String ifaceName)980     public boolean sendCurrentNetworkEapSimGsmAuthFailure(@NonNull String ifaceName) {
981         synchronized (mLock) {
982             SupplicantStaNetworkHalAidlImpl networkHandle =
983                     checkStaNetworkAndLogFailure(
984                             ifaceName, "sendCurrentNetworkEapSimGsmAuthFailure");
985             if (networkHandle == null) {
986                 return false;
987             }
988             return networkHandle.sendNetworkEapSimGsmAuthFailure();
989         }
990     }
991 
992     /**
993      * Send the eap sim umts auth response for the currently configured network.
994      *
995      * @param ifaceName Name of the interface.
996      * @param paramsStr String to send.
997      * @return true if succeeds, false otherwise.
998      */
sendCurrentNetworkEapSimUmtsAuthResponse( @onNull String ifaceName, String paramsStr)999     public boolean sendCurrentNetworkEapSimUmtsAuthResponse(
1000             @NonNull String ifaceName, String paramsStr) {
1001         synchronized (mLock) {
1002             SupplicantStaNetworkHalAidlImpl networkHandle =
1003                     checkStaNetworkAndLogFailure(
1004                             ifaceName, "sendCurrentNetworkEapSimUmtsAuthResponse");
1005             if (networkHandle == null) {
1006                 return false;
1007             }
1008             return networkHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr);
1009         }
1010     }
1011 
1012     /**
1013      * Send the eap sim umts auts response for the currently configured network.
1014      *
1015      * @param ifaceName Name of the interface.
1016      * @param paramsStr String to send.
1017      * @return true if succeeds, false otherwise.
1018      */
sendCurrentNetworkEapSimUmtsAutsResponse( @onNull String ifaceName, String paramsStr)1019     public boolean sendCurrentNetworkEapSimUmtsAutsResponse(
1020             @NonNull String ifaceName, String paramsStr) {
1021         synchronized (mLock) {
1022             SupplicantStaNetworkHalAidlImpl networkHandle =
1023                     checkStaNetworkAndLogFailure(
1024                             ifaceName, "sendCurrentNetworkEapSimUmtsAutsResponse");
1025             if (networkHandle == null) {
1026                 return false;
1027             }
1028             return networkHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr);
1029         }
1030     }
1031 
1032     /**
1033      * Send the eap sim umts auth failure for the currently configured network.
1034      *
1035      * @param ifaceName Name of the interface.
1036      * @return true if succeeds, false otherwise.
1037      */
sendCurrentNetworkEapSimUmtsAuthFailure(@onNull String ifaceName)1038     public boolean sendCurrentNetworkEapSimUmtsAuthFailure(@NonNull String ifaceName) {
1039         synchronized (mLock) {
1040             SupplicantStaNetworkHalAidlImpl networkHandle =
1041                     checkStaNetworkAndLogFailure(
1042                             ifaceName, "sendCurrentNetworkEapSimUmtsAuthFailure");
1043             if (networkHandle == null) {
1044                 return false;
1045             }
1046             return networkHandle.sendNetworkEapSimUmtsAuthFailure();
1047         }
1048     }
1049 
1050     /**
1051      * Adds a new network.
1052      *
1053      * @return SupplicantStaNetworkHalAidlImpl object for the new network, or null if the call fails
1054      */
addNetwork(@onNull String ifaceName)1055     private SupplicantStaNetworkHalAidlImpl addNetwork(@NonNull String ifaceName) {
1056         synchronized (mLock) {
1057             final String methodStr = "addNetwork";
1058             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1059             if (iface == null) {
1060                 return null;
1061             }
1062             try {
1063                 ISupplicantStaNetwork network = iface.addNetwork();
1064                 // Get framework wrapper around the AIDL network object
1065                 return getStaNetworkHalMockable(ifaceName, network);
1066             } catch (RemoteException e) {
1067                 handleRemoteException(e, methodStr);
1068             } catch (ServiceSpecificException e) {
1069                 handleServiceSpecificException(e, methodStr);
1070             }
1071             return null;
1072         }
1073     }
1074 
1075     /**
1076      * Remove network with specified network Id from supplicant.
1077      *
1078      * @return true if request is sent successfully, false otherwise.
1079      */
removeNetwork(@onNull String ifaceName, int id)1080     private boolean removeNetwork(@NonNull String ifaceName, int id) {
1081         synchronized (mLock) {
1082             final String methodStr = "removeNetwork";
1083             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1084             if (iface == null) {
1085                 return false;
1086             }
1087             try {
1088                 iface.removeNetwork(id);
1089                 return true;
1090             } catch (RemoteException e) {
1091                 handleRemoteException(e, methodStr);
1092             } catch (ServiceSpecificException e) {
1093                 handleServiceSpecificException(e, methodStr);
1094             }
1095             return false;
1096         }
1097     }
1098 
1099     /**
1100      * Creates a SupplicantStaNetworkHal wrapper around an AIDL ISupplicantStaNetwork object.
1101      * Declared mockable for use in unit tests.
1102      *
1103      * @param ifaceName Name of the interface.
1104      * @param network ISupplicantStaNetwork instance retrieved from AIDL.
1105      * @return SupplicantStaNetworkHal object for the given network, or null if
1106      * the call fails
1107      */
getStaNetworkHalMockable( @onNull String ifaceName, ISupplicantStaNetwork network)1108     protected SupplicantStaNetworkHalAidlImpl getStaNetworkHalMockable(
1109             @NonNull String ifaceName, ISupplicantStaNetwork network) {
1110         synchronized (mLock) {
1111             SupplicantStaNetworkHalAidlImpl networkWrapper =
1112                     new SupplicantStaNetworkHalAidlImpl(mServiceVersion,
1113                             network, ifaceName, mContext,
1114                             mWifiMonitor, mWifiGlobals,
1115                             getAdvancedCapabilities(ifaceName),
1116                             getWpaDriverFeatureSet(ifaceName));
1117             if (networkWrapper != null) {
1118                 networkWrapper.enableVerboseLogging(
1119                         mVerboseLoggingEnabled, mVerboseHalLoggingEnabled);
1120             }
1121             return networkWrapper;
1122         }
1123     }
1124 
registerCallback( ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback)1125     private boolean registerCallback(
1126             ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback) {
1127         synchronized (mLock) {
1128             String methodStr = "registerCallback";
1129             if (iface == null) {
1130                 return false;
1131             }
1132             try {
1133                 iface.registerCallback(callback);
1134                 return true;
1135             } catch (RemoteException e) {
1136                 handleRemoteException(e, methodStr);
1137             } catch (ServiceSpecificException e) {
1138                 handleServiceSpecificException(e, methodStr);
1139             }
1140             return false;
1141         }
1142     }
1143 
1144     /**
1145      * Get list of id's of all networks controlled by supplicant.
1146      *
1147      * @return list of network id's, null if failed
1148      */
listNetworks(@onNull String ifaceName)1149     private int[] listNetworks(@NonNull String ifaceName) {
1150         synchronized (mLock) {
1151             final String methodStr = "listNetworks";
1152             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1153             if (iface == null) {
1154                 return null;
1155             }
1156             try {
1157                 return iface.listNetworks();
1158             } catch (RemoteException e) {
1159                 handleRemoteException(e, methodStr);
1160             } catch (ServiceSpecificException e) {
1161                 handleServiceSpecificException(e, methodStr);
1162             }
1163             return null;
1164         }
1165     }
1166 
1167     /**
1168      * Set WPS device name.
1169      *
1170      * @param ifaceName Name of the interface.
1171      * @param name String to be set.
1172      * @return true if request is sent successfully, false otherwise.
1173      */
setWpsDeviceName(@onNull String ifaceName, String name)1174     public boolean setWpsDeviceName(@NonNull String ifaceName, String name) {
1175         synchronized (mLock) {
1176             final String methodStr = "setWpsDeviceName";
1177             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1178             if (iface == null) {
1179                 return false;
1180             }
1181             try {
1182                 iface.setWpsDeviceName(name);
1183                 return true;
1184             } catch (RemoteException e) {
1185                 handleRemoteException(e, methodStr);
1186             } catch (ServiceSpecificException e) {
1187                 handleServiceSpecificException(e, methodStr);
1188             }
1189             return false;
1190         }
1191     }
1192 
1193     /**
1194      * Set WPS device type.
1195      *
1196      * @param ifaceName Name of the interface.
1197      * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
1198      * @return true if request is sent successfully, false otherwise.
1199      */
setWpsDeviceType(@onNull String ifaceName, String typeStr)1200     public boolean setWpsDeviceType(@NonNull String ifaceName, String typeStr) {
1201         synchronized (mLock) {
1202             try {
1203                 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr);
1204                 if (!match.find() || match.groupCount() != 3) {
1205                     Log.e(TAG, "Malformed WPS device type " + typeStr);
1206                     return false;
1207                 }
1208                 short categ = Short.parseShort(match.group(1));
1209                 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2));
1210                 short subCateg = Short.parseShort(match.group(3));
1211 
1212                 byte[] bytes = new byte[8];
1213                 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
1214                 byteBuffer.putShort(categ);
1215                 byteBuffer.put(oui);
1216                 byteBuffer.putShort(subCateg);
1217                 return setWpsDeviceType(ifaceName, bytes);
1218             } catch (IllegalArgumentException e) {
1219                 Log.e(TAG, "Illegal argument " + typeStr, e);
1220                 return false;
1221             }
1222         }
1223     }
1224 
setWpsDeviceType(@onNull String ifaceName, byte[ ] type)1225     private boolean setWpsDeviceType(@NonNull String ifaceName, byte[/* 8 */] type) {
1226         synchronized (mLock) {
1227             final String methodStr = "setWpsDeviceType";
1228             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1229             if (iface == null) {
1230                 return false;
1231             }
1232             try {
1233                 iface.setWpsDeviceType(type);
1234                 return true;
1235             } catch (RemoteException e) {
1236                 handleRemoteException(e, methodStr);
1237             } catch (ServiceSpecificException e) {
1238                 handleServiceSpecificException(e, methodStr);
1239             }
1240             return false;
1241         }
1242     }
1243 
1244     /**
1245      * Set WPS manufacturer.
1246      *
1247      * @param ifaceName Name of the interface.
1248      * @param manufacturer String to be set.
1249      * @return true if request is sent successfully, false otherwise.
1250      */
setWpsManufacturer(@onNull String ifaceName, String manufacturer)1251     public boolean setWpsManufacturer(@NonNull String ifaceName, String manufacturer) {
1252         synchronized (mLock) {
1253             final String methodStr = "setWpsManufacturer";
1254             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1255             if (iface == null) {
1256                 return false;
1257             }
1258             try {
1259                 iface.setWpsManufacturer(manufacturer);
1260                 return true;
1261             } catch (RemoteException e) {
1262                 handleRemoteException(e, methodStr);
1263             } catch (ServiceSpecificException e) {
1264                 handleServiceSpecificException(e, methodStr);
1265             }
1266             return false;
1267         }
1268     }
1269 
1270     /**
1271      * Set WPS model name.
1272      *
1273      * @param ifaceName Name of the interface.
1274      * @param modelName String to be set.
1275      * @return true if request is sent successfully, false otherwise.
1276      */
setWpsModelName(@onNull String ifaceName, String modelName)1277     public boolean setWpsModelName(@NonNull String ifaceName, String modelName) {
1278         synchronized (mLock) {
1279             final String methodStr = "setWpsModelName";
1280             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1281             if (iface == null) {
1282                 return false;
1283             }
1284             try {
1285                 iface.setWpsModelName(modelName);
1286                 return true;
1287             } catch (RemoteException e) {
1288                 handleRemoteException(e, methodStr);
1289             } catch (ServiceSpecificException e) {
1290                 handleServiceSpecificException(e, methodStr);
1291             }
1292             return false;
1293         }
1294     }
1295 
1296     /**
1297      * Set WPS model number.
1298      *
1299      * @param ifaceName Name of the interface.
1300      * @param modelNumber String to be set.
1301      * @return true if request is sent successfully, false otherwise.
1302      */
setWpsModelNumber(@onNull String ifaceName, String modelNumber)1303     public boolean setWpsModelNumber(@NonNull String ifaceName, String modelNumber) {
1304         synchronized (mLock) {
1305             final String methodStr = "setWpsModelNumber";
1306             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1307             if (iface == null) {
1308                 return false;
1309             }
1310             try {
1311                 iface.setWpsModelNumber(modelNumber);
1312                 return true;
1313             } catch (RemoteException e) {
1314                 handleRemoteException(e, methodStr);
1315             } catch (ServiceSpecificException e) {
1316                 handleServiceSpecificException(e, methodStr);
1317             }
1318             return false;
1319         }
1320     }
1321 
1322     /**
1323      * Set WPS serial number.
1324      *
1325      * @param ifaceName Name of the interface.
1326      * @param serialNumber String to be set.
1327      * @return true if request is sent successfully, false otherwise.
1328      */
setWpsSerialNumber(@onNull String ifaceName, String serialNumber)1329     public boolean setWpsSerialNumber(@NonNull String ifaceName, String serialNumber) {
1330         synchronized (mLock) {
1331             final String methodStr = "setWpsSerialNumber";
1332             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1333             if (iface == null) {
1334                 return false;
1335             }
1336             try {
1337                 iface.setWpsSerialNumber(serialNumber);
1338                 return true;
1339             } catch (RemoteException e) {
1340                 handleRemoteException(e, methodStr);
1341             } catch (ServiceSpecificException e) {
1342                 handleServiceSpecificException(e, methodStr);
1343             }
1344             return false;
1345         }
1346     }
1347 
1348     /**
1349      * Set WPS config methods
1350      *
1351      * @param ifaceName Name of the interface.
1352      * @param configMethodsStr List of config methods.
1353      * @return true if request is sent successfully, false otherwise.
1354      */
setWpsConfigMethods(@onNull String ifaceName, String configMethodsStr)1355     public boolean setWpsConfigMethods(@NonNull String ifaceName, String configMethodsStr) {
1356         synchronized (mLock) {
1357             int configMethodsMask = 0;
1358             String[] configMethodsStrArr = configMethodsStr.split("\\s+");
1359             for (int i = 0; i < configMethodsStrArr.length; i++) {
1360                 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]);
1361             }
1362             return setWpsConfigMethods(ifaceName, configMethodsMask);
1363         }
1364     }
1365 
setWpsConfigMethods(@onNull String ifaceName, int configMethods)1366     private boolean setWpsConfigMethods(@NonNull String ifaceName, int configMethods) {
1367         synchronized (mLock) {
1368             final String methodStr = "setWpsConfigMethods";
1369             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1370             if (iface == null) {
1371                 return false;
1372             }
1373             try {
1374                 iface.setWpsConfigMethods(configMethods);
1375                 return true;
1376             } catch (RemoteException e) {
1377                 handleRemoteException(e, methodStr);
1378             } catch (ServiceSpecificException e) {
1379                 handleServiceSpecificException(e, methodStr);
1380             }
1381             return false;
1382         }
1383     }
1384 
1385     /**
1386      * Trigger a reassociation even if the iface is currently connected.
1387      *
1388      * @param ifaceName Name of the interface.
1389      * @return true if request is sent successfully, false otherwise.
1390      */
reassociate(@onNull String ifaceName)1391     public boolean reassociate(@NonNull String ifaceName) {
1392         synchronized (mLock) {
1393             final String methodStr = "reassociate";
1394             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1395             if (iface == null) {
1396                 return false;
1397             }
1398             try {
1399                 iface.reassociate();
1400                 return true;
1401             } catch (RemoteException e) {
1402                 handleRemoteException(e, methodStr);
1403             } catch (ServiceSpecificException e) {
1404                 handleServiceSpecificException(e, methodStr);
1405             }
1406             return false;
1407         }
1408     }
1409 
1410     /**
1411      * Trigger a reconnection if the iface is disconnected.
1412      *
1413      * @param ifaceName Name of the interface.
1414      * @return true if request is sent successfully, false otherwise.
1415      */
reconnect(@onNull String ifaceName)1416     public boolean reconnect(@NonNull String ifaceName) {
1417         synchronized (mLock) {
1418             final String methodStr = "reconnect";
1419             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1420             if (iface == null) {
1421                 return false;
1422             }
1423             try {
1424                 iface.reconnect();
1425                 return true;
1426             } catch (RemoteException e) {
1427                 handleRemoteException(e, methodStr);
1428             } catch (ServiceSpecificException e) {
1429                 handleServiceSpecificException(e, methodStr);
1430             }
1431             return false;
1432         }
1433     }
1434 
1435 
1436     /**
1437      * Trigger a disconnection from the currently connected network.
1438      *
1439      * @param ifaceName Name of the interface.
1440      * @return true if request is sent successfully, false otherwise.
1441      */
disconnect(@onNull String ifaceName)1442     public boolean disconnect(@NonNull String ifaceName) {
1443         synchronized (mLock) {
1444             final String methodStr = "disconnect";
1445             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1446             if (iface == null) {
1447                 return false;
1448             }
1449             try {
1450                 iface.disconnect();
1451                 return true;
1452             } catch (RemoteException e) {
1453                 handleRemoteException(e, methodStr);
1454             } catch (ServiceSpecificException e) {
1455                 handleServiceSpecificException(e, methodStr);
1456             }
1457             return false;
1458         }
1459     }
1460 
1461     /**
1462      * Enable or disable power save mode.
1463      *
1464      * @param ifaceName Name of the interface.
1465      * @param enable true to enable, false to disable.
1466      * @return true if request is sent successfully, false otherwise.
1467      */
setPowerSave(@onNull String ifaceName, boolean enable)1468     public boolean setPowerSave(@NonNull String ifaceName, boolean enable) {
1469         synchronized (mLock) {
1470             final String methodStr = "setPowerSave";
1471             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1472             if (iface == null) {
1473                 return false;
1474             }
1475             try {
1476                 iface.setPowerSave(enable);
1477                 return true;
1478             } catch (RemoteException e) {
1479                 handleRemoteException(e, methodStr);
1480             } catch (ServiceSpecificException e) {
1481                 handleServiceSpecificException(e, methodStr);
1482             }
1483             return false;
1484         }
1485     }
1486 
1487     /**
1488      * Initiate TDLS discover with the specified AP.
1489      *
1490      * @param ifaceName Name of the interface.
1491      * @param macAddress MAC Address of the AP.
1492      * @return true if request is sent successfully, false otherwise.
1493      */
initiateTdlsDiscover(@onNull String ifaceName, String macAddress)1494     public boolean initiateTdlsDiscover(@NonNull String ifaceName, String macAddress) {
1495         synchronized (mLock) {
1496             try {
1497                 return initiateTdlsDiscover(
1498                         ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1499             } catch (IllegalArgumentException e) {
1500                 Log.e(TAG, "Illegal argument " + macAddress, e);
1501                 return false;
1502             }
1503         }
1504     }
1505 
initiateTdlsDiscover(@onNull String ifaceName, byte[ ] macAddress)1506     private boolean initiateTdlsDiscover(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1507         synchronized (mLock) {
1508             final String methodStr = "initiateTdlsDiscover";
1509             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1510             if (iface == null) {
1511                 return false;
1512             }
1513             try {
1514                 iface.initiateTdlsDiscover(macAddress);
1515                 return true;
1516             } catch (RemoteException e) {
1517                 handleRemoteException(e, methodStr);
1518             } catch (ServiceSpecificException e) {
1519                 handleServiceSpecificException(e, methodStr);
1520             }
1521             return false;
1522         }
1523     }
1524 
1525     /**
1526      * Initiate TDLS setup with the specified AP.
1527      *
1528      * @param ifaceName Name of the interface.
1529      * @param macAddress MAC Address of the AP.
1530      * @return true if request is sent successfully, false otherwise.
1531      */
initiateTdlsSetup(@onNull String ifaceName, String macAddress)1532     public boolean initiateTdlsSetup(@NonNull String ifaceName, String macAddress) {
1533         synchronized (mLock) {
1534             try {
1535                 return initiateTdlsSetup(ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1536             } catch (IllegalArgumentException e) {
1537                 Log.e(TAG, "Illegal argument " + macAddress, e);
1538                 return false;
1539             }
1540         }
1541     }
1542 
initiateTdlsSetup(@onNull String ifaceName, byte[ ] macAddress)1543     private boolean initiateTdlsSetup(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1544         synchronized (mLock) {
1545             final String methodStr = "initiateTdlsSetup";
1546             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1547             if (iface == null) {
1548                 return false;
1549             }
1550             try {
1551                 iface.initiateTdlsSetup(macAddress);
1552                 return true;
1553             } catch (RemoteException e) {
1554                 handleRemoteException(e, methodStr);
1555             } catch (ServiceSpecificException e) {
1556                 handleServiceSpecificException(e, methodStr);
1557             }
1558             return false;
1559         }
1560     }
1561 
1562     /**
1563      * Initiate TDLS teardown with the specified AP.
1564      *
1565      * @param ifaceName Name of the interface.
1566      * @param macAddress MAC Address of the AP.
1567      * @return true if request is sent successfully, false otherwise.
1568      */
initiateTdlsTeardown(@onNull String ifaceName, String macAddress)1569     public boolean initiateTdlsTeardown(@NonNull String ifaceName, String macAddress) {
1570         synchronized (mLock) {
1571             try {
1572                 return initiateTdlsTeardown(
1573                         ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1574             } catch (IllegalArgumentException e) {
1575                 Log.e(TAG, "Illegal argument " + macAddress, e);
1576                 return false;
1577             }
1578         }
1579     }
1580 
initiateTdlsTeardown(@onNull String ifaceName, byte[ ] macAddress)1581     private boolean initiateTdlsTeardown(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1582         synchronized (mLock) {
1583             final String methodStr = "initiateTdlsTeardown";
1584             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1585             if (iface == null) {
1586                 return false;
1587             }
1588             try {
1589                 iface.initiateTdlsTeardown(macAddress);
1590                 return true;
1591             } catch (RemoteException e) {
1592                 handleRemoteException(e, methodStr);
1593             } catch (ServiceSpecificException e) {
1594                 handleServiceSpecificException(e, methodStr);
1595             }
1596             return false;
1597         }
1598     }
1599 
1600     /**
1601      * Request the specified ANQP elements |elements| from the specified AP |bssid|.
1602      *
1603      * @param ifaceName Name of the interface.
1604      * @param bssid BSSID of the AP
1605      * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId.
1606      * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes.
1607      * @return true if request is sent successfully, false otherwise.
1608      */
initiateAnqpQuery(@onNull String ifaceName, String bssid, ArrayList<Short> infoElements, ArrayList<Integer> hs20SubTypes)1609     public boolean initiateAnqpQuery(@NonNull String ifaceName, String bssid,
1610             ArrayList<Short> infoElements,
1611             ArrayList<Integer> hs20SubTypes) {
1612         synchronized (mLock) {
1613             try {
1614                 int[] infoElementsCast = new int[infoElements.size()];
1615                 int[] hs20SubTypesCast = new int[hs20SubTypes.size()];
1616                 for (int i = 0; i < infoElements.size(); i++) {
1617                     infoElementsCast[i] = infoElements.get(i);
1618                 }
1619                 for (int i = 0; i < hs20SubTypes.size(); i++) {
1620                     hs20SubTypesCast[i] = hs20SubTypes.get(i);
1621                 }
1622                 return initiateAnqpQuery(
1623                         ifaceName,
1624                         NativeUtil.macAddressToByteArray(bssid),
1625                         infoElementsCast, hs20SubTypesCast);
1626             } catch (IllegalArgumentException e) {
1627                 Log.e(TAG, "Illegal argument " + bssid, e);
1628                 return false;
1629             }
1630         }
1631     }
1632 
initiateAnqpQuery(@onNull String ifaceName, byte[ ] macAddress, int[] infoElements, int[] subTypes)1633     private boolean initiateAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress,
1634             int[] infoElements, int[] subTypes) {
1635         synchronized (mLock) {
1636             final String methodStr = "initiateAnqpQuery";
1637             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1638             if (iface == null) {
1639                 return false;
1640             }
1641             try {
1642                 iface.initiateAnqpQuery(macAddress, infoElements, subTypes);
1643                 return true;
1644             } catch (RemoteException e) {
1645                 handleRemoteException(e, methodStr);
1646             } catch (ServiceSpecificException e) {
1647                 handleServiceSpecificException(e, methodStr);
1648             }
1649             return false;
1650         }
1651     }
1652 
1653     /**
1654      * Request Venue URL ANQP element from the specified AP |bssid|.
1655      *
1656      * @param ifaceName Name of the interface.
1657      * @param bssid BSSID of the AP
1658      * @return true if request is sent successfully, false otherwise.
1659      */
initiateVenueUrlAnqpQuery(@onNull String ifaceName, String bssid)1660     public boolean initiateVenueUrlAnqpQuery(@NonNull String ifaceName, String bssid) {
1661         synchronized (mLock) {
1662             try {
1663                 return initiateVenueUrlAnqpQuery(
1664                         ifaceName, NativeUtil.macAddressToByteArray(bssid));
1665             } catch (IllegalArgumentException e) {
1666                 Log.e(TAG, "Illegal argument " + bssid, e);
1667                 return false;
1668             }
1669         }
1670     }
1671 
initiateVenueUrlAnqpQuery(@onNull String ifaceName, byte[ ] macAddress)1672     private boolean initiateVenueUrlAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1673         synchronized (mLock) {
1674             final String methodStr = "initiateVenueUrlAnqpQuery";
1675             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1676             if (iface == null) {
1677                 return false;
1678             }
1679             try {
1680                 iface.initiateVenueUrlAnqpQuery(macAddress);
1681                 return true;
1682             } catch (RemoteException e) {
1683                 handleRemoteException(e, methodStr);
1684             } catch (ServiceSpecificException e) {
1685                 handleServiceSpecificException(e, methodStr);
1686             }
1687             return false;
1688         }
1689     }
1690 
1691     /**
1692      * Request the specified ANQP ICON from the specified AP |bssid|.
1693      *
1694      * @param ifaceName Name of the interface.
1695      * @param bssid BSSID of the AP
1696      * @param fileName Name of the file to request.
1697      * @return true if request is sent successfully, false otherwise.
1698      */
initiateHs20IconQuery(@onNull String ifaceName, String bssid, String fileName)1699     public boolean initiateHs20IconQuery(@NonNull String ifaceName, String bssid, String fileName) {
1700         synchronized (mLock) {
1701             try {
1702                 return initiateHs20IconQuery(
1703                         ifaceName, NativeUtil.macAddressToByteArray(bssid), fileName);
1704             } catch (IllegalArgumentException e) {
1705                 Log.e(TAG, "Illegal argument " + bssid, e);
1706                 return false;
1707             }
1708         }
1709     }
1710 
initiateHs20IconQuery(@onNull String ifaceName, byte[ ] macAddress, String fileName)1711     private boolean initiateHs20IconQuery(@NonNull String ifaceName,
1712             byte[/* 6 */] macAddress, String fileName) {
1713         synchronized (mLock) {
1714             final String methodStr = "initiateHs20IconQuery";
1715             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1716             if (iface == null) {
1717                 return false;
1718             }
1719             try {
1720                 iface.initiateHs20IconQuery(macAddress, fileName);
1721                 return true;
1722             } catch (RemoteException e) {
1723                 handleRemoteException(e, methodStr);
1724             } catch (ServiceSpecificException e) {
1725                 handleServiceSpecificException(e, methodStr);
1726             }
1727             return false;
1728         }
1729     }
1730 
1731     /**
1732      * Gets MAC Address from the supplicant.
1733      *
1734      * @param ifaceName Name of the interface.
1735      * @return string containing the MAC address, or null on a failed call
1736      */
getMacAddress(@onNull String ifaceName)1737     public String getMacAddress(@NonNull String ifaceName) {
1738         synchronized (mLock) {
1739             final String methodStr = "getMacAddress";
1740             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1741             if (iface == null) {
1742                 return null;
1743             }
1744             try {
1745                 byte[] macAddr = iface.getMacAddress();
1746                 return NativeUtil.macAddressFromByteArray(macAddr);
1747             } catch (RemoteException e) {
1748                 handleRemoteException(e, methodStr);
1749             } catch (ServiceSpecificException e) {
1750                 handleServiceSpecificException(e, methodStr);
1751             } catch (IllegalArgumentException e) {
1752                 Log.e(TAG, "Invalid MAC address value", e);
1753             }
1754             return null;
1755         }
1756     }
1757 
1758     /**
1759      * Start using the added RX filters.
1760      *
1761      * @param ifaceName Name of the interface.
1762      * @return true if request is sent successfully, false otherwise.
1763      */
startRxFilter(@onNull String ifaceName)1764     public boolean startRxFilter(@NonNull String ifaceName) {
1765         synchronized (mLock) {
1766             final String methodStr = "startRxFilter";
1767             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1768             if (iface == null) {
1769                 return false;
1770             }
1771             try {
1772                 iface.startRxFilter();
1773                 return true;
1774             } catch (RemoteException e) {
1775                 handleRemoteException(e, methodStr);
1776             } catch (ServiceSpecificException e) {
1777                 handleServiceSpecificException(e, methodStr);
1778             }
1779             return false;
1780         }
1781     }
1782 
1783     /**
1784      * Stop using the added RX filters.
1785      *
1786      * @param ifaceName Name of the interface.
1787      * @return true if request is sent successfully, false otherwise.
1788      */
stopRxFilter(@onNull String ifaceName)1789     public boolean stopRxFilter(@NonNull String ifaceName) {
1790         synchronized (mLock) {
1791             final String methodStr = "stopRxFilter";
1792             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1793             if (iface == null) {
1794                 return false;
1795             }
1796             try {
1797                 iface.stopRxFilter();
1798                 return true;
1799             } catch (RemoteException e) {
1800                 handleRemoteException(e, methodStr);
1801             } catch (ServiceSpecificException e) {
1802                 handleServiceSpecificException(e, methodStr);
1803             }
1804             return false;
1805         }
1806     }
1807 
1808     /**
1809      * Add an RX filter.
1810      *
1811      * @param ifaceName Name of the interface.
1812      * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
1813      *        {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
1814      * @return true if request is sent successfully, false otherwise.
1815      */
addRxFilter(@onNull String ifaceName, int type)1816     public boolean addRxFilter(@NonNull String ifaceName, int type) {
1817         synchronized (mLock) {
1818             byte halType;
1819             switch (type) {
1820                 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
1821                     halType = RxFilterType.V4_MULTICAST;
1822                     break;
1823                 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
1824                     halType = RxFilterType.V6_MULTICAST;
1825                     break;
1826                 default:
1827                     Log.e(TAG, "Invalid Rx Filter type: " + type);
1828                     return false;
1829             }
1830             return addRxFilter(ifaceName, halType);
1831         }
1832     }
1833 
addRxFilter(@onNull String ifaceName, byte type)1834     private boolean addRxFilter(@NonNull String ifaceName, byte type) {
1835         synchronized (mLock) {
1836             final String methodStr = "addRxFilter";
1837             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1838             if (iface == null) {
1839                 return false;
1840             }
1841             try {
1842                 iface.addRxFilter(type);
1843                 return true;
1844             } catch (RemoteException e) {
1845                 handleRemoteException(e, methodStr);
1846             } catch (ServiceSpecificException e) {
1847                 handleServiceSpecificException(e, methodStr);
1848             }
1849             return false;
1850         }
1851     }
1852 
1853     /**
1854      * Remove an RX filter.
1855      *
1856      * @param ifaceName Name of the interface.
1857      * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
1858      *        {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
1859      * @return true if request is sent successfully, false otherwise.
1860      */
removeRxFilter(@onNull String ifaceName, int type)1861     public boolean removeRxFilter(@NonNull String ifaceName, int type) {
1862         synchronized (mLock) {
1863             byte halType;
1864             switch (type) {
1865                 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
1866                     halType = RxFilterType.V4_MULTICAST;
1867                     break;
1868                 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
1869                     halType = RxFilterType.V6_MULTICAST;
1870                     break;
1871                 default:
1872                     Log.e(TAG, "Invalid Rx Filter type: " + type);
1873                     return false;
1874             }
1875             return removeRxFilter(ifaceName, halType);
1876         }
1877     }
1878 
removeRxFilter(@onNull String ifaceName, byte type)1879     private boolean removeRxFilter(@NonNull String ifaceName, byte type) {
1880         synchronized (mLock) {
1881             final String methodStr = "removeRxFilter";
1882             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1883             if (iface == null) {
1884                 return false;
1885             }
1886             try {
1887                 iface.removeRxFilter(type);
1888                 return true;
1889             } catch (RemoteException e) {
1890                 handleRemoteException(e, methodStr);
1891             } catch (ServiceSpecificException e) {
1892                 handleServiceSpecificException(e, methodStr);
1893             }
1894             return false;
1895         }
1896     }
1897 
1898     /**
1899      * Set Bt co existense mode.
1900      *
1901      * @param ifaceName Name of the interface.
1902      * @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED},
1903      *             {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or
1904      *             {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}.
1905      * @return true if request is sent successfully, false otherwise.
1906      */
setBtCoexistenceMode(@onNull String ifaceName, int mode)1907     public boolean setBtCoexistenceMode(@NonNull String ifaceName, int mode) {
1908         synchronized (mLock) {
1909             byte halMode;
1910             switch (mode) {
1911                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_ENABLED:
1912                     halMode = BtCoexistenceMode.ENABLED;
1913                     break;
1914                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED:
1915                     halMode = BtCoexistenceMode.DISABLED;
1916                     break;
1917                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE:
1918                     halMode = BtCoexistenceMode.SENSE;
1919                     break;
1920                 default:
1921                     Log.e(TAG, "Invalid Bt Coex mode: " + mode);
1922                     return false;
1923             }
1924             return setBtCoexistenceMode(ifaceName, halMode);
1925         }
1926     }
1927 
setBtCoexistenceMode(@onNull String ifaceName, byte mode)1928     private boolean setBtCoexistenceMode(@NonNull String ifaceName, byte mode) {
1929         synchronized (mLock) {
1930             final String methodStr = "setBtCoexistenceMode";
1931             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1932             if (iface == null) {
1933                 return false;
1934             }
1935             try {
1936                 iface.setBtCoexistenceMode(mode);
1937                 return true;
1938             } catch (RemoteException e) {
1939                 handleRemoteException(e, methodStr);
1940             } catch (ServiceSpecificException e) {
1941                 handleServiceSpecificException(e, methodStr);
1942             }
1943             return false;
1944         }
1945     }
1946 
1947     /** Enable or disable BT coexistence mode.
1948      *
1949      * @param ifaceName Name of the interface.
1950      * @param enable true to enable, false to disable.
1951      * @return true if request is sent successfully, false otherwise.
1952      */
setBtCoexistenceScanModeEnabled(@onNull String ifaceName, boolean enable)1953     public boolean setBtCoexistenceScanModeEnabled(@NonNull String ifaceName, boolean enable) {
1954         synchronized (mLock) {
1955             final String methodStr = "setBtCoexistenceScanModeEnabled";
1956             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1957             if (iface == null) {
1958                 return false;
1959             }
1960             try {
1961                 iface.setBtCoexistenceScanModeEnabled(enable);
1962                 return true;
1963             } catch (RemoteException e) {
1964                 handleRemoteException(e, methodStr);
1965             } catch (ServiceSpecificException e) {
1966                 handleServiceSpecificException(e, methodStr);
1967             }
1968             return false;
1969         }
1970     }
1971 
1972     /**
1973      * Enable or disable suspend mode optimizations.
1974      *
1975      * @param ifaceName Name of the interface.
1976      * @param enable true to enable, false otherwise.
1977      * @return true if request is sent successfully, false otherwise.
1978      */
setSuspendModeEnabled(@onNull String ifaceName, boolean enable)1979     public boolean setSuspendModeEnabled(@NonNull String ifaceName, boolean enable) {
1980         synchronized (mLock) {
1981             final String methodStr = "setSuspendModeEnabled";
1982             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1983             if (iface == null) {
1984                 return false;
1985             }
1986             try {
1987                 iface.setSuspendModeEnabled(enable);
1988                 return true;
1989             } catch (RemoteException e) {
1990                 handleRemoteException(e, methodStr);
1991             } catch (ServiceSpecificException e) {
1992                 handleServiceSpecificException(e, methodStr);
1993             }
1994             return false;
1995         }
1996     }
1997 
1998     /**
1999      * Set country code.
2000      *
2001      * @param ifaceName Name of the interface.
2002      * @param codeStr 2 byte ASCII string. For ex: US, CA.
2003      * @return true if request is sent successfully, false otherwise.
2004      */
setCountryCode(@onNull String ifaceName, String codeStr)2005     public boolean setCountryCode(@NonNull String ifaceName, String codeStr) {
2006         synchronized (mLock) {
2007             if (TextUtils.isEmpty(codeStr)) {
2008                 return false;
2009             }
2010             byte[] countryCodeBytes = NativeUtil.stringToByteArray(codeStr);
2011             if (countryCodeBytes.length != 2) {
2012                 return false;
2013             }
2014             return setCountryCode(ifaceName, countryCodeBytes);
2015         }
2016     }
2017 
setCountryCode(@onNull String ifaceName, byte[ ] code)2018     private boolean setCountryCode(@NonNull String ifaceName, byte[/* 2 */] code) {
2019         synchronized (mLock) {
2020             final String methodStr = "setCountryCode";
2021             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2022             if (iface == null) {
2023                 return false;
2024             }
2025             try {
2026                 iface.setCountryCode(code);
2027                 return true;
2028             } catch (RemoteException e) {
2029                 handleRemoteException(e, methodStr);
2030             } catch (ServiceSpecificException e) {
2031                 handleServiceSpecificException(e, methodStr);
2032             }
2033             return false;
2034         }
2035     }
2036 
2037     /**
2038      * Flush all previously configured HLPs.
2039      *
2040      * @param ifaceName Name of the interface.
2041      * @return true if request is sent successfully, false otherwise.
2042      */
flushAllHlp(@onNull String ifaceName)2043     public boolean flushAllHlp(@NonNull String ifaceName) {
2044         synchronized (mLock) {
2045             final String methodStr = "filsHlpFlushRequest";
2046             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2047             if (iface == null) {
2048                 return false;
2049             }
2050             try {
2051                 iface.filsHlpFlushRequest();
2052                 return true;
2053             } catch (RemoteException e) {
2054                 handleRemoteException(e, methodStr);
2055             } catch (ServiceSpecificException e) {
2056                 handleServiceSpecificException(e, methodStr);
2057             }
2058             return false;
2059         }
2060     }
2061 
2062     /**
2063      * Set FILS HLP packet.
2064      *
2065      * @param ifaceName Name of the interface.
2066      * @param dst Destination MAC address.
2067      * @param hlpPacket Hlp Packet data in hex.
2068      * @return true if request is sent successfully, false otherwise.
2069      */
addHlpReq(@onNull String ifaceName, byte[] dst, byte[] hlpPacket)2070     public boolean addHlpReq(@NonNull String ifaceName, byte[] dst, byte[] hlpPacket) {
2071         synchronized (mLock) {
2072             final String methodStr = "filsHlpAddRequest";
2073             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2074             if (iface == null) {
2075                 return false;
2076             }
2077             try {
2078                 iface.filsHlpAddRequest(dst, hlpPacket);
2079                 return true;
2080             } catch (RemoteException e) {
2081                 handleRemoteException(e, methodStr);
2082             } catch (ServiceSpecificException e) {
2083                 handleServiceSpecificException(e, methodStr);
2084             }
2085             return false;
2086         }
2087     }
2088 
2089     /**
2090      * Start WPS pin registrar operation with the specified peer and pin.
2091      *
2092      * @param ifaceName Name of the interface.
2093      * @param bssidStr BSSID of the peer.
2094      * @param pin Pin to be used.
2095      * @return true if request is sent successfully, false otherwise.
2096      */
startWpsRegistrar(@onNull String ifaceName, String bssidStr, String pin)2097     public boolean startWpsRegistrar(@NonNull String ifaceName, String bssidStr, String pin) {
2098         synchronized (mLock) {
2099             if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) {
2100                 return false;
2101             }
2102             try {
2103                 return startWpsRegistrar(
2104                         ifaceName, NativeUtil.macAddressToByteArray(bssidStr), pin);
2105             } catch (IllegalArgumentException e) {
2106                 Log.e(TAG, "Illegal argument " + bssidStr, e);
2107                 return false;
2108             }
2109         }
2110     }
2111 
startWpsRegistrar(@onNull String ifaceName, byte[ ] bssid, String pin)2112     private boolean startWpsRegistrar(@NonNull String ifaceName, byte[/* 6 */] bssid, String pin) {
2113         synchronized (mLock) {
2114             final String methodStr = "startWpsRegistrar";
2115             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2116             if (iface == null) {
2117                 return false;
2118             }
2119             try {
2120                 iface.startWpsRegistrar(bssid, pin);
2121                 return true;
2122             } catch (RemoteException e) {
2123                 handleRemoteException(e, methodStr);
2124             } catch (ServiceSpecificException e) {
2125                 handleServiceSpecificException(e, methodStr);
2126             }
2127             return false;
2128         }
2129     }
2130 
2131     /**
2132      * Start WPS pin display operation with the specified peer.
2133      *
2134      * @param ifaceName Name of the interface.
2135      * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
2136      * @return true if request is sent successfully, false otherwise.
2137      */
startWpsPbc(@onNull String ifaceName, String bssidStr)2138     public boolean startWpsPbc(@NonNull String ifaceName, String bssidStr) {
2139         synchronized (mLock) {
2140             try {
2141                 return startWpsPbc(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
2142             } catch (IllegalArgumentException e) {
2143                 Log.e(TAG, "Illegal argument " + bssidStr, e);
2144                 return false;
2145             }
2146         }
2147     }
2148 
startWpsPbc(@onNull String ifaceName, byte[ ] bssid)2149     private boolean startWpsPbc(@NonNull String ifaceName, byte[/* 6 */] bssid) {
2150         synchronized (mLock) {
2151             final String methodStr = "startWpsPbc";
2152             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2153             if (iface == null) {
2154                 return false;
2155             }
2156             try {
2157                 iface.startWpsPbc(bssid);
2158                 return true;
2159             } catch (RemoteException e) {
2160                 handleRemoteException(e, methodStr);
2161             } catch (ServiceSpecificException e) {
2162                 handleServiceSpecificException(e, methodStr);
2163             }
2164             return false;
2165         }
2166     }
2167 
2168     /**
2169      * Start WPS pin keypad operation with the specified pin.
2170      *
2171      * @param ifaceName Name of the interface.
2172      * @param pin Pin to be used.
2173      * @return true if request is sent successfully, false otherwise.
2174      */
startWpsPinKeypad(@onNull String ifaceName, String pin)2175     public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
2176         if (TextUtils.isEmpty(pin)) {
2177             return false;
2178         }
2179         synchronized (mLock) {
2180             final String methodStr = "startWpsPinKeypad";
2181             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2182             if (iface == null) {
2183                 return false;
2184             }
2185             try {
2186                 iface.startWpsPinKeypad(pin);
2187                 return true;
2188             } catch (RemoteException e) {
2189                 handleRemoteException(e, methodStr);
2190             } catch (ServiceSpecificException e) {
2191                 handleServiceSpecificException(e, methodStr);
2192             }
2193             return false;
2194         }
2195     }
2196 
2197     /**
2198      * Start WPS pin display operation with the specified peer.
2199      *
2200      * @param ifaceName Name of the interface.
2201      * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
2202      * @return new pin generated on success, null otherwise.
2203      */
startWpsPinDisplay(@onNull String ifaceName, String bssidStr)2204     public String startWpsPinDisplay(@NonNull String ifaceName, String bssidStr) {
2205         synchronized (mLock) {
2206             try {
2207                 return startWpsPinDisplay(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
2208             } catch (IllegalArgumentException e) {
2209                 Log.e(TAG, "Illegal argument " + bssidStr, e);
2210                 return null;
2211             }
2212         }
2213     }
2214 
startWpsPinDisplay(@onNull String ifaceName, byte[ ] bssid)2215     private String startWpsPinDisplay(@NonNull String ifaceName, byte[/* 6 */] bssid) {
2216         synchronized (mLock) {
2217             final String methodStr = "startWpsPinDisplay";
2218             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2219             if (iface == null) {
2220                 return null;
2221             }
2222             try {
2223                 return iface.startWpsPinDisplay(bssid);
2224             } catch (RemoteException e) {
2225                 handleRemoteException(e, methodStr);
2226             } catch (ServiceSpecificException e) {
2227                 handleServiceSpecificException(e, methodStr);
2228             }
2229             return null;
2230         }
2231     }
2232 
2233     /**
2234      * Cancels any ongoing WPS requests.
2235      *
2236      * @param ifaceName Name of the interface.
2237      * @return true if request is sent successfully, false otherwise.
2238      */
cancelWps(@onNull String ifaceName)2239     public boolean cancelWps(@NonNull String ifaceName) {
2240         synchronized (mLock) {
2241             final String methodStr = "cancelWps";
2242             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2243             if (iface == null) {
2244                 return false;
2245             }
2246             try {
2247                 iface.cancelWps();
2248                 return true;
2249             } catch (RemoteException e) {
2250                 handleRemoteException(e, methodStr);
2251             } catch (ServiceSpecificException e) {
2252                 handleServiceSpecificException(e, methodStr);
2253             }
2254             return false;
2255         }
2256     }
2257 
2258     /**
2259      * Sets whether to use external sim for SIM/USIM processing.
2260      *
2261      * @param ifaceName Name of the interface.
2262      * @param useExternalSim true to enable, false otherwise.
2263      * @return true if request is sent successfully, false otherwise.
2264      */
setExternalSim(@onNull String ifaceName, boolean useExternalSim)2265     public boolean setExternalSim(@NonNull String ifaceName, boolean useExternalSim) {
2266         synchronized (mLock) {
2267             final String methodStr = "setExternalSim";
2268             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2269             if (iface == null) {
2270                 return false;
2271             }
2272             try {
2273                 iface.setExternalSim(useExternalSim);
2274                 return true;
2275             } catch (RemoteException e) {
2276                 handleRemoteException(e, methodStr);
2277             } catch (ServiceSpecificException e) {
2278                 handleServiceSpecificException(e, methodStr);
2279             }
2280             return false;
2281         }
2282     }
2283 
2284     /**
2285      * Enable/Disable auto reconnect to networks.
2286      * Use this to prevent wpa_supplicant from trying to connect to networks
2287      * on its own.
2288      *
2289      * @param enable true to enable, false to disable.
2290      * @return true if no exceptions occurred, false otherwise
2291      */
enableAutoReconnect(@onNull String ifaceName, boolean enable)2292     public boolean enableAutoReconnect(@NonNull String ifaceName, boolean enable) {
2293         synchronized (mLock) {
2294             final String methodStr = "enableAutoReconnect";
2295             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2296             if (iface == null) {
2297                 return false;
2298             }
2299             try {
2300                 iface.enableAutoReconnect(enable);
2301                 return true;
2302             } catch (RemoteException e) {
2303                 handleRemoteException(e, methodStr);
2304             } catch (ServiceSpecificException e) {
2305                 handleServiceSpecificException(e, methodStr);
2306             }
2307             return false;
2308         }
2309     }
2310 
2311     /**
2312      * Set the debug log level for wpa_supplicant
2313      *
2314      * @param turnOnVerbose Whether to turn on verbose logging or not.
2315      * @return true if request is sent successfully, false otherwise.
2316      */
setLogLevel(boolean turnOnVerbose)2317     public boolean setLogLevel(boolean turnOnVerbose) {
2318         synchronized (mLock) {
2319             int logLevel = turnOnVerbose
2320                     ? DebugLevel.DEBUG
2321                     : DebugLevel.INFO;
2322             return setDebugParams(logLevel, false,
2323                     turnOnVerbose && mWifiGlobals.getShowKeyVerboseLoggingModeEnabled());
2324         }
2325     }
2326 
2327     /**
2328      * Set debug parameters for the ISupplicant service.
2329      *
2330      * @param level Debug logging level for the supplicant.
2331      *        (one of |DebugLevel| values).
2332      * @param showTimestamp Determines whether to show timestamps in logs or not.
2333      * @param showKeys Determines whether to show keys in debug logs or not.
2334      *        CAUTION: Do not set this param in production code!
2335      * @return true if no exceptions occurred, false otherwise
2336      */
setDebugParams(int level, boolean showTimestamp, boolean showKeys)2337     private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) {
2338         synchronized (mLock) {
2339             final String methodStr = "setDebugParams";
2340             if (!checkSupplicantAndLogFailure(methodStr)) {
2341                 return false;
2342             }
2343             try {
2344                 mISupplicant.setDebugParams(level, showTimestamp, showKeys);
2345                 return true;
2346             } catch (RemoteException e) {
2347                 handleRemoteException(e, methodStr);
2348             } catch (ServiceSpecificException e) {
2349                 handleServiceSpecificException(e, methodStr);
2350             }
2351             return false;
2352         }
2353     }
2354 
2355     /**
2356      * Set concurrency priority between P2P & STA operations.
2357      *
2358      * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
2359      *                            false otherwise.
2360      * @return true if request is sent successfully, false otherwise.
2361      */
setConcurrencyPriority(boolean isStaHigherPriority)2362     public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
2363         synchronized (mLock) {
2364             if (isStaHigherPriority) {
2365                 return setConcurrencyPriority(IfaceType.STA);
2366             } else {
2367                 return setConcurrencyPriority(IfaceType.P2P);
2368             }
2369         }
2370     }
2371 
setConcurrencyPriority(int type)2372     private boolean setConcurrencyPriority(int type) {
2373         synchronized (mLock) {
2374             final String methodStr = "setConcurrencyPriority";
2375             if (!checkSupplicantAndLogFailure(methodStr)) {
2376                 return false;
2377             }
2378             try {
2379                 mISupplicant.setConcurrencyPriority(type);
2380                 return true;
2381             } catch (RemoteException e) {
2382                 handleRemoteException(e, methodStr);
2383             } catch (ServiceSpecificException e) {
2384                 handleServiceSpecificException(e, methodStr);
2385             }
2386             return false;
2387         }
2388     }
2389 
2390     /**
2391      * Returns false if mISupplicant is null and logs failure message
2392      */
checkSupplicantAndLogFailure(final String methodStr)2393     private boolean checkSupplicantAndLogFailure(final String methodStr) {
2394         synchronized (mLock) {
2395             if (mISupplicant == null) {
2396                 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null");
2397                 return false;
2398             }
2399             return true;
2400         }
2401     }
2402 
2403     /**
2404      * Returns specified STA iface if it exists. Otherwise, logs error and returns null.
2405      */
checkStaIfaceAndLogFailure( @onNull String ifaceName, final String methodStr)2406     private ISupplicantStaIface checkStaIfaceAndLogFailure(
2407             @NonNull String ifaceName, final String methodStr) {
2408         synchronized (mLock) {
2409             ISupplicantStaIface iface = getStaIface(ifaceName);
2410             if (iface == null) {
2411                 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null for "
2412                         + "iface=" + ifaceName);
2413                 return null;
2414             }
2415             return iface;
2416         }
2417     }
2418 
2419     /**
2420      * Returns network belonging to the specified STA iface if it exists.
2421      * Otherwise, logs error and returns null.
2422      */
checkStaNetworkAndLogFailure( @onNull String ifaceName, final String methodStr)2423     private SupplicantStaNetworkHalAidlImpl checkStaNetworkAndLogFailure(
2424             @NonNull String ifaceName, final String methodStr) {
2425         synchronized (mLock) {
2426             SupplicantStaNetworkHalAidlImpl networkHandle =
2427                     getCurrentNetworkRemoteHandle(ifaceName);
2428             if (networkHandle == null) {
2429                 Log.e(TAG, "Can't call " + methodStr + ", SupplicantStaNetwork for iface="
2430                         + ifaceName + " is null.");
2431                 return null;
2432             }
2433             return networkHandle;
2434         }
2435     }
2436 
2437     /**
2438      * Helper function to log callback events
2439      */
logCallback(final String methodStr)2440     protected void logCallback(final String methodStr) {
2441         synchronized (mLock) {
2442             if (mVerboseLoggingEnabled) {
2443                 Log.d(TAG, "ISupplicantStaIfaceCallback." + methodStr + " received");
2444             }
2445         }
2446     }
2447 
handleRemoteException(RemoteException e, String methodStr)2448     private void handleRemoteException(RemoteException e, String methodStr) {
2449         synchronized (mLock) {
2450             clearState();
2451             Log.e(TAG,
2452                     "ISupplicantStaIface." + methodStr + " failed with remote exception: ", e);
2453         }
2454     }
2455 
handleServiceSpecificException(ServiceSpecificException e, String methodStr)2456     private void handleServiceSpecificException(ServiceSpecificException e, String methodStr) {
2457         synchronized (mLock) {
2458             Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with "
2459                     + "service specific exception: ", e);
2460         }
2461     }
2462 
2463     /**
2464      * Converts the Wps config method string to the equivalent enum value.
2465      */
stringToWpsConfigMethod(String configMethod)2466     private static int stringToWpsConfigMethod(String configMethod) {
2467         switch (configMethod) {
2468             case "usba":
2469                 return WpsConfigMethods.USBA;
2470             case "ethernet":
2471                 return WpsConfigMethods.ETHERNET;
2472             case "label":
2473                 return WpsConfigMethods.LABEL;
2474             case "display":
2475                 return WpsConfigMethods.DISPLAY;
2476             case "int_nfc_token":
2477                 return WpsConfigMethods.INT_NFC_TOKEN;
2478             case "ext_nfc_token":
2479                 return WpsConfigMethods.EXT_NFC_TOKEN;
2480             case "nfc_interface":
2481                 return WpsConfigMethods.NFC_INTERFACE;
2482             case "push_button":
2483                 return WpsConfigMethods.PUSHBUTTON;
2484             case "keypad":
2485                 return WpsConfigMethods.KEYPAD;
2486             case "virtual_push_button":
2487                 return WpsConfigMethods.VIRT_PUSHBUTTON;
2488             case "physical_push_button":
2489                 return WpsConfigMethods.PHY_PUSHBUTTON;
2490             case "p2ps":
2491                 return WpsConfigMethods.P2PS;
2492             case "virtual_display":
2493                 return WpsConfigMethods.VIRT_DISPLAY;
2494             case "physical_display":
2495                 return WpsConfigMethods.PHY_DISPLAY;
2496             default:
2497                 throw new IllegalArgumentException(
2498                         "Invalid WPS config method: " + configMethod);
2499         }
2500     }
2501 
addPmkCacheEntry(String ifaceName, int networkId, byte[ ] bssid, long expirationTimeInSec, ArrayList<Byte> serializedEntry)2502     protected void addPmkCacheEntry(String ifaceName, int networkId, byte[/* 6 */] bssid,
2503             long expirationTimeInSec, ArrayList<Byte> serializedEntry) {
2504         synchronized (mLock) {
2505             String macAddressStr = getMacAddress(ifaceName);
2506             try {
2507                 MacAddress bssAddr = bssid != null ? MacAddress.fromBytes(bssid) : null;
2508                 if (!mPmkCacheManager.add(MacAddress.fromString(macAddressStr), networkId,
2509                         bssAddr, expirationTimeInSec, serializedEntry)) {
2510                     Log.w(TAG, "Cannot add PMK cache for " + ifaceName);
2511                 }
2512             } catch (IllegalArgumentException ex) {
2513                 Log.w(TAG, "Cannot add PMK cache: " + ex);
2514             }
2515         }
2516     }
2517 
removePmkCacheEntry(int networkId)2518     protected void removePmkCacheEntry(int networkId) {
2519         synchronized (mLock) {
2520             mPmkCacheManager.remove(networkId);
2521         }
2522     }
2523 
2524     /**
2525      * Returns a bitmask of advanced capabilities: WPA3 SAE/SUITE B and OWE
2526      * Bitmask used is:
2527      * - WIFI_FEATURE_WPA3_SAE
2528      * - WIFI_FEATURE_WPA3_SUITE_B
2529      * - WIFI_FEATURE_OWE
2530      *
2531      *  @return true if successful, false otherwise.
2532      */
getAdvancedCapabilities(@onNull String ifaceName)2533     public long getAdvancedCapabilities(@NonNull String ifaceName) {
2534         synchronized (mLock) {
2535             final String methodStr = "getAdvancedCapabilities";
2536             long advancedCapabilities = 0;
2537             int keyMgmtCapabilities = getKeyMgmtCapabilities(ifaceName);
2538 
2539             advancedCapabilities |= WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS
2540                     | WIFI_FEATURE_DECORATED_IDENTITY;
2541             if (mVerboseLoggingEnabled) {
2542                 Log.v(TAG, methodStr + ": Passpoint T&C supported");
2543                 Log.v(TAG, methodStr + ": RFC 7542 decorated identity supported");
2544             }
2545 
2546             if ((keyMgmtCapabilities & KeyMgmtMask.SAE) != 0) {
2547                 advancedCapabilities |= WIFI_FEATURE_WPA3_SAE;
2548 
2549                 if (mVerboseLoggingEnabled) {
2550                     Log.v(TAG, methodStr + ": SAE supported");
2551                 }
2552             }
2553 
2554             if ((keyMgmtCapabilities & KeyMgmtMask.SUITE_B_192) != 0) {
2555                 advancedCapabilities |= WIFI_FEATURE_WPA3_SUITE_B;
2556 
2557                 if (mVerboseLoggingEnabled) {
2558                     Log.v(TAG, methodStr + ": SUITE_B supported");
2559                 }
2560             }
2561 
2562             if ((keyMgmtCapabilities & KeyMgmtMask.OWE) != 0) {
2563                 advancedCapabilities |= WIFI_FEATURE_OWE;
2564 
2565                 if (mVerboseLoggingEnabled) {
2566                     Log.v(TAG, methodStr + ": OWE supported");
2567                 }
2568             }
2569 
2570             if ((keyMgmtCapabilities & KeyMgmtMask.DPP) != 0) {
2571                 advancedCapabilities |= WIFI_FEATURE_DPP
2572                         | WIFI_FEATURE_DPP_ENROLLEE_RESPONDER;
2573 
2574                 if (mVerboseLoggingEnabled) {
2575                     Log.v(TAG, methodStr + ": DPP supported");
2576                     Log.v(TAG, methodStr + ": DPP ENROLLEE RESPONDER supported");
2577                 }
2578             }
2579 
2580             if ((keyMgmtCapabilities & KeyMgmtMask.WAPI_PSK) != 0) {
2581                 advancedCapabilities |= WIFI_FEATURE_WAPI;
2582 
2583                 if (mVerboseLoggingEnabled) {
2584                     Log.v(TAG, methodStr + ": WAPI supported");
2585                 }
2586             }
2587 
2588             if ((keyMgmtCapabilities & KeyMgmtMask.FILS_SHA256) != 0) {
2589                 advancedCapabilities |= WIFI_FEATURE_FILS_SHA256;
2590 
2591                 if (mVerboseLoggingEnabled) {
2592                     Log.v(TAG, methodStr + ": FILS_SHA256 supported");
2593                 }
2594             }
2595 
2596             if ((keyMgmtCapabilities & KeyMgmtMask.FILS_SHA384) != 0) {
2597                 advancedCapabilities |= WIFI_FEATURE_FILS_SHA384;
2598 
2599                 if (mVerboseLoggingEnabled) {
2600                     Log.v(TAG, methodStr + ": FILS_SHA384 supported");
2601                 }
2602             }
2603 
2604             if (mVerboseLoggingEnabled) {
2605                 Log.v(TAG, methodStr + ": Capability flags = " + keyMgmtCapabilities);
2606             }
2607 
2608             return advancedCapabilities;
2609         }
2610     }
2611 
2612     /**
2613      * Get the bitmask of supplicant/driver supported key management capabilities in
2614      * AIDL KeyMgmtMask format.
2615      */
getKeyMgmtCapabilities(@onNull String ifaceName)2616     private int getKeyMgmtCapabilities(@NonNull String ifaceName) {
2617         synchronized (mLock) {
2618             final String methodStr = "getKeyMgmtCapabilities";
2619             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2620             if (iface == null) {
2621                 return 0;
2622             }
2623             try {
2624                 return iface.getKeyMgmtCapabilities();
2625             } catch (RemoteException e) {
2626                 handleRemoteException(e, methodStr);
2627             } catch (ServiceSpecificException e) {
2628                 handleServiceSpecificException(e, methodStr);
2629             }
2630             return 0;
2631         }
2632     }
2633 
aidlWpaDrvFeatureSetToFrameworkV2(int drvCapabilitiesMask)2634     private long aidlWpaDrvFeatureSetToFrameworkV2(int drvCapabilitiesMask) {
2635         if (!isServiceVersionAtLeast(2)) return 0;
2636 
2637         final String methodStr = "getWpaDriverFeatureSetV2";
2638         long featureSet = 0;
2639 
2640         if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.SET_TLS_MINIMUM_VERSION) != 0) {
2641             featureSet |= WIFI_FEATURE_SET_TLS_MINIMUM_VERSION;
2642             if (mVerboseLoggingEnabled) {
2643                 Log.v(TAG, methodStr + ": EAP-TLS minimum version supported");
2644             }
2645         }
2646 
2647         if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.TLS_V1_3) != 0) {
2648             featureSet |= WIFI_FEATURE_TLS_V1_3;
2649             if (mVerboseLoggingEnabled) {
2650                 Log.v(TAG, methodStr + ": EAP-TLS v1.3 supported");
2651             }
2652         }
2653         return featureSet;
2654     }
2655 
2656     /**
2657      * Get the driver supported features through supplicant.
2658      *
2659      * @param ifaceName Name of the interface.
2660      * @return bitmask defined by WifiManager.WIFI_FEATURE_*.
2661      */
getWpaDriverFeatureSet(@onNull String ifaceName)2662     public long getWpaDriverFeatureSet(@NonNull String ifaceName) {
2663         synchronized (mLock) {
2664             final String methodStr = "getWpaDriverFeatureSet";
2665             int drvCapabilitiesMask = getWpaDriverCapabilities(ifaceName);
2666             long featureSet = 0;
2667 
2668             if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.MBO) != 0) {
2669                 featureSet |= WIFI_FEATURE_MBO;
2670                 if (mVerboseLoggingEnabled) {
2671                     Log.v(TAG, methodStr + ": MBO supported");
2672                 }
2673                 if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.OCE) != 0) {
2674                     featureSet |= WIFI_FEATURE_OCE;
2675                     if (mVerboseLoggingEnabled) {
2676                         Log.v(TAG, methodStr + ": OCE supported");
2677                     }
2678                 }
2679             }
2680 
2681             if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.SAE_PK) != 0) {
2682                 featureSet |= WIFI_FEATURE_SAE_PK;
2683                 if (mVerboseLoggingEnabled) {
2684                     Log.v(TAG, methodStr + ": SAE-PK supported");
2685                 }
2686             }
2687 
2688             if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.WFD_R2) != 0) {
2689                 featureSet |= WIFI_FEATURE_WFD_R2;
2690                 if (mVerboseLoggingEnabled) {
2691                     Log.v(TAG, methodStr + ": WFD-R2 supported");
2692                 }
2693             }
2694 
2695             if ((drvCapabilitiesMask
2696                     & WpaDriverCapabilitiesMask.TRUST_ON_FIRST_USE) != 0) {
2697                 featureSet |= WIFI_FEATURE_TRUST_ON_FIRST_USE;
2698                 if (mVerboseLoggingEnabled) {
2699                     Log.v(TAG, methodStr + ": Trust-On-First-Use supported");
2700                 }
2701             }
2702 
2703             featureSet |= aidlWpaDrvFeatureSetToFrameworkV2(drvCapabilitiesMask);
2704 
2705             return featureSet;
2706         }
2707     }
2708 
2709     /**
2710      * Get the bitmask of supplicant/driver supported features in
2711      * AIDL WpaDriverCapabilitiesMask format.
2712      */
getWpaDriverCapabilities(@onNull String ifaceName)2713     private int getWpaDriverCapabilities(@NonNull String ifaceName) {
2714         synchronized (mLock) {
2715             final String methodStr = "getWpaDriverCapabilities";
2716             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2717             if (iface == null) {
2718                 return 0;
2719             }
2720             try {
2721                 return iface.getWpaDriverCapabilities();
2722             } catch (RemoteException e) {
2723                 handleRemoteException(e, methodStr);
2724             } catch (ServiceSpecificException e) {
2725                 handleServiceSpecificException(e, methodStr);
2726             }
2727             return 0;
2728         }
2729     }
2730 
getWifiStandard(int technology)2731     private @WifiAnnotations.WifiStandard int getWifiStandard(int technology) {
2732         switch(technology) {
2733             case WifiTechnology.EHT:
2734                 return ScanResult.WIFI_STANDARD_11BE;
2735             case WifiTechnology.HE:
2736                 return ScanResult.WIFI_STANDARD_11AX;
2737             case WifiTechnology.VHT:
2738                 return ScanResult.WIFI_STANDARD_11AC;
2739             case WifiTechnology.HT:
2740                 return ScanResult.WIFI_STANDARD_11N;
2741             case WifiTechnology.LEGACY:
2742                 return ScanResult.WIFI_STANDARD_LEGACY;
2743             default:
2744                 return ScanResult.WIFI_STANDARD_UNKNOWN;
2745         }
2746     }
2747 
getChannelBandwidth(int channelBandwidth)2748     private int getChannelBandwidth(int channelBandwidth) {
2749         switch(channelBandwidth) {
2750             case WifiChannelWidthInMhz.WIDTH_20:
2751                 return ScanResult.CHANNEL_WIDTH_20MHZ;
2752             case WifiChannelWidthInMhz.WIDTH_40:
2753                 return ScanResult.CHANNEL_WIDTH_40MHZ;
2754             case WifiChannelWidthInMhz.WIDTH_80:
2755                 return ScanResult.CHANNEL_WIDTH_80MHZ;
2756             case WifiChannelWidthInMhz.WIDTH_160:
2757                 return ScanResult.CHANNEL_WIDTH_160MHZ;
2758             case WifiChannelWidthInMhz.WIDTH_80P80:
2759                 return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
2760             case WifiChannelWidthInMhz.WIDTH_320:
2761                 return ScanResult.CHANNEL_WIDTH_320MHZ;
2762             default:
2763                 return ScanResult.CHANNEL_WIDTH_20MHZ;
2764         }
2765     }
2766 
frameworkToAidlDppAkm(int dppAkm)2767     private int frameworkToAidlDppAkm(int dppAkm) {
2768         switch(dppAkm) {
2769             case SupplicantStaIfaceHal.DppAkm.PSK:
2770                 return DppAkm.PSK;
2771             case SupplicantStaIfaceHal.DppAkm.PSK_SAE:
2772                 return DppAkm.PSK_SAE;
2773             case SupplicantStaIfaceHal.DppAkm.SAE:
2774                 return DppAkm.SAE;
2775             case SupplicantStaIfaceHal.DppAkm.DPP:
2776                 return DppAkm.DPP;
2777             default:
2778                 Log.e(TAG, "Invalid DppAkm received");
2779                 return -1;
2780         }
2781     }
2782 
frameworkToAidlDppCurve(int dppCurve)2783     private int frameworkToAidlDppCurve(int dppCurve) {
2784         switch(dppCurve) {
2785             case SupplicantStaIfaceHal.DppCurve.PRIME256V1:
2786                 return DppCurve.PRIME256V1;
2787             case SupplicantStaIfaceHal.DppCurve.SECP384R1:
2788                 return DppCurve.SECP384R1;
2789             case SupplicantStaIfaceHal.DppCurve.SECP521R1:
2790                 return DppCurve.SECP521R1;
2791             case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP256R1:
2792                 return DppCurve.BRAINPOOLP256R1;
2793             case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP384R1:
2794                 return DppCurve.BRAINPOOLP384R1;
2795             case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP512R1:
2796                 return DppCurve.BRAINPOOLP512R1;
2797             default:
2798                 Log.e(TAG, "Invalid DppCurve received");
2799                 return -1;
2800         }
2801     }
2802 
frameworkToAidlDppNetRole(int dppNetRole)2803     private int frameworkToAidlDppNetRole(int dppNetRole) {
2804         switch(dppNetRole) {
2805             case SupplicantStaIfaceHal.DppNetRole.STA:
2806                 return DppNetRole.STA;
2807             case SupplicantStaIfaceHal.DppNetRole.AP:
2808                 return DppNetRole.AP;
2809             default:
2810                 Log.e(TAG, "Invalid DppNetRole received");
2811                 return -1;
2812         }
2813     }
2814 
dscpPolicyToAidlQosPolicyStatusCode(int status)2815     protected byte dscpPolicyToAidlQosPolicyStatusCode(int status) {
2816         switch (status) {
2817             case NetworkAgent.DSCP_POLICY_STATUS_SUCCESS:
2818             case NetworkAgent.DSCP_POLICY_STATUS_DELETED:
2819                 return QosPolicyStatusCode.QOS_POLICY_SUCCESS;
2820             case NetworkAgent.DSCP_POLICY_STATUS_REQUEST_DECLINED:
2821                 return QosPolicyStatusCode.QOS_POLICY_REQUEST_DECLINED;
2822             case NetworkAgent.DSCP_POLICY_STATUS_REQUESTED_CLASSIFIER_NOT_SUPPORTED:
2823                 return QosPolicyStatusCode.QOS_POLICY_CLASSIFIER_NOT_SUPPORTED;
2824             case NetworkAgent.DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES:
2825                 return QosPolicyStatusCode.QOS_POLICY_INSUFFICIENT_RESOURCES;
2826             default:
2827                 Log.e(TAG, "Invalid DSCP policy failure code received: " + status);
2828                 return QosPolicyStatusCode.QOS_POLICY_REQUEST_DECLINED;
2829         }
2830     }
2831 
halToFrameworkQosPolicyRequestType(byte requestType)2832     protected static int halToFrameworkQosPolicyRequestType(byte requestType) {
2833         switch (requestType) {
2834             case QosPolicyRequestType.QOS_POLICY_ADD:
2835                 return SupplicantStaIfaceHal.QOS_POLICY_REQUEST_ADD;
2836             case QosPolicyRequestType.QOS_POLICY_REMOVE:
2837                 return SupplicantStaIfaceHal.QOS_POLICY_REQUEST_REMOVE;
2838             default:
2839                 Log.e(TAG, "Invalid QosPolicyRequestType received: " + requestType);
2840                 return -1;
2841         }
2842     }
2843 
qosClassifierParamHasValue(int classifierParamMask, int paramBit)2844     private static boolean qosClassifierParamHasValue(int classifierParamMask, int paramBit) {
2845         return (classifierParamMask & paramBit) != 0;
2846     }
2847 
2848     /**
2849      * Convert from a HAL QosPolicyData object to a framework QosPolicy object.
2850      */
halToFrameworkQosPolicy( QosPolicyData halQosPolicy)2851     public static SupplicantStaIfaceHal.QosPolicyRequest halToFrameworkQosPolicy(
2852             QosPolicyData halQosPolicy) {
2853         QosPolicyClassifierParams classifierParams = halQosPolicy.classifierParams;
2854         int classifierParamMask = classifierParams.classifierParamMask;
2855 
2856         byte[] srcIp = null;
2857         byte[] dstIp = null;
2858         int srcPort = DscpPolicy.SOURCE_PORT_ANY;
2859         int[] dstPortRange = null;
2860         int protocol = DscpPolicy.PROTOCOL_ANY;
2861         boolean hasSrcIp = false;
2862         boolean hasDstIp = false;
2863 
2864         if (qosClassifierParamHasValue(classifierParamMask, QosPolicyClassifierParamsMask.SRC_IP)) {
2865             hasSrcIp = true;
2866             srcIp = classifierParams.srcIp;
2867         }
2868         if (qosClassifierParamHasValue(classifierParamMask, QosPolicyClassifierParamsMask.DST_IP)) {
2869             hasDstIp = true;
2870             dstIp = classifierParams.dstIp;
2871         }
2872         if (qosClassifierParamHasValue(classifierParamMask,
2873                 QosPolicyClassifierParamsMask.SRC_PORT)) {
2874             srcPort = classifierParams.srcPort;
2875         }
2876         if (qosClassifierParamHasValue(classifierParamMask,
2877                 QosPolicyClassifierParamsMask.DST_PORT_RANGE)) {
2878             dstPortRange = new int[2];
2879             dstPortRange[0] = classifierParams.dstPortRange.startPort;
2880             dstPortRange[1] = classifierParams.dstPortRange.endPort;
2881         }
2882         if (qosClassifierParamHasValue(classifierParamMask,
2883                 QosPolicyClassifierParamsMask.PROTOCOL_NEXT_HEADER)) {
2884             protocol = classifierParams.protocolNextHdr;
2885         }
2886 
2887         return new SupplicantStaIfaceHal.QosPolicyRequest(halQosPolicy.policyId,
2888                 halToFrameworkQosPolicyRequestType(halQosPolicy.requestType), halQosPolicy.dscp,
2889                 new SupplicantStaIfaceHal.QosPolicyClassifierParams(
2890                         hasSrcIp, srcIp, hasDstIp, dstIp, srcPort, dstPortRange, protocol));
2891     }
2892 
2893     /**
2894      * Convert from a framework {@link QosPolicyParams} to a HAL QosPolicyScsData object.
2895      */
2896     @VisibleForTesting
frameworkToHalQosPolicyScsData(QosPolicyParams params)2897     protected static QosPolicyScsData frameworkToHalQosPolicyScsData(QosPolicyParams params) {
2898         QosPolicyScsData halData = new QosPolicyScsData();
2899         halData.policyId = (byte) params.getTranslatedPolicyId();
2900         halData.userPriority = (byte) params.getUserPriority();
2901         QosPolicyClassifierParams classifierParams = new QosPolicyClassifierParams();
2902         int paramsMask = 0;
2903 
2904         classifierParams.srcIp = new byte[0];
2905         classifierParams.dstIp = new byte[0];
2906         classifierParams.dstPortRange = new PortRange();
2907         classifierParams.flowLabelIpv6 = new byte[0];
2908         classifierParams.domainName = "";
2909         classifierParams.ipVersion = params.getIpVersion() == QosPolicyParams.IP_VERSION_4
2910                 ? IpVersion.VERSION_4 : IpVersion.VERSION_6;
2911 
2912         if (params.getSourceAddress() != null) {
2913             paramsMask |= QosPolicyClassifierParamsMask.SRC_IP;
2914             classifierParams.srcIp = params.getSourceAddress().getAddress();
2915         }
2916         if (params.getDestinationAddress() != null) {
2917             paramsMask |= QosPolicyClassifierParamsMask.DST_IP;
2918             classifierParams.dstIp = params.getDestinationAddress().getAddress();
2919         }
2920         if (params.getSourcePort() != DscpPolicy.SOURCE_PORT_ANY) {
2921             paramsMask |= QosPolicyClassifierParamsMask.SRC_PORT;
2922             classifierParams.srcPort = params.getSourcePort();
2923         }
2924         if (params.getDestinationPortRange() != null) {
2925             paramsMask |= QosPolicyClassifierParamsMask.DST_PORT_RANGE;
2926             classifierParams.dstPortRange.startPort = params.getDestinationPortRange()[0];
2927             classifierParams.dstPortRange.endPort = params.getDestinationPortRange()[1];
2928         }
2929         if (params.getProtocol() != QosPolicyParams.PROTOCOL_ANY) {
2930             paramsMask |= QosPolicyClassifierParamsMask.PROTOCOL_NEXT_HEADER;
2931             classifierParams.protocolNextHdr = (byte) params.getProtocol();
2932         }
2933         if (params.getDscp() != QosPolicyParams.DSCP_ANY) {
2934             paramsMask |= QosPolicyClassifierParamsMask.DSCP;
2935             classifierParams.dscp = (byte) params.getDscp();
2936         }
2937         if (params.getFlowLabel() != null) {
2938             paramsMask |= QosPolicyClassifierParamsMask.FLOW_LABEL;
2939             classifierParams.flowLabelIpv6 = params.getFlowLabel();
2940         }
2941 
2942         classifierParams.classifierParamMask = paramsMask;
2943         halData.classifierParams = classifierParams;
2944         return halData;
2945     }
2946 
frameworkToHalQosPolicyScsDataList( List<QosPolicyParams> frameworkPolicies)2947     private static QosPolicyScsData[] frameworkToHalQosPolicyScsDataList(
2948             List<QosPolicyParams> frameworkPolicies) {
2949         QosPolicyScsData[] halDataList = new QosPolicyScsData[frameworkPolicies.size()];
2950         int index = 0;
2951         for (QosPolicyParams policy : frameworkPolicies) {
2952             halDataList[index] = frameworkToHalQosPolicyScsData(policy);
2953             index++;
2954         }
2955         return halDataList;
2956     }
2957 
2958     private static @SupplicantStaIfaceHal.QosPolicyScsRequestStatusCode int
halToFrameworkQosPolicyScsRequestStatusCode(int statusCode)2959             halToFrameworkQosPolicyScsRequestStatusCode(int statusCode) {
2960         switch (statusCode) {
2961             case QosPolicyScsRequestStatusCode.SENT:
2962                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_SENT;
2963             case QosPolicyScsRequestStatusCode.ALREADY_ACTIVE:
2964                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_ALREADY_ACTIVE;
2965             case QosPolicyScsRequestStatusCode.NOT_EXIST:
2966                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_NOT_EXIST;
2967             case QosPolicyScsRequestStatusCode.INVALID:
2968                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_INVALID;
2969             default:
2970                 Log.wtf(TAG, "Invalid QosPolicyScsRequestStatusCode: " + statusCode);
2971                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_ERROR_UNKNOWN;
2972         }
2973     }
2974 
2975     private static List<SupplicantStaIfaceHal.QosPolicyStatus>
halToFrameworkQosPolicyScsRequestStatusList(QosPolicyScsRequestStatus[] halStatusList)2976             halToFrameworkQosPolicyScsRequestStatusList(QosPolicyScsRequestStatus[] halStatusList) {
2977         List<SupplicantStaIfaceHal.QosPolicyStatus> frameworkStatusList = new ArrayList<>();
2978         for (QosPolicyScsRequestStatus halStatus : halStatusList) {
2979             frameworkStatusList.add(new SupplicantStaIfaceHal.QosPolicyStatus(
2980                     halStatus.policyId,
2981                     halToFrameworkQosPolicyScsRequestStatusCode(
2982                             halStatus.qosPolicyScsRequestStatusCode)));
2983         }
2984         return frameworkStatusList;
2985     }
2986 
2987     /**
2988      * Returns connection capabilities of the current network
2989      *
2990      * @param ifaceName Name of the interface.
2991      * @return connection capabilities of the current network
2992      */
getConnectionCapabilities(@onNull String ifaceName)2993     public WifiNative.ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) {
2994         synchronized (mLock) {
2995             final String methodStr = "getConnectionCapabilities";
2996             WifiNative.ConnectionCapabilities capOut = new WifiNative.ConnectionCapabilities();
2997             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2998             if (iface == null) {
2999                 return capOut;
3000             }
3001             try {
3002                 ConnectionCapabilities cap = iface.getConnectionCapabilities();
3003                 capOut.wifiStandard = getWifiStandard(cap.technology);
3004                 capOut.channelBandwidth = getChannelBandwidth(cap.channelBandwidth);
3005                 capOut.is11bMode = (cap.legacyMode == LegacyMode.B_MODE);
3006                 capOut.maxNumberTxSpatialStreams = cap.maxNumberTxSpatialStreams;
3007                 capOut.maxNumberRxSpatialStreams = cap.maxNumberRxSpatialStreams;
3008                 capOut.apTidToLinkMapNegotiationSupported = cap.apTidToLinkMapNegotiationSupported;
3009                 return capOut;
3010             } catch (RemoteException e) {
3011                 handleRemoteException(e, methodStr);
3012             } catch (ServiceSpecificException e) {
3013                 handleServiceSpecificException(e, methodStr);
3014             }
3015             return capOut;
3016         }
3017     }
3018 
3019     /**
3020      * Returns signal poll results for all Wi-Fi links of the interface. Need service version at
3021      * least 2 or higher.
3022      *
3023      * @param ifaceName Name of the interface.
3024      * @return Signal poll results or null if error.
3025      */
getSignalPollResults(@onNull String ifaceName)3026     public WifiSignalPollResults getSignalPollResults(@NonNull String ifaceName) {
3027         if (!isServiceVersionAtLeast(2)) return null;
3028         synchronized (mLock) {
3029             final String methodStr = "getSignalPollResult";
3030             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3031             if (iface == null) {
3032                 return null;
3033             }
3034             try {
3035                 SignalPollResult[] halSignalPollResults = iface.getSignalPollResults();
3036                 if (halSignalPollResults == null) {
3037                     return null;
3038                 }
3039                 WifiSignalPollResults nativeSignalPollResults =
3040                         new WifiSignalPollResults();
3041                 for (SignalPollResult r : halSignalPollResults) {
3042                     nativeSignalPollResults.addEntry(r.linkId, r.currentRssiDbm, r.txBitrateMbps,
3043                             r.rxBitrateMbps, r.frequencyMhz);
3044                 }
3045                 return nativeSignalPollResults;
3046             } catch (RemoteException e) {
3047                 handleRemoteException(e, methodStr);
3048             } catch (ServiceSpecificException e) {
3049                 handleServiceSpecificException(e, methodStr);
3050             }
3051             return null;
3052         }
3053     }
3054 
3055     /**
3056      * Returns connection MLO links info
3057      *
3058      * @param ifaceName Name of the interface.
3059      * @return connection MLO links info
3060      */
getConnectionMloLinksInfo(@onNull String ifaceName)3061     public WifiNative.ConnectionMloLinksInfo getConnectionMloLinksInfo(@NonNull String ifaceName) {
3062         synchronized (mLock) {
3063             final String methodStr = "getConnectionMloLinksInfo";
3064             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3065             if (iface == null) {
3066                 return null;
3067             }
3068             try {
3069                 MloLinksInfo halInfo = iface.getConnectionMloLinksInfo();
3070                 if (halInfo == null) {
3071                     return null;
3072                 }
3073 
3074                 WifiNative.ConnectionMloLinksInfo nativeInfo =
3075                         new WifiNative.ConnectionMloLinksInfo();
3076 
3077                 // The parameter 'apMldMacAddress' can come as null.
3078                 if (halInfo.apMldMacAddress != null) {
3079                     nativeInfo.apMldMacAddress = MacAddress.fromBytes(halInfo.apMldMacAddress);
3080                 }
3081                 nativeInfo.apMloLinkId = halInfo.apMloLinkId;
3082                 nativeInfo.links = new WifiNative.ConnectionMloLink[halInfo.links.length];
3083 
3084                 for (int i = 0; i < halInfo.links.length; i++) {
3085                     // The parameter 'apLinkMacAddress' can come as null.
3086                     nativeInfo.links[i] = new WifiNative.ConnectionMloLink(
3087                             halInfo.links[i].linkId,
3088                             MacAddress.fromBytes(halInfo.links[i].staLinkMacAddress),
3089                             (halInfo.links[i].apLinkMacAddress != null) ? MacAddress.fromBytes(
3090                                     halInfo.links[i].apLinkMacAddress) : null,
3091                             halInfo.links[i].tidsUplinkMap, halInfo.links[i].tidsDownlinkMap,
3092                             halInfo.links[i].frequencyMHz);
3093                 }
3094                 return nativeInfo;
3095             } catch (RemoteException e) {
3096                 handleRemoteException(e, methodStr);
3097             } catch (ServiceSpecificException e) {
3098                 handleServiceSpecificException(e, methodStr);
3099             } catch (IllegalArgumentException e) {
3100                 Log.e(TAG, "Invalid STA Mac Address received from HAL");
3101                 return null;
3102             }
3103 
3104             return null;
3105         }
3106     }
3107 
3108     /**
3109      * Adds a DPP peer URI to the URI list.
3110      *
3111      * Returns an ID to be used later to refer to this URI (>0).
3112      * On error, -1 is returned.
3113      */
addDppPeerUri(@onNull String ifaceName, @NonNull String uri)3114     public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) {
3115         synchronized (mLock) {
3116             final String methodStr = "addDppPeerUri";
3117             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3118             if (iface == null) {
3119                 return -1;
3120             }
3121             try {
3122                 return iface.addDppPeerUri(uri);
3123             } catch (RemoteException e) {
3124                 handleRemoteException(e, methodStr);
3125             } catch (ServiceSpecificException e) {
3126                 handleServiceSpecificException(e, methodStr);
3127             }
3128             return -1;
3129         }
3130     }
3131 
3132     /**
3133      * Removes a DPP URI to the URI list given an ID.
3134      *
3135      * Returns true when operation is successful
3136      * On error, false is returned.
3137      */
removeDppUri(@onNull String ifaceName, int bootstrapId)3138     public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId)  {
3139         synchronized (mLock) {
3140             final String methodStr = "removeDppUri";
3141             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3142             if (iface == null) {
3143                 return false;
3144             }
3145             try {
3146                 iface.removeDppUri(bootstrapId);
3147                 return true;
3148             } catch (RemoteException e) {
3149                 handleRemoteException(e, methodStr);
3150             } catch (ServiceSpecificException e) {
3151                 handleServiceSpecificException(e, methodStr);
3152             }
3153             return false;
3154         }
3155     }
3156 
3157     /**
3158      * Stops/aborts DPP Initiator request
3159      *
3160      * Returns true when operation is successful
3161      * On error, false is returned.
3162      */
stopDppInitiator(@onNull String ifaceName)3163     public boolean stopDppInitiator(@NonNull String ifaceName)  {
3164         synchronized (mLock) {
3165             final String methodStr = "stopDppInitiator";
3166             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3167             if (iface == null) {
3168                 return false;
3169             }
3170             try {
3171                 iface.stopDppInitiator();
3172                 return true;
3173             } catch (RemoteException e) {
3174                 handleRemoteException(e, methodStr);
3175             } catch (ServiceSpecificException e) {
3176                 handleServiceSpecificException(e, methodStr);
3177             }
3178             return false;
3179         }
3180     }
3181 
3182     /**
3183      * Starts DPP Configurator-Initiator request
3184      *
3185      * Returns true when operation is successful
3186      * On error, false is returned.
3187      */
startDppConfiguratorInitiator(@onNull String ifaceName, int peerBootstrapId, int ownBootstrapId, @NonNull String ssid, String password, String psk, int netRole, int securityAkm, byte[] privEcKey)3188     public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId,
3189             int ownBootstrapId, @NonNull String ssid, String password, String psk,
3190             int netRole, int securityAkm, byte[] privEcKey)  {
3191         synchronized (mLock) {
3192             final String methodStr = "startDppConfiguratorInitiator";
3193             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3194             if (iface == null) {
3195                 return false;
3196             }
3197             try {
3198                 byte[] key = iface.startDppConfiguratorInitiator(peerBootstrapId, ownBootstrapId,
3199                         ssid, password != null ? password : "", psk != null ? psk : "",
3200                         frameworkToAidlDppNetRole(netRole), frameworkToAidlDppAkm(securityAkm),
3201                         privEcKey != null ? privEcKey : new byte[] {});
3202                 if (key != null && key.length > 0 && mDppCallback != null) {
3203                     mDppCallback.onDppConfiguratorKeyUpdate(key);
3204                 }
3205                 return true;
3206             } catch (RemoteException e) {
3207                 handleRemoteException(e, methodStr);
3208             } catch (ServiceSpecificException e) {
3209                 handleServiceSpecificException(e, methodStr);
3210             }
3211             return false;
3212         }
3213     }
3214 
3215     /**
3216      * Starts DPP Enrollee-Initiator request
3217      *
3218      * Returns true when operation is successful
3219      * On error, false is returned.
3220      */
startDppEnrolleeInitiator(@onNull String ifaceName, int peerBootstrapId, int ownBootstrapId)3221     public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId,
3222             int ownBootstrapId)  {
3223         synchronized (mLock) {
3224             final String methodStr = "startDppEnrolleeInitiator";
3225             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3226             if (iface == null) {
3227                 return false;
3228             }
3229             try {
3230                 iface.startDppEnrolleeInitiator(peerBootstrapId, ownBootstrapId);
3231                 return true;
3232             } catch (RemoteException e) {
3233                 handleRemoteException(e, methodStr);
3234             } catch (ServiceSpecificException e) {
3235                 handleServiceSpecificException(e, methodStr);
3236             }
3237             return false;
3238         }
3239     }
3240 
3241     /**
3242      * Generate a DPP QR code based boot strap info
3243      *
3244      * Returns DppResponderBootstrapInfo;
3245      */
generateDppBootstrapInfoForResponder( @onNull String ifaceName, String macAddress, @NonNull String deviceInfo, int dppCurve)3246     public WifiNative.DppBootstrapQrCodeInfo generateDppBootstrapInfoForResponder(
3247             @NonNull String ifaceName, String macAddress, @NonNull String deviceInfo,
3248             int dppCurve) {
3249         synchronized (mLock) {
3250             final String methodStr = "generateDppBootstrapInfoForResponder";
3251             WifiNative.DppBootstrapQrCodeInfo bootstrapInfoOut =
3252                     new WifiNative.DppBootstrapQrCodeInfo();
3253             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3254             if (iface == null) {
3255                 return bootstrapInfoOut;
3256             }
3257             try {
3258                 DppResponderBootstrapInfo info = iface.generateDppBootstrapInfoForResponder(
3259                         NativeUtil.macAddressToByteArray(macAddress), deviceInfo,
3260                         frameworkToAidlDppCurve(dppCurve));
3261                 bootstrapInfoOut.bootstrapId = info.bootstrapId;
3262                 bootstrapInfoOut.listenChannel = info.listenChannel;
3263                 bootstrapInfoOut.uri = info.uri;
3264                 return bootstrapInfoOut;
3265             } catch (RemoteException e) {
3266                 handleRemoteException(e, methodStr);
3267             } catch (ServiceSpecificException e) {
3268                 handleServiceSpecificException(e, methodStr);
3269             }
3270             return bootstrapInfoOut;
3271         }
3272     }
3273 
3274     /**
3275      * Starts DPP Enrollee-Responder request
3276      *
3277      * Returns true when operation is successful
3278      * On error, false is returned.
3279      */
startDppEnrolleeResponder(@onNull String ifaceName, int listenChannel)3280     public boolean startDppEnrolleeResponder(@NonNull String ifaceName, int listenChannel) {
3281         synchronized (mLock) {
3282             final String methodStr = "startDppEnrolleeResponder";
3283             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3284             if (iface == null) {
3285                 return false;
3286             }
3287             try {
3288                 iface.startDppEnrolleeResponder(listenChannel);
3289                 return true;
3290             } catch (RemoteException e) {
3291                 handleRemoteException(e, methodStr);
3292             } catch (ServiceSpecificException e) {
3293                 handleServiceSpecificException(e, methodStr);
3294             }
3295             return false;
3296         }
3297     }
3298 
3299     /**
3300      * Stops/aborts DPP Responder request.
3301      *
3302      * Returns true when operation is successful
3303      * On error, false is returned.
3304      */
stopDppResponder(@onNull String ifaceName, int ownBootstrapId)3305     public boolean stopDppResponder(@NonNull String ifaceName, int ownBootstrapId)  {
3306         synchronized (mLock) {
3307             final String methodStr = "stopDppResponder";
3308             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3309             if (iface == null) {
3310                 return false;
3311             }
3312             try {
3313                 iface.stopDppResponder(ownBootstrapId);
3314                 return true;
3315             } catch (RemoteException e) {
3316                 handleRemoteException(e, methodStr);
3317             } catch (ServiceSpecificException e) {
3318                 handleServiceSpecificException(e, methodStr);
3319             }
3320             return false;
3321         }
3322     }
3323 
3324     /**
3325      * Register callbacks for DPP events.
3326      *
3327      * @param dppCallback DPP callback object.
3328      */
registerDppCallback(WifiNative.DppEventCallback dppCallback)3329     public void registerDppCallback(WifiNative.DppEventCallback dppCallback) {
3330         synchronized (mLock) {
3331             mDppCallback = dppCallback;
3332         }
3333     }
3334 
getDppCallback()3335     protected WifiNative.DppEventCallback getDppCallback() {
3336         synchronized (mLock) {
3337             return mDppCallback;
3338         }
3339     }
3340 
3341     /**
3342      * Set MBO cellular data availability.
3343      *
3344      * @param ifaceName Name of the interface.
3345      * @param available true means cellular data available, false otherwise.
3346      * @return true is operation is successful, false otherwise.
3347      */
setMboCellularDataStatus(@onNull String ifaceName, boolean available)3348     public boolean setMboCellularDataStatus(@NonNull String ifaceName, boolean available) {
3349         synchronized (mLock) {
3350             final String methodStr = "setMboCellularDataStatus";
3351             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3352             if (iface == null) {
3353                 return false;
3354             }
3355             try {
3356                 iface.setMboCellularDataStatus(available);
3357                 return true;
3358             } catch (RemoteException e) {
3359                 handleRemoteException(e, methodStr);
3360             } catch (ServiceSpecificException e) {
3361                 handleServiceSpecificException(e, methodStr);
3362             }
3363             return false;
3364         }
3365     }
3366 
3367     /**
3368      * Set whether the network-centric QoS policy feature is enabled or not for this interface.
3369      *
3370      * @param ifaceName name of the interface.
3371      * @param isEnabled true if feature is enabled, false otherwise.
3372      * @return true if operation is successful, false otherwise.
3373      */
setNetworkCentricQosPolicyFeatureEnabled(@onNull String ifaceName, boolean isEnabled)3374     public boolean setNetworkCentricQosPolicyFeatureEnabled(@NonNull String ifaceName,
3375             boolean isEnabled) {
3376         synchronized (mLock) {
3377             String methodStr = "setNetworkCentricQosPolicyFeatureEnabled";
3378             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3379             if (iface == null) {
3380                 return false;
3381             }
3382             try {
3383                 iface.setQosPolicyFeatureEnabled(isEnabled);
3384                 return true;
3385             } catch (RemoteException e) {
3386                 handleRemoteException(e, methodStr);
3387             } catch (ServiceSpecificException e) {
3388                 handleServiceSpecificException(e, methodStr);
3389             }
3390             return false;
3391         }
3392     }
3393 
3394     /**
3395      * Check if we've roamed to a linked network and make the linked network the current network
3396      * if we have.
3397      *
3398      * @param ifaceName Name of the interface.
3399      * @param newNetworkId Network id of the new network we've roamed to. If fromFramework is
3400      *                     {@code true}, this will be a framework network id. Otherwise, this will
3401      *                     be a remote network id.
3402      * @param fromFramework {@code true} if the network id is a framework network id, {@code false}
3403                             if the network id is a remote network id.
3404      * @return true if we've roamed to a linked network, false if not.
3405      */
updateOnLinkedNetworkRoaming( @onNull String ifaceName, int newNetworkId, boolean fromFramework)3406     public boolean updateOnLinkedNetworkRoaming(
3407             @NonNull String ifaceName, int newNetworkId, boolean fromFramework) {
3408         synchronized (mLock) {
3409             List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>> linkedNetworkHandles =
3410                     mLinkedNetworkLocalAndRemoteConfigs.get(ifaceName);
3411             SupplicantStaNetworkHalAidlImpl currentHandle =
3412                     getCurrentNetworkRemoteHandle(ifaceName);
3413             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
3414             if (linkedNetworkHandles == null || currentHandle == null || currentConfig == null) {
3415                 return false;
3416             }
3417             if (fromFramework ? currentConfig.networkId == newNetworkId
3418                     : currentHandle.getNetworkId() == newNetworkId) {
3419                 return false;
3420             }
3421             for (Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair
3422                     : linkedNetworkHandles) {
3423                 if (fromFramework ? pair.second.networkId == newNetworkId
3424                         : pair.first.getNetworkId() == newNetworkId) {
3425                     Log.i(TAG, "Roamed to linked network, make linked network as current network");
3426                     mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
3427                     mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
3428                     return true;
3429                 }
3430             }
3431             return false;
3432         }
3433     }
3434 
3435     /**
3436      * Updates the linked networks for the current network and sends them to the supplicant.
3437      *
3438      * @param ifaceName Name of the interface.
3439      * @param networkId Network id of the network to link the configurations to.
3440      * @param linkedConfigurations Map of config profile key to config for linking.
3441      * @return true if networks were successfully linked, false otherwise.
3442      */
updateLinkedNetworks(@onNull String ifaceName, int networkId, Map<String, WifiConfiguration> linkedConfigurations)3443     public boolean updateLinkedNetworks(@NonNull String ifaceName, int networkId,
3444             Map<String, WifiConfiguration> linkedConfigurations) {
3445         synchronized (mLock) {
3446             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
3447             SupplicantStaNetworkHalAidlImpl currentHandle =
3448                     getCurrentNetworkRemoteHandle(ifaceName);
3449 
3450             if (currentConfig == null || currentHandle == null) {
3451                 Log.e(TAG, "current network not configured yet.");
3452                 return false;
3453             }
3454 
3455             if (networkId != currentConfig.networkId) {
3456                 Log.e(TAG, "current config network id is not matching");
3457                 return false;
3458             }
3459 
3460             final int remoteNetworkId = currentHandle.getNetworkId();
3461             if (remoteNetworkId == -1) {
3462                 Log.e(TAG, "current handle getNetworkId failed");
3463                 return false;
3464             }
3465 
3466             if (!removeAllNetworksExcept(ifaceName, remoteNetworkId)) {
3467                 Log.e(TAG, "couldn't remove non-current supplicant networks");
3468                 return false;
3469             }
3470 
3471             mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
3472 
3473             if (linkedConfigurations == null || linkedConfigurations.size() == 0) {
3474                 Log.i(TAG, "cleared linked networks");
3475                 return true;
3476             }
3477 
3478             List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>> linkedNetworkHandles =
3479                     new ArrayList<>();
3480             linkedNetworkHandles.add(new Pair(currentHandle, currentConfig));
3481             for (String linkedNetwork : linkedConfigurations.keySet()) {
3482                 Log.i(TAG, "add linked network: " + linkedNetwork);
3483                 Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair =
3484                         addNetworkAndSaveConfig(ifaceName, linkedConfigurations.get(linkedNetwork));
3485                 if (pair == null) {
3486                     Log.e(TAG, "failed to add/save linked network: " + linkedNetwork);
3487                     return false;
3488                 }
3489                 pair.first.enable(true);
3490                 linkedNetworkHandles.add(pair);
3491             }
3492 
3493             mLinkedNetworkLocalAndRemoteConfigs.put(ifaceName, linkedNetworkHandles);
3494 
3495             return true;
3496         }
3497     }
3498 
3499     /**
3500      * Remove all networks except the supplied network ID from supplicant
3501      *
3502      * @param ifaceName Name of the interface
3503      * @param networkId network id to keep
3504      */
removeAllNetworksExcept(@onNull String ifaceName, int networkId)3505     private boolean removeAllNetworksExcept(@NonNull String ifaceName, int networkId) {
3506         synchronized (mLock) {
3507             int[] networks = listNetworks(ifaceName);
3508             if (networks == null) {
3509                 Log.e(TAG, "removeAllNetworksExcept failed, got null networks");
3510                 return false;
3511             }
3512             for (int id : networks) {
3513                 if (networkId == id) {
3514                     continue;
3515                 }
3516                 if (!removeNetwork(ifaceName, id)) {
3517                     Log.e(TAG, "removeAllNetworksExcept failed to remove network: " + id);
3518                     return false;
3519                 }
3520             }
3521             return true;
3522         }
3523     }
3524 
3525     /**
3526      * Gets the security params of the current network associated with this interface
3527      *
3528      * @param ifaceName Name of the interface
3529      * @return Security params of the current network associated with the interface
3530      */
getCurrentNetworkSecurityParams(@onNull String ifaceName)3531     public SecurityParams getCurrentNetworkSecurityParams(@NonNull String ifaceName) {
3532         WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
3533 
3534         if (currentConfig == null) {
3535             return null;
3536         }
3537 
3538         return currentConfig.getNetworkSelectionStatus().getCandidateSecurityParams();
3539     }
3540 
3541     /**
3542      * Sends a QoS policy response.
3543      *
3544      * @param ifaceName Name of the interface.
3545      * @param qosPolicyRequestId Dialog token to identify the request.
3546      * @param morePolicies Flag to indicate more QoS policies can be accommodated.
3547      * @param qosPolicyStatusList List of framework QosPolicyStatus objects.
3548      * @return true if response is sent successfully, false otherwise.
3549      */
sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId, boolean morePolicies, @NonNull List<SupplicantStaIfaceHal.QosPolicyStatus> qosPolicyStatusList)3550     public boolean sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId,
3551             boolean morePolicies,
3552             @NonNull List<SupplicantStaIfaceHal.QosPolicyStatus> qosPolicyStatusList) {
3553         synchronized (mLock) {
3554             final String methodStr = "sendQosPolicyResponse";
3555             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3556             if (iface == null) {
3557                 return false;
3558             }
3559 
3560             int index = 0;
3561             QosPolicyStatus[] halPolicyStatusList = new QosPolicyStatus[qosPolicyStatusList.size()];
3562             for (SupplicantStaIfaceHal.QosPolicyStatus frameworkPolicyStatus
3563                     : qosPolicyStatusList) {
3564                 if (frameworkPolicyStatus == null) {
3565                     return false;
3566                 }
3567                 QosPolicyStatus halPolicyStatus = new QosPolicyStatus();
3568                 halPolicyStatus.policyId = (byte) frameworkPolicyStatus.policyId;
3569                 halPolicyStatus.status = dscpPolicyToAidlQosPolicyStatusCode(
3570                         frameworkPolicyStatus.statusCode);
3571                 halPolicyStatusList[index] = halPolicyStatus;
3572                 index++;
3573             }
3574 
3575             try {
3576                 iface.sendQosPolicyResponse(qosPolicyRequestId, morePolicies, halPolicyStatusList);
3577                 return true;
3578             } catch (RemoteException e) {
3579                 handleRemoteException(e, methodStr);
3580             } catch (ServiceSpecificException e) {
3581                 handleServiceSpecificException(e, methodStr);
3582             }
3583             return false;
3584         }
3585     }
3586 
3587     /**
3588      * Indicates the removal of all active QoS policies configured by the AP.
3589      *
3590      * @param ifaceName Name of the interface.
3591      */
removeAllQosPolicies(String ifaceName)3592     public boolean removeAllQosPolicies(String ifaceName) {
3593         final String methodStr = "removeAllQosPolicies";
3594         ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3595         if (iface == null) {
3596             return false;
3597         }
3598 
3599         try {
3600             iface.removeAllQosPolicies();
3601             return true;
3602         } catch (RemoteException e) {
3603             handleRemoteException(e, methodStr);
3604         } catch (ServiceSpecificException e) {
3605             handleServiceSpecificException(e, methodStr);
3606         }
3607         return false;
3608     }
3609 
3610     /**
3611      * See comments for {@link ISupplicantStaIfaceHal#addQosPolicyRequestForScs(String, List)}
3612      */
addQosPolicyRequestForScs( @onNull String ifaceName, @NonNull List<QosPolicyParams> policies)3613     public List<SupplicantStaIfaceHal.QosPolicyStatus> addQosPolicyRequestForScs(
3614             @NonNull String ifaceName, @NonNull List<QosPolicyParams> policies) {
3615         synchronized (mLock) {
3616             final String methodStr = "addQosPolicyRequestForScs";
3617             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3618             if (iface == null) {
3619                 return null;
3620             }
3621             try {
3622                 QosPolicyScsData[] halPolicies = frameworkToHalQosPolicyScsDataList(policies);
3623                 QosPolicyScsRequestStatus[] halStatusList =
3624                         iface.addQosPolicyRequestForScs(halPolicies);
3625                 return halToFrameworkQosPolicyScsRequestStatusList(halStatusList);
3626             } catch (RemoteException e) {
3627                 handleRemoteException(e, methodStr);
3628             } catch (ServiceSpecificException e) {
3629                 handleServiceSpecificException(e, methodStr);
3630             }
3631             return null;
3632         }
3633     }
3634 
3635     /**
3636      * See comments for {@link ISupplicantStaIfaceHal#removeQosPolicyForScs(String, List)}
3637      */
removeQosPolicyForScs( @onNull String ifaceName, @NonNull List<Byte> policyIds)3638     public List<SupplicantStaIfaceHal.QosPolicyStatus> removeQosPolicyForScs(
3639             @NonNull String ifaceName, @NonNull List<Byte> policyIds) {
3640         synchronized (mLock) {
3641             final String methodStr = "removeQosPolicyForScs";
3642             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3643             if (iface == null) {
3644                 return null;
3645             }
3646             try {
3647                 byte[] halPolicyIds = new byte[policyIds.size()];
3648                 for (int i = 0; i < policyIds.size(); i++) {
3649                     halPolicyIds[i] = policyIds.get(i);
3650                 }
3651                 QosPolicyScsRequestStatus[] halStatusList =
3652                         iface.removeQosPolicyForScs(halPolicyIds);
3653                 return halToFrameworkQosPolicyScsRequestStatusList(halStatusList);
3654             } catch (RemoteException e) {
3655                 handleRemoteException(e, methodStr);
3656             } catch (ServiceSpecificException e) {
3657                 handleServiceSpecificException(e, methodStr);
3658             }
3659             return null;
3660         }
3661     }
3662 
3663     /**
3664      * See comments for {@link ISupplicantStaIfaceHal#registerQosScsResponseCallback(
3665      *                             SupplicantStaIfaceHal.QosScsResponseCallback)}
3666      */
registerQosScsResponseCallback( @onNull SupplicantStaIfaceHal.QosScsResponseCallback callback)3667     public void registerQosScsResponseCallback(
3668             @NonNull SupplicantStaIfaceHal.QosScsResponseCallback callback) {
3669         synchronized (mLock) {
3670             if (callback == null) {
3671                 Log.e(TAG, "QosScsResponseCallback should not be null");
3672                 return;
3673             } else if (mQosScsResponseCallback != null) {
3674                 Log.e(TAG, "mQosScsResponseCallback has already been assigned");
3675                 return;
3676             }
3677             mQosScsResponseCallback = callback;
3678         }
3679     }
3680 
getQosScsResponseCallback()3681     protected SupplicantStaIfaceHal.QosScsResponseCallback getQosScsResponseCallback() {
3682         return mQosScsResponseCallback;
3683     }
3684 
3685     /**
3686      * Generate DPP credential for network access
3687      *
3688      * @param ifaceName Name of the interface.
3689      * @param ssid ssid of the network
3690      * @param privEcKey Private EC Key for DPP Configurator
3691      * Returns true when operation is successful. On error, false is returned.
3692      */
generateSelfDppConfiguration(@onNull String ifaceName, @NonNull String ssid, byte[] privEcKey)3693     public boolean generateSelfDppConfiguration(@NonNull String ifaceName, @NonNull String ssid,
3694             byte[] privEcKey) {
3695         synchronized (mLock) {
3696             final String methodStr = "generateSelfDppConfiguration";
3697             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3698             if (iface == null) {
3699                 return false;
3700             }
3701             try {
3702                 iface.generateSelfDppConfiguration(
3703                         NativeUtil.removeEnclosingQuotes(ssid), privEcKey);
3704                 return true;
3705             } catch (RemoteException e) {
3706                 handleRemoteException(e, methodStr);
3707             } catch (ServiceSpecificException e) {
3708                 handleServiceSpecificException(e, methodStr);
3709             }
3710             return false;
3711         }
3712     }
3713 
3714     /**
3715      * Set the currently configured network's anonymous identity.
3716      *
3717      * @param ifaceName Name of the interface.
3718      * @param anonymousIdentity the anonymouns identity.
3719      * @param updateToNativeService write the data to the native service.
3720      * @return true if succeeds, false otherwise.
3721      */
setEapAnonymousIdentity(@onNull String ifaceName, String anonymousIdentity, boolean updateToNativeService)3722     public boolean setEapAnonymousIdentity(@NonNull String ifaceName, String anonymousIdentity,
3723             boolean updateToNativeService) {
3724         synchronized (mLock) {
3725             SupplicantStaNetworkHalAidlImpl networkHandle =
3726                     checkStaNetworkAndLogFailure(ifaceName, "setEapAnonymousIdentity");
3727             if (networkHandle == null) return false;
3728             if (anonymousIdentity == null) return false;
3729             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
3730             if (currentConfig == null) return false;
3731             if (!currentConfig.isEnterprise()) return false;
3732 
3733             if (updateToNativeService) {
3734                 if (!networkHandle.setEapAnonymousIdentity(anonymousIdentity.getBytes())) {
3735                     Log.w(TAG, "Cannot set EAP anonymous identity.");
3736                     return false;
3737                 }
3738             }
3739 
3740             // Update cached config after setting native data successfully.
3741             currentConfig.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
3742             return true;
3743         }
3744     }
3745 
3746     private class NonStandardCertCallback extends INonStandardCertCallback.Stub {
3747         @Override
getBlob(String alias)3748         public byte[] getBlob(String alias) {
3749             byte[] blob = null;
3750             if (SdkLevel.isAtLeastU()) {
3751                 Log.i(TAG, "Non-standard certificate requested");
3752                 blob = WifiKeystore.get(alias);
3753             }
3754             if (blob != null) {
3755                 return blob;
3756             } else {
3757                 Log.e(TAG, "Unable to retrieve the blob");
3758                 throw new ServiceSpecificException(SupplicantStatusCode.FAILURE_UNKNOWN);
3759             }
3760         }
3761 
3762         @Override
listAliases(String prefix)3763         public String[] listAliases(String prefix) {
3764             Log.i(TAG, "Alias list was requested");
3765             return SdkLevel.isAtLeastU() ? WifiKeystore.list(prefix) : null;
3766         }
3767 
3768         @Override
getInterfaceHash()3769         public String getInterfaceHash() {
3770             return INonStandardCertCallback.HASH;
3771         }
3772 
3773         @Override
getInterfaceVersion()3774         public int getInterfaceVersion() {
3775             return INonStandardCertCallback.VERSION;
3776         }
3777     }
3778 
registerNonStandardCertCallback()3779     private void registerNonStandardCertCallback() {
3780         synchronized (mLock) {
3781             final String methodStr = "registerNonStandardCertCallback";
3782             if (!checkSupplicantAndLogFailure(methodStr) || !isServiceVersionAtLeast(2)) {
3783                 return;
3784             } else if (mNonStandardCertCallback != null) {
3785                 Log.i(TAG, "Non-standard cert callback has already been registered");
3786                 return;
3787             }
3788 
3789             try {
3790                 INonStandardCertCallback tempCallback = new NonStandardCertCallback();
3791                 mISupplicant.registerNonStandardCertCallback(tempCallback);
3792                 mNonStandardCertCallback = tempCallback;
3793                 Log.i(TAG, "Non-standard cert callback was registered");
3794             } catch (RemoteException e) {
3795                 handleRemoteException(e, methodStr);
3796             } catch (ServiceSpecificException e) {
3797                 handleServiceSpecificException(e, methodStr);
3798             }
3799         }
3800     }
3801 }
3802