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