3351 lines
125 KiB
Java
3351 lines
125 KiB
Java
/*
|
|
* Copyright (C) 2021 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.server.wifi;
|
|
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_DECORATED_IDENTITY;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP_ENROLLEE_RESPONDER;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA256;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA384;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_MBO;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_OCE;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_SAE_PK;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_WAPI;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_WFD_R2;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
|
|
import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
|
|
|
|
import android.annotation.NonNull;
|
|
import android.content.Context;
|
|
import android.hardware.wifi.V1_6.WifiChannelWidthInMhz;
|
|
import android.hardware.wifi.supplicant.BtCoexistenceMode;
|
|
import android.hardware.wifi.supplicant.ConnectionCapabilities;
|
|
import android.hardware.wifi.supplicant.DebugLevel;
|
|
import android.hardware.wifi.supplicant.DppAkm;
|
|
import android.hardware.wifi.supplicant.DppCurve;
|
|
import android.hardware.wifi.supplicant.DppNetRole;
|
|
import android.hardware.wifi.supplicant.DppResponderBootstrapInfo;
|
|
import android.hardware.wifi.supplicant.ISupplicant;
|
|
import android.hardware.wifi.supplicant.ISupplicantStaIface;
|
|
import android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback;
|
|
import android.hardware.wifi.supplicant.ISupplicantStaNetwork;
|
|
import android.hardware.wifi.supplicant.IfaceInfo;
|
|
import android.hardware.wifi.supplicant.IfaceType;
|
|
import android.hardware.wifi.supplicant.KeyMgmtMask;
|
|
import android.hardware.wifi.supplicant.LegacyMode;
|
|
import android.hardware.wifi.supplicant.MloLinksInfo;
|
|
import android.hardware.wifi.supplicant.QosPolicyClassifierParams;
|
|
import android.hardware.wifi.supplicant.QosPolicyClassifierParamsMask;
|
|
import android.hardware.wifi.supplicant.QosPolicyData;
|
|
import android.hardware.wifi.supplicant.QosPolicyRequestType;
|
|
import android.hardware.wifi.supplicant.QosPolicyStatus;
|
|
import android.hardware.wifi.supplicant.QosPolicyStatusCode;
|
|
import android.hardware.wifi.supplicant.RxFilterType;
|
|
import android.hardware.wifi.supplicant.WifiTechnology;
|
|
import android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask;
|
|
import android.hardware.wifi.supplicant.WpsConfigMethods;
|
|
import android.net.DscpPolicy;
|
|
import android.net.MacAddress;
|
|
import android.net.NetworkAgent;
|
|
import android.net.wifi.ScanResult;
|
|
import android.net.wifi.SecurityParams;
|
|
import android.net.wifi.WifiAnnotations;
|
|
import android.net.wifi.WifiConfiguration;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.os.IBinder.DeathRecipient;
|
|
import android.os.RemoteException;
|
|
import android.os.ServiceManager;
|
|
import android.os.ServiceSpecificException;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
import android.util.Pair;
|
|
|
|
import com.android.internal.annotations.VisibleForTesting;
|
|
import com.android.modules.utils.build.SdkLevel;
|
|
import com.android.server.wifi.util.NativeUtil;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Objects;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
/**
|
|
* HAL calls to set up/tear down the supplicant daemon and make requests
|
|
* related to station mode. Uses the AIDL supplicant interface.
|
|
* To maintain thread-safety, the locking protocol is that every non-static method (regardless of
|
|
* access level) acquires mLock.
|
|
*/
|
|
public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal {
|
|
private static final String TAG = "SupplicantStaIfaceHalAidlImpl";
|
|
@VisibleForTesting
|
|
private static final String HAL_INSTANCE_NAME = ISupplicant.DESCRIPTOR + "/default";
|
|
|
|
/**
|
|
* Regex pattern for extracting the wps device type bytes.
|
|
* Matches a strings like the following: "<categ>-<OUI>-<subcateg>";
|
|
*/
|
|
private static final Pattern WPS_DEVICE_TYPE_PATTERN =
|
|
Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$");
|
|
|
|
private static final int MIN_PORT_NUM = 0;
|
|
private static final int MAX_PORT_NUM = 65535;
|
|
|
|
private final Object mLock = new Object();
|
|
private boolean mVerboseLoggingEnabled = false;
|
|
private boolean mVerboseHalLoggingEnabled = false;
|
|
private boolean mServiceDeclared = false;
|
|
|
|
// Supplicant HAL interface objects
|
|
private ISupplicant mISupplicant = null;
|
|
private Map<String, ISupplicantStaIface> mISupplicantStaIfaces = new HashMap<>();
|
|
private Map<String, ISupplicantStaIfaceCallback>
|
|
mISupplicantStaIfaceCallbacks = new HashMap<>();
|
|
private Map<String, SupplicantStaNetworkHalAidlImpl>
|
|
mCurrentNetworkRemoteHandles = new HashMap<>();
|
|
private Map<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>();
|
|
private Map<String, List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>>>
|
|
mLinkedNetworkLocalAndRemoteConfigs = new HashMap<>();
|
|
@VisibleForTesting
|
|
PmkCacheManager mPmkCacheManager;
|
|
private WifiNative.SupplicantDeathEventHandler mDeathEventHandler;
|
|
private SupplicantDeathRecipient mSupplicantDeathRecipient;
|
|
private final Context mContext;
|
|
private final WifiMonitor mWifiMonitor;
|
|
private final Handler mEventHandler;
|
|
private WifiNative.DppEventCallback mDppCallback = null;
|
|
private final Clock mClock;
|
|
private final WifiMetrics mWifiMetrics;
|
|
private final WifiGlobals mWifiGlobals;
|
|
|
|
private class SupplicantDeathRecipient implements DeathRecipient {
|
|
@Override
|
|
public void binderDied() {
|
|
mEventHandler.post(() -> {
|
|
synchronized (mLock) {
|
|
Log.w(TAG, "ISupplicant binder died.");
|
|
supplicantServiceDiedHandler();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Linked to supplicant service death on call to terminate()
|
|
*/
|
|
private class TerminateDeathRecipient implements DeathRecipient {
|
|
@Override
|
|
public void binderDied() {
|
|
mEventHandler.post(() -> {
|
|
synchronized (mLock) {
|
|
Log.w(TAG, "ISupplicant was killed by terminate()");
|
|
// nothing more to be done here
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public SupplicantStaIfaceHalAidlImpl(Context context, WifiMonitor monitor, Handler handler,
|
|
Clock clock, WifiMetrics wifiMetrics, WifiGlobals wifiGlobals) {
|
|
mContext = context;
|
|
mWifiMonitor = monitor;
|
|
mEventHandler = handler;
|
|
mClock = clock;
|
|
mWifiMetrics = wifiMetrics;
|
|
mWifiGlobals = wifiGlobals;
|
|
mSupplicantDeathRecipient = new SupplicantDeathRecipient();
|
|
mPmkCacheManager = new PmkCacheManager(mClock, mEventHandler);
|
|
}
|
|
|
|
/**
|
|
* Enable/Disable verbose logging.
|
|
*
|
|
* @param verboseEnabled Verbose flag set in overlay XML.
|
|
* @param halVerboseEnabled Verbose flag set by the user.
|
|
*/
|
|
public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) {
|
|
synchronized (mLock) {
|
|
mVerboseLoggingEnabled = verboseEnabled;
|
|
mVerboseHalLoggingEnabled = halVerboseEnabled;
|
|
setLogLevel(mVerboseHalLoggingEnabled);
|
|
}
|
|
}
|
|
|
|
protected boolean isVerboseLoggingEnabled() {
|
|
synchronized (mLock) {
|
|
return mVerboseLoggingEnabled;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks whether the ISupplicant service is declared, and therefore should be available.
|
|
*
|
|
* @return true if the ISupplicant service is declared
|
|
*/
|
|
public boolean initialize() {
|
|
synchronized (mLock) {
|
|
if (mISupplicant != null) {
|
|
Log.i(TAG, "Service is already initialized, skipping initialize method");
|
|
return true;
|
|
}
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.i(TAG, "Checking for ISupplicant service.");
|
|
}
|
|
mISupplicantStaIfaces.clear();
|
|
mServiceDeclared = serviceDeclared();
|
|
return mServiceDeclared;
|
|
}
|
|
}
|
|
|
|
protected int getCurrentNetworkId(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
|
|
if (currentConfig == null) {
|
|
return WifiConfiguration.INVALID_NETWORK_ID;
|
|
}
|
|
return currentConfig.networkId;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Setup a STA interface for the specified iface name.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true on success, false otherwise.
|
|
*/
|
|
public boolean setupIface(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
if (getStaIface(ifaceName) != null) {
|
|
Log.e(TAG, "Iface " + ifaceName + " already exists.");
|
|
return false;
|
|
}
|
|
|
|
ISupplicantStaIface iface = addIface(ifaceName);
|
|
if (iface == null) {
|
|
Log.e(TAG, "Unable to add iface " + ifaceName);
|
|
return false;
|
|
}
|
|
|
|
ISupplicantStaIfaceCallback callback = new SupplicantStaIfaceCallbackAidlImpl(
|
|
SupplicantStaIfaceHalAidlImpl.this, ifaceName,
|
|
new Object(), mContext, mWifiMonitor);
|
|
if (registerCallback(iface, callback)) {
|
|
mISupplicantStaIfaces.put(ifaceName, iface);
|
|
// Keep callback in a store to avoid recycling by garbage collector
|
|
mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
|
|
return true;
|
|
} else {
|
|
Log.e(TAG, "Unable to register callback for iface " + ifaceName);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a STA interface for the specified iface name.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return ISupplicantStaIface object on success, null otherwise.
|
|
*/
|
|
private ISupplicantStaIface addIface(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
String methodStr = "addIface";
|
|
if (!checkSupplicantAndLogFailure(methodStr)) {
|
|
return null;
|
|
}
|
|
try {
|
|
return mISupplicant.addStaInterface(ifaceName);
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
} catch (NoSuchElementException | IllegalArgumentException e) {
|
|
Log.e(TAG, "Encountered exception at addIface: ", e);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Teardown a STA interface for the specified iface name.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true on success, false otherwise.
|
|
*/
|
|
public boolean teardownIface(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "teardownIface";
|
|
if (checkStaIfaceAndLogFailure(ifaceName, methodStr) == null) {
|
|
return false;
|
|
}
|
|
if (!checkSupplicantAndLogFailure(methodStr)) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
IfaceInfo ifaceInfo = new IfaceInfo();
|
|
ifaceInfo.name = ifaceName;
|
|
ifaceInfo.type = IfaceType.STA;
|
|
mISupplicant.removeInterface(ifaceInfo);
|
|
mISupplicantStaIfaces.remove(ifaceName);
|
|
mISupplicantStaIfaceCallbacks.remove(ifaceName);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
} catch (NoSuchElementException e) {
|
|
Log.e(TAG, "Encountered exception at teardownIface: ", e);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Registers a death notification for supplicant.
|
|
* @return Returns true on success.
|
|
*/
|
|
public boolean registerDeathHandler(@NonNull WifiNative.SupplicantDeathEventHandler handler) {
|
|
synchronized (mLock) {
|
|
if (mDeathEventHandler != null) {
|
|
Log.e(TAG, "Death handler already present");
|
|
}
|
|
mDeathEventHandler = handler;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deregisters a death notification for supplicant.
|
|
* @return Returns true on success.
|
|
*/
|
|
public boolean deregisterDeathHandler() {
|
|
synchronized (mLock) {
|
|
if (mDeathEventHandler == null) {
|
|
Log.e(TAG, "No Death handler present");
|
|
}
|
|
mDeathEventHandler = null;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Signals whether initialization started successfully.
|
|
*/
|
|
public boolean isInitializationStarted() {
|
|
synchronized (mLock) {
|
|
return mServiceDeclared;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Signals whether initialization completed successfully.
|
|
*/
|
|
public boolean isInitializationComplete() {
|
|
synchronized (mLock) {
|
|
return mISupplicant != null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates whether the AIDL service is declared
|
|
*/
|
|
public static boolean serviceDeclared() {
|
|
// Service Manager API ServiceManager#isDeclared supported after T.
|
|
if (!SdkLevel.isAtLeastT()) {
|
|
return false;
|
|
}
|
|
return ServiceManager.isDeclared(HAL_INSTANCE_NAME);
|
|
}
|
|
|
|
private void clearState() {
|
|
synchronized (mLock) {
|
|
mISupplicant = null;
|
|
mISupplicantStaIfaces.clear();
|
|
mCurrentNetworkLocalConfigs.clear();
|
|
mCurrentNetworkRemoteHandles.clear();
|
|
mLinkedNetworkLocalAndRemoteConfigs.clear();
|
|
}
|
|
}
|
|
|
|
private void supplicantServiceDiedHandler() {
|
|
synchronized (mLock) {
|
|
clearState();
|
|
if (mDeathEventHandler != null) {
|
|
mDeathEventHandler.onDeath();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start the supplicant daemon.
|
|
*
|
|
* @return true on success, false otherwise.
|
|
*/
|
|
public boolean startDaemon() {
|
|
final String methodStr = "startDaemon";
|
|
if (mISupplicant != null) {
|
|
Log.i(TAG, "Service is already initialized, skipping " + methodStr);
|
|
return true;
|
|
}
|
|
|
|
mISupplicant = getSupplicantMockable();
|
|
if (mISupplicant == null) {
|
|
Log.e(TAG, "Unable to obtain ISupplicant binder.");
|
|
return false;
|
|
}
|
|
Log.i(TAG, "Obtained ISupplicant binder.");
|
|
|
|
try {
|
|
IBinder serviceBinder = getServiceBinderMockable();
|
|
if (serviceBinder == null) {
|
|
return false;
|
|
}
|
|
serviceBinder.linkToDeath(mSupplicantDeathRecipient, /* flags= */ 0);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Terminate the supplicant daemon & wait for its death.
|
|
*/
|
|
public void terminate() {
|
|
synchronized (mLock) {
|
|
final String methodStr = "terminate";
|
|
if (!checkSupplicantAndLogFailure(methodStr)) {
|
|
return;
|
|
}
|
|
try {
|
|
// Register a new death listener to confirm that terminate() killed supplicant
|
|
IBinder serviceBinder = getServiceBinderMockable();
|
|
if (serviceBinder == null) {
|
|
return;
|
|
}
|
|
serviceBinder.linkToDeath(new TerminateDeathRecipient(), /* flags= */ 0);
|
|
} catch (RemoteException e) {
|
|
Log.e(TAG, "Unable to register death recipient.");
|
|
handleRemoteException(e, methodStr);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
mISupplicant.terminate();
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrapper functions to access HAL objects, created to be mockable in unit tests
|
|
*/
|
|
@VisibleForTesting
|
|
protected ISupplicant getSupplicantMockable() {
|
|
synchronized (mLock) {
|
|
try {
|
|
return ISupplicant.Stub.asInterface(
|
|
ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME));
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Unable to get ISupplicant service, " + e);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
@VisibleForTesting
|
|
protected IBinder getServiceBinderMockable() {
|
|
synchronized (mLock) {
|
|
if (mISupplicant == null) {
|
|
return null;
|
|
}
|
|
return mISupplicant.asBinder();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper method to look up the specified iface.
|
|
*/
|
|
private ISupplicantStaIface getStaIface(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
return mISupplicantStaIfaces.get(ifaceName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper method to look up the network object for the specified iface.
|
|
*/
|
|
private SupplicantStaNetworkHalAidlImpl getCurrentNetworkRemoteHandle(
|
|
@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
return mCurrentNetworkRemoteHandles.get(ifaceName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper method to look up the network config for the specified iface.
|
|
*/
|
|
protected WifiConfiguration getCurrentNetworkLocalConfig(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
return mCurrentNetworkLocalConfigs.get(ifaceName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a network configuration to wpa_supplicant.
|
|
*
|
|
* @param config Config corresponding to the network.
|
|
* @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects
|
|
* for the current network.
|
|
*/
|
|
private Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>
|
|
addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) {
|
|
synchronized (mLock) {
|
|
if (config == null) {
|
|
Log.e(TAG, "Cannot add null network.");
|
|
return null;
|
|
}
|
|
SupplicantStaNetworkHalAidlImpl network = addNetwork(ifaceName);
|
|
if (network == null) {
|
|
Log.e(TAG, "Failed to add network.");
|
|
return null;
|
|
}
|
|
boolean saveSuccess = false;
|
|
try {
|
|
saveSuccess = network.saveWifiConfiguration(config);
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Exception while saving config params: " + config, e);
|
|
}
|
|
if (!saveSuccess) {
|
|
Log.e(TAG, "Failed to save variables for: " + config.getProfileKey());
|
|
if (!removeAllNetworks(ifaceName)) {
|
|
Log.e(TAG, "Failed to remove all networks on failure.");
|
|
}
|
|
return null;
|
|
}
|
|
return new Pair(network, new WifiConfiguration(config));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add the provided network configuration to wpa_supplicant and initiate connection to it.
|
|
* This method does the following:
|
|
* 1. If |config| is different to the current supplicant network, removes all supplicant
|
|
* networks and saves |config|.
|
|
* 2. Select the new network in wpa_supplicant.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param config WifiConfiguration parameters for the provided network.
|
|
* @return true if it succeeds, false otherwise
|
|
*/
|
|
public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
|
|
synchronized (mLock) {
|
|
Log.d(TAG, "connectToNetwork " + config.getProfileKey());
|
|
WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
|
|
if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) {
|
|
String networkSelectionBSSID = config.getNetworkSelectionStatus()
|
|
.getNetworkSelectionBSSID();
|
|
String networkSelectionBSSIDCurrent = currentConfig.getNetworkSelectionStatus()
|
|
.getNetworkSelectionBSSID();
|
|
if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
|
|
Log.d(TAG, "Network is already saved, will not trigger remove and add.");
|
|
} else {
|
|
Log.d(TAG, "Network is already saved, but need to update BSSID.");
|
|
if (!setCurrentNetworkBssid(
|
|
ifaceName,
|
|
config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
|
|
Log.e(TAG, "Failed to set current network BSSID.");
|
|
return false;
|
|
}
|
|
mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
|
|
}
|
|
} else {
|
|
mCurrentNetworkRemoteHandles.remove(ifaceName);
|
|
mCurrentNetworkLocalConfigs.remove(ifaceName);
|
|
mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
|
|
if (!removeAllNetworks(ifaceName)) {
|
|
Log.e(TAG, "Failed to remove existing networks");
|
|
return false;
|
|
}
|
|
Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair =
|
|
addNetworkAndSaveConfig(ifaceName, config);
|
|
if (pair == null) {
|
|
Log.e(TAG, "Failed to add/save network configuration: " + config
|
|
.getProfileKey());
|
|
return false;
|
|
}
|
|
mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
|
|
mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
|
|
}
|
|
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
|
|
if (networkHandle == null) {
|
|
Log.e(TAG, "No valid remote network handle for network configuration: "
|
|
+ config.getProfileKey());
|
|
return false;
|
|
}
|
|
|
|
SecurityParams params = config.getNetworkSelectionStatus()
|
|
.getCandidateSecurityParams();
|
|
if (params != null && !(params.isSecurityType(WifiConfiguration.SECURITY_TYPE_PSK)
|
|
|| params.isSecurityType(WifiConfiguration.SECURITY_TYPE_DPP))) {
|
|
List<ArrayList<Byte>> pmkDataList = mPmkCacheManager.get(config.networkId);
|
|
if (pmkDataList != null) {
|
|
Log.i(TAG, "Set PMK cache for config id " + config.networkId);
|
|
pmkDataList.forEach(pmkData -> {
|
|
if (networkHandle.setPmkCache(NativeUtil.byteArrayFromArrayList(pmkData))) {
|
|
mWifiMetrics.setConnectionPmkCache(ifaceName, true);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!networkHandle.select()) {
|
|
Log.e(TAG, "Failed to select network configuration: " + config.getProfileKey());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initiates roaming to the already configured network in wpa_supplicant. If the network
|
|
* configuration provided does not match the already configured network, then this triggers
|
|
* a new connection attempt (instead of roam).
|
|
* 1. First check if we're attempting to connect to a linked network, and select the existing
|
|
* supplicant network if there is one.
|
|
* 2. Set the new bssid for the network in wpa_supplicant.
|
|
* 3. Trigger reassociate command to wpa_supplicant.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param config WifiConfiguration parameters for the provided network.
|
|
* @return {@code true} if it succeeds, {@code false} otherwise
|
|
*/
|
|
public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration config) {
|
|
synchronized (mLock) {
|
|
if (updateOnLinkedNetworkRoaming(ifaceName, config.networkId, true)) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
getCurrentNetworkRemoteHandle(ifaceName);
|
|
if (networkHandle == null) {
|
|
Log.e(TAG, "Roaming config matches a linked config, "
|
|
+ "but a linked network handle was not found.");
|
|
return false;
|
|
}
|
|
return networkHandle.select();
|
|
}
|
|
if (getCurrentNetworkId(ifaceName) != config.networkId) {
|
|
Log.w(TAG, "Cannot roam to a different network, initiate new connection. "
|
|
+ "Current network ID: " + getCurrentNetworkId(ifaceName));
|
|
return connectToNetwork(ifaceName, config);
|
|
}
|
|
String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
|
|
Log.d(TAG, "roamToNetwork" + config.getProfileKey() + " (bssid " + bssid + ")");
|
|
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(ifaceName, "roamToNetwork");
|
|
if (networkHandle == null || !networkHandle.setBssid(bssid)) {
|
|
Log.e(TAG, "Failed to set new bssid on network: " + config.getProfileKey());
|
|
return false;
|
|
}
|
|
if (!reassociate(ifaceName)) {
|
|
Log.e(TAG, "Failed to trigger reassociate");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clean HAL cached data for |networkId| in the framework.
|
|
*
|
|
* @param networkId network id of the network to be removed from supplicant.
|
|
*/
|
|
public void removeNetworkCachedData(int networkId) {
|
|
synchronized (mLock) {
|
|
Log.d(TAG, "Remove cached HAL data for config id " + networkId);
|
|
removePmkCacheEntry(networkId);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Clear HAL cached data if MAC address is changed.
|
|
*
|
|
* @param networkId network id of the network to be checked.
|
|
* @param curMacAddress current MAC address
|
|
*/
|
|
public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) {
|
|
synchronized (mLock) {
|
|
mPmkCacheManager.remove(networkId, curMacAddress);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove all networks from supplicant
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
*/
|
|
public boolean removeAllNetworks(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
int[] networks = listNetworks(ifaceName);
|
|
if (networks == null) {
|
|
Log.e(TAG, "removeAllNetworks failed, got null networks");
|
|
return false;
|
|
}
|
|
for (int id : networks) {
|
|
if (!removeNetwork(ifaceName, id)) {
|
|
Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
|
|
return false;
|
|
}
|
|
}
|
|
// Reset current network info.
|
|
mCurrentNetworkRemoteHandles.remove(ifaceName);
|
|
mCurrentNetworkLocalConfigs.remove(ifaceName);
|
|
mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disable the current network in supplicant
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
*/
|
|
public boolean disableCurrentNetwork(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(ifaceName, "disableCurrentNetwork");
|
|
if (networkHandle == null) {
|
|
return false;
|
|
}
|
|
return networkHandle.disable();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the currently configured network's bssid.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX"
|
|
* @return true if succeeds, false otherwise.
|
|
*/
|
|
public boolean setCurrentNetworkBssid(@NonNull String ifaceName, String bssidStr) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(ifaceName, "setCurrentNetworkBssid");
|
|
if (networkHandle == null) {
|
|
return false;
|
|
}
|
|
return networkHandle.setBssid(bssidStr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the currently configured network's WPS NFC token.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return Hex string corresponding to the WPS NFC token.
|
|
*/
|
|
public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(
|
|
ifaceName, "getCurrentNetworkWpsNfcConfigurationToken");
|
|
if (networkHandle == null) {
|
|
return null;
|
|
}
|
|
return networkHandle.getWpsNfcConfigurationToken();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the eap anonymous identity for the currently configured network.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return anonymous identity string if succeeds, null otherwise.
|
|
*/
|
|
public String getCurrentNetworkEapAnonymousIdentity(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(
|
|
ifaceName, "getCurrentNetworkEapAnonymousIdentity");
|
|
if (networkHandle == null) {
|
|
return null;
|
|
}
|
|
return networkHandle.fetchEapAnonymousIdentity();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the eap identity response for the currently configured network.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param identity identity used for EAP-Identity
|
|
* @param encryptedIdentity encrypted identity used for EAP-AKA/EAP-SIM
|
|
* @return true if succeeds, false otherwise.
|
|
*/
|
|
public boolean sendCurrentNetworkEapIdentityResponse(
|
|
@NonNull String ifaceName, @NonNull String identity, String encryptedIdentity) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(
|
|
ifaceName, "sendCurrentNetworkEapIdentityResponse");
|
|
if (networkHandle == null) {
|
|
return false;
|
|
}
|
|
return networkHandle.sendNetworkEapIdentityResponse(identity, encryptedIdentity);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the eap sim gsm auth response for the currently configured network.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param paramsStr String to send.
|
|
* @return true if succeeds, false otherwise.
|
|
*/
|
|
public boolean sendCurrentNetworkEapSimGsmAuthResponse(
|
|
@NonNull String ifaceName, String paramsStr) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(
|
|
ifaceName, "sendCurrentNetworkEapSimGsmAuthResponse");
|
|
if (networkHandle == null) {
|
|
return false;
|
|
}
|
|
return networkHandle.sendNetworkEapSimGsmAuthResponse(paramsStr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the eap sim gsm auth failure for the currently configured network.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if succeeds, false otherwise.
|
|
*/
|
|
public boolean sendCurrentNetworkEapSimGsmAuthFailure(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(
|
|
ifaceName, "sendCurrentNetworkEapSimGsmAuthFailure");
|
|
if (networkHandle == null) {
|
|
return false;
|
|
}
|
|
return networkHandle.sendNetworkEapSimGsmAuthFailure();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the eap sim umts auth response for the currently configured network.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param paramsStr String to send.
|
|
* @return true if succeeds, false otherwise.
|
|
*/
|
|
public boolean sendCurrentNetworkEapSimUmtsAuthResponse(
|
|
@NonNull String ifaceName, String paramsStr) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(
|
|
ifaceName, "sendCurrentNetworkEapSimUmtsAuthResponse");
|
|
if (networkHandle == null) {
|
|
return false;
|
|
}
|
|
return networkHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the eap sim umts auts response for the currently configured network.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param paramsStr String to send.
|
|
* @return true if succeeds, false otherwise.
|
|
*/
|
|
public boolean sendCurrentNetworkEapSimUmtsAutsResponse(
|
|
@NonNull String ifaceName, String paramsStr) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(
|
|
ifaceName, "sendCurrentNetworkEapSimUmtsAutsResponse");
|
|
if (networkHandle == null) {
|
|
return false;
|
|
}
|
|
return networkHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the eap sim umts auth failure for the currently configured network.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if succeeds, false otherwise.
|
|
*/
|
|
public boolean sendCurrentNetworkEapSimUmtsAuthFailure(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(
|
|
ifaceName, "sendCurrentNetworkEapSimUmtsAuthFailure");
|
|
if (networkHandle == null) {
|
|
return false;
|
|
}
|
|
return networkHandle.sendNetworkEapSimUmtsAuthFailure();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a new network.
|
|
*
|
|
* @return SupplicantStaNetworkHalAidlImpl object for the new network, or null if the call fails
|
|
*/
|
|
private SupplicantStaNetworkHalAidlImpl addNetwork(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "addNetwork";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return null;
|
|
}
|
|
try {
|
|
ISupplicantStaNetwork network = iface.addNetwork();
|
|
// Get framework wrapper around the AIDL network object
|
|
return getStaNetworkHalMockable(ifaceName, network);
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove network with specified network Id from supplicant.
|
|
*
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
private boolean removeNetwork(@NonNull String ifaceName, int id) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "removeNetwork";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.removeNetwork(id);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a SupplicantStaNetworkHal wrapper around an AIDL ISupplicantStaNetwork object.
|
|
* Declared mockable for use in unit tests.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param network ISupplicantStaNetwork instance retrieved from AIDL.
|
|
* @return SupplicantStaNetworkHal object for the given network, or null if
|
|
* the call fails
|
|
*/
|
|
protected SupplicantStaNetworkHalAidlImpl getStaNetworkHalMockable(
|
|
@NonNull String ifaceName, ISupplicantStaNetwork network) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkWrapper =
|
|
new SupplicantStaNetworkHalAidlImpl(network, ifaceName, mContext,
|
|
mWifiMonitor, mWifiGlobals, getAdvancedCapabilities(ifaceName));
|
|
if (networkWrapper != null) {
|
|
networkWrapper.enableVerboseLogging(
|
|
mVerboseLoggingEnabled, mVerboseHalLoggingEnabled);
|
|
}
|
|
return networkWrapper;
|
|
}
|
|
}
|
|
|
|
private boolean registerCallback(
|
|
ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback) {
|
|
synchronized (mLock) {
|
|
String methodStr = "registerCallback";
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.registerCallback(callback);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get list of id's of all networks controlled by supplicant.
|
|
*
|
|
* @return list of network id's, null if failed
|
|
*/
|
|
private int[] listNetworks(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "listNetworks";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return null;
|
|
}
|
|
try {
|
|
return iface.listNetworks();
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set WPS device name.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param name String to be set.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setWpsDeviceName(@NonNull String ifaceName, String name) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setWpsDeviceName";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setWpsDeviceName(name);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set WPS device type.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setWpsDeviceType(@NonNull String ifaceName, String typeStr) {
|
|
synchronized (mLock) {
|
|
try {
|
|
Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr);
|
|
if (!match.find() || match.groupCount() != 3) {
|
|
Log.e(TAG, "Malformed WPS device type " + typeStr);
|
|
return false;
|
|
}
|
|
short categ = Short.parseShort(match.group(1));
|
|
byte[] oui = NativeUtil.hexStringToByteArray(match.group(2));
|
|
short subCateg = Short.parseShort(match.group(3));
|
|
|
|
byte[] bytes = new byte[8];
|
|
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
|
byteBuffer.putShort(categ);
|
|
byteBuffer.put(oui);
|
|
byteBuffer.putShort(subCateg);
|
|
return setWpsDeviceType(ifaceName, bytes);
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + typeStr, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean setWpsDeviceType(@NonNull String ifaceName, byte[/* 8 */] type) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setWpsDeviceType";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setWpsDeviceType(type);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set WPS manufacturer.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param manufacturer String to be set.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setWpsManufacturer(@NonNull String ifaceName, String manufacturer) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setWpsManufacturer";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setWpsManufacturer(manufacturer);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set WPS model name.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param modelName String to be set.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setWpsModelName(@NonNull String ifaceName, String modelName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setWpsModelName";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setWpsModelName(modelName);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set WPS model number.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param modelNumber String to be set.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setWpsModelNumber(@NonNull String ifaceName, String modelNumber) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setWpsModelNumber";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setWpsModelNumber(modelNumber);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set WPS serial number.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param serialNumber String to be set.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setWpsSerialNumber(@NonNull String ifaceName, String serialNumber) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setWpsSerialNumber";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setWpsSerialNumber(serialNumber);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set WPS config methods
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param configMethodsStr List of config methods.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setWpsConfigMethods(@NonNull String ifaceName, String configMethodsStr) {
|
|
synchronized (mLock) {
|
|
int configMethodsMask = 0;
|
|
String[] configMethodsStrArr = configMethodsStr.split("\\s+");
|
|
for (int i = 0; i < configMethodsStrArr.length; i++) {
|
|
configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]);
|
|
}
|
|
return setWpsConfigMethods(ifaceName, configMethodsMask);
|
|
}
|
|
}
|
|
|
|
private boolean setWpsConfigMethods(@NonNull String ifaceName, int configMethods) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setWpsConfigMethods";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setWpsConfigMethods(configMethods);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trigger a reassociation even if the iface is currently connected.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean reassociate(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "reassociate";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.reassociate();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trigger a reconnection if the iface is disconnected.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean reconnect(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "reconnect";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.reconnect();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Trigger a disconnection from the currently connected network.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean disconnect(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "disconnect";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.disconnect();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enable or disable power save mode.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param enable true to enable, false to disable.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setPowerSave(@NonNull String ifaceName, boolean enable) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setPowerSave";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setPowerSave(enable);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initiate TDLS discover with the specified AP.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param macAddress MAC Address of the AP.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean initiateTdlsDiscover(@NonNull String ifaceName, String macAddress) {
|
|
synchronized (mLock) {
|
|
try {
|
|
return initiateTdlsDiscover(
|
|
ifaceName, NativeUtil.macAddressToByteArray(macAddress));
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + macAddress, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean initiateTdlsDiscover(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "initiateTdlsDiscover";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.initiateTdlsDiscover(macAddress);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initiate TDLS setup with the specified AP.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param macAddress MAC Address of the AP.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean initiateTdlsSetup(@NonNull String ifaceName, String macAddress) {
|
|
synchronized (mLock) {
|
|
try {
|
|
return initiateTdlsSetup(ifaceName, NativeUtil.macAddressToByteArray(macAddress));
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + macAddress, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean initiateTdlsSetup(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "initiateTdlsSetup";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.initiateTdlsSetup(macAddress);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initiate TDLS teardown with the specified AP.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param macAddress MAC Address of the AP.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean initiateTdlsTeardown(@NonNull String ifaceName, String macAddress) {
|
|
synchronized (mLock) {
|
|
try {
|
|
return initiateTdlsTeardown(
|
|
ifaceName, NativeUtil.macAddressToByteArray(macAddress));
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + macAddress, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean initiateTdlsTeardown(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "initiateTdlsTeardown";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.initiateTdlsTeardown(macAddress);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Request the specified ANQP elements |elements| from the specified AP |bssid|.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param bssid BSSID of the AP
|
|
* @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId.
|
|
* @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean initiateAnqpQuery(@NonNull String ifaceName, String bssid,
|
|
ArrayList<Short> infoElements,
|
|
ArrayList<Integer> hs20SubTypes) {
|
|
synchronized (mLock) {
|
|
try {
|
|
int[] infoElementsCast = new int[infoElements.size()];
|
|
int[] hs20SubTypesCast = new int[hs20SubTypes.size()];
|
|
for (int i = 0; i < infoElements.size(); i++) {
|
|
infoElementsCast[i] = infoElements.get(i);
|
|
}
|
|
for (int i = 0; i < hs20SubTypes.size(); i++) {
|
|
hs20SubTypesCast[i] = hs20SubTypes.get(i);
|
|
}
|
|
return initiateAnqpQuery(
|
|
ifaceName,
|
|
NativeUtil.macAddressToByteArray(bssid),
|
|
infoElementsCast, hs20SubTypesCast);
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + bssid, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean initiateAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress,
|
|
int[] infoElements, int[] subTypes) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "initiateAnqpQuery";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.initiateAnqpQuery(macAddress, infoElements, subTypes);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Request Venue URL ANQP element from the specified AP |bssid|.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param bssid BSSID of the AP
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean initiateVenueUrlAnqpQuery(@NonNull String ifaceName, String bssid) {
|
|
synchronized (mLock) {
|
|
try {
|
|
return initiateVenueUrlAnqpQuery(
|
|
ifaceName, NativeUtil.macAddressToByteArray(bssid));
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + bssid, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean initiateVenueUrlAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "initiateVenueUrlAnqpQuery";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.initiateVenueUrlAnqpQuery(macAddress);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Request the specified ANQP ICON from the specified AP |bssid|.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param bssid BSSID of the AP
|
|
* @param fileName Name of the file to request.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean initiateHs20IconQuery(@NonNull String ifaceName, String bssid, String fileName) {
|
|
synchronized (mLock) {
|
|
try {
|
|
return initiateHs20IconQuery(
|
|
ifaceName, NativeUtil.macAddressToByteArray(bssid), fileName);
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + bssid, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean initiateHs20IconQuery(@NonNull String ifaceName,
|
|
byte[/* 6 */] macAddress, String fileName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "initiateHs20IconQuery";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.initiateHs20IconQuery(macAddress, fileName);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets MAC Address from the supplicant.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return string containing the MAC address, or null on a failed call
|
|
*/
|
|
public String getMacAddress(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "getMacAddress";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return null;
|
|
}
|
|
try {
|
|
byte[] macAddr = iface.getMacAddress();
|
|
return NativeUtil.macAddressFromByteArray(macAddr);
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Invalid MAC address value", e);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start using the added RX filters.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean startRxFilter(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "startRxFilter";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.startRxFilter();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stop using the added RX filters.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean stopRxFilter(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "stopRxFilter";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.stopRxFilter();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add an RX filter.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
|
|
* {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean addRxFilter(@NonNull String ifaceName, int type) {
|
|
synchronized (mLock) {
|
|
byte halType;
|
|
switch (type) {
|
|
case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
|
|
halType = RxFilterType.V4_MULTICAST;
|
|
break;
|
|
case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
|
|
halType = RxFilterType.V6_MULTICAST;
|
|
break;
|
|
default:
|
|
Log.e(TAG, "Invalid Rx Filter type: " + type);
|
|
return false;
|
|
}
|
|
return addRxFilter(ifaceName, halType);
|
|
}
|
|
}
|
|
|
|
private boolean addRxFilter(@NonNull String ifaceName, byte type) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "addRxFilter";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.addRxFilter(type);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove an RX filter.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
|
|
* {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean removeRxFilter(@NonNull String ifaceName, int type) {
|
|
synchronized (mLock) {
|
|
byte halType;
|
|
switch (type) {
|
|
case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
|
|
halType = RxFilterType.V4_MULTICAST;
|
|
break;
|
|
case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
|
|
halType = RxFilterType.V6_MULTICAST;
|
|
break;
|
|
default:
|
|
Log.e(TAG, "Invalid Rx Filter type: " + type);
|
|
return false;
|
|
}
|
|
return removeRxFilter(ifaceName, halType);
|
|
}
|
|
}
|
|
|
|
private boolean removeRxFilter(@NonNull String ifaceName, byte type) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "removeRxFilter";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.removeRxFilter(type);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set Bt co existense mode.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED},
|
|
* {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or
|
|
* {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setBtCoexistenceMode(@NonNull String ifaceName, int mode) {
|
|
synchronized (mLock) {
|
|
byte halMode;
|
|
switch (mode) {
|
|
case WifiNative.BLUETOOTH_COEXISTENCE_MODE_ENABLED:
|
|
halMode = BtCoexistenceMode.ENABLED;
|
|
break;
|
|
case WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED:
|
|
halMode = BtCoexistenceMode.DISABLED;
|
|
break;
|
|
case WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE:
|
|
halMode = BtCoexistenceMode.SENSE;
|
|
break;
|
|
default:
|
|
Log.e(TAG, "Invalid Bt Coex mode: " + mode);
|
|
return false;
|
|
}
|
|
return setBtCoexistenceMode(ifaceName, halMode);
|
|
}
|
|
}
|
|
|
|
private boolean setBtCoexistenceMode(@NonNull String ifaceName, byte mode) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setBtCoexistenceMode";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setBtCoexistenceMode(mode);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/** Enable or disable BT coexistence mode.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param enable true to enable, false to disable.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setBtCoexistenceScanModeEnabled(@NonNull String ifaceName, boolean enable) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setBtCoexistenceScanModeEnabled";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setBtCoexistenceScanModeEnabled(enable);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enable or disable suspend mode optimizations.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param enable true to enable, false otherwise.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setSuspendModeEnabled(@NonNull String ifaceName, boolean enable) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setSuspendModeEnabled";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setSuspendModeEnabled(enable);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set country code.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param codeStr 2 byte ASCII string. For ex: US, CA.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setCountryCode(@NonNull String ifaceName, String codeStr) {
|
|
synchronized (mLock) {
|
|
if (TextUtils.isEmpty(codeStr)) {
|
|
return false;
|
|
}
|
|
byte[] countryCodeBytes = NativeUtil.stringToByteArray(codeStr);
|
|
if (countryCodeBytes.length != 2) {
|
|
return false;
|
|
}
|
|
return setCountryCode(ifaceName, countryCodeBytes);
|
|
}
|
|
}
|
|
|
|
private boolean setCountryCode(@NonNull String ifaceName, byte[/* 2 */] code) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setCountryCode";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setCountryCode(code);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flush all previously configured HLPs.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean flushAllHlp(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "filsHlpFlushRequest";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.filsHlpFlushRequest();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set FILS HLP packet.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param dst Destination MAC address.
|
|
* @param hlpPacket Hlp Packet data in hex.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean addHlpReq(@NonNull String ifaceName, byte[] dst, byte[] hlpPacket) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "filsHlpAddRequest";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.filsHlpAddRequest(dst, hlpPacket);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start WPS pin registrar operation with the specified peer and pin.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param bssidStr BSSID of the peer.
|
|
* @param pin Pin to be used.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean startWpsRegistrar(@NonNull String ifaceName, String bssidStr, String pin) {
|
|
synchronized (mLock) {
|
|
if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) {
|
|
return false;
|
|
}
|
|
try {
|
|
return startWpsRegistrar(
|
|
ifaceName, NativeUtil.macAddressToByteArray(bssidStr), pin);
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + bssidStr, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean startWpsRegistrar(@NonNull String ifaceName, byte[/* 6 */] bssid, String pin) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "startWpsRegistrar";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.startWpsRegistrar(bssid, pin);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start WPS pin display operation with the specified peer.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean startWpsPbc(@NonNull String ifaceName, String bssidStr) {
|
|
synchronized (mLock) {
|
|
try {
|
|
return startWpsPbc(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + bssidStr, e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean startWpsPbc(@NonNull String ifaceName, byte[/* 6 */] bssid) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "startWpsPbc";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.startWpsPbc(bssid);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start WPS pin keypad operation with the specified pin.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param pin Pin to be used.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
|
|
if (TextUtils.isEmpty(pin)) {
|
|
return false;
|
|
}
|
|
synchronized (mLock) {
|
|
final String methodStr = "startWpsPinKeypad";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.startWpsPinKeypad(pin);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start WPS pin display operation with the specified peer.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
|
|
* @return new pin generated on success, null otherwise.
|
|
*/
|
|
public String startWpsPinDisplay(@NonNull String ifaceName, String bssidStr) {
|
|
synchronized (mLock) {
|
|
try {
|
|
return startWpsPinDisplay(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Illegal argument " + bssidStr, e);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private String startWpsPinDisplay(@NonNull String ifaceName, byte[/* 6 */] bssid) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "startWpsPinDisplay";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return null;
|
|
}
|
|
try {
|
|
return iface.startWpsPinDisplay(bssid);
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cancels any ongoing WPS requests.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean cancelWps(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "cancelWps";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.cancelWps();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets whether to use external sim for SIM/USIM processing.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param useExternalSim true to enable, false otherwise.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setExternalSim(@NonNull String ifaceName, boolean useExternalSim) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setExternalSim";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setExternalSim(useExternalSim);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enable/Disable auto reconnect to networks.
|
|
* Use this to prevent wpa_supplicant from trying to connect to networks
|
|
* on its own.
|
|
*
|
|
* @param enable true to enable, false to disable.
|
|
* @return true if no exceptions occurred, false otherwise
|
|
*/
|
|
public boolean enableAutoReconnect(@NonNull String ifaceName, boolean enable) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "enableAutoReconnect";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.enableAutoReconnect(enable);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the debug log level for wpa_supplicant
|
|
*
|
|
* @param turnOnVerbose Whether to turn on verbose logging or not.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setLogLevel(boolean turnOnVerbose) {
|
|
synchronized (mLock) {
|
|
int logLevel = turnOnVerbose
|
|
? DebugLevel.DEBUG
|
|
: DebugLevel.INFO;
|
|
return setDebugParams(logLevel, false,
|
|
turnOnVerbose && mWifiGlobals.getShowKeyVerboseLoggingModeEnabled());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set debug parameters for the ISupplicant service.
|
|
*
|
|
* @param level Debug logging level for the supplicant.
|
|
* (one of |DebugLevel| values).
|
|
* @param showTimestamp Determines whether to show timestamps in logs or not.
|
|
* @param showKeys Determines whether to show keys in debug logs or not.
|
|
* CAUTION: Do not set this param in production code!
|
|
* @return true if no exceptions occurred, false otherwise
|
|
*/
|
|
private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setDebugParams";
|
|
if (!checkSupplicantAndLogFailure(methodStr)) {
|
|
return false;
|
|
}
|
|
try {
|
|
mISupplicant.setDebugParams(level, showTimestamp, showKeys);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set concurrency priority between P2P & STA operations.
|
|
*
|
|
* @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
|
|
* false otherwise.
|
|
* @return true if request is sent successfully, false otherwise.
|
|
*/
|
|
public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
|
|
synchronized (mLock) {
|
|
if (isStaHigherPriority) {
|
|
return setConcurrencyPriority(IfaceType.STA);
|
|
} else {
|
|
return setConcurrencyPriority(IfaceType.P2P);
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean setConcurrencyPriority(int type) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setConcurrencyPriority";
|
|
if (!checkSupplicantAndLogFailure(methodStr)) {
|
|
return false;
|
|
}
|
|
try {
|
|
mISupplicant.setConcurrencyPriority(type);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns false if mISupplicant is null and logs failure message
|
|
*/
|
|
private boolean checkSupplicantAndLogFailure(final String methodStr) {
|
|
synchronized (mLock) {
|
|
if (mISupplicant == null) {
|
|
Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns specified STA iface if it exists. Otherwise, logs error and returns null.
|
|
*/
|
|
private ISupplicantStaIface checkStaIfaceAndLogFailure(
|
|
@NonNull String ifaceName, final String methodStr) {
|
|
synchronized (mLock) {
|
|
ISupplicantStaIface iface = getStaIface(ifaceName);
|
|
if (iface == null) {
|
|
Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null for "
|
|
+ "iface=" + ifaceName);
|
|
return null;
|
|
}
|
|
return iface;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns network belonging to the specified STA iface if it exists.
|
|
* Otherwise, logs error and returns null.
|
|
*/
|
|
private SupplicantStaNetworkHalAidlImpl checkStaNetworkAndLogFailure(
|
|
@NonNull String ifaceName, final String methodStr) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
getCurrentNetworkRemoteHandle(ifaceName);
|
|
if (networkHandle == null) {
|
|
Log.e(TAG, "Can't call " + methodStr + ", SupplicantStaNetwork for iface="
|
|
+ ifaceName + " is null.");
|
|
return null;
|
|
}
|
|
return networkHandle;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function to log callback events
|
|
*/
|
|
protected void logCallback(final String methodStr) {
|
|
synchronized (mLock) {
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.d(TAG, "ISupplicantStaIfaceCallback." + methodStr + " received");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void handleRemoteException(RemoteException e, String methodStr) {
|
|
synchronized (mLock) {
|
|
clearState();
|
|
Log.e(TAG,
|
|
"ISupplicantStaIface." + methodStr + " failed with remote exception: ", e);
|
|
}
|
|
}
|
|
|
|
private void handleServiceSpecificException(ServiceSpecificException e, String methodStr) {
|
|
synchronized (mLock) {
|
|
Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with "
|
|
+ "service specific exception: ", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Converts the Wps config method string to the equivalent enum value.
|
|
*/
|
|
private static int stringToWpsConfigMethod(String configMethod) {
|
|
switch (configMethod) {
|
|
case "usba":
|
|
return WpsConfigMethods.USBA;
|
|
case "ethernet":
|
|
return WpsConfigMethods.ETHERNET;
|
|
case "label":
|
|
return WpsConfigMethods.LABEL;
|
|
case "display":
|
|
return WpsConfigMethods.DISPLAY;
|
|
case "int_nfc_token":
|
|
return WpsConfigMethods.INT_NFC_TOKEN;
|
|
case "ext_nfc_token":
|
|
return WpsConfigMethods.EXT_NFC_TOKEN;
|
|
case "nfc_interface":
|
|
return WpsConfigMethods.NFC_INTERFACE;
|
|
case "push_button":
|
|
return WpsConfigMethods.PUSHBUTTON;
|
|
case "keypad":
|
|
return WpsConfigMethods.KEYPAD;
|
|
case "virtual_push_button":
|
|
return WpsConfigMethods.VIRT_PUSHBUTTON;
|
|
case "physical_push_button":
|
|
return WpsConfigMethods.PHY_PUSHBUTTON;
|
|
case "p2ps":
|
|
return WpsConfigMethods.P2PS;
|
|
case "virtual_display":
|
|
return WpsConfigMethods.VIRT_DISPLAY;
|
|
case "physical_display":
|
|
return WpsConfigMethods.PHY_DISPLAY;
|
|
default:
|
|
throw new IllegalArgumentException(
|
|
"Invalid WPS config method: " + configMethod);
|
|
}
|
|
}
|
|
|
|
protected void addPmkCacheEntry(
|
|
String ifaceName, int networkId,
|
|
long expirationTimeInSec, ArrayList<Byte> serializedEntry) {
|
|
synchronized (mLock) {
|
|
String macAddressStr = getMacAddress(ifaceName);
|
|
try {
|
|
if (!mPmkCacheManager.add(MacAddress.fromString(macAddressStr),
|
|
networkId, expirationTimeInSec, serializedEntry)) {
|
|
Log.w(TAG, "Cannot add PMK cache for " + ifaceName);
|
|
}
|
|
} catch (IllegalArgumentException ex) {
|
|
Log.w(TAG, "Cannot add PMK cache: " + ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void removePmkCacheEntry(int networkId) {
|
|
synchronized (mLock) {
|
|
mPmkCacheManager.remove(networkId);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a bitmask of advanced capabilities: WPA3 SAE/SUITE B and OWE
|
|
* Bitmask used is:
|
|
* - WIFI_FEATURE_WPA3_SAE
|
|
* - WIFI_FEATURE_WPA3_SUITE_B
|
|
* - WIFI_FEATURE_OWE
|
|
*
|
|
* @return true if successful, false otherwise.
|
|
*/
|
|
public long getAdvancedCapabilities(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "getAdvancedCapabilities";
|
|
long advancedCapabilities = 0;
|
|
int keyMgmtCapabilities = getKeyMgmtCapabilities(ifaceName);
|
|
|
|
advancedCapabilities |= WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS
|
|
| WIFI_FEATURE_DECORATED_IDENTITY;
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": Passpoint T&C supported");
|
|
Log.v(TAG, methodStr + ": RFC 7542 decorated identity supported");
|
|
}
|
|
|
|
if ((keyMgmtCapabilities & KeyMgmtMask.SAE) != 0) {
|
|
advancedCapabilities |= WIFI_FEATURE_WPA3_SAE;
|
|
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": SAE supported");
|
|
}
|
|
}
|
|
|
|
if ((keyMgmtCapabilities & KeyMgmtMask.SUITE_B_192) != 0) {
|
|
advancedCapabilities |= WIFI_FEATURE_WPA3_SUITE_B;
|
|
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": SUITE_B supported");
|
|
}
|
|
}
|
|
|
|
if ((keyMgmtCapabilities & KeyMgmtMask.OWE) != 0) {
|
|
advancedCapabilities |= WIFI_FEATURE_OWE;
|
|
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": OWE supported");
|
|
}
|
|
}
|
|
|
|
if ((keyMgmtCapabilities & KeyMgmtMask.DPP) != 0) {
|
|
advancedCapabilities |= WIFI_FEATURE_DPP
|
|
| WIFI_FEATURE_DPP_ENROLLEE_RESPONDER;
|
|
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": DPP supported");
|
|
Log.v(TAG, methodStr + ": DPP ENROLLEE RESPONDER supported");
|
|
}
|
|
}
|
|
|
|
if ((keyMgmtCapabilities & KeyMgmtMask.WAPI_PSK) != 0) {
|
|
advancedCapabilities |= WIFI_FEATURE_WAPI;
|
|
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": WAPI supported");
|
|
}
|
|
}
|
|
|
|
if ((keyMgmtCapabilities & KeyMgmtMask.FILS_SHA256) != 0) {
|
|
advancedCapabilities |= WIFI_FEATURE_FILS_SHA256;
|
|
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": FILS_SHA256 supported");
|
|
}
|
|
}
|
|
|
|
if ((keyMgmtCapabilities & KeyMgmtMask.FILS_SHA384) != 0) {
|
|
advancedCapabilities |= WIFI_FEATURE_FILS_SHA384;
|
|
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": FILS_SHA384 supported");
|
|
}
|
|
}
|
|
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": Capability flags = " + keyMgmtCapabilities);
|
|
}
|
|
|
|
return advancedCapabilities;
|
|
}
|
|
}
|
|
|
|
private int getKeyMgmtCapabilities(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "getKeyMgmtCapabilities";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return 0;
|
|
}
|
|
try {
|
|
return iface.getKeyMgmtCapabilities();
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the driver supported features through supplicant.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return bitmask defined by WifiManager.WIFI_FEATURE_*.
|
|
*/
|
|
public long getWpaDriverFeatureSet(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "getWpaDriverFeatureSet";
|
|
int drvCapabilitiesMask = getWpaDriverCapabilities(ifaceName);
|
|
long featureSet = 0;
|
|
|
|
if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.MBO) != 0) {
|
|
featureSet |= WIFI_FEATURE_MBO;
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": MBO supported");
|
|
}
|
|
if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.OCE) != 0) {
|
|
featureSet |= WIFI_FEATURE_OCE;
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": OCE supported");
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.SAE_PK) != 0) {
|
|
featureSet |= WIFI_FEATURE_SAE_PK;
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": SAE-PK supported");
|
|
}
|
|
}
|
|
|
|
if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.WFD_R2) != 0) {
|
|
featureSet |= WIFI_FEATURE_WFD_R2;
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": WFD-R2 supported");
|
|
}
|
|
}
|
|
|
|
if ((drvCapabilitiesMask
|
|
& WpaDriverCapabilitiesMask.TRUST_ON_FIRST_USE) != 0) {
|
|
featureSet |= WIFI_FEATURE_TRUST_ON_FIRST_USE;
|
|
if (mVerboseLoggingEnabled) {
|
|
Log.v(TAG, methodStr + ": Trust-On-First-Use supported");
|
|
}
|
|
}
|
|
|
|
return featureSet;
|
|
}
|
|
}
|
|
|
|
private int getWpaDriverCapabilities(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "getWpaDriverCapabilities";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return 0;
|
|
}
|
|
try {
|
|
return iface.getWpaDriverCapabilities();
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private @WifiAnnotations.WifiStandard int getWifiStandard(int technology) {
|
|
switch(technology) {
|
|
case WifiTechnology.EHT:
|
|
return ScanResult.WIFI_STANDARD_11BE;
|
|
case WifiTechnology.HE:
|
|
return ScanResult.WIFI_STANDARD_11AX;
|
|
case WifiTechnology.VHT:
|
|
return ScanResult.WIFI_STANDARD_11AC;
|
|
case WifiTechnology.HT:
|
|
return ScanResult.WIFI_STANDARD_11N;
|
|
case WifiTechnology.LEGACY:
|
|
return ScanResult.WIFI_STANDARD_LEGACY;
|
|
default:
|
|
return ScanResult.WIFI_STANDARD_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
private int getChannelBandwidth(int channelBandwidth) {
|
|
switch(channelBandwidth) {
|
|
case WifiChannelWidthInMhz.WIDTH_20:
|
|
return ScanResult.CHANNEL_WIDTH_20MHZ;
|
|
case WifiChannelWidthInMhz.WIDTH_40:
|
|
return ScanResult.CHANNEL_WIDTH_40MHZ;
|
|
case WifiChannelWidthInMhz.WIDTH_80:
|
|
return ScanResult.CHANNEL_WIDTH_80MHZ;
|
|
case WifiChannelWidthInMhz.WIDTH_160:
|
|
return ScanResult.CHANNEL_WIDTH_160MHZ;
|
|
case WifiChannelWidthInMhz.WIDTH_80P80:
|
|
return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
|
|
case WifiChannelWidthInMhz.WIDTH_320:
|
|
return ScanResult.CHANNEL_WIDTH_320MHZ;
|
|
default:
|
|
return ScanResult.CHANNEL_WIDTH_20MHZ;
|
|
}
|
|
}
|
|
|
|
private int frameworkToAidlDppAkm(int dppAkm) {
|
|
switch(dppAkm) {
|
|
case SupplicantStaIfaceHal.DppAkm.PSK:
|
|
return DppAkm.PSK;
|
|
case SupplicantStaIfaceHal.DppAkm.PSK_SAE:
|
|
return DppAkm.PSK_SAE;
|
|
case SupplicantStaIfaceHal.DppAkm.SAE:
|
|
return DppAkm.SAE;
|
|
case SupplicantStaIfaceHal.DppAkm.DPP:
|
|
return DppAkm.DPP;
|
|
default:
|
|
Log.e(TAG, "Invalid DppAkm received");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private int frameworkToAidlDppCurve(int dppCurve) {
|
|
switch(dppCurve) {
|
|
case SupplicantStaIfaceHal.DppCurve.PRIME256V1:
|
|
return DppCurve.PRIME256V1;
|
|
case SupplicantStaIfaceHal.DppCurve.SECP384R1:
|
|
return DppCurve.SECP384R1;
|
|
case SupplicantStaIfaceHal.DppCurve.SECP521R1:
|
|
return DppCurve.SECP521R1;
|
|
case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP256R1:
|
|
return DppCurve.BRAINPOOLP256R1;
|
|
case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP384R1:
|
|
return DppCurve.BRAINPOOLP384R1;
|
|
case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP512R1:
|
|
return DppCurve.BRAINPOOLP512R1;
|
|
default:
|
|
Log.e(TAG, "Invalid DppCurve received");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private int frameworkToAidlDppNetRole(int dppNetRole) {
|
|
switch(dppNetRole) {
|
|
case SupplicantStaIfaceHal.DppNetRole.STA:
|
|
return DppNetRole.STA;
|
|
case SupplicantStaIfaceHal.DppNetRole.AP:
|
|
return DppNetRole.AP;
|
|
default:
|
|
Log.e(TAG, "Invalid DppNetRole received");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
protected byte dscpPolicyToAidlQosPolicyStatusCode(int status) {
|
|
switch (status) {
|
|
case NetworkAgent.DSCP_POLICY_STATUS_SUCCESS:
|
|
case NetworkAgent.DSCP_POLICY_STATUS_DELETED:
|
|
return QosPolicyStatusCode.QOS_POLICY_SUCCESS;
|
|
case NetworkAgent.DSCP_POLICY_STATUS_REQUEST_DECLINED:
|
|
return QosPolicyStatusCode.QOS_POLICY_REQUEST_DECLINED;
|
|
case NetworkAgent.DSCP_POLICY_STATUS_REQUESTED_CLASSIFIER_NOT_SUPPORTED:
|
|
return QosPolicyStatusCode.QOS_POLICY_CLASSIFIER_NOT_SUPPORTED;
|
|
case NetworkAgent.DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES:
|
|
return QosPolicyStatusCode.QOS_POLICY_INSUFFICIENT_RESOURCES;
|
|
default:
|
|
Log.e(TAG, "Invalid DSCP policy failure code received: " + status);
|
|
return QosPolicyStatusCode.QOS_POLICY_REQUEST_DECLINED;
|
|
}
|
|
}
|
|
|
|
protected static int halToFrameworkQosPolicyRequestType(byte requestType) {
|
|
switch (requestType) {
|
|
case QosPolicyRequestType.QOS_POLICY_ADD:
|
|
return SupplicantStaIfaceHal.QOS_POLICY_REQUEST_ADD;
|
|
case QosPolicyRequestType.QOS_POLICY_REMOVE:
|
|
return SupplicantStaIfaceHal.QOS_POLICY_REQUEST_REMOVE;
|
|
default:
|
|
Log.e(TAG, "Invalid QosPolicyRequestType received: " + requestType);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private static boolean qosClassifierParamHasValue(int classifierParamMask, int paramBit) {
|
|
return (classifierParamMask & paramBit) != 0;
|
|
}
|
|
|
|
/**
|
|
* Convert from a HAL QosPolicyData object to a framework QosPolicy object.
|
|
*/
|
|
public static SupplicantStaIfaceHal.QosPolicyRequest halToFrameworkQosPolicy(
|
|
QosPolicyData halQosPolicy) {
|
|
QosPolicyClassifierParams classifierParams = halQosPolicy.classifierParams;
|
|
int classifierParamMask = classifierParams.classifierParamMask;
|
|
|
|
byte[] srcIp = null;
|
|
byte[] dstIp = null;
|
|
int srcPort = DscpPolicy.SOURCE_PORT_ANY;
|
|
int[] dstPortRange = new int[]{MIN_PORT_NUM, MAX_PORT_NUM};
|
|
int protocol = DscpPolicy.PROTOCOL_ANY;
|
|
boolean hasSrcIp = false;
|
|
boolean hasDstIp = false;
|
|
|
|
if (qosClassifierParamHasValue(classifierParamMask, QosPolicyClassifierParamsMask.SRC_IP)) {
|
|
hasSrcIp = true;
|
|
srcIp = classifierParams.srcIp;
|
|
}
|
|
if (qosClassifierParamHasValue(classifierParamMask, QosPolicyClassifierParamsMask.DST_IP)) {
|
|
hasDstIp = true;
|
|
dstIp = classifierParams.dstIp;
|
|
}
|
|
if (qosClassifierParamHasValue(classifierParamMask,
|
|
QosPolicyClassifierParamsMask.SRC_PORT)) {
|
|
srcPort = classifierParams.srcPort;
|
|
}
|
|
if (qosClassifierParamHasValue(classifierParamMask,
|
|
QosPolicyClassifierParamsMask.DST_PORT_RANGE)) {
|
|
dstPortRange[0] = classifierParams.dstPortRange.startPort;
|
|
dstPortRange[1] = classifierParams.dstPortRange.endPort;
|
|
}
|
|
if (qosClassifierParamHasValue(classifierParamMask,
|
|
QosPolicyClassifierParamsMask.PROTOCOL_NEXT_HEADER)) {
|
|
protocol = classifierParams.protocolNextHdr;
|
|
}
|
|
|
|
return new SupplicantStaIfaceHal.QosPolicyRequest(halQosPolicy.policyId,
|
|
halToFrameworkQosPolicyRequestType(halQosPolicy.requestType), halQosPolicy.dscp,
|
|
new SupplicantStaIfaceHal.QosPolicyClassifierParams(
|
|
hasSrcIp, srcIp, hasDstIp, dstIp, srcPort, dstPortRange, protocol));
|
|
}
|
|
|
|
/**
|
|
* Returns connection capabilities of the current network
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return connection capabilities of the current network
|
|
*/
|
|
public WifiNative.ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "getConnectionCapabilities";
|
|
WifiNative.ConnectionCapabilities capOut = new WifiNative.ConnectionCapabilities();
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return capOut;
|
|
}
|
|
try {
|
|
ConnectionCapabilities cap = iface.getConnectionCapabilities();
|
|
capOut.wifiStandard = getWifiStandard(cap.technology);
|
|
capOut.channelBandwidth = getChannelBandwidth(cap.channelBandwidth);
|
|
capOut.is11bMode = (cap.legacyMode == LegacyMode.B_MODE);
|
|
capOut.maxNumberTxSpatialStreams = cap.maxNumberTxSpatialStreams;
|
|
capOut.maxNumberRxSpatialStreams = cap.maxNumberRxSpatialStreams;
|
|
return capOut;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return capOut;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns connection MLO links info
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @return connection MLO links info
|
|
*/
|
|
public WifiNative.ConnectionMloLinksInfo getConnectionMloLinksInfo(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "getConnectionMloLinksInfo";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return null;
|
|
}
|
|
try {
|
|
MloLinksInfo halInfo = iface.getConnectionMloLinksInfo();
|
|
if (halInfo == null) {
|
|
return null;
|
|
}
|
|
|
|
WifiNative.ConnectionMloLinksInfo nativeInfo =
|
|
new WifiNative.ConnectionMloLinksInfo();
|
|
|
|
nativeInfo.links = new WifiNative.ConnectionMloLink[halInfo.links.length];
|
|
|
|
for (int i = 0; i < halInfo.links.length; i++) {
|
|
nativeInfo.links[i].linkId = halInfo.links[i].linkId;
|
|
nativeInfo.links[i].staMacAddress = MacAddress.fromBytes(
|
|
halInfo.links[i].staLinkMacAddress);
|
|
}
|
|
return nativeInfo;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
} catch (IllegalArgumentException e) {
|
|
Log.e(TAG, "Invalid STA Mac Address received from HAL");
|
|
return null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a DPP peer URI to the URI list.
|
|
*
|
|
* Returns an ID to be used later to refer to this URI (>0).
|
|
* On error, -1 is returned.
|
|
*/
|
|
public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "addDppPeerUri";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return -1;
|
|
}
|
|
try {
|
|
return iface.addDppPeerUri(uri);
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes a DPP URI to the URI list given an ID.
|
|
*
|
|
* Returns true when operation is successful
|
|
* On error, false is returned.
|
|
*/
|
|
public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "removeDppUri";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.removeDppUri(bootstrapId);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stops/aborts DPP Initiator request
|
|
*
|
|
* Returns true when operation is successful
|
|
* On error, false is returned.
|
|
*/
|
|
public boolean stopDppInitiator(@NonNull String ifaceName) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "stopDppInitiator";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.stopDppInitiator();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Starts DPP Configurator-Initiator request
|
|
*
|
|
* Returns true when operation is successful
|
|
* On error, false is returned.
|
|
*/
|
|
public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId,
|
|
int ownBootstrapId, @NonNull String ssid, String password, String psk,
|
|
int netRole, int securityAkm, byte[] privEcKey) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "startDppConfiguratorInitiator";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
byte[] key = iface.startDppConfiguratorInitiator(peerBootstrapId, ownBootstrapId,
|
|
ssid, password != null ? password : "", psk != null ? psk : "",
|
|
frameworkToAidlDppNetRole(netRole), frameworkToAidlDppAkm(securityAkm),
|
|
privEcKey != null ? privEcKey : new byte[] {});
|
|
if (key != null && key.length > 0 && mDppCallback != null) {
|
|
mDppCallback.onDppConfiguratorKeyUpdate(key);
|
|
}
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Starts DPP Enrollee-Initiator request
|
|
*
|
|
* Returns true when operation is successful
|
|
* On error, false is returned.
|
|
*/
|
|
public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId,
|
|
int ownBootstrapId) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "startDppEnrolleeInitiator";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.startDppEnrolleeInitiator(peerBootstrapId, ownBootstrapId);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate a DPP QR code based boot strap info
|
|
*
|
|
* Returns DppResponderBootstrapInfo;
|
|
*/
|
|
public WifiNative.DppBootstrapQrCodeInfo generateDppBootstrapInfoForResponder(
|
|
@NonNull String ifaceName, String macAddress, @NonNull String deviceInfo,
|
|
int dppCurve) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "generateDppBootstrapInfoForResponder";
|
|
WifiNative.DppBootstrapQrCodeInfo bootstrapInfoOut =
|
|
new WifiNative.DppBootstrapQrCodeInfo();
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return bootstrapInfoOut;
|
|
}
|
|
try {
|
|
DppResponderBootstrapInfo info = iface.generateDppBootstrapInfoForResponder(
|
|
NativeUtil.macAddressToByteArray(macAddress), deviceInfo,
|
|
frameworkToAidlDppCurve(dppCurve));
|
|
bootstrapInfoOut.bootstrapId = info.bootstrapId;
|
|
bootstrapInfoOut.listenChannel = info.listenChannel;
|
|
bootstrapInfoOut.uri = info.uri;
|
|
return bootstrapInfoOut;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return bootstrapInfoOut;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Starts DPP Enrollee-Responder request
|
|
*
|
|
* Returns true when operation is successful
|
|
* On error, false is returned.
|
|
*/
|
|
public boolean startDppEnrolleeResponder(@NonNull String ifaceName, int listenChannel) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "startDppEnrolleeResponder";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.startDppEnrolleeResponder(listenChannel);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stops/aborts DPP Responder request.
|
|
*
|
|
* Returns true when operation is successful
|
|
* On error, false is returned.
|
|
*/
|
|
public boolean stopDppResponder(@NonNull String ifaceName, int ownBootstrapId) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "stopDppResponder";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.stopDppResponder(ownBootstrapId);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register callbacks for DPP events.
|
|
*
|
|
* @param dppCallback DPP callback object.
|
|
*/
|
|
public void registerDppCallback(WifiNative.DppEventCallback dppCallback) {
|
|
synchronized (mLock) {
|
|
mDppCallback = dppCallback;
|
|
}
|
|
}
|
|
|
|
protected WifiNative.DppEventCallback getDppCallback() {
|
|
synchronized (mLock) {
|
|
return mDppCallback;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set MBO cellular data availability.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param available true means cellular data available, false otherwise.
|
|
* @return true is operation is successful, false otherwise.
|
|
*/
|
|
public boolean setMboCellularDataStatus(@NonNull String ifaceName, boolean available) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "setMboCellularDataStatus";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setMboCellularDataStatus(available);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set whether the network-centric QoS policy feature is enabled or not for this interface.
|
|
*
|
|
* @param ifaceName name of the interface.
|
|
* @param isEnabled true if feature is enabled, false otherwise.
|
|
* @return true if operation is successful, false otherwise.
|
|
*/
|
|
public boolean setNetworkCentricQosPolicyFeatureEnabled(@NonNull String ifaceName,
|
|
boolean isEnabled) {
|
|
synchronized (mLock) {
|
|
String methodStr = "setNetworkCentricQosPolicyFeatureEnabled";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.setQosPolicyFeatureEnabled(isEnabled);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if we've roamed to a linked network and make the linked network the current network
|
|
* if we have.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param newNetworkId Network id of the new network we've roamed to. If fromFramework is
|
|
* {@code true}, this will be a framework network id. Otherwise, this will
|
|
* be a remote network id.
|
|
* @param fromFramework {@code true} if the network id is a framework network id, {@code false}
|
|
if the network id is a remote network id.
|
|
* @return true if we've roamed to a linked network, false if not.
|
|
*/
|
|
public boolean updateOnLinkedNetworkRoaming(
|
|
@NonNull String ifaceName, int newNetworkId, boolean fromFramework) {
|
|
synchronized (mLock) {
|
|
List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>> linkedNetworkHandles =
|
|
mLinkedNetworkLocalAndRemoteConfigs.get(ifaceName);
|
|
SupplicantStaNetworkHalAidlImpl currentHandle =
|
|
getCurrentNetworkRemoteHandle(ifaceName);
|
|
WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
|
|
if (linkedNetworkHandles == null || currentHandle == null || currentConfig == null) {
|
|
return false;
|
|
}
|
|
if (fromFramework ? currentConfig.networkId == newNetworkId
|
|
: currentHandle.getNetworkId() == newNetworkId) {
|
|
return false;
|
|
}
|
|
for (Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair
|
|
: linkedNetworkHandles) {
|
|
if (fromFramework ? pair.second.networkId == newNetworkId
|
|
: pair.first.getNetworkId() == newNetworkId) {
|
|
Log.i(TAG, "Roamed to linked network, make linked network as current network");
|
|
mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
|
|
mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the linked networks for the current network and sends them to the supplicant.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param networkId Network id of the network to link the configurations to.
|
|
* @param linkedConfigurations Map of config profile key to config for linking.
|
|
* @return true if networks were successfully linked, false otherwise.
|
|
*/
|
|
public boolean updateLinkedNetworks(@NonNull String ifaceName, int networkId,
|
|
Map<String, WifiConfiguration> linkedConfigurations) {
|
|
synchronized (mLock) {
|
|
WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
|
|
SupplicantStaNetworkHalAidlImpl currentHandle =
|
|
getCurrentNetworkRemoteHandle(ifaceName);
|
|
|
|
if (currentConfig == null || currentHandle == null) {
|
|
Log.e(TAG, "current network not configured yet.");
|
|
return false;
|
|
}
|
|
|
|
if (networkId != currentConfig.networkId) {
|
|
Log.e(TAG, "current config network id is not matching");
|
|
return false;
|
|
}
|
|
|
|
final int remoteNetworkId = currentHandle.getNetworkId();
|
|
if (remoteNetworkId == -1) {
|
|
Log.e(TAG, "current handle getNetworkId failed");
|
|
return false;
|
|
}
|
|
|
|
if (!removeAllNetworksExcept(ifaceName, remoteNetworkId)) {
|
|
Log.e(TAG, "couldn't remove non-current supplicant networks");
|
|
return false;
|
|
}
|
|
|
|
mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
|
|
|
|
if (linkedConfigurations == null || linkedConfigurations.size() == 0) {
|
|
Log.i(TAG, "cleared linked networks");
|
|
return true;
|
|
}
|
|
|
|
List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>> linkedNetworkHandles =
|
|
new ArrayList<>();
|
|
linkedNetworkHandles.add(new Pair(currentHandle, currentConfig));
|
|
for (String linkedNetwork : linkedConfigurations.keySet()) {
|
|
Log.i(TAG, "add linked network: " + linkedNetwork);
|
|
Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair =
|
|
addNetworkAndSaveConfig(ifaceName, linkedConfigurations.get(linkedNetwork));
|
|
if (pair == null) {
|
|
Log.e(TAG, "failed to add/save linked network: " + linkedNetwork);
|
|
return false;
|
|
}
|
|
pair.first.enable(true);
|
|
linkedNetworkHandles.add(pair);
|
|
}
|
|
|
|
mLinkedNetworkLocalAndRemoteConfigs.put(ifaceName, linkedNetworkHandles);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove all networks except the supplied network ID from supplicant
|
|
*
|
|
* @param ifaceName Name of the interface
|
|
* @param networkId network id to keep
|
|
*/
|
|
private boolean removeAllNetworksExcept(@NonNull String ifaceName, int networkId) {
|
|
synchronized (mLock) {
|
|
int[] networks = listNetworks(ifaceName);
|
|
if (networks == null) {
|
|
Log.e(TAG, "removeAllNetworksExcept failed, got null networks");
|
|
return false;
|
|
}
|
|
for (int id : networks) {
|
|
if (networkId == id) {
|
|
continue;
|
|
}
|
|
if (!removeNetwork(ifaceName, id)) {
|
|
Log.e(TAG, "removeAllNetworksExcept failed to remove network: " + id);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the security params of the current network associated with this interface
|
|
*
|
|
* @param ifaceName Name of the interface
|
|
* @return Security params of the current network associated with the interface
|
|
*/
|
|
public SecurityParams getCurrentNetworkSecurityParams(@NonNull String ifaceName) {
|
|
WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
|
|
|
|
if (currentConfig == null) {
|
|
return null;
|
|
}
|
|
|
|
return currentConfig.getNetworkSelectionStatus().getCandidateSecurityParams();
|
|
}
|
|
|
|
/**
|
|
* Sends a QoS policy response.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param qosPolicyRequestId Dialog token to identify the request.
|
|
* @param morePolicies Flag to indicate more QoS policies can be accommodated.
|
|
* @param qosPolicyStatusList List of framework QosPolicyStatus objects.
|
|
* @return true if response is sent successfully, false otherwise.
|
|
*/
|
|
public boolean sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId,
|
|
boolean morePolicies,
|
|
@NonNull List<SupplicantStaIfaceHal.QosPolicyStatus> qosPolicyStatusList) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "sendQosPolicyResponse";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
|
|
int index = 0;
|
|
QosPolicyStatus[] halPolicyStatusList = new QosPolicyStatus[qosPolicyStatusList.size()];
|
|
for (SupplicantStaIfaceHal.QosPolicyStatus frameworkPolicyStatus
|
|
: qosPolicyStatusList) {
|
|
if (frameworkPolicyStatus == null) {
|
|
return false;
|
|
}
|
|
QosPolicyStatus halPolicyStatus = new QosPolicyStatus();
|
|
halPolicyStatus.policyId = (byte) frameworkPolicyStatus.policyId;
|
|
halPolicyStatus.status = dscpPolicyToAidlQosPolicyStatusCode(
|
|
frameworkPolicyStatus.dscpPolicyStatus);
|
|
halPolicyStatusList[index] = halPolicyStatus;
|
|
index++;
|
|
}
|
|
|
|
try {
|
|
iface.sendQosPolicyResponse(qosPolicyRequestId, morePolicies, halPolicyStatusList);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates the removal of all active QoS policies configured by the AP.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
*/
|
|
public boolean removeAllQosPolicies(String ifaceName) {
|
|
final String methodStr = "removeAllQosPolicies";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
iface.removeAllQosPolicies();
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Generate DPP credential for network access
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param ssid ssid of the network
|
|
* @param privEcKey Private EC Key for DPP Configurator
|
|
* Returns true when operation is successful. On error, false is returned.
|
|
*/
|
|
public boolean generateSelfDppConfiguration(@NonNull String ifaceName, @NonNull String ssid,
|
|
byte[] privEcKey) {
|
|
synchronized (mLock) {
|
|
final String methodStr = "generateSelfDppConfiguration";
|
|
ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
|
|
if (iface == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
iface.generateSelfDppConfiguration(
|
|
NativeUtil.removeEnclosingQuotes(ssid), privEcKey);
|
|
return true;
|
|
} catch (RemoteException e) {
|
|
handleRemoteException(e, methodStr);
|
|
} catch (ServiceSpecificException e) {
|
|
handleServiceSpecificException(e, methodStr);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the currently configured network's anonymous identity.
|
|
*
|
|
* @param ifaceName Name of the interface.
|
|
* @param anonymousIdentity the anonymouns identity.
|
|
* @return true if succeeds, false otherwise.
|
|
*/
|
|
public boolean setEapAnonymousIdentity(@NonNull String ifaceName, String anonymousIdentity) {
|
|
synchronized (mLock) {
|
|
SupplicantStaNetworkHalAidlImpl networkHandle =
|
|
checkStaNetworkAndLogFailure(ifaceName, "setEapAnonymousIdentity");
|
|
if (networkHandle == null) return false;
|
|
if (anonymousIdentity == null) return false;
|
|
return networkHandle.setEapAnonymousIdentity(anonymousIdentity.getBytes());
|
|
}
|
|
}
|
|
}
|