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