• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.wifi;
17 
18 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQP3GPPNetwork;
19 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPDomName;
20 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPIPAddrAvailability;
21 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPNAIRealm;
22 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPRoamingConsortium;
23 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPVenueName;
24 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSConnCapability;
25 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSFriendlyName;
26 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSOSUProviders;
27 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSWANMetrics;
28 
29 import android.annotation.NonNull;
30 import android.content.Context;
31 import android.hardware.wifi.supplicant.V1_0.ISupplicant;
32 import android.hardware.wifi.supplicant.V1_0.ISupplicantIface;
33 import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork;
34 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface;
35 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
36 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback.BssidChangeReason;
37 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork;
38 import android.hardware.wifi.supplicant.V1_0.IfaceType;
39 import android.hardware.wifi.supplicant.V1_0.SupplicantStatus;
40 import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode;
41 import android.hardware.wifi.supplicant.V1_0.WpsConfigMethods;
42 import android.hidl.manager.V1_0.IServiceManager;
43 import android.hidl.manager.V1_0.IServiceNotification;
44 import android.net.IpConfiguration;
45 import android.net.wifi.SupplicantState;
46 import android.net.wifi.WifiConfiguration;
47 import android.net.wifi.WifiManager;
48 import android.net.wifi.WifiSsid;
49 import android.os.HwRemoteBinder;
50 import android.os.RemoteException;
51 import android.text.TextUtils;
52 import android.util.Log;
53 import android.util.Pair;
54 import android.util.SparseArray;
55 
56 import com.android.server.wifi.hotspot2.AnqpEvent;
57 import com.android.server.wifi.hotspot2.IconEvent;
58 import com.android.server.wifi.hotspot2.WnmData;
59 import com.android.server.wifi.hotspot2.anqp.ANQPElement;
60 import com.android.server.wifi.hotspot2.anqp.ANQPParser;
61 import com.android.server.wifi.hotspot2.anqp.Constants;
62 import com.android.server.wifi.util.NativeUtil;
63 
64 import java.io.IOException;
65 import java.nio.BufferUnderflowException;
66 import java.nio.ByteBuffer;
67 import java.nio.ByteOrder;
68 import java.util.ArrayList;
69 import java.util.HashMap;
70 import java.util.List;
71 import java.util.Map;
72 import java.util.regex.Matcher;
73 import java.util.regex.Pattern;
74 
75 import javax.annotation.concurrent.ThreadSafe;
76 
77 /**
78  * Hal calls for bring up/shut down of the supplicant daemon and for
79  * sending requests to the supplicant daemon
80  * To maintain thread-safety, the locking protocol is that every non-static method (regardless of
81  * access level) acquires mLock.
82  */
83 @ThreadSafe
84 public class SupplicantStaIfaceHal {
85     private static final String TAG = "SupplicantStaIfaceHal";
86     /**
87      * Regex pattern for extracting the wps device type bytes.
88      * Matches a strings like the following: "<categ>-<OUI>-<subcateg>";
89      */
90     private static final Pattern WPS_DEVICE_TYPE_PATTERN =
91             Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$");
92 
93     private final Object mLock = new Object();
94     private boolean mVerboseLoggingEnabled = false;
95 
96     // Supplicant HAL interface objects
97     private IServiceManager mIServiceManager = null;
98     private ISupplicant mISupplicant;
99     private ISupplicantStaIface mISupplicantStaIface;
100     private ISupplicantStaIfaceCallback mISupplicantStaIfaceCallback;
101     private final IServiceNotification mServiceNotificationCallback =
102             new IServiceNotification.Stub() {
103         public void onRegistration(String fqName, String name, boolean preexisting) {
104             synchronized (mLock) {
105                 if (mVerboseLoggingEnabled) {
106                     Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName
107                             + ", " + name + " preexisting=" + preexisting);
108                 }
109                 if (!initSupplicantService() || !initSupplicantStaIface()) {
110                     Log.e(TAG, "initalizing ISupplicantIfaces failed.");
111                     supplicantServiceDiedHandler();
112                 } else {
113                     Log.i(TAG, "Completed initialization of ISupplicant interfaces.");
114                 }
115             }
116         }
117     };
118     private final HwRemoteBinder.DeathRecipient mServiceManagerDeathRecipient =
119             cookie -> {
120                 synchronized (mLock) {
121                     Log.w(TAG, "IServiceManager died: cookie=" + cookie);
122                     supplicantServiceDiedHandler();
123                     mIServiceManager = null; // Will need to register a new ServiceNotification
124                 }
125             };
126     private final HwRemoteBinder.DeathRecipient mSupplicantDeathRecipient =
127             cookie -> {
128                 synchronized (mLock) {
129                     Log.w(TAG, "ISupplicant/ISupplicantStaIface died: cookie=" + cookie);
130                     supplicantServiceDiedHandler();
131                 }
132             };
133 
134     private String mIfaceName;
135     private SupplicantStaNetworkHal mCurrentNetworkRemoteHandle;
136     private WifiConfiguration mCurrentNetworkLocalConfig;
137     private final Context mContext;
138     private final WifiMonitor mWifiMonitor;
139 
SupplicantStaIfaceHal(Context context, WifiMonitor monitor)140     public SupplicantStaIfaceHal(Context context, WifiMonitor monitor) {
141         mContext = context;
142         mWifiMonitor = monitor;
143         mISupplicantStaIfaceCallback = new SupplicantStaIfaceHalCallback();
144     }
145 
146     /**
147      * Enable/Disable verbose logging.
148      *
149      * @param enable true to enable, false to disable.
150      */
enableVerboseLogging(boolean enable)151     void enableVerboseLogging(boolean enable) {
152         synchronized (mLock) {
153             mVerboseLoggingEnabled = enable;
154         }
155     }
156 
linkToServiceManagerDeath()157     private boolean linkToServiceManagerDeath() {
158         synchronized (mLock) {
159             if (mIServiceManager == null) return false;
160             try {
161                 if (!mIServiceManager.linkToDeath(mServiceManagerDeathRecipient, 0)) {
162                     Log.wtf(TAG, "Error on linkToDeath on IServiceManager");
163                     supplicantServiceDiedHandler();
164                     mIServiceManager = null; // Will need to register a new ServiceNotification
165                     return false;
166                 }
167             } catch (RemoteException e) {
168                 Log.e(TAG, "IServiceManager.linkToDeath exception", e);
169                 return false;
170             }
171             return true;
172         }
173     }
174 
175     /**
176      * Registers a service notification for the ISupplicant service, which triggers intialization of
177      * the ISupplicantStaIface
178      * @return true if the service notification was successfully registered
179      */
initialize()180     public boolean initialize() {
181         synchronized (mLock) {
182             if (mVerboseLoggingEnabled) {
183                 Log.i(TAG, "Registering ISupplicant service ready callback.");
184             }
185             mISupplicant = null;
186             mISupplicantStaIface = null;
187             if (mIServiceManager != null) {
188                 // Already have an IServiceManager and serviceNotification registered, don't
189                 // don't register another.
190                 return true;
191             }
192             try {
193                 mIServiceManager = getServiceManagerMockable();
194                 if (mIServiceManager == null) {
195                     Log.e(TAG, "Failed to get HIDL Service Manager");
196                     return false;
197                 }
198                 if (!linkToServiceManagerDeath()) {
199                     return false;
200                 }
201                 /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it
202                    exists */
203                 if (!mIServiceManager.registerForNotifications(
204                         ISupplicant.kInterfaceName, "", mServiceNotificationCallback)) {
205                     Log.e(TAG, "Failed to register for notifications to "
206                             + ISupplicant.kInterfaceName);
207                     mIServiceManager = null; // Will need to register a new ServiceNotification
208                     return false;
209                 }
210             } catch (RemoteException e) {
211                 Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: "
212                         + e);
213                 supplicantServiceDiedHandler();
214             }
215             return true;
216         }
217     }
218 
linkToSupplicantDeath()219     private boolean linkToSupplicantDeath() {
220         synchronized (mLock) {
221             if (mISupplicant == null) return false;
222             try {
223                 if (!mISupplicant.linkToDeath(mSupplicantDeathRecipient, 0)) {
224                     Log.wtf(TAG, "Error on linkToDeath on ISupplicant");
225                     supplicantServiceDiedHandler();
226                     return false;
227                 }
228             } catch (RemoteException e) {
229                 Log.e(TAG, "ISupplicant.linkToDeath exception", e);
230                 return false;
231             }
232             return true;
233         }
234     }
235 
initSupplicantService()236     private boolean initSupplicantService() {
237         synchronized (mLock) {
238             try {
239                 mISupplicant = getSupplicantMockable();
240             } catch (RemoteException e) {
241                 Log.e(TAG, "ISupplicant.getService exception: " + e);
242                 return false;
243             }
244             if (mISupplicant == null) {
245                 Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup");
246                 return false;
247             }
248             if (!linkToSupplicantDeath()) {
249                 return false;
250             }
251         }
252         return true;
253     }
254 
linkToSupplicantStaIfaceDeath()255     private boolean linkToSupplicantStaIfaceDeath() {
256         synchronized (mLock) {
257             if (mISupplicantStaIface == null) return false;
258             try {
259                 if (!mISupplicantStaIface.linkToDeath(mSupplicantDeathRecipient, 0)) {
260                     Log.wtf(TAG, "Error on linkToDeath on ISupplicantStaIface");
261                     supplicantServiceDiedHandler();
262                     return false;
263                 }
264             } catch (RemoteException e) {
265                 Log.e(TAG, "ISupplicantStaIface.linkToDeath exception", e);
266                 return false;
267             }
268             return true;
269         }
270     }
271 
getCurrentNetworkId()272     private int getCurrentNetworkId() {
273         synchronized (mLock) {
274             if (mCurrentNetworkLocalConfig == null) {
275                 return WifiConfiguration.INVALID_NETWORK_ID;
276             }
277             return mCurrentNetworkLocalConfig.networkId;
278         }
279     }
280 
initSupplicantStaIface()281     private boolean initSupplicantStaIface() {
282         synchronized (mLock) {
283             /** List all supplicant Ifaces */
284             final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>();
285             try {
286                 mISupplicant.listInterfaces((SupplicantStatus status,
287                         ArrayList<ISupplicant.IfaceInfo> ifaces) -> {
288                     if (status.code != SupplicantStatusCode.SUCCESS) {
289                         Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code);
290                         return;
291                     }
292                     supplicantIfaces.addAll(ifaces);
293                 });
294             } catch (RemoteException e) {
295                 Log.e(TAG, "ISupplicant.listInterfaces exception: " + e);
296                 return false;
297             }
298             if (supplicantIfaces.size() == 0) {
299                 Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup.");
300                 return false;
301             }
302             Mutable<ISupplicantIface> supplicantIface = new Mutable<>();
303             Mutable<String> ifaceName = new Mutable<>();
304             for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) {
305                 if (ifaceInfo.type == IfaceType.STA) {
306                     try {
307                         mISupplicant.getInterface(ifaceInfo,
308                                 (SupplicantStatus status, ISupplicantIface iface) -> {
309                                 if (status.code != SupplicantStatusCode.SUCCESS) {
310                                     Log.e(TAG, "Failed to get ISupplicantIface " + status.code);
311                                     return;
312                                 }
313                                 supplicantIface.value = iface;
314                             });
315                     } catch (RemoteException e) {
316                         Log.e(TAG, "ISupplicant.getInterface exception: " + e);
317                         return false;
318                     }
319                     ifaceName.value = ifaceInfo.name;
320                     break;
321                 }
322             }
323             if (supplicantIface.value == null) {
324                 Log.e(TAG, "initSupplicantStaIface got null iface");
325                 return false;
326             }
327             mISupplicantStaIface = getStaIfaceMockable(supplicantIface.value);
328             mIfaceName = ifaceName.value;
329             if (!linkToSupplicantStaIfaceDeath()) {
330                 return false;
331             }
332             if (!registerCallback(mISupplicantStaIfaceCallback)) {
333                 return false;
334             }
335             return true;
336         }
337     }
338 
supplicantServiceDiedHandler()339     private void supplicantServiceDiedHandler() {
340         synchronized (mLock) {
341             mISupplicant = null;
342             mISupplicantStaIface = null;
343             mWifiMonitor.broadcastSupplicantDisconnectionEvent(mIfaceName);
344         }
345     }
346 
347     /**
348      * Signals whether Initialization completed successfully.
349      */
isInitializationStarted()350     public boolean isInitializationStarted() {
351         synchronized (mLock) {
352             return mIServiceManager != null;
353         }
354     }
355 
356     /**
357      * Signals whether Initialization completed successfully.
358      */
isInitializationComplete()359     public boolean isInitializationComplete() {
360         synchronized (mLock) {
361             return mISupplicantStaIface != null;
362         }
363     }
364 
365     /**
366      * Wrapper functions to access static HAL methods, created to be mockable in unit tests
367      */
getServiceManagerMockable()368     protected IServiceManager getServiceManagerMockable() throws RemoteException {
369         synchronized (mLock) {
370             return IServiceManager.getService();
371         }
372     }
373 
getSupplicantMockable()374     protected ISupplicant getSupplicantMockable() throws RemoteException {
375         synchronized (mLock) {
376             return ISupplicant.getService();
377         }
378     }
379 
getStaIfaceMockable(ISupplicantIface iface)380     protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) {
381         synchronized (mLock) {
382             return ISupplicantStaIface.asInterface(iface.asBinder());
383         }
384     }
385 
386     /**
387      * Add a network configuration to wpa_supplicant.
388      *
389      * @param config Config corresponding to the network.
390      * @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects
391      * for the current network.
392      */
393     private Pair<SupplicantStaNetworkHal, WifiConfiguration>
addNetworkAndSaveConfig(WifiConfiguration config)394             addNetworkAndSaveConfig(WifiConfiguration config) {
395         synchronized (mLock) {
396             logi("addSupplicantStaNetwork via HIDL");
397             if (config == null) {
398                 loge("Cannot add NULL network!");
399                 return null;
400             }
401             SupplicantStaNetworkHal network = addNetwork();
402             if (network == null) {
403                 loge("Failed to add a network!");
404                 return null;
405             }
406             boolean saveSuccess = false;
407             try {
408                 saveSuccess = network.saveWifiConfiguration(config);
409             } catch (IllegalArgumentException e) {
410                 Log.e(TAG, "Exception while saving config params: " + config, e);
411             }
412             if (!saveSuccess) {
413                 loge("Failed to save variables for: " + config.configKey());
414                 if (!removeAllNetworks()) {
415                     loge("Failed to remove all networks on failure.");
416                 }
417                 return null;
418             }
419             return new Pair(network, new WifiConfiguration(config));
420         }
421     }
422 
423     /**
424      * Add the provided network configuration to wpa_supplicant and initiate connection to it.
425      * This method does the following:
426      * 1. If |config| is different to the current supplicant network, removes all supplicant
427      * networks and saves |config|.
428      * 2. Select the new network in wpa_supplicant.
429      *
430      * @param config WifiConfiguration parameters for the provided network.
431      * @return {@code true} if it succeeds, {@code false} otherwise
432      */
connectToNetwork(@onNull WifiConfiguration config)433     public boolean connectToNetwork(@NonNull WifiConfiguration config) {
434         synchronized (mLock) {
435             logd("connectToNetwork " + config.configKey());
436             if (WifiConfigurationUtil.isSameNetwork(config, mCurrentNetworkLocalConfig)) {
437                 logd("Network is already saved, will not trigger remove and add operation.");
438             } else {
439                 mCurrentNetworkRemoteHandle = null;
440                 mCurrentNetworkLocalConfig = null;
441                 if (!removeAllNetworks()) {
442                     loge("Failed to remove existing networks");
443                     return false;
444                 }
445                 Pair<SupplicantStaNetworkHal, WifiConfiguration> pair =
446                         addNetworkAndSaveConfig(config);
447                 if (pair == null) {
448                     loge("Failed to add/save network configuration: " + config.configKey());
449                     return false;
450                 }
451                 mCurrentNetworkRemoteHandle = pair.first;
452                 mCurrentNetworkLocalConfig = pair.second;
453             }
454 
455             if (!mCurrentNetworkRemoteHandle.select()) {
456                 loge("Failed to select network configuration: " + config.configKey());
457                 return false;
458             }
459             return true;
460         }
461     }
462 
463     /**
464      * Initiates roaming to the already configured network in wpa_supplicant. If the network
465      * configuration provided does not match the already configured network, then this triggers
466      * a new connection attempt (instead of roam).
467      * 1. First check if we're attempting to connect to the same network as we currently have
468      * configured.
469      * 2. Set the new bssid for the network in wpa_supplicant.
470      * 3. Trigger reassociate command to wpa_supplicant.
471      *
472      * @param config WifiConfiguration parameters for the provided network.
473      * @return {@code true} if it succeeds, {@code false} otherwise
474      */
roamToNetwork(WifiConfiguration config)475     public boolean roamToNetwork(WifiConfiguration config) {
476         synchronized (mLock) {
477             if (getCurrentNetworkId() != config.networkId) {
478                 Log.w(TAG, "Cannot roam to a different network, initiate new connection. "
479                         + "Current network ID: " + getCurrentNetworkId());
480                 return connectToNetwork(config);
481             }
482             String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
483             logd("roamToNetwork" + config.configKey() + " (bssid " + bssid + ")");
484             if (!mCurrentNetworkRemoteHandle.setBssid(bssid)) {
485                 loge("Failed to set new bssid on network: " + config.configKey());
486                 return false;
487             }
488             if (!reassociate()) {
489                 loge("Failed to trigger reassociate");
490                 return false;
491             }
492             return true;
493         }
494     }
495 
496     /**
497      * Load all the configured networks from wpa_supplicant.
498      *
499      * @param configs       Map of configuration key to configuration objects corresponding to all
500      *                      the networks.
501      * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf
502      * @return true if succeeds, false otherwise.
503      */
loadNetworks(Map<String, WifiConfiguration> configs, SparseArray<Map<String, String>> networkExtras)504     public boolean loadNetworks(Map<String, WifiConfiguration> configs,
505                                 SparseArray<Map<String, String>> networkExtras) {
506         synchronized (mLock) {
507             List<Integer> networkIds = listNetworks();
508             if (networkIds == null) {
509                 Log.e(TAG, "Failed to list networks");
510                 return false;
511             }
512             for (Integer networkId : networkIds) {
513                 SupplicantStaNetworkHal network = getNetwork(networkId);
514                 if (network == null) {
515                     Log.e(TAG, "Failed to get network with ID: " + networkId);
516                     return false;
517                 }
518                 WifiConfiguration config = new WifiConfiguration();
519                 Map<String, String> networkExtra = new HashMap<>();
520                 boolean loadSuccess = false;
521                 try {
522                     loadSuccess = network.loadWifiConfiguration(config, networkExtra);
523                 } catch (IllegalArgumentException e) {
524                     Log.wtf(TAG, "Exception while loading config params: " + config, e);
525                 }
526                 if (!loadSuccess) {
527                     Log.e(TAG, "Failed to load wifi configuration for network with ID: " + networkId
528                             + ". Skipping...");
529                     continue;
530                 }
531                 // Set the default IP assignments.
532                 config.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
533                 config.setProxySettings(IpConfiguration.ProxySettings.NONE);
534 
535                 networkExtras.put(networkId, networkExtra);
536                 String configKey =
537                         networkExtra.get(SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY);
538                 final WifiConfiguration duplicateConfig = configs.put(configKey, config);
539                 if (duplicateConfig != null) {
540                     // The network is already known. Overwrite the duplicate entry.
541                     Log.i(TAG, "Replacing duplicate network: " + duplicateConfig.networkId);
542                     removeNetwork(duplicateConfig.networkId);
543                     networkExtras.remove(duplicateConfig.networkId);
544                 }
545             }
546             return true;
547         }
548     }
549 
550     /**
551      * Remove the request |networkId| from supplicant if it's the current network,
552      * if the current configured network matches |networkId|.
553      *
554      * @param networkId network id of the network to be removed from supplicant.
555      */
removeNetworkIfCurrent(int networkId)556     public void removeNetworkIfCurrent(int networkId) {
557         synchronized (mLock) {
558             if (getCurrentNetworkId() == networkId) {
559                 // Currently we only save 1 network in supplicant.
560                 removeAllNetworks();
561             }
562         }
563     }
564 
565     /**
566      * Remove all networks from supplicant
567      */
removeAllNetworks()568     public boolean removeAllNetworks() {
569         synchronized (mLock) {
570             ArrayList<Integer> networks = listNetworks();
571             if (networks == null) {
572                 Log.e(TAG, "removeAllNetworks failed, got null networks");
573                 return false;
574             }
575             for (int id : networks) {
576                 if (!removeNetwork(id)) {
577                     Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
578                     return false;
579                 }
580             }
581             // Reset current network info.  Probably not needed once we add support to remove/reset
582             // current network on receiving disconnection event from supplicant (b/32898136).
583             mCurrentNetworkLocalConfig = null;
584             mCurrentNetworkRemoteHandle = null;
585             return true;
586         }
587     }
588 
589     /**
590      * Set the currently configured network's bssid.
591      *
592      * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX"
593      * @return true if succeeds, false otherwise.
594      */
setCurrentNetworkBssid(String bssidStr)595     public boolean setCurrentNetworkBssid(String bssidStr) {
596         synchronized (mLock) {
597             if (mCurrentNetworkRemoteHandle == null) return false;
598             return mCurrentNetworkRemoteHandle.setBssid(bssidStr);
599         }
600     }
601 
602     /**
603      * Get the currently configured network's WPS NFC token.
604      *
605      * @return Hex string corresponding to the WPS NFC token.
606      */
getCurrentNetworkWpsNfcConfigurationToken()607     public String getCurrentNetworkWpsNfcConfigurationToken() {
608         synchronized (mLock) {
609             if (mCurrentNetworkRemoteHandle == null) return null;
610             return mCurrentNetworkRemoteHandle.getWpsNfcConfigurationToken();
611         }
612     }
613 
614     /**
615      * Get the eap anonymous identity for the currently configured network.
616      *
617      * @return anonymous identity string if succeeds, null otherwise.
618      */
getCurrentNetworkEapAnonymousIdentity()619     public String getCurrentNetworkEapAnonymousIdentity() {
620         synchronized (mLock) {
621             if (mCurrentNetworkRemoteHandle == null) return null;
622             return mCurrentNetworkRemoteHandle.fetchEapAnonymousIdentity();
623         }
624     }
625 
626     /**
627      * Send the eap identity response for the currently configured network.
628      *
629      * @param identityStr String to send.
630      * @return true if succeeds, false otherwise.
631      */
sendCurrentNetworkEapIdentityResponse(String identityStr)632     public boolean sendCurrentNetworkEapIdentityResponse(String identityStr) {
633         synchronized (mLock) {
634             if (mCurrentNetworkRemoteHandle == null) return false;
635             return mCurrentNetworkRemoteHandle.sendNetworkEapIdentityResponse(identityStr);
636         }
637     }
638 
639     /**
640      * Send the eap sim gsm auth response for the currently configured network.
641      *
642      * @param paramsStr String to send.
643      * @return true if succeeds, false otherwise.
644      */
sendCurrentNetworkEapSimGsmAuthResponse(String paramsStr)645     public boolean sendCurrentNetworkEapSimGsmAuthResponse(String paramsStr) {
646         synchronized (mLock) {
647             if (mCurrentNetworkRemoteHandle == null) return false;
648             return mCurrentNetworkRemoteHandle.sendNetworkEapSimGsmAuthResponse(paramsStr);
649         }
650     }
651 
652     /**
653      * Send the eap sim gsm auth failure for the currently configured network.
654      *
655      * @return true if succeeds, false otherwise.
656      */
sendCurrentNetworkEapSimGsmAuthFailure()657     public boolean sendCurrentNetworkEapSimGsmAuthFailure() {
658         synchronized (mLock) {
659             if (mCurrentNetworkRemoteHandle == null) return false;
660             return mCurrentNetworkRemoteHandle.sendNetworkEapSimGsmAuthFailure();
661         }
662     }
663 
664     /**
665      * Send the eap sim umts auth response for the currently configured network.
666      *
667      * @param paramsStr String to send.
668      * @return true if succeeds, false otherwise.
669      */
sendCurrentNetworkEapSimUmtsAuthResponse(String paramsStr)670     public boolean sendCurrentNetworkEapSimUmtsAuthResponse(String paramsStr) {
671         synchronized (mLock) {
672             if (mCurrentNetworkRemoteHandle == null) return false;
673             return mCurrentNetworkRemoteHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr);
674         }
675     }
676 
677     /**
678      * Send the eap sim umts auts response for the currently configured network.
679      *
680      * @param paramsStr String to send.
681      * @return true if succeeds, false otherwise.
682      */
sendCurrentNetworkEapSimUmtsAutsResponse(String paramsStr)683     public boolean sendCurrentNetworkEapSimUmtsAutsResponse(String paramsStr) {
684         synchronized (mLock) {
685             if (mCurrentNetworkRemoteHandle == null) return false;
686             return mCurrentNetworkRemoteHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr);
687         }
688     }
689 
690     /**
691      * Send the eap sim umts auth failure for the currently configured network.
692      *
693      * @return true if succeeds, false otherwise.
694      */
sendCurrentNetworkEapSimUmtsAuthFailure()695     public boolean sendCurrentNetworkEapSimUmtsAuthFailure() {
696         synchronized (mLock) {
697             if (mCurrentNetworkRemoteHandle == null) return false;
698             return mCurrentNetworkRemoteHandle.sendNetworkEapSimUmtsAuthFailure();
699         }
700     }
701 
702     /**
703      * Adds a new network.
704      *
705      * @return The ISupplicantNetwork object for the new network, or null if the call fails
706      */
addNetwork()707     private SupplicantStaNetworkHal addNetwork() {
708         synchronized (mLock) {
709             final String methodStr = "addNetwork";
710             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
711             Mutable<ISupplicantNetwork> newNetwork = new Mutable<>();
712             try {
713                 mISupplicantStaIface.addNetwork((SupplicantStatus status,
714                         ISupplicantNetwork network) -> {
715                     if (checkStatusAndLogFailure(status, methodStr)) {
716                         newNetwork.value = network;
717                     }
718                 });
719             } catch (RemoteException e) {
720                 handleRemoteException(e, methodStr);
721             }
722             if (newNetwork.value != null) {
723                 return getStaNetworkMockable(
724                         ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder()));
725             } else {
726                 return null;
727             }
728         }
729     }
730 
731     /**
732      * Remove network from supplicant with network Id
733      *
734      * @return true if request is sent successfully, false otherwise.
735      */
removeNetwork(int id)736     private boolean removeNetwork(int id) {
737         synchronized (mLock) {
738             final String methodStr = "removeNetwork";
739             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
740             try {
741                 SupplicantStatus status = mISupplicantStaIface.removeNetwork(id);
742                 return checkStatusAndLogFailure(status, methodStr);
743             } catch (RemoteException e) {
744                 handleRemoteException(e, methodStr);
745                 return false;
746             }
747         }
748     }
749 
750     /**
751      * Use this to mock the creation of SupplicantStaNetworkHal instance.
752      *
753      * @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL.
754      * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
755      * the call fails
756      */
getStaNetworkMockable( ISupplicantStaNetwork iSupplicantStaNetwork)757     protected SupplicantStaNetworkHal getStaNetworkMockable(
758             ISupplicantStaNetwork iSupplicantStaNetwork) {
759         synchronized (mLock) {
760             SupplicantStaNetworkHal network =
761                     new SupplicantStaNetworkHal(iSupplicantStaNetwork, mIfaceName, mContext,
762                             mWifiMonitor);
763             if (network != null) {
764                 network.enableVerboseLogging(mVerboseLoggingEnabled);
765             }
766             return network;
767         }
768     }
769 
770     /**
771      * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
772      * the call fails
773      */
getNetwork(int id)774     private SupplicantStaNetworkHal getNetwork(int id) {
775         synchronized (mLock) {
776             final String methodStr = "getNetwork";
777             Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>();
778             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
779             try {
780                 mISupplicantStaIface.getNetwork(id, (SupplicantStatus status,
781                         ISupplicantNetwork network) -> {
782                     if (checkStatusAndLogFailure(status, methodStr)) {
783                         gotNetwork.value = network;
784                     }
785                 });
786             } catch (RemoteException e) {
787                 handleRemoteException(e, methodStr);
788             }
789             if (gotNetwork.value != null) {
790                 return getStaNetworkMockable(
791                         ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder()));
792             } else {
793                 return null;
794             }
795         }
796     }
797 
798     /** See ISupplicantStaNetwork.hal for documentation */
registerCallback(ISupplicantStaIfaceCallback callback)799     private boolean registerCallback(ISupplicantStaIfaceCallback callback) {
800         synchronized (mLock) {
801             final String methodStr = "registerCallback";
802             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
803             try {
804                 SupplicantStatus status =  mISupplicantStaIface.registerCallback(callback);
805                 return checkStatusAndLogFailure(status, methodStr);
806             } catch (RemoteException e) {
807                 handleRemoteException(e, methodStr);
808                 return false;
809             }
810         }
811     }
812 
813     /**
814      * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns
815      * null if the call fails
816      */
listNetworks()817     private java.util.ArrayList<Integer> listNetworks() {
818         synchronized (mLock) {
819             final String methodStr = "listNetworks";
820             Mutable<ArrayList<Integer>> networkIdList = new Mutable<>();
821             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
822             try {
823                 mISupplicantStaIface.listNetworks((SupplicantStatus status,
824                         java.util.ArrayList<Integer> networkIds) -> {
825                     if (checkStatusAndLogFailure(status, methodStr)) {
826                         networkIdList.value = networkIds;
827                     }
828                 });
829             } catch (RemoteException e) {
830                 handleRemoteException(e, methodStr);
831             }
832             return networkIdList.value;
833         }
834     }
835 
836     /**
837      * Set WPS device name.
838      *
839      * @param name String to be set.
840      * @return true if request is sent successfully, false otherwise.
841      */
setWpsDeviceName(String name)842     public boolean setWpsDeviceName(String name) {
843         synchronized (mLock) {
844             final String methodStr = "setWpsDeviceName";
845             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
846             try {
847                 SupplicantStatus status = mISupplicantStaIface.setWpsDeviceName(name);
848                 return checkStatusAndLogFailure(status, methodStr);
849             } catch (RemoteException e) {
850                 handleRemoteException(e, methodStr);
851                 return false;
852             }
853         }
854     }
855 
856     /**
857      * Set WPS device type.
858      *
859      * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
860      * @return true if request is sent successfully, false otherwise.
861      */
setWpsDeviceType(String typeStr)862     public boolean setWpsDeviceType(String typeStr) {
863         synchronized (mLock) {
864             try {
865                 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr);
866                 if (!match.find() || match.groupCount() != 3) {
867                     Log.e(TAG, "Malformed WPS device type " + typeStr);
868                     return false;
869                 }
870                 short categ = Short.parseShort(match.group(1));
871                 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2));
872                 short subCateg = Short.parseShort(match.group(3));
873 
874                 byte[] bytes = new byte[8];
875                 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
876                 byteBuffer.putShort(categ);
877                 byteBuffer.put(oui);
878                 byteBuffer.putShort(subCateg);
879                 return setWpsDeviceType(bytes);
880             } catch (IllegalArgumentException e) {
881                 Log.e(TAG, "Illegal argument " + typeStr, e);
882                 return false;
883             }
884         }
885     }
886 
setWpsDeviceType(byte[ ] type)887     private boolean setWpsDeviceType(byte[/* 8 */] type) {
888         synchronized (mLock) {
889             final String methodStr = "setWpsDeviceType";
890             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
891             try {
892                 SupplicantStatus status = mISupplicantStaIface.setWpsDeviceType(type);
893                 return checkStatusAndLogFailure(status, methodStr);
894             } catch (RemoteException e) {
895                 handleRemoteException(e, methodStr);
896                 return false;
897             }
898         }
899     }
900 
901     /**
902      * Set WPS manufacturer.
903      *
904      * @param manufacturer String to be set.
905      * @return true if request is sent successfully, false otherwise.
906      */
setWpsManufacturer(String manufacturer)907     public boolean setWpsManufacturer(String manufacturer) {
908         synchronized (mLock) {
909             final String methodStr = "setWpsManufacturer";
910             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
911             try {
912                 SupplicantStatus status = mISupplicantStaIface.setWpsManufacturer(manufacturer);
913                 return checkStatusAndLogFailure(status, methodStr);
914             } catch (RemoteException e) {
915                 handleRemoteException(e, methodStr);
916                 return false;
917             }
918         }
919     }
920 
921     /**
922      * Set WPS model name.
923      *
924      * @param modelName String to be set.
925      * @return true if request is sent successfully, false otherwise.
926      */
setWpsModelName(String modelName)927     public boolean setWpsModelName(String modelName) {
928         synchronized (mLock) {
929             final String methodStr = "setWpsModelName";
930             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
931             try {
932                 SupplicantStatus status = mISupplicantStaIface.setWpsModelName(modelName);
933                 return checkStatusAndLogFailure(status, methodStr);
934             } catch (RemoteException e) {
935                 handleRemoteException(e, methodStr);
936                 return false;
937             }
938         }
939     }
940 
941     /**
942      * Set WPS model number.
943      *
944      * @param modelNumber String to be set.
945      * @return true if request is sent successfully, false otherwise.
946      */
setWpsModelNumber(String modelNumber)947     public boolean setWpsModelNumber(String modelNumber) {
948         synchronized (mLock) {
949             final String methodStr = "setWpsModelNumber";
950             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
951             try {
952                 SupplicantStatus status = mISupplicantStaIface.setWpsModelNumber(modelNumber);
953                 return checkStatusAndLogFailure(status, methodStr);
954             } catch (RemoteException e) {
955                 handleRemoteException(e, methodStr);
956                 return false;
957             }
958         }
959     }
960 
961     /**
962      * Set WPS serial number.
963      *
964      * @param serialNumber String to be set.
965      * @return true if request is sent successfully, false otherwise.
966      */
setWpsSerialNumber(String serialNumber)967     public boolean setWpsSerialNumber(String serialNumber) {
968         synchronized (mLock) {
969             final String methodStr = "setWpsSerialNumber";
970             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
971             try {
972                 SupplicantStatus status = mISupplicantStaIface.setWpsSerialNumber(serialNumber);
973                 return checkStatusAndLogFailure(status, methodStr);
974             } catch (RemoteException e) {
975                 handleRemoteException(e, methodStr);
976                 return false;
977             }
978         }
979     }
980 
981     /**
982      * Set WPS config methods
983      *
984      * @param configMethodsStr List of config methods.
985      * @return true if request is sent successfully, false otherwise.
986      */
setWpsConfigMethods(String configMethodsStr)987     public boolean setWpsConfigMethods(String configMethodsStr) {
988         synchronized (mLock) {
989             short configMethodsMask = 0;
990             String[] configMethodsStrArr = configMethodsStr.split("\\s+");
991             for (int i = 0; i < configMethodsStrArr.length; i++) {
992                 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]);
993             }
994             return setWpsConfigMethods(configMethodsMask);
995         }
996     }
997 
setWpsConfigMethods(short configMethods)998     private boolean setWpsConfigMethods(short configMethods) {
999         synchronized (mLock) {
1000             final String methodStr = "setWpsConfigMethods";
1001             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1002             try {
1003                 SupplicantStatus status = mISupplicantStaIface.setWpsConfigMethods(configMethods);
1004                 return checkStatusAndLogFailure(status, methodStr);
1005             } catch (RemoteException e) {
1006                 handleRemoteException(e, methodStr);
1007                 return false;
1008             }
1009         }
1010     }
1011 
1012     /**
1013      * Trigger a reassociation even if the iface is currently connected.
1014      *
1015      * @return true if request is sent successfully, false otherwise.
1016      */
reassociate()1017     public boolean reassociate() {
1018         synchronized (mLock) {
1019             final String methodStr = "reassociate";
1020             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1021             try {
1022                 SupplicantStatus status = mISupplicantStaIface.reassociate();
1023                 return checkStatusAndLogFailure(status, methodStr);
1024             } catch (RemoteException e) {
1025                 handleRemoteException(e, methodStr);
1026                 return false;
1027             }
1028         }
1029     }
1030 
1031     /**
1032      * Trigger a reconnection if the iface is disconnected.
1033      *
1034      * @return true if request is sent successfully, false otherwise.
1035      */
reconnect()1036     public boolean reconnect() {
1037         synchronized (mLock) {
1038             final String methodStr = "reconnect";
1039             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1040             try {
1041                 SupplicantStatus status = mISupplicantStaIface.reconnect();
1042                 return checkStatusAndLogFailure(status, methodStr);
1043             } catch (RemoteException e) {
1044                 handleRemoteException(e, methodStr);
1045                 return false;
1046             }
1047         }
1048     }
1049 
1050     /**
1051      * Trigger a disconnection from the currently connected network.
1052      *
1053      * @return true if request is sent successfully, false otherwise.
1054      */
disconnect()1055     public boolean disconnect() {
1056         synchronized (mLock) {
1057             final String methodStr = "disconnect";
1058             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1059             try {
1060                 SupplicantStatus status = mISupplicantStaIface.disconnect();
1061                 return checkStatusAndLogFailure(status, methodStr);
1062             } catch (RemoteException e) {
1063                 handleRemoteException(e, methodStr);
1064                 return false;
1065             }
1066         }
1067     }
1068 
1069     /**
1070      * Enable or disable power save mode.
1071      *
1072      * @param enable true to enable, false to disable.
1073      * @return true if request is sent successfully, false otherwise.
1074      */
setPowerSave(boolean enable)1075     public boolean setPowerSave(boolean enable) {
1076         synchronized (mLock) {
1077             final String methodStr = "setPowerSave";
1078             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1079             try {
1080                 SupplicantStatus status = mISupplicantStaIface.setPowerSave(enable);
1081                 return checkStatusAndLogFailure(status, methodStr);
1082             } catch (RemoteException e) {
1083                 handleRemoteException(e, methodStr);
1084                 return false;
1085             }
1086         }
1087     }
1088 
1089     /**
1090      * Initiate TDLS discover with the specified AP.
1091      *
1092      * @param macAddress MAC Address of the AP.
1093      * @return true if request is sent successfully, false otherwise.
1094      */
initiateTdlsDiscover(String macAddress)1095     public boolean initiateTdlsDiscover(String macAddress) {
1096         synchronized (mLock) {
1097             try {
1098                 return initiateTdlsDiscover(NativeUtil.macAddressToByteArray(macAddress));
1099             } catch (IllegalArgumentException e) {
1100                 Log.e(TAG, "Illegal argument " + macAddress, e);
1101                 return false;
1102             }
1103         }
1104     }
1105     /** See ISupplicantStaIface.hal for documentation */
initiateTdlsDiscover(byte[ ] macAddress)1106     private boolean initiateTdlsDiscover(byte[/* 6 */] macAddress) {
1107         synchronized (mLock) {
1108             final String methodStr = "initiateTdlsDiscover";
1109             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1110             try {
1111                 SupplicantStatus status = mISupplicantStaIface.initiateTdlsDiscover(macAddress);
1112                 return checkStatusAndLogFailure(status, methodStr);
1113             } catch (RemoteException e) {
1114                 handleRemoteException(e, methodStr);
1115                 return false;
1116             }
1117         }
1118     }
1119 
1120     /**
1121      * Initiate TDLS setup with the specified AP.
1122      *
1123      * @param macAddress MAC Address of the AP.
1124      * @return true if request is sent successfully, false otherwise.
1125      */
initiateTdlsSetup(String macAddress)1126     public boolean initiateTdlsSetup(String macAddress) {
1127         synchronized (mLock) {
1128             try {
1129                 return initiateTdlsSetup(NativeUtil.macAddressToByteArray(macAddress));
1130             } catch (IllegalArgumentException e) {
1131                 Log.e(TAG, "Illegal argument " + macAddress, e);
1132                 return false;
1133             }
1134         }
1135     }
1136     /** See ISupplicantStaIface.hal for documentation */
initiateTdlsSetup(byte[ ] macAddress)1137     private boolean initiateTdlsSetup(byte[/* 6 */] macAddress) {
1138         synchronized (mLock) {
1139             final String methodStr = "initiateTdlsSetup";
1140             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1141             try {
1142                 SupplicantStatus status = mISupplicantStaIface.initiateTdlsSetup(macAddress);
1143                 return checkStatusAndLogFailure(status, methodStr);
1144             } catch (RemoteException e) {
1145                 handleRemoteException(e, methodStr);
1146                 return false;
1147             }
1148         }
1149     }
1150 
1151     /**
1152      * Initiate TDLS teardown with the specified AP.
1153      * @param macAddress MAC Address of the AP.
1154      * @return true if request is sent successfully, false otherwise.
1155      */
initiateTdlsTeardown(String macAddress)1156     public boolean initiateTdlsTeardown(String macAddress) {
1157         synchronized (mLock) {
1158             try {
1159                 return initiateTdlsTeardown(NativeUtil.macAddressToByteArray(macAddress));
1160             } catch (IllegalArgumentException e) {
1161                 Log.e(TAG, "Illegal argument " + macAddress, e);
1162                 return false;
1163             }
1164         }
1165     }
1166 
1167     /** See ISupplicantStaIface.hal for documentation */
initiateTdlsTeardown(byte[ ] macAddress)1168     private boolean initiateTdlsTeardown(byte[/* 6 */] macAddress) {
1169         synchronized (mLock) {
1170             final String methodStr = "initiateTdlsTeardown";
1171             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1172             try {
1173                 SupplicantStatus status = mISupplicantStaIface.initiateTdlsTeardown(macAddress);
1174                 return checkStatusAndLogFailure(status, methodStr);
1175             } catch (RemoteException e) {
1176                 handleRemoteException(e, methodStr);
1177                 return false;
1178             }
1179         }
1180     }
1181 
1182     /**
1183      * Request the specified ANQP elements |elements| from the specified AP |bssid|.
1184      *
1185      * @param bssid BSSID of the AP
1186      * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId.
1187      * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes.
1188      * @return true if request is sent successfully, false otherwise.
1189      */
initiateAnqpQuery(String bssid, ArrayList<Short> infoElements, ArrayList<Integer> hs20SubTypes)1190     public boolean initiateAnqpQuery(String bssid, ArrayList<Short> infoElements,
1191                                      ArrayList<Integer> hs20SubTypes) {
1192         synchronized (mLock) {
1193             try {
1194                 return initiateAnqpQuery(
1195                         NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes);
1196             } catch (IllegalArgumentException e) {
1197                 Log.e(TAG, "Illegal argument " + bssid, e);
1198                 return false;
1199             }
1200         }
1201     }
1202 
1203     /** See ISupplicantStaIface.hal for documentation */
initiateAnqpQuery(byte[ ] macAddress, java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes)1204     private boolean initiateAnqpQuery(byte[/* 6 */] macAddress,
1205             java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) {
1206         synchronized (mLock) {
1207             final String methodStr = "initiateAnqpQuery";
1208             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1209             try {
1210                 SupplicantStatus status = mISupplicantStaIface.initiateAnqpQuery(macAddress,
1211                         infoElements, subTypes);
1212                 return checkStatusAndLogFailure(status, methodStr);
1213             } catch (RemoteException e) {
1214                 handleRemoteException(e, methodStr);
1215                 return false;
1216             }
1217         }
1218     }
1219 
1220     /**
1221      * Request the specified ANQP ICON from the specified AP |bssid|.
1222      *
1223      * @param bssid BSSID of the AP
1224      * @param fileName Name of the file to request.
1225      * @return true if request is sent successfully, false otherwise.
1226      */
initiateHs20IconQuery(String bssid, String fileName)1227     public boolean initiateHs20IconQuery(String bssid, String fileName) {
1228         synchronized (mLock) {
1229             try {
1230                 return initiateHs20IconQuery(NativeUtil.macAddressToByteArray(bssid), fileName);
1231             } catch (IllegalArgumentException e) {
1232                 Log.e(TAG, "Illegal argument " + bssid, e);
1233                 return false;
1234             }
1235         }
1236     }
1237 
1238     /** See ISupplicantStaIface.hal for documentation */
initiateHs20IconQuery(byte[ ] macAddress, String fileName)1239     private boolean initiateHs20IconQuery(byte[/* 6 */] macAddress, String fileName) {
1240         synchronized (mLock) {
1241             final String methodStr = "initiateHs20IconQuery";
1242             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1243             try {
1244                 SupplicantStatus status = mISupplicantStaIface.initiateHs20IconQuery(macAddress,
1245                         fileName);
1246                 return checkStatusAndLogFailure(status, methodStr);
1247             } catch (RemoteException e) {
1248                 handleRemoteException(e, methodStr);
1249                 return false;
1250             }
1251         }
1252     }
1253 
1254     /**
1255      * Makes a callback to HIDL to getMacAddress from supplicant
1256      *
1257      * @return string containing the MAC address, or null on a failed call
1258      */
getMacAddress()1259     public String getMacAddress() {
1260         synchronized (mLock) {
1261             final String methodStr = "getMacAddress";
1262             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
1263             Mutable<String> gotMac = new Mutable<>();
1264             try {
1265                 mISupplicantStaIface.getMacAddress((SupplicantStatus status,
1266                         byte[/* 6 */] macAddr) -> {
1267                     if (checkStatusAndLogFailure(status, methodStr)) {
1268                         gotMac.value = NativeUtil.macAddressFromByteArray(macAddr);
1269                     }
1270                 });
1271             } catch (RemoteException e) {
1272                 handleRemoteException(e, methodStr);
1273             }
1274             return gotMac.value;
1275         }
1276     }
1277 
1278     /**
1279      * Start using the added RX filters.
1280      *
1281      * @return true if request is sent successfully, false otherwise.
1282      */
startRxFilter()1283     public boolean startRxFilter() {
1284         synchronized (mLock) {
1285             final String methodStr = "startRxFilter";
1286             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1287             try {
1288                 SupplicantStatus status = mISupplicantStaIface.startRxFilter();
1289                 return checkStatusAndLogFailure(status, methodStr);
1290             } catch (RemoteException e) {
1291                 handleRemoteException(e, methodStr);
1292                 return false;
1293             }
1294         }
1295     }
1296 
1297     /**
1298      * Stop using the added RX filters.
1299      *
1300      * @return true if request is sent successfully, false otherwise.
1301      */
stopRxFilter()1302     public boolean stopRxFilter() {
1303         synchronized (mLock) {
1304             final String methodStr = "stopRxFilter";
1305             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1306             try {
1307                 SupplicantStatus status = mISupplicantStaIface.stopRxFilter();
1308                 return checkStatusAndLogFailure(status, methodStr);
1309             } catch (RemoteException e) {
1310                 handleRemoteException(e, methodStr);
1311                 return false;
1312             }
1313         }
1314     }
1315 
1316     /**
1317      * Add an RX filter.
1318      *
1319      * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
1320      *        {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
1321      * @return true if request is sent successfully, false otherwise.
1322      */
addRxFilter(int type)1323     public boolean addRxFilter(int type) {
1324         synchronized (mLock) {
1325             byte halType;
1326             switch (type) {
1327                 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
1328                     halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST;
1329                     break;
1330                 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
1331                     halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST;
1332                     break;
1333                 default:
1334                     Log.e(TAG, "Invalid Rx Filter type: " + type);
1335                     return false;
1336             }
1337             return addRxFilter(halType);
1338         }
1339     }
1340 
addRxFilter(byte type)1341     public boolean addRxFilter(byte type) {
1342         synchronized (mLock) {
1343             final String methodStr = "addRxFilter";
1344             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1345             try {
1346                 SupplicantStatus status = mISupplicantStaIface.addRxFilter(type);
1347                 return checkStatusAndLogFailure(status, methodStr);
1348             } catch (RemoteException e) {
1349                 handleRemoteException(e, methodStr);
1350                 return false;
1351             }
1352         }
1353     }
1354 
1355     /**
1356      * Remove an RX filter.
1357      *
1358      * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
1359      *        {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
1360      * @return true if request is sent successfully, false otherwise.
1361      */
removeRxFilter(int type)1362     public boolean removeRxFilter(int type) {
1363         synchronized (mLock) {
1364             byte halType;
1365             switch (type) {
1366                 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
1367                     halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST;
1368                     break;
1369                 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
1370                     halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST;
1371                     break;
1372                 default:
1373                     Log.e(TAG, "Invalid Rx Filter type: " + type);
1374                     return false;
1375             }
1376             return removeRxFilter(halType);
1377         }
1378     }
1379 
removeRxFilter(byte type)1380     public boolean removeRxFilter(byte type) {
1381         synchronized (mLock) {
1382             final String methodStr = "removeRxFilter";
1383             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1384             try {
1385                 SupplicantStatus status = mISupplicantStaIface.removeRxFilter(type);
1386                 return checkStatusAndLogFailure(status, methodStr);
1387             } catch (RemoteException e) {
1388                 handleRemoteException(e, methodStr);
1389                 return false;
1390             }
1391         }
1392     }
1393 
1394     /**
1395      * Set Bt co existense mode.
1396      *
1397      * @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED},
1398      *             {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or
1399      *             {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}.
1400      * @return true if request is sent successfully, false otherwise.
1401      */
setBtCoexistenceMode(int mode)1402     public boolean setBtCoexistenceMode(int mode) {
1403         synchronized (mLock) {
1404             byte halMode;
1405             switch (mode) {
1406                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_ENABLED:
1407                     halMode = ISupplicantStaIface.BtCoexistenceMode.ENABLED;
1408                     break;
1409                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED:
1410                     halMode = ISupplicantStaIface.BtCoexistenceMode.DISABLED;
1411                     break;
1412                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE:
1413                     halMode = ISupplicantStaIface.BtCoexistenceMode.SENSE;
1414                     break;
1415                 default:
1416                     Log.e(TAG, "Invalid Bt Coex mode: " + mode);
1417                     return false;
1418             }
1419             return setBtCoexistenceMode(halMode);
1420         }
1421     }
1422 
setBtCoexistenceMode(byte mode)1423     private boolean setBtCoexistenceMode(byte mode) {
1424         synchronized (mLock) {
1425             final String methodStr = "setBtCoexistenceMode";
1426             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1427             try {
1428                 SupplicantStatus status = mISupplicantStaIface.setBtCoexistenceMode(mode);
1429                 return checkStatusAndLogFailure(status, methodStr);
1430             } catch (RemoteException e) {
1431                 handleRemoteException(e, methodStr);
1432                 return false;
1433             }
1434         }
1435     }
1436 
1437     /** Enable or disable BT coexistence mode.
1438      *
1439      * @param enable true to enable, false to disable.
1440      * @return true if request is sent successfully, false otherwise.
1441      */
setBtCoexistenceScanModeEnabled(boolean enable)1442     public boolean setBtCoexistenceScanModeEnabled(boolean enable) {
1443         synchronized (mLock) {
1444             final String methodStr = "setBtCoexistenceScanModeEnabled";
1445             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1446             try {
1447                 SupplicantStatus status =
1448                         mISupplicantStaIface.setBtCoexistenceScanModeEnabled(enable);
1449                 return checkStatusAndLogFailure(status, methodStr);
1450             } catch (RemoteException e) {
1451                 handleRemoteException(e, methodStr);
1452                 return false;
1453             }
1454         }
1455     }
1456 
1457     /**
1458      * Enable or disable suspend mode optimizations.
1459      *
1460      * @param enable true to enable, false otherwise.
1461      * @return true if request is sent successfully, false otherwise.
1462      */
setSuspendModeEnabled(boolean enable)1463     public boolean setSuspendModeEnabled(boolean enable) {
1464         synchronized (mLock) {
1465             final String methodStr = "setSuspendModeEnabled";
1466             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1467             try {
1468                 SupplicantStatus status = mISupplicantStaIface.setSuspendModeEnabled(enable);
1469                 return checkStatusAndLogFailure(status, methodStr);
1470             } catch (RemoteException e) {
1471                 handleRemoteException(e, methodStr);
1472                 return false;
1473             }
1474         }
1475     }
1476 
1477     /**
1478      * Set country code.
1479      *
1480      * @param codeStr 2 byte ASCII string. For ex: US, CA.
1481      * @return true if request is sent successfully, false otherwise.
1482      */
setCountryCode(String codeStr)1483     public boolean setCountryCode(String codeStr) {
1484         synchronized (mLock) {
1485             if (TextUtils.isEmpty(codeStr)) return false;
1486             return setCountryCode(NativeUtil.stringToByteArray(codeStr));
1487         }
1488     }
1489 
1490     /** See ISupplicantStaIface.hal for documentation */
setCountryCode(byte[ ] code)1491     private boolean setCountryCode(byte[/* 2 */] code) {
1492         synchronized (mLock) {
1493             final String methodStr = "setCountryCode";
1494             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1495             try {
1496                 SupplicantStatus status = mISupplicantStaIface.setCountryCode(code);
1497                 return checkStatusAndLogFailure(status, methodStr);
1498             } catch (RemoteException e) {
1499                 handleRemoteException(e, methodStr);
1500                 return false;
1501             }
1502         }
1503     }
1504 
1505     /**
1506      * Start WPS pin registrar operation with the specified peer and pin.
1507      *
1508      * @param bssidStr BSSID of the peer.
1509      * @param pin Pin to be used.
1510      * @return true if request is sent successfully, false otherwise.
1511      */
startWpsRegistrar(String bssidStr, String pin)1512     public boolean startWpsRegistrar(String bssidStr, String pin) {
1513         synchronized (mLock) {
1514             if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) return false;
1515             try {
1516                 return startWpsRegistrar(NativeUtil.macAddressToByteArray(bssidStr), pin);
1517             } catch (IllegalArgumentException e) {
1518                 Log.e(TAG, "Illegal argument " + bssidStr, e);
1519                 return false;
1520             }
1521         }
1522     }
1523 
1524     /** See ISupplicantStaIface.hal for documentation */
startWpsRegistrar(byte[ ] bssid, String pin)1525     private boolean startWpsRegistrar(byte[/* 6 */] bssid, String pin) {
1526         synchronized (mLock) {
1527             final String methodStr = "startWpsRegistrar";
1528             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1529             try {
1530                 SupplicantStatus status = mISupplicantStaIface.startWpsRegistrar(bssid, pin);
1531                 return checkStatusAndLogFailure(status, methodStr);
1532             } catch (RemoteException e) {
1533                 handleRemoteException(e, methodStr);
1534                 return false;
1535             }
1536         }
1537     }
1538 
1539     /**
1540      * Start WPS pin display operation with the specified peer.
1541      *
1542      * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
1543      * @return true if request is sent successfully, false otherwise.
1544      */
startWpsPbc(String bssidStr)1545     public boolean startWpsPbc(String bssidStr) {
1546         synchronized (mLock) {
1547             try {
1548                 return startWpsPbc(NativeUtil.macAddressToByteArray(bssidStr));
1549             } catch (IllegalArgumentException e) {
1550                 Log.e(TAG, "Illegal argument " + bssidStr, e);
1551                 return false;
1552             }
1553         }
1554     }
1555 
1556     /** See ISupplicantStaIface.hal for documentation */
startWpsPbc(byte[ ] bssid)1557     private boolean startWpsPbc(byte[/* 6 */] bssid) {
1558         synchronized (mLock) {
1559             final String methodStr = "startWpsPbc";
1560             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1561             try {
1562                 SupplicantStatus status = mISupplicantStaIface.startWpsPbc(bssid);
1563                 return checkStatusAndLogFailure(status, methodStr);
1564             } catch (RemoteException e) {
1565                 handleRemoteException(e, methodStr);
1566                 return false;
1567             }
1568         }
1569     }
1570 
1571     /**
1572      * Start WPS pin keypad operation with the specified pin.
1573      *
1574      * @param pin Pin to be used.
1575      * @return true if request is sent successfully, false otherwise.
1576      */
startWpsPinKeypad(String pin)1577     public boolean startWpsPinKeypad(String pin) {
1578         if (TextUtils.isEmpty(pin)) return false;
1579         synchronized (mLock) {
1580             final String methodStr = "startWpsPinKeypad";
1581             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1582             try {
1583                 SupplicantStatus status = mISupplicantStaIface.startWpsPinKeypad(pin);
1584                 return checkStatusAndLogFailure(status, methodStr);
1585             } catch (RemoteException e) {
1586                 handleRemoteException(e, methodStr);
1587                 return false;
1588             }
1589         }
1590     }
1591 
1592     /**
1593      * Start WPS pin display operation with the specified peer.
1594      *
1595      * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
1596      * @return new pin generated on success, null otherwise.
1597      */
startWpsPinDisplay(String bssidStr)1598     public String startWpsPinDisplay(String bssidStr) {
1599         synchronized (mLock) {
1600             try {
1601                 return startWpsPinDisplay(NativeUtil.macAddressToByteArray(bssidStr));
1602             } catch (IllegalArgumentException e) {
1603                 Log.e(TAG, "Illegal argument " + bssidStr, e);
1604                 return null;
1605             }
1606         }
1607     }
1608 
1609     /** See ISupplicantStaIface.hal for documentation */
startWpsPinDisplay(byte[ ] bssid)1610     private String startWpsPinDisplay(byte[/* 6 */] bssid) {
1611         synchronized (mLock) {
1612             final String methodStr = "startWpsPinDisplay";
1613             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
1614             final Mutable<String> gotPin = new Mutable<>();
1615             try {
1616                 mISupplicantStaIface.startWpsPinDisplay(bssid,
1617                         (SupplicantStatus status, String pin) -> {
1618                             if (checkStatusAndLogFailure(status, methodStr)) {
1619                                 gotPin.value = pin;
1620                             }
1621                         });
1622             } catch (RemoteException e) {
1623                 handleRemoteException(e, methodStr);
1624             }
1625             return gotPin.value;
1626         }
1627     }
1628 
1629     /**
1630      * Cancels any ongoing WPS requests.
1631      *
1632      * @return true if request is sent successfully, false otherwise.
1633      */
cancelWps()1634     public boolean cancelWps() {
1635         synchronized (mLock) {
1636             final String methodStr = "cancelWps";
1637             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1638             try {
1639                 SupplicantStatus status = mISupplicantStaIface.cancelWps();
1640                 return checkStatusAndLogFailure(status, methodStr);
1641             } catch (RemoteException e) {
1642                 handleRemoteException(e, methodStr);
1643                 return false;
1644             }
1645         }
1646     }
1647 
1648     /**
1649      * Sets whether to use external sim for SIM/USIM processing.
1650      *
1651      * @param useExternalSim true to enable, false otherwise.
1652      * @return true if request is sent successfully, false otherwise.
1653      */
setExternalSim(boolean useExternalSim)1654     public boolean setExternalSim(boolean useExternalSim) {
1655         synchronized (mLock) {
1656             final String methodStr = "setExternalSim";
1657             if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1658             try {
1659                 SupplicantStatus status = mISupplicantStaIface.setExternalSim(useExternalSim);
1660                 return checkStatusAndLogFailure(status, methodStr);
1661             } catch (RemoteException e) {
1662                 handleRemoteException(e, methodStr);
1663                 return false;
1664             }
1665         }
1666     }
1667 
1668     /** See ISupplicant.hal for documentation */
enableAutoReconnect(boolean enable)1669     public boolean enableAutoReconnect(boolean enable) {
1670         synchronized (mLock) {
1671             final String methodStr = "enableAutoReconnect";
1672             if (!checkSupplicantAndLogFailure(methodStr)) return false;
1673             try {
1674                 SupplicantStatus status = mISupplicantStaIface.enableAutoReconnect(enable);
1675                 return checkStatusAndLogFailure(status, methodStr);
1676             } catch (RemoteException e) {
1677                 handleRemoteException(e, methodStr);
1678                 return false;
1679             }
1680         }
1681     }
1682 
1683     /**
1684      * Set the debug log level for wpa_supplicant
1685      *
1686      * @param turnOnVerbose Whether to turn on verbose logging or not.
1687      * @return true if request is sent successfully, false otherwise.
1688      */
setLogLevel(boolean turnOnVerbose)1689     public boolean setLogLevel(boolean turnOnVerbose) {
1690         synchronized (mLock) {
1691             int logLevel = turnOnVerbose
1692                     ? ISupplicant.DebugLevel.DEBUG
1693                     : ISupplicant.DebugLevel.INFO;
1694             return setDebugParams(logLevel, false, false);
1695         }
1696     }
1697 
1698     /** See ISupplicant.hal for documentation */
setDebugParams(int level, boolean showTimestamp, boolean showKeys)1699     private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) {
1700         synchronized (mLock) {
1701             final String methodStr = "setDebugParams";
1702             if (!checkSupplicantAndLogFailure(methodStr)) return false;
1703             try {
1704                 SupplicantStatus status =
1705                         mISupplicant.setDebugParams(level, showTimestamp, showKeys);
1706                 return checkStatusAndLogFailure(status, methodStr);
1707             } catch (RemoteException e) {
1708                 handleRemoteException(e, methodStr);
1709                 return false;
1710             }
1711         }
1712     }
1713 
1714     /**
1715      * Set concurrency priority between P2P & STA operations.
1716      *
1717      * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
1718      *                            false otherwise.
1719      * @return true if request is sent successfully, false otherwise.
1720      */
setConcurrencyPriority(boolean isStaHigherPriority)1721     public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
1722         synchronized (mLock) {
1723             if (isStaHigherPriority) {
1724                 return setConcurrencyPriority(IfaceType.STA);
1725             } else {
1726                 return setConcurrencyPriority(IfaceType.P2P);
1727             }
1728         }
1729     }
1730 
1731     /** See ISupplicant.hal for documentation */
setConcurrencyPriority(int type)1732     private boolean setConcurrencyPriority(int type) {
1733         synchronized (mLock) {
1734             final String methodStr = "setConcurrencyPriority";
1735             if (!checkSupplicantAndLogFailure(methodStr)) return false;
1736             try {
1737                 SupplicantStatus status = mISupplicant.setConcurrencyPriority(type);
1738                 return checkStatusAndLogFailure(status, methodStr);
1739             } catch (RemoteException e) {
1740                 handleRemoteException(e, methodStr);
1741                 return false;
1742             }
1743         }
1744     }
1745 
1746     /**
1747      * Returns false if Supplicant is null, and logs failure to call methodStr
1748      */
checkSupplicantAndLogFailure(final String methodStr)1749     private boolean checkSupplicantAndLogFailure(final String methodStr) {
1750         synchronized (mLock) {
1751             if (mISupplicant == null) {
1752                 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null");
1753                 return false;
1754             }
1755             return true;
1756         }
1757     }
1758 
1759     /**
1760      * Returns false if SupplicantStaIface is null, and logs failure to call methodStr
1761      */
checkSupplicantStaIfaceAndLogFailure(final String methodStr)1762     private boolean checkSupplicantStaIfaceAndLogFailure(final String methodStr) {
1763         synchronized (mLock) {
1764             if (mISupplicantStaIface == null) {
1765                 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null");
1766                 return false;
1767             }
1768             return true;
1769         }
1770     }
1771 
1772     /**
1773      * Returns true if provided status code is SUCCESS, logs debug message and returns false
1774      * otherwise
1775      */
checkStatusAndLogFailure(SupplicantStatus status, final String methodStr)1776     private boolean checkStatusAndLogFailure(SupplicantStatus status,
1777             final String methodStr) {
1778         synchronized (mLock) {
1779             if (status.code != SupplicantStatusCode.SUCCESS) {
1780                 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed: "
1781                         + supplicantStatusCodeToString(status.code) + ", " + status.debugMessage);
1782                 return false;
1783             } else {
1784                 if (mVerboseLoggingEnabled) {
1785                     Log.d(TAG, "ISupplicantStaIface." + methodStr + " succeeded");
1786                 }
1787                 return true;
1788             }
1789         }
1790     }
1791 
1792     /**
1793      * Helper function to log callbacks.
1794      */
logCallback(final String methodStr)1795     private void logCallback(final String methodStr) {
1796         synchronized (mLock) {
1797             if (mVerboseLoggingEnabled) {
1798                 Log.d(TAG, "ISupplicantStaIfaceCallback." + methodStr + " received");
1799             }
1800         }
1801     }
1802 
1803 
handleRemoteException(RemoteException e, String methodStr)1804     private void handleRemoteException(RemoteException e, String methodStr) {
1805         synchronized (mLock) {
1806             supplicantServiceDiedHandler();
1807             Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e);
1808         }
1809     }
1810 
1811     /**
1812      * Converts SupplicantStatus code values to strings for debug logging
1813      * TODO(b/34811152) Remove this, or make it more break resistance
1814      */
supplicantStatusCodeToString(int code)1815     public static String supplicantStatusCodeToString(int code) {
1816         switch (code) {
1817             case 0:
1818                 return "SUCCESS";
1819             case 1:
1820                 return "FAILURE_UNKNOWN";
1821             case 2:
1822                 return "FAILURE_ARGS_INVALID";
1823             case 3:
1824                 return "FAILURE_IFACE_INVALID";
1825             case 4:
1826                 return "FAILURE_IFACE_UNKNOWN";
1827             case 5:
1828                 return "FAILURE_IFACE_EXISTS";
1829             case 6:
1830                 return "FAILURE_IFACE_DISABLED";
1831             case 7:
1832                 return "FAILURE_IFACE_NOT_DISCONNECTED";
1833             case 8:
1834                 return "FAILURE_NETWORK_INVALID";
1835             case 9:
1836                 return "FAILURE_NETWORK_UNKNOWN";
1837             default:
1838                 return "??? UNKNOWN_CODE";
1839         }
1840     }
1841 
1842 
1843     /**
1844      * Converts the Wps config method string to the equivalent enum value.
1845      */
stringToWpsConfigMethod(String configMethod)1846     private static short stringToWpsConfigMethod(String configMethod) {
1847         switch (configMethod) {
1848             case "usba":
1849                 return WpsConfigMethods.USBA;
1850             case "ethernet":
1851                 return WpsConfigMethods.ETHERNET;
1852             case "label":
1853                 return WpsConfigMethods.LABEL;
1854             case "display":
1855                 return WpsConfigMethods.DISPLAY;
1856             case "int_nfc_token":
1857                 return WpsConfigMethods.INT_NFC_TOKEN;
1858             case "ext_nfc_token":
1859                 return WpsConfigMethods.EXT_NFC_TOKEN;
1860             case "nfc_interface":
1861                 return WpsConfigMethods.NFC_INTERFACE;
1862             case "push_button":
1863                 return WpsConfigMethods.PUSHBUTTON;
1864             case "keypad":
1865                 return WpsConfigMethods.KEYPAD;
1866             case "virtual_push_button":
1867                 return WpsConfigMethods.VIRT_PUSHBUTTON;
1868             case "physical_push_button":
1869                 return WpsConfigMethods.PHY_PUSHBUTTON;
1870             case "p2ps":
1871                 return WpsConfigMethods.P2PS;
1872             case "virtual_display":
1873                 return WpsConfigMethods.VIRT_DISPLAY;
1874             case "physical_display":
1875                 return WpsConfigMethods.PHY_DISPLAY;
1876             default:
1877                 throw new IllegalArgumentException(
1878                         "Invalid WPS config method: " + configMethod);
1879         }
1880     }
1881 
1882     /**
1883      * Converts the supplicant state received from HIDL to the equivalent framework state.
1884      */
supplicantHidlStateToFrameworkState(int state)1885     private static SupplicantState supplicantHidlStateToFrameworkState(int state) {
1886         switch (state) {
1887             case ISupplicantStaIfaceCallback.State.DISCONNECTED:
1888                 return SupplicantState.DISCONNECTED;
1889             case ISupplicantStaIfaceCallback.State.IFACE_DISABLED:
1890                 return SupplicantState.INTERFACE_DISABLED;
1891             case ISupplicantStaIfaceCallback.State.INACTIVE:
1892                 return SupplicantState.INACTIVE;
1893             case ISupplicantStaIfaceCallback.State.SCANNING:
1894                 return SupplicantState.SCANNING;
1895             case ISupplicantStaIfaceCallback.State.AUTHENTICATING:
1896                 return SupplicantState.AUTHENTICATING;
1897             case ISupplicantStaIfaceCallback.State.ASSOCIATING:
1898                 return SupplicantState.ASSOCIATING;
1899             case ISupplicantStaIfaceCallback.State.ASSOCIATED:
1900                 return SupplicantState.ASSOCIATED;
1901             case ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE:
1902                 return SupplicantState.FOUR_WAY_HANDSHAKE;
1903             case ISupplicantStaIfaceCallback.State.GROUP_HANDSHAKE:
1904                 return SupplicantState.GROUP_HANDSHAKE;
1905             case ISupplicantStaIfaceCallback.State.COMPLETED:
1906                 return SupplicantState.COMPLETED;
1907             default:
1908                 throw new IllegalArgumentException("Invalid state: " + state);
1909         }
1910     }
1911 
1912     private static class Mutable<E> {
1913         public E value;
1914 
Mutable()1915         Mutable() {
1916             value = null;
1917         }
1918 
Mutable(E value)1919         Mutable(E value) {
1920             this.value = value;
1921         }
1922     }
1923 
1924     private class SupplicantStaIfaceHalCallback extends ISupplicantStaIfaceCallback.Stub {
1925         private static final int WLAN_REASON_IE_IN_4WAY_DIFFERS = 17; // IEEE 802.11i
1926         private boolean mStateIsFourway = false; // Used to help check for PSK password mismatch
1927 
1928         /**
1929          * Parses the provided payload into an ANQP element.
1930          *
1931          * @param infoID  Element type.
1932          * @param payload Raw payload bytes.
1933          * @return AnqpElement instance on success, null on failure.
1934          */
parseAnqpElement(Constants.ANQPElementType infoID, ArrayList<Byte> payload)1935         private ANQPElement parseAnqpElement(Constants.ANQPElementType infoID,
1936                                              ArrayList<Byte> payload) {
1937             synchronized (mLock) {
1938                 try {
1939                     return Constants.getANQPElementID(infoID) != null
1940                             ? ANQPParser.parseElement(
1941                             infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload)))
1942                             : ANQPParser.parseHS20Element(
1943                             infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload)));
1944                 } catch (IOException | BufferUnderflowException e) {
1945                     Log.e(TAG, "Failed parsing ANQP element payload: " + infoID, e);
1946                     return null;
1947                 }
1948             }
1949         }
1950 
1951         /**
1952          * Parse the ANQP element data and add to the provided elements map if successful.
1953          *
1954          * @param elementsMap Map to add the parsed out element to.
1955          * @param infoID  Element type.
1956          * @param payload Raw payload bytes.
1957          */
addAnqpElementToMap(Map<Constants.ANQPElementType, ANQPElement> elementsMap, Constants.ANQPElementType infoID, ArrayList<Byte> payload)1958         private void addAnqpElementToMap(Map<Constants.ANQPElementType, ANQPElement> elementsMap,
1959                                          Constants.ANQPElementType infoID,
1960                                          ArrayList<Byte> payload) {
1961             synchronized (mLock) {
1962                 if (payload == null || payload.isEmpty()) return;
1963                 ANQPElement element = parseAnqpElement(infoID, payload);
1964                 if (element != null) {
1965                     elementsMap.put(infoID, element);
1966                 }
1967             }
1968         }
1969 
1970         @Override
onNetworkAdded(int id)1971         public void onNetworkAdded(int id) {
1972             synchronized (mLock) {
1973                 logCallback("onNetworkAdded");
1974             }
1975         }
1976 
1977         @Override
onNetworkRemoved(int id)1978         public void onNetworkRemoved(int id) {
1979             synchronized (mLock) {
1980                 logCallback("onNetworkRemoved");
1981             }
1982         }
1983 
1984         @Override
onStateChanged(int newState, byte[ ] bssid, int id, ArrayList<Byte> ssid)1985         public void onStateChanged(int newState, byte[/* 6 */] bssid, int id,
1986                                    ArrayList<Byte> ssid) {
1987             synchronized (mLock) {
1988                 logCallback("onStateChanged");
1989                 SupplicantState newSupplicantState = supplicantHidlStateToFrameworkState(newState);
1990                 WifiSsid wifiSsid =
1991                         WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid));
1992                 String bssidStr = NativeUtil.macAddressFromByteArray(bssid);
1993                 mStateIsFourway = (newState == ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE);
1994                 if (newSupplicantState == SupplicantState.COMPLETED) {
1995                     mWifiMonitor.broadcastNetworkConnectionEvent(
1996                             mIfaceName, getCurrentNetworkId(), bssidStr);
1997                 }
1998                 mWifiMonitor.broadcastSupplicantStateChangeEvent(
1999                         mIfaceName, getCurrentNetworkId(), wifiSsid, bssidStr, newSupplicantState);
2000             }
2001         }
2002 
2003         @Override
onAnqpQueryDone(byte[ ] bssid, ISupplicantStaIfaceCallback.AnqpData data, ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data)2004         public void onAnqpQueryDone(byte[/* 6 */] bssid,
2005                                     ISupplicantStaIfaceCallback.AnqpData data,
2006                                     ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) {
2007             synchronized (mLock) {
2008                 logCallback("onAnqpQueryDone");
2009                 Map<Constants.ANQPElementType, ANQPElement> elementsMap = new HashMap<>();
2010                 addAnqpElementToMap(elementsMap, ANQPVenueName, data.venueName);
2011                 addAnqpElementToMap(elementsMap, ANQPRoamingConsortium, data.roamingConsortium);
2012                 addAnqpElementToMap(
2013                         elementsMap, ANQPIPAddrAvailability, data.ipAddrTypeAvailability);
2014                 addAnqpElementToMap(elementsMap, ANQPNAIRealm, data.naiRealm);
2015                 addAnqpElementToMap(elementsMap, ANQP3GPPNetwork, data.anqp3gppCellularNetwork);
2016                 addAnqpElementToMap(elementsMap, ANQPDomName, data.domainName);
2017                 addAnqpElementToMap(elementsMap, HSFriendlyName, hs20Data.operatorFriendlyName);
2018                 addAnqpElementToMap(elementsMap, HSWANMetrics, hs20Data.wanMetrics);
2019                 addAnqpElementToMap(elementsMap, HSConnCapability, hs20Data.connectionCapability);
2020                 addAnqpElementToMap(elementsMap, HSOSUProviders, hs20Data.osuProvidersList);
2021                 mWifiMonitor.broadcastAnqpDoneEvent(
2022                         mIfaceName, new AnqpEvent(NativeUtil.macAddressToLong(bssid), elementsMap));
2023             }
2024         }
2025 
2026         @Override
onHs20IconQueryDone(byte[ ] bssid, String fileName, ArrayList<Byte> data)2027         public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName,
2028                                         ArrayList<Byte> data) {
2029             synchronized (mLock) {
2030                 logCallback("onHs20IconQueryDone");
2031                 mWifiMonitor.broadcastIconDoneEvent(
2032                         mIfaceName,
2033                         new IconEvent(NativeUtil.macAddressToLong(bssid), fileName, data.size(),
2034                                 NativeUtil.byteArrayFromArrayList(data)));
2035             }
2036         }
2037 
2038         @Override
onHs20SubscriptionRemediation(byte[ ] bssid, byte osuMethod, String url)2039         public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, byte osuMethod, String url) {
2040             synchronized (mLock) {
2041                 logCallback("onHs20SubscriptionRemediation");
2042                 mWifiMonitor.broadcastWnmEvent(
2043                         mIfaceName,
2044                         new WnmData(NativeUtil.macAddressToLong(bssid), url, osuMethod));
2045             }
2046         }
2047 
2048         @Override
onHs20DeauthImminentNotice(byte[ ] bssid, int reasonCode, int reAuthDelayInSec, String url)2049         public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode,
2050                                                int reAuthDelayInSec, String url) {
2051             synchronized (mLock) {
2052                 logCallback("onHs20DeauthImminentNotice");
2053                 mWifiMonitor.broadcastWnmEvent(
2054                         mIfaceName,
2055                         new WnmData(NativeUtil.macAddressToLong(bssid), url,
2056                                 reasonCode == WnmData.ESS, reAuthDelayInSec));
2057             }
2058         }
2059 
2060         @Override
onDisconnected(byte[ ] bssid, boolean locallyGenerated, int reasonCode)2061         public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, int reasonCode) {
2062             synchronized (mLock) {
2063                 logCallback("onDisconnected");
2064                 if (mVerboseLoggingEnabled) {
2065                     Log.e(TAG, "onDisconnected 4way=" + mStateIsFourway
2066                             + " locallyGenerated=" + locallyGenerated
2067                             + " reasonCode=" + reasonCode);
2068                 }
2069                 if (mStateIsFourway
2070                         && (!locallyGenerated || reasonCode != WLAN_REASON_IE_IN_4WAY_DIFFERS)) {
2071                     mWifiMonitor.broadcastAuthenticationFailureEvent(
2072                             mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
2073                 }
2074                 mWifiMonitor.broadcastNetworkDisconnectionEvent(
2075                         mIfaceName, locallyGenerated ? 1 : 0, reasonCode,
2076                         NativeUtil.macAddressFromByteArray(bssid));
2077             }
2078         }
2079 
2080         @Override
onAssociationRejected(byte[ ] bssid, int statusCode, boolean timedOut)2081         public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode, boolean timedOut) {
2082             synchronized (mLock) {
2083                 logCallback("onAssociationRejected");
2084                 mWifiMonitor.broadcastAssociationRejectionEvent(mIfaceName, statusCode, timedOut,
2085                         NativeUtil.macAddressFromByteArray(bssid));
2086             }
2087         }
2088 
2089         @Override
onAuthenticationTimeout(byte[ ] bssid)2090         public void onAuthenticationTimeout(byte[/* 6 */] bssid) {
2091             synchronized (mLock) {
2092                 logCallback("onAuthenticationTimeout");
2093                 mWifiMonitor.broadcastAuthenticationFailureEvent(
2094                         mIfaceName, WifiManager.ERROR_AUTH_FAILURE_TIMEOUT);
2095             }
2096         }
2097 
2098         @Override
onBssidChanged(byte reason, byte[ ] bssid)2099         public void onBssidChanged(byte reason, byte[/* 6 */] bssid) {
2100             synchronized (mLock) {
2101                 logCallback("onBssidChanged");
2102                 if (reason == BssidChangeReason.ASSOC_START) {
2103                     mWifiMonitor.broadcastTargetBssidEvent(
2104                             mIfaceName, NativeUtil.macAddressFromByteArray(bssid));
2105                 } else if (reason == BssidChangeReason.ASSOC_COMPLETE) {
2106                     mWifiMonitor.broadcastAssociatedBssidEvent(
2107                             mIfaceName, NativeUtil.macAddressFromByteArray(bssid));
2108                 }
2109             }
2110         }
2111 
2112         @Override
onEapFailure()2113         public void onEapFailure() {
2114             synchronized (mLock) {
2115                 logCallback("onEapFailure");
2116                 mWifiMonitor.broadcastAuthenticationFailureEvent(
2117                         mIfaceName, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE);
2118             }
2119         }
2120 
2121         @Override
onWpsEventSuccess()2122         public void onWpsEventSuccess() {
2123             logCallback("onWpsEventSuccess");
2124             synchronized (mLock) {
2125                 mWifiMonitor.broadcastWpsSuccessEvent(mIfaceName);
2126             }
2127         }
2128 
2129         @Override
onWpsEventFail(byte[ ] bssid, short configError, short errorInd)2130         public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) {
2131             synchronized (mLock) {
2132                 logCallback("onWpsEventFail");
2133                 if (configError == WpsConfigError.MSG_TIMEOUT
2134                         && errorInd == WpsErrorIndication.NO_ERROR) {
2135                     mWifiMonitor.broadcastWpsTimeoutEvent(mIfaceName);
2136                 } else {
2137                     mWifiMonitor.broadcastWpsFailEvent(mIfaceName, configError, errorInd);
2138                 }
2139             }
2140         }
2141 
2142         @Override
onWpsEventPbcOverlap()2143         public void onWpsEventPbcOverlap() {
2144             synchronized (mLock) {
2145                 logCallback("onWpsEventPbcOverlap");
2146                 mWifiMonitor.broadcastWpsOverlapEvent(mIfaceName);
2147             }
2148         }
2149 
2150         @Override
onExtRadioWorkStart(int id)2151         public void onExtRadioWorkStart(int id) {
2152             synchronized (mLock) {
2153                 logCallback("onExtRadioWorkStart");
2154             }
2155         }
2156 
2157         @Override
onExtRadioWorkTimeout(int id)2158         public void onExtRadioWorkTimeout(int id) {
2159             synchronized (mLock) {
2160                 logCallback("onExtRadioWorkTimeout");
2161             }
2162         }
2163     }
2164 
logd(String s)2165     private static void logd(String s) {
2166         Log.d(TAG, s);
2167     }
2168 
logi(String s)2169     private static void logi(String s) {
2170         Log.i(TAG, s);
2171     }
2172 
loge(String s)2173     private static void loge(String s) {
2174         Log.e(TAG, s);
2175     }
2176 }
2177