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