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