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