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