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