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