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