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