1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.wifi; 17 18 import static android.net.wifi.WifiManager.WIFI_FEATURE_DECORATED_IDENTITY; 19 import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP; 20 import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP_ENROLLEE_RESPONDER; 21 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA256; 22 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA384; 23 import static android.net.wifi.WifiManager.WIFI_FEATURE_MBO; 24 import static android.net.wifi.WifiManager.WIFI_FEATURE_OCE; 25 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE; 26 import static android.net.wifi.WifiManager.WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS; 27 import static android.net.wifi.WifiManager.WIFI_FEATURE_SAE_PK; 28 import static android.net.wifi.WifiManager.WIFI_FEATURE_WAPI; 29 import static android.net.wifi.WifiManager.WIFI_FEATURE_WFD_R2; 30 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE; 31 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B; 32 33 import android.annotation.NonNull; 34 import android.content.Context; 35 import android.hardware.wifi.V1_0.WifiChannelWidthInMhz; 36 import android.hardware.wifi.supplicant.V1_0.ISupplicant; 37 import android.hardware.wifi.supplicant.V1_0.ISupplicantIface; 38 import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork; 39 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface; 40 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback; 41 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork; 42 import android.hardware.wifi.supplicant.V1_0.IfaceType; 43 import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; 44 import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; 45 import android.hardware.wifi.supplicant.V1_0.WpsConfigMethods; 46 import android.hardware.wifi.supplicant.V1_2.DppAkm; 47 import android.hardware.wifi.supplicant.V1_2.DppNetRole; 48 import android.hardware.wifi.supplicant.V1_3.ConnectionCapabilities; 49 import android.hardware.wifi.supplicant.V1_3.WifiTechnology; 50 import android.hardware.wifi.supplicant.V1_3.WpaDriverCapabilitiesMask; 51 import android.hardware.wifi.supplicant.V1_4.DppCurve; 52 import android.hardware.wifi.supplicant.V1_4.LegacyMode; 53 import android.hidl.manager.V1_0.IServiceManager; 54 import android.hidl.manager.V1_0.IServiceNotification; 55 import android.net.MacAddress; 56 import android.net.wifi.ScanResult; 57 import android.net.wifi.SecurityParams; 58 import android.net.wifi.WifiAnnotations.WifiStandard; 59 import android.net.wifi.WifiConfiguration; 60 import android.net.wifi.WifiSsid; 61 import android.os.Handler; 62 import android.os.IHwBinder.DeathRecipient; 63 import android.os.RemoteException; 64 import android.text.TextUtils; 65 import android.util.Log; 66 import android.util.Pair; 67 68 import com.android.internal.annotations.VisibleForTesting; 69 import com.android.server.wifi.WifiNative.DppEventCallback; 70 import com.android.server.wifi.WifiNative.SupplicantDeathEventHandler; 71 import com.android.server.wifi.util.GeneralUtil.Mutable; 72 import com.android.server.wifi.util.NativeUtil; 73 74 import java.nio.ByteBuffer; 75 import java.nio.ByteOrder; 76 import java.util.ArrayList; 77 import java.util.BitSet; 78 import java.util.HashMap; 79 import java.util.List; 80 import java.util.Map; 81 import java.util.NoSuchElementException; 82 import java.util.Objects; 83 import java.util.concurrent.CountDownLatch; 84 import java.util.concurrent.TimeUnit; 85 import java.util.regex.Matcher; 86 import java.util.regex.Pattern; 87 88 import javax.annotation.concurrent.ThreadSafe; 89 90 /** 91 * Hal calls for bring up/shut down of the supplicant daemon and for 92 * sending requests to the supplicant daemon 93 * To maintain thread-safety, the locking protocol is that every non-static method (regardless of 94 * access level) acquires mLock. 95 */ 96 @ThreadSafe 97 public class SupplicantStaIfaceHalHidlImpl implements ISupplicantStaIfaceHal { 98 private static final String TAG = "SupplicantStaIfaceHalHidlImpl"; 99 @VisibleForTesting 100 public static final String HAL_INSTANCE_NAME = "default"; 101 @VisibleForTesting 102 public static final long WAIT_FOR_DEATH_TIMEOUT_MS = 50L; 103 private static final long INVALID_CONNECT_TO_NETWORK_TIMESTAMP = -1L; 104 @VisibleForTesting 105 public static final long IGNORE_NETWORK_NOT_FOUND_DURATION_MS = 1000L; 106 /** 107 * Regex pattern for extracting the wps device type bytes. 108 * Matches a strings like the following: "<categ>-<OUI>-<subcateg>"; 109 */ 110 private static final Pattern WPS_DEVICE_TYPE_PATTERN = 111 Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$"); 112 113 private final Object mLock = new Object(); 114 private boolean mVerboseLoggingEnabled = false; 115 private boolean mVerboseHalLoggingEnabled = false; 116 117 // Supplicant HAL interface objects 118 private IServiceManager mIServiceManager = null; 119 private ISupplicant mISupplicant; 120 private Map<String, ISupplicantStaIface> mISupplicantStaIfaces = new HashMap<>(); 121 private Map<String, ISupplicantStaIfaceCallback> mISupplicantStaIfaceCallbacks = 122 new HashMap<>(); 123 private Map<String, SupplicantStaNetworkHalHidlImpl> mCurrentNetworkRemoteHandles = 124 new HashMap<>(); 125 private Map<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>(); 126 private Map<String, Long> mCurrentNetworkConnectTimestamp = new HashMap<>(); 127 private Map<String, List<WifiSsid>> mCurrentNetworkFallbackSsids = new HashMap<>(); 128 private Map<String, Integer> mCurrentNetworkFallbackSsidIndex = new HashMap<>(); 129 private Map<String, List<Pair<SupplicantStaNetworkHalHidlImpl, WifiConfiguration>>> 130 mLinkedNetworkLocalAndRemoteConfigs = new HashMap<>(); 131 @VisibleForTesting 132 PmkCacheManager mPmkCacheManager; 133 private SupplicantDeathEventHandler mDeathEventHandler; 134 private ServiceManagerDeathRecipient mServiceManagerDeathRecipient; 135 private SupplicantDeathRecipient mSupplicantDeathRecipient; 136 // Death recipient cookie registered for current supplicant instance. 137 private long mDeathRecipientCookie = 0; 138 private CountDownLatch mWaitForDeathLatch; 139 private final Context mContext; 140 private final WifiMonitor mWifiMonitor; 141 private final FrameworkFacade mFrameworkFacade; 142 private final Handler mEventHandler; 143 private DppEventCallback mDppCallback = null; 144 private final Clock mClock; 145 private final WifiMetrics mWifiMetrics; 146 private final WifiGlobals mWifiGlobals; 147 private final @NonNull SsidTranslator mSsidTranslator; 148 149 private final IServiceNotification mServiceNotificationCallback = 150 new IServiceNotification.Stub() { 151 public void onRegistration(String fqName, String name, boolean preexisting) { 152 synchronized (mLock) { 153 if (mVerboseLoggingEnabled) { 154 Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName 155 + ", " + name + " preexisting=" + preexisting); 156 } 157 if (mISupplicant == null) { 158 Log.e(TAG, "ISupplicant interface is null!"); 159 return; 160 } 161 if (!linkToSupplicantDeath(mSupplicantDeathRecipient, 162 ++mDeathRecipientCookie)) { 163 Log.e(TAG, "Registering ISupplicant death recipient failed."); 164 return; 165 } 166 Log.i(TAG, "Completed service registration of ISupplicant."); 167 } 168 } 169 }; 170 private class ServiceManagerDeathRecipient implements DeathRecipient { 171 @Override serviceDied(long cookie)172 public void serviceDied(long cookie) { 173 mEventHandler.post(() -> { 174 synchronized (mLock) { 175 Log.w(TAG, "IServiceManager died: cookie=" + cookie); 176 supplicantServiceDiedHandler(mDeathRecipientCookie); 177 mIServiceManager = null; // Will need to register a new ServiceNotification 178 } 179 }); 180 } 181 } 182 private class SupplicantDeathRecipient implements DeathRecipient { 183 @Override serviceDied(long cookie)184 public void serviceDied(long cookie) { 185 synchronized (mLock) { 186 if (mWaitForDeathLatch != null) { 187 mWaitForDeathLatch.countDown(); 188 } 189 } 190 191 mEventHandler.post(() -> { 192 synchronized (mLock) { 193 Log.w(TAG, "ISupplicant died: cookie=" + cookie); 194 supplicantServiceDiedHandler(cookie); 195 } 196 }); 197 } 198 } 199 SupplicantStaIfaceHalHidlImpl(Context context, WifiMonitor monitor, FrameworkFacade frameworkFacade, Handler handler, Clock clock, WifiMetrics wifiMetrics, WifiGlobals wifiGlobals, @NonNull SsidTranslator ssidTranslator)200 public SupplicantStaIfaceHalHidlImpl(Context context, WifiMonitor monitor, 201 FrameworkFacade frameworkFacade, Handler handler, 202 Clock clock, WifiMetrics wifiMetrics, 203 WifiGlobals wifiGlobals, 204 @NonNull SsidTranslator ssidTranslator) { 205 mContext = context; 206 mWifiMonitor = monitor; 207 mFrameworkFacade = frameworkFacade; 208 mEventHandler = handler; 209 mClock = clock; 210 mWifiMetrics = wifiMetrics; 211 mWifiGlobals = wifiGlobals; 212 mSsidTranslator = ssidTranslator; 213 214 mServiceManagerDeathRecipient = new ServiceManagerDeathRecipient(); 215 mSupplicantDeathRecipient = new SupplicantDeathRecipient(); 216 mPmkCacheManager = new PmkCacheManager(mClock, mEventHandler); 217 } 218 219 /** 220 * Enable/Disable verbose logging. 221 */ enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)222 public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) { 223 synchronized (mLock) { 224 mVerboseLoggingEnabled = verboseEnabled; 225 mVerboseHalLoggingEnabled = halVerboseEnabled; 226 setLogLevel(mVerboseHalLoggingEnabled); 227 } 228 } 229 isVerboseLoggingEnabled()230 protected boolean isVerboseLoggingEnabled() { 231 return mVerboseLoggingEnabled; 232 } 233 linkToServiceManagerDeath()234 private boolean linkToServiceManagerDeath() { 235 synchronized (mLock) { 236 if (mIServiceManager == null) return false; 237 try { 238 if (!mIServiceManager.linkToDeath(mServiceManagerDeathRecipient, 0)) { 239 Log.wtf(TAG, "Error on linkToDeath on IServiceManager"); 240 supplicantServiceDiedHandler(mDeathRecipientCookie); 241 mIServiceManager = null; // Will need to register a new ServiceNotification 242 return false; 243 } 244 } catch (RemoteException e) { 245 Log.e(TAG, "IServiceManager.linkToDeath exception", e); 246 return false; 247 } 248 return true; 249 } 250 } 251 252 /** 253 * Registers a service notification for the ISupplicant service, which triggers initialization 254 * of the ISupplicantStaIface 255 * @return true if the service notification was successfully registered 256 */ initialize()257 public boolean initialize() { 258 synchronized (mLock) { 259 if (mVerboseLoggingEnabled) { 260 Log.i(TAG, "Registering ISupplicant service ready callback."); 261 } 262 mISupplicant = null; 263 mISupplicantStaIfaces.clear(); 264 if (mIServiceManager != null) { 265 // Already have an IServiceManager and serviceNotification registered, don't 266 // don't register another. 267 return true; 268 } 269 try { 270 mIServiceManager = getServiceManagerMockable(); 271 if (mIServiceManager == null) { 272 Log.e(TAG, "Failed to get HIDL Service Manager"); 273 return false; 274 } 275 if (!linkToServiceManagerDeath()) { 276 return false; 277 } 278 /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it 279 exists */ 280 if (!mIServiceManager.registerForNotifications( 281 ISupplicant.kInterfaceName, "", mServiceNotificationCallback)) { 282 Log.e(TAG, "Failed to register for notifications to " 283 + ISupplicant.kInterfaceName); 284 mIServiceManager = null; // Will need to register a new ServiceNotification 285 return false; 286 } 287 } catch (RemoteException e) { 288 Log.e(TAG, "Exception while trying to register a listener for " 289 + "ISupplicant service: " + e); 290 supplicantServiceDiedHandler(mDeathRecipientCookie); 291 } 292 return true; 293 } 294 } 295 linkToSupplicantDeath( DeathRecipient deathRecipient, long cookie)296 private boolean linkToSupplicantDeath( 297 DeathRecipient deathRecipient, long cookie) { 298 synchronized (mLock) { 299 if (mISupplicant == null) return false; 300 try { 301 if (!mISupplicant.linkToDeath(deathRecipient, cookie)) { 302 Log.wtf(TAG, "Error on linkToDeath on ISupplicant"); 303 supplicantServiceDiedHandler(mDeathRecipientCookie); 304 return false; 305 } 306 } catch (RemoteException e) { 307 Log.e(TAG, "ISupplicant.linkToDeath exception", e); 308 return false; 309 } 310 return true; 311 } 312 } 313 getCurrentNetworkId(@onNull String ifaceName)314 protected int getCurrentNetworkId(@NonNull String ifaceName) { 315 synchronized (mLock) { 316 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 317 if (currentConfig == null) { 318 return WifiConfiguration.INVALID_NETWORK_ID; 319 } 320 return currentConfig.networkId; 321 } 322 } 323 trySetupStaIfaceV1_4(@onNull String ifaceName, @NonNull ISupplicantStaIface iface)324 private boolean trySetupStaIfaceV1_4(@NonNull String ifaceName, 325 @NonNull ISupplicantStaIface iface) throws RemoteException { 326 if (!isV1_4()) return false; 327 328 SupplicantStaIfaceHalCallbackV1_4 callbackV14 = 329 new SupplicantStaIfaceHalCallbackV1_4(ifaceName); 330 if (!registerCallbackV1_4(getStaIfaceMockableV1_4(iface), callbackV14)) { 331 throw new RemoteException("Init StaIface V1_4 failed."); 332 } 333 /* keep this in a store to avoid recycling by garbage collector. */ 334 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV14); 335 return true; 336 } 337 trySetupStaIfaceV1_3(@onNull String ifaceName, @NonNull ISupplicantStaIface iface)338 private boolean trySetupStaIfaceV1_3(@NonNull String ifaceName, 339 @NonNull ISupplicantStaIface iface) throws RemoteException { 340 if (!isV1_3()) return false; 341 342 /* try newer version first. */ 343 if (trySetupStaIfaceV1_4(ifaceName, iface)) { 344 logd("Newer HAL is found, skip V1_3 remaining init flow."); 345 return true; 346 } 347 SupplicantStaIfaceHalCallbackV1_3 callbackV13 = 348 new SupplicantStaIfaceHalCallbackV1_3(ifaceName); 349 if (!registerCallbackV1_3(getStaIfaceMockableV1_3(iface), callbackV13)) { 350 throw new RemoteException("Init StaIface V1_3 failed."); 351 } 352 /* keep this in a store to avoid recycling by garbage collector. */ 353 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV13); 354 return true; 355 } 356 trySetupStaIfaceV1_2(@onNull String ifaceName, @NonNull ISupplicantStaIface iface)357 private boolean trySetupStaIfaceV1_2(@NonNull String ifaceName, 358 @NonNull ISupplicantStaIface iface) throws RemoteException { 359 if (!isV1_2()) return false; 360 361 /* try newer version first. */ 362 if (trySetupStaIfaceV1_3(ifaceName, iface)) { 363 logd("Newer HAL is found, skip V1_2 remaining init flow."); 364 return true; 365 } 366 367 SupplicantStaIfaceHalCallbackV1_2 callbackV12 = 368 new SupplicantStaIfaceHalCallbackV1_2(ifaceName); 369 if (!registerCallbackV1_2(getStaIfaceMockableV1_2(iface), callbackV12)) { 370 throw new RemoteException("Init StaIface V1_2 failed."); 371 } 372 /* keep this in a store to avoid recycling by garbage collector. */ 373 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV12); 374 return true; 375 } 376 trySetupStaIfaceV1_1(@onNull String ifaceName, @NonNull ISupplicantStaIface iface)377 private boolean trySetupStaIfaceV1_1(@NonNull String ifaceName, 378 @NonNull ISupplicantStaIface iface) throws RemoteException { 379 if (!isV1_1()) return false; 380 381 /* try newer version first. */ 382 if (trySetupStaIfaceV1_2(ifaceName, iface)) { 383 logd("Newer HAL is found, skip V1_1 remaining init flow."); 384 return true; 385 } 386 387 SupplicantStaIfaceHalCallbackV1_1 callbackV11 = 388 new SupplicantStaIfaceHalCallbackV1_1(ifaceName); 389 if (!registerCallbackV1_1(getStaIfaceMockableV1_1(iface), callbackV11)) { 390 throw new RemoteException("Init StaIface V1_1 failed."); 391 } 392 /* keep this in a store to avoid recycling by garbage collector. */ 393 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV11); 394 return true; 395 } 396 397 /** 398 * Helper function to set up StaIface with different HAL version. 399 * 400 * This helper function would try newer version recursively. 401 * Once the latest version is found, it would register the callback 402 * of the latest version and skip unnecessary older HAL init flow. 403 * 404 * New version callback will be extended from the older one, as a result, 405 * older callback is always created regardless of the latest version. 406 * 407 * Uprev steps: 408 * 1. add new helper function trySetupStaIfaceV1_Y. 409 * 2. call newly added function in trySetupStaIfaceV1_X (X should be Y-1). 410 */ setupStaIface(@onNull String ifaceName, @NonNull ISupplicantIface ifaceHwBinder)411 private ISupplicantStaIface setupStaIface(@NonNull String ifaceName, 412 @NonNull ISupplicantIface ifaceHwBinder) throws RemoteException { 413 /* Prepare base type for later cast. */ 414 ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder); 415 416 /* try newer version first. */ 417 if (trySetupStaIfaceV1_1(ifaceName, iface)) { 418 logd("Newer HAL is found, skip V1_0 remaining init flow."); 419 return iface; 420 } 421 422 SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName); 423 if (!registerCallback(iface, callback)) { 424 throw new RemoteException("Init StaIface V1_0 failed."); 425 } 426 /* keep this in a store to avoid recycling by garbage collector. */ 427 mISupplicantStaIfaceCallbacks.put(ifaceName, callback); 428 return iface; 429 } 430 431 /** 432 * Setup a STA interface for the specified iface name. 433 * 434 * @param ifaceName Name of the interface. 435 * @return true on success, false otherwise. 436 */ setupIface(@onNull String ifaceName)437 public boolean setupIface(@NonNull String ifaceName) { 438 final String methodStr = "setupIface"; 439 if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) != null) return false; 440 ISupplicantIface ifaceHwBinder; 441 442 if (isV1_1()) { 443 ifaceHwBinder = addIfaceV1_1(ifaceName); 444 } else { 445 ifaceHwBinder = getIfaceV1_0(ifaceName); 446 } 447 if (ifaceHwBinder == null) { 448 Log.e(TAG, "setupIface got null iface"); 449 return false; 450 } 451 452 try { 453 ISupplicantStaIface iface = setupStaIface(ifaceName, ifaceHwBinder); 454 mISupplicantStaIfaces.put(ifaceName, iface); 455 } catch (RemoteException e) { 456 loge("setup StaIface failed: " + e.toString()); 457 return false; 458 } 459 460 return true; 461 } 462 463 /** 464 * Get a STA interface for the specified iface name. 465 * 466 * @param ifaceName Name of the interface. 467 * @return true on success, false otherwise. 468 */ getIfaceV1_0(@onNull String ifaceName)469 private ISupplicantIface getIfaceV1_0(@NonNull String ifaceName) { 470 synchronized (mLock) { 471 if (mISupplicant == null) { 472 return null; 473 } 474 475 /** List all supplicant Ifaces */ 476 final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>(); 477 try { 478 mISupplicant.listInterfaces((SupplicantStatus status, 479 ArrayList<ISupplicant.IfaceInfo> ifaces) -> { 480 if (status.code != SupplicantStatusCode.SUCCESS) { 481 Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code); 482 return; 483 } 484 supplicantIfaces.addAll(ifaces); 485 }); 486 } catch (RemoteException e) { 487 Log.e(TAG, "ISupplicant.listInterfaces exception: " + e); 488 handleRemoteException(e, "listInterfaces"); 489 return null; 490 } 491 if (supplicantIfaces.size() == 0) { 492 Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup."); 493 return null; 494 } 495 Mutable<ISupplicantIface> supplicantIface = new Mutable<>(); 496 for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) { 497 if (ifaceInfo.type == IfaceType.STA 498 && TextUtils.equals(ifaceName, ifaceInfo.name)) { 499 try { 500 mISupplicant.getInterface(ifaceInfo, 501 (SupplicantStatus status, ISupplicantIface iface) -> { 502 if (status.code != SupplicantStatusCode.SUCCESS) { 503 Log.e(TAG, "Fail to get ISupplicantIface " + status.code); 504 return; 505 } 506 supplicantIface.value = iface; 507 }); 508 } catch (RemoteException e) { 509 Log.e(TAG, "ISupplicant.getInterface exception: " + e); 510 handleRemoteException(e, "getInterface"); 511 return null; 512 } 513 break; 514 } 515 } 516 return supplicantIface.value; 517 } 518 } 519 520 /** 521 * Create a STA interface for the specified iface name. 522 * 523 * @param ifaceName Name of the interface. 524 * @return true on success, false otherwise. 525 */ addIfaceV1_1(@onNull String ifaceName)526 private ISupplicantIface addIfaceV1_1(@NonNull String ifaceName) { 527 synchronized (mLock) { 528 ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo(); 529 ifaceInfo.name = ifaceName; 530 ifaceInfo.type = IfaceType.STA; 531 Mutable<ISupplicantIface> supplicantIface = new Mutable<>(); 532 try { 533 getSupplicantMockableV1_1().addInterface(ifaceInfo, 534 (SupplicantStatus status, ISupplicantIface iface) -> { 535 if (status.code != SupplicantStatusCode.SUCCESS 536 && status.code != SupplicantStatusCode.FAILURE_IFACE_EXISTS) { 537 Log.e(TAG, "Failed to create ISupplicantIface " + status.code); 538 return; 539 } 540 supplicantIface.value = iface; 541 }); 542 } catch (RemoteException e) { 543 Log.e(TAG, "ISupplicant.addInterface exception: " + e); 544 handleRemoteException(e, "addInterface"); 545 return null; 546 } catch (NoSuchElementException e) { 547 Log.e(TAG, "ISupplicant.addInterface exception: " + e); 548 handleNoSuchElementException(e, "addInterface"); 549 return null; 550 } catch (IllegalArgumentException e) { 551 handleIllegalArgumentException(e, "addInterface"); 552 Log.e(TAG, "ISupplicant.addInterface exception: " + e); 553 return null; 554 } 555 return supplicantIface.value; 556 } 557 } 558 559 /** 560 * Teardown a STA interface for the specified iface name. 561 * 562 * @param ifaceName Name of the interface. 563 * @return true on success, false otherwise. 564 */ teardownIface(@onNull String ifaceName)565 public boolean teardownIface(@NonNull String ifaceName) { 566 synchronized (mLock) { 567 final String methodStr = "teardownIface"; 568 if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) == null) return false; 569 if (isV1_1()) { 570 if (!removeIfaceV1_1(ifaceName)) { 571 Log.e(TAG, "Failed to remove iface = " + ifaceName); 572 return false; 573 } 574 } 575 if (mISupplicantStaIfaces.remove(ifaceName) == null) { 576 Log.e(TAG, "Trying to teardown unknown interface"); 577 return false; 578 } 579 mISupplicantStaIfaceCallbacks.remove(ifaceName); 580 return true; 581 } 582 } 583 584 /** 585 * Remove a STA interface for the specified iface name. 586 * 587 * @param ifaceName Name of the interface. 588 * @return true on success, false otherwise. 589 */ removeIfaceV1_1(@onNull String ifaceName)590 private boolean removeIfaceV1_1(@NonNull String ifaceName) { 591 synchronized (mLock) { 592 try { 593 ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo(); 594 ifaceInfo.name = ifaceName; 595 ifaceInfo.type = IfaceType.STA; 596 SupplicantStatus status = getSupplicantMockableV1_1().removeInterface(ifaceInfo); 597 if (status.code != SupplicantStatusCode.SUCCESS) { 598 Log.e(TAG, "Failed to remove iface " + status.code); 599 return false; 600 } 601 } catch (RemoteException e) { 602 Log.e(TAG, "ISupplicant.removeInterface exception: " + e); 603 handleRemoteException(e, "removeInterface"); 604 return false; 605 } catch (NoSuchElementException e) { 606 Log.e(TAG, "ISupplicant.removeInterface exception: " + e); 607 handleNoSuchElementException(e, "removeInterface"); 608 return false; 609 } catch (IllegalArgumentException e) { 610 Log.e(TAG, "ISupplicant.removeInterface exception: " + e); 611 handleIllegalArgumentException(e, "removeInterface"); 612 return false; 613 } 614 return true; 615 } 616 } 617 618 /** 619 * Registers a death notification for supplicant. 620 * @return Returns true on success. 621 */ registerDeathHandler(@onNull SupplicantDeathEventHandler handler)622 public boolean registerDeathHandler(@NonNull SupplicantDeathEventHandler handler) { 623 if (mDeathEventHandler != null) { 624 Log.e(TAG, "Death handler already present"); 625 } 626 mDeathEventHandler = handler; 627 return true; 628 } 629 630 /** 631 * Deregisters a death notification for supplicant. 632 * @return Returns true on success. 633 */ deregisterDeathHandler()634 public boolean deregisterDeathHandler() { 635 if (mDeathEventHandler == null) { 636 Log.e(TAG, "No Death handler present"); 637 } 638 mDeathEventHandler = null; 639 return true; 640 } 641 642 clearState()643 private void clearState() { 644 synchronized (mLock) { 645 mISupplicant = null; 646 mISupplicantStaIfaces.clear(); 647 mCurrentNetworkLocalConfigs.clear(); 648 mCurrentNetworkRemoteHandles.clear(); 649 mLinkedNetworkLocalAndRemoteConfigs.clear(); 650 mCurrentNetworkConnectTimestamp.clear(); 651 mCurrentNetworkFallbackSsidIndex.clear(); 652 mCurrentNetworkFallbackSsids.clear(); 653 } 654 } 655 supplicantServiceDiedHandler(long cookie)656 private void supplicantServiceDiedHandler(long cookie) { 657 synchronized (mLock) { 658 if (mDeathRecipientCookie != cookie) { 659 Log.i(TAG, "Ignoring stale death recipient notification"); 660 return; 661 } 662 Log.i(TAG, "Handling service death"); 663 clearState(); 664 if (mDeathEventHandler != null) { 665 mDeathEventHandler.onDeath(); 666 } 667 } 668 } 669 670 /** 671 * Signals whether Initialization completed successfully. 672 */ isInitializationStarted()673 public boolean isInitializationStarted() { 674 synchronized (mLock) { 675 return mIServiceManager != null; 676 } 677 } 678 679 /** 680 * Signals whether Initialization completed successfully. 681 */ isInitializationComplete()682 public boolean isInitializationComplete() { 683 synchronized (mLock) { 684 return mISupplicant != null; 685 } 686 } 687 688 /** 689 * Start the supplicant daemon. 690 * 691 * @return true on success, false otherwise. 692 */ startDaemon()693 public boolean startDaemon() { 694 synchronized (mLock) { 695 try { 696 if (isV1_1()) { 697 Log.i(TAG, "Starting supplicant using HIDL 1.1"); 698 mISupplicant = getSupplicantMockableV1_1(); 699 } else { 700 Log.i(TAG, "Starting supplicant using init"); 701 if (!mFrameworkFacade.startSupplicant()) { 702 return false; 703 } 704 mISupplicant = getSupplicantMockable(); 705 } 706 setLogLevel(mVerboseHalLoggingEnabled); 707 } catch (RemoteException | NoSuchElementException e) { 708 Log.e(TAG, "Exception while trying to start supplicant: " + e); 709 supplicantServiceDiedHandler(mDeathRecipientCookie); 710 return false; 711 } 712 } 713 return true; 714 } 715 716 /** 717 * Terminate the supplicant daemon for V1_1 service. 718 */ terminate_V1_1()719 private void terminate_V1_1() { 720 synchronized (mLock) { 721 final String methodStr = "terminate"; 722 if (!checkSupplicantAndLogFailure(methodStr)) return; 723 try { 724 getSupplicantMockableV1_1().terminate(); 725 } catch (RemoteException e) { 726 handleRemoteException(e, methodStr); 727 } catch (NoSuchElementException e) { 728 handleNoSuchElementException(e, methodStr); 729 } 730 } 731 } 732 733 /** 734 * Terminate the supplicant daemon & wait for it's death. 735 */ terminate()736 public void terminate() { 737 synchronized (mLock) { 738 mWaitForDeathLatch = new CountDownLatch(1); 739 if (isV1_1()) { 740 Log.i(TAG, "Terminating supplicant using HIDL"); 741 terminate_V1_1(); 742 } else { 743 Log.i(TAG, "Terminating supplicant using init"); 744 mFrameworkFacade.stopSupplicant(); 745 } 746 } 747 748 // Now wait for death listener callback to confirm that it's dead. 749 try { 750 if (!mWaitForDeathLatch.await(WAIT_FOR_DEATH_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 751 Log.w(TAG, "Timed out waiting for confirmation of supplicant death"); 752 } 753 } catch (InterruptedException e) { 754 Log.w(TAG, "Failed to wait for supplicant death"); 755 } 756 } 757 758 /** 759 * Indicates whether the HIDL service is declared. Uses the IServiceManager to check 760 * if the device is running a version >= V1_0 of the HAL from the VINTF for the device. 761 */ serviceDeclared()762 public static boolean serviceDeclared() { 763 try { 764 IServiceManager serviceManager = IServiceManager.getService(); 765 String interfaceName = android.hardware.wifi.supplicant.V1_0.ISupplicant.kInterfaceName; 766 if (serviceManager.getTransport(interfaceName, HAL_INSTANCE_NAME) 767 != IServiceManager.Transport.EMPTY) { 768 return true; 769 } 770 return false; 771 } catch (RemoteException e) { 772 Log.e(TAG, "Unable to check for existence of HIDL service."); 773 return false; 774 } 775 } 776 777 /** 778 * Wrapper functions to access static HAL methods, created to be mockable in unit tests 779 */ getServiceManagerMockable()780 protected IServiceManager getServiceManagerMockable() throws RemoteException { 781 synchronized (mLock) { 782 return IServiceManager.getService(); 783 } 784 } 785 getSupplicantMockable()786 protected ISupplicant getSupplicantMockable() throws RemoteException, NoSuchElementException { 787 synchronized (mLock) { 788 ISupplicant iSupplicant = ISupplicant.getService(true); 789 if (iSupplicant == null) { 790 throw new NoSuchElementException("Cannot get ISupplicant default service."); 791 } 792 return iSupplicant; 793 } 794 } 795 getSupplicantMockableV1_1()796 protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1() 797 throws RemoteException, NoSuchElementException { 798 synchronized (mLock) { 799 android.hardware.wifi.supplicant.V1_1.ISupplicant iSupplicantDerived = 800 android.hardware.wifi.supplicant.V1_1.ISupplicant.castFrom( 801 getSupplicantMockable()); 802 if (iSupplicantDerived == null) { 803 throw new NoSuchElementException("Cannot cast to V1.1 service."); 804 } 805 return iSupplicantDerived; 806 } 807 } 808 getStaIfaceMockable(ISupplicantIface iface)809 protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) { 810 synchronized (mLock) { 811 return ISupplicantStaIface.asInterface(iface.asBinder()); 812 } 813 } 814 815 protected android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface getStaIfaceMockableV1_1(ISupplicantIface iface)816 getStaIfaceMockableV1_1(ISupplicantIface iface) { 817 synchronized (mLock) { 818 return android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface 819 .asInterface(iface.asBinder()); 820 } 821 } 822 823 protected android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface getStaIfaceMockableV1_2(ISupplicantIface iface)824 getStaIfaceMockableV1_2(ISupplicantIface iface) { 825 synchronized (mLock) { 826 return android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface 827 .asInterface(iface.asBinder()); 828 } 829 } 830 831 protected android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface getStaIfaceMockableV1_3(ISupplicantIface iface)832 getStaIfaceMockableV1_3(ISupplicantIface iface) { 833 synchronized (mLock) { 834 return android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface 835 .asInterface(iface.asBinder()); 836 } 837 } 838 839 protected android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface getStaIfaceMockableV1_4(ISupplicantIface iface)840 getStaIfaceMockableV1_4(ISupplicantIface iface) { 841 synchronized (mLock) { 842 return android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface 843 .asInterface(iface.asBinder()); 844 } 845 } 846 847 /** 848 * Uses the IServiceManager to check if the device is running V1_1 of the HAL from the VINTF for 849 * the device. 850 * @return true if supported, false otherwise. 851 */ isV1_1()852 private boolean isV1_1() { 853 return checkHalVersionByInterfaceName( 854 android.hardware.wifi.supplicant.V1_1.ISupplicant.kInterfaceName); 855 } 856 857 /** 858 * Uses the IServiceManager to check if the device is running V1_2 of the HAL from the VINTF for 859 * the device. 860 * @return true if supported, false otherwise. 861 */ isV1_2()862 private boolean isV1_2() { 863 return checkHalVersionByInterfaceName( 864 android.hardware.wifi.supplicant.V1_2.ISupplicant.kInterfaceName); 865 } 866 867 /** 868 * Uses the IServiceManager to check if the device is running V1_3 of the HAL from the VINTF for 869 * the device. 870 * @return true if supported, false otherwise. 871 */ isV1_3()872 private boolean isV1_3() { 873 return checkHalVersionByInterfaceName( 874 android.hardware.wifi.supplicant.V1_3.ISupplicant.kInterfaceName); 875 } 876 877 /** 878 * Uses the IServiceManager to check if the device is running V1_4 of the HAL from the VINTF for 879 * the device. 880 * @return true if supported, false otherwise. 881 */ isV1_4()882 private boolean isV1_4() { 883 return checkHalVersionByInterfaceName( 884 android.hardware.wifi.supplicant.V1_4.ISupplicant.kInterfaceName); 885 } 886 checkHalVersionByInterfaceName(String interfaceName)887 private boolean checkHalVersionByInterfaceName(String interfaceName) { 888 if (interfaceName == null) { 889 return false; 890 } 891 synchronized (mLock) { 892 if (mIServiceManager == null) { 893 Log.e(TAG, "checkHalVersionByInterfaceName: called but " 894 + "mServiceManager is null"); 895 return false; 896 } 897 try { 898 return (mIServiceManager.getTransport( 899 interfaceName, 900 HAL_INSTANCE_NAME) 901 != IServiceManager.Transport.EMPTY); 902 } catch (RemoteException e) { 903 Log.e(TAG, "Exception while operating on IServiceManager: " + e); 904 handleRemoteException(e, "getTransport"); 905 return false; 906 } 907 } 908 } 909 910 /** 911 * Helper method to look up the network object for the specified iface. 912 */ getStaIface(@onNull String ifaceName)913 private ISupplicantStaIface getStaIface(@NonNull String ifaceName) { 914 return mISupplicantStaIfaces.get(ifaceName); 915 } 916 917 /** 918 * Helper method to look up the network object for the specified iface. 919 */ getCurrentNetworkRemoteHandle( @onNull String ifaceName)920 private SupplicantStaNetworkHalHidlImpl getCurrentNetworkRemoteHandle( 921 @NonNull String ifaceName) { 922 return mCurrentNetworkRemoteHandles.get(ifaceName); 923 } 924 925 /** 926 * Helper method to look up the network config for the specified iface. 927 */ getCurrentNetworkLocalConfig(@onNull String ifaceName)928 protected WifiConfiguration getCurrentNetworkLocalConfig(@NonNull String ifaceName) { 929 return mCurrentNetworkLocalConfigs.get(ifaceName); 930 } 931 932 /** 933 * Add a network configuration to wpa_supplicant. 934 * 935 * @param config Config corresponding to the network. 936 * @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects 937 * for the current network. 938 */ 939 private Pair<SupplicantStaNetworkHalHidlImpl, WifiConfiguration> addNetworkAndSaveConfig(@onNull String ifaceName, WifiConfiguration config)940 addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) { 941 synchronized (mLock) { 942 logi("addSupplicantStaNetwork via HIDL"); 943 if (config == null) { 944 loge("Cannot add NULL network!"); 945 return null; 946 } 947 SupplicantStaNetworkHalHidlImpl network = addNetwork(ifaceName); 948 if (network == null) { 949 loge("Failed to add a network!"); 950 return null; 951 } 952 boolean saveSuccess = false; 953 try { 954 saveSuccess = network.saveWifiConfiguration(config); 955 } catch (IllegalArgumentException e) { 956 Log.e(TAG, "Exception while saving config params: " + config, e); 957 } 958 if (!saveSuccess) { 959 loge("Failed to save variables for: " + config.getProfileKey()); 960 if (!removeAllNetworks(ifaceName)) { 961 loge("Failed to remove all networks on failure."); 962 } 963 return null; 964 } 965 return new Pair(network, new WifiConfiguration(config)); 966 } 967 } 968 969 /** 970 * Add the provided network configuration to wpa_supplicant and initiate connection to it. 971 * This method does the following: 972 * 1. If |config| is different to the current supplicant network, removes all supplicant 973 * networks and saves |config|. 974 * 2. Select the new network in wpa_supplicant. 975 * 976 * @param ifaceName Name of the interface. 977 * @param config WifiConfiguration parameters for the provided network. 978 * @return true if it succeeds, false otherwise 979 */ connectToNetwork(@onNull String ifaceName, @NonNull WifiConfiguration config)980 public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) { 981 return connectToNetwork(ifaceName, config, null); 982 } 983 984 /** 985 * Returns whether to ignore the NETWORK_NOT_FOUND event in case it is based on stale cached 986 * scans. 987 * 988 * @param ifaceName Name of the interface. 989 * @return true if we should ignore NETWORK_NOT_FOUND, false otherwise 990 */ shouldIgnoreNetworkNotFound(@onNull String ifaceName)991 public boolean shouldIgnoreNetworkNotFound(@NonNull String ifaceName) { 992 synchronized (mLock) { 993 return mClock.getElapsedSinceBootMillis() 994 - mCurrentNetworkConnectTimestamp.getOrDefault( 995 ifaceName, INVALID_CONNECT_TO_NETWORK_TIMESTAMP) 996 < IGNORE_NETWORK_NOT_FOUND_DURATION_MS; 997 } 998 } 999 1000 /** 1001 * Connects to the next fallback SSID (if any) of the current network upon a network not found 1002 * notification. If all the fallback SSIDs have been tried, return to the first SSID and go 1003 * through the fallbacks again. 1004 * 1005 * @return true if we're connecting to a fallback SSID, false if there are no fallback SSIDs, or 1006 * we've looped back to the first SSID. 1007 */ connectToFallbackSsid(@onNull String ifaceName)1008 public boolean connectToFallbackSsid(@NonNull String ifaceName) { 1009 synchronized (mLock) { 1010 List<WifiSsid> fallbackSsids = mCurrentNetworkFallbackSsids.get(ifaceName); 1011 if (fallbackSsids == null || fallbackSsids.isEmpty()) { 1012 return false; 1013 } 1014 // Select the next fallback ssid. 1015 // Note that the very first SSID we connect to is index 0, so the next SSID (i.e the 1016 // first fallback SSID) will start with index 1. Once the entire list has been tried, 1017 // wrap back to the first SSID at index 0. 1018 int nextIndex = mCurrentNetworkFallbackSsidIndex.getOrDefault(ifaceName, 0) + 1; 1019 if (nextIndex >= fallbackSsids.size()) { 1020 nextIndex = 0; 1021 } 1022 mCurrentNetworkFallbackSsidIndex.put(ifaceName, nextIndex); 1023 WifiSsid nextSsid = fallbackSsids.get(nextIndex); 1024 Log.d(TAG, "connectToFallbackSsid " + nextSsid + " at index " + nextIndex); 1025 connectToNetwork(ifaceName, getCurrentNetworkLocalConfig(ifaceName), nextSsid); 1026 return nextIndex != 0; 1027 } 1028 } 1029 1030 /** 1031 * Add the provided network configuration to wpa_supplicant and initiate connection to it. 1032 * This method does the following: 1033 * 1. If |config| is different to the current supplicant network, removes all supplicant 1034 * networks and saves |config|. 1035 * 2. Selects an SSID from the 2 possible original SSIDs derived from config.SSID to pass to 1036 * wpa_supplicant, and stores the unused one as fallback if the first one is not found. 1037 * 3. Select the new network in wpa_supplicant. 1038 * 1039 * @param ifaceName Name of the interface. 1040 * @param config WifiConfiguration parameters for the provided network. 1041 * @param actualSsid The actual, untranslated SSID to send to supplicant. If this is null, then 1042 * we will connect to either of the 2 possible original SSIDs based on the 1043 * config's network selection BSSID or network selection candidate. If that 1044 * SSID is not found, then we will immediately connect to the other one. 1045 * @return true if it succeeds, false otherwise 1046 */ connectToNetwork(@onNull String ifaceName, @NonNull WifiConfiguration config, WifiSsid actualSsid)1047 private boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config, 1048 WifiSsid actualSsid) { 1049 synchronized (mLock) { 1050 logd("connectToNetwork " + config.getProfileKey()); 1051 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 1052 if (actualSsid == null && WifiConfigurationUtil.isSameNetwork(config, currentConfig)) { 1053 String networkSelectionBSSID = config.getNetworkSelectionStatus() 1054 .getNetworkSelectionBSSID(); 1055 String networkSelectionBSSIDCurrent = 1056 currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID(); 1057 if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) { 1058 logd("Network is already saved, will not trigger remove and add operation."); 1059 } else { 1060 logd("Network is already saved, but need to update BSSID."); 1061 if (!setCurrentNetworkBssid( 1062 ifaceName, 1063 config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) { 1064 loge("Failed to set current network BSSID."); 1065 return false; 1066 } 1067 mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config)); 1068 } 1069 } else { 1070 mCurrentNetworkRemoteHandles.remove(ifaceName); 1071 mCurrentNetworkLocalConfigs.remove(ifaceName); 1072 mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName); 1073 if (!removeAllNetworks(ifaceName)) { 1074 loge("Failed to remove existing networks"); 1075 return false; 1076 } 1077 WifiConfiguration supplicantConfig = new WifiConfiguration(config); 1078 if (actualSsid != null) { 1079 supplicantConfig.SSID = actualSsid.toString(); 1080 } else { 1081 mCurrentNetworkFallbackSsids.remove(ifaceName); 1082 mCurrentNetworkFallbackSsidIndex.remove(ifaceName); 1083 if (config.SSID != null) { 1084 // No actual SSID supplied, so select from the network selection BSSID 1085 // or the latest candidate BSSID. 1086 WifiSsid configSsid = WifiSsid.fromString(config.SSID); 1087 WifiSsid supplicantSsid = mSsidTranslator.getOriginalSsid(config); 1088 if (supplicantSsid != null) { 1089 Log.d(TAG, "Selecting supplicant SSID " + supplicantSsid); 1090 supplicantConfig.SSID = supplicantSsid.toString(); 1091 1092 List<WifiSsid> fallbackSsids = mSsidTranslator 1093 .getAllPossibleOriginalSsids(configSsid); 1094 fallbackSsids.remove(supplicantSsid); 1095 if (!fallbackSsids.isEmpty()) { 1096 // Store the unused SSIDs to fallback on in 1097 // connectToFallbackSsid(String) if the chosen SSID isn't found. 1098 fallbackSsids.add(0, supplicantSsid); 1099 mCurrentNetworkFallbackSsids.put(ifaceName, fallbackSsids); 1100 mCurrentNetworkFallbackSsidIndex.put(ifaceName, 0); 1101 } 1102 } 1103 // Set the actual translation of the original SSID in case the untranslated 1104 // SSID has an ambiguous encoding. 1105 mSsidTranslator.setTranslatedSsidForStaIface(configSsid, ifaceName); 1106 } 1107 } 1108 Pair<SupplicantStaNetworkHalHidlImpl, WifiConfiguration> pair = 1109 addNetworkAndSaveConfig(ifaceName, supplicantConfig); 1110 if (pair == null) { 1111 loge("Failed to add/save network configuration: " + config 1112 .getProfileKey()); 1113 return false; 1114 } 1115 mCurrentNetworkRemoteHandles.put(ifaceName, pair.first); 1116 mCurrentNetworkLocalConfigs.put(ifaceName, pair.second); 1117 } 1118 SupplicantStaNetworkHalHidlImpl networkHandle = 1119 checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork"); 1120 if (networkHandle == null) { 1121 loge("No valid remote network handle for network configuration: " 1122 + config.getProfileKey()); 1123 return false; 1124 } 1125 1126 SecurityParams params = config.getNetworkSelectionStatus() 1127 .getCandidateSecurityParams(); 1128 if (params != null && !params.isSecurityType(WifiConfiguration.SECURITY_TYPE_PSK)) { 1129 List<ArrayList<Byte>> pmkDataList = mPmkCacheManager.get(config.networkId); 1130 if (pmkDataList != null) { 1131 logi("Set PMK cache for config id " + config.networkId); 1132 pmkDataList.forEach(pmkData -> { 1133 if (networkHandle.setPmkCache(pmkData)) { 1134 mWifiMetrics.setConnectionPmkCache(ifaceName, true); 1135 } 1136 }); 1137 } 1138 } 1139 1140 if (!networkHandle.select()) { 1141 loge("Failed to select network configuration: " + config.getProfileKey()); 1142 return false; 1143 } 1144 mCurrentNetworkConnectTimestamp.put(ifaceName, mClock.getElapsedSinceBootMillis()); 1145 return true; 1146 } 1147 } 1148 1149 /** 1150 * Initiates roaming to the already configured network in wpa_supplicant. If the network 1151 * configuration provided does not match the already configured network, then this triggers 1152 * a new connection attempt (instead of roam). 1153 * 1. First check if we're attempting to connect to a linked network, and select the existing 1154 * supplicant network if there is one. 1155 * 2. Set the new bssid for the network in wpa_supplicant. 1156 * 3. Trigger reassociate command to wpa_supplicant. 1157 * 1158 * @param ifaceName Name of the interface. 1159 * @param config WifiConfiguration parameters for the provided network. 1160 * @return {@code true} if it succeeds, {@code false} otherwise 1161 */ roamToNetwork(@onNull String ifaceName, WifiConfiguration config)1162 public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration config) { 1163 synchronized (mLock) { 1164 if (updateOnLinkedNetworkRoaming(ifaceName, config.networkId, true)) { 1165 SupplicantStaNetworkHalHidlImpl networkHandle = 1166 getCurrentNetworkRemoteHandle(ifaceName); 1167 if (networkHandle == null) { 1168 loge("Roaming config matches a linked config, but a linked network handle was" 1169 + " not found."); 1170 return false; 1171 } 1172 return networkHandle.select(); 1173 } 1174 if (getCurrentNetworkId(ifaceName) != config.networkId) { 1175 Log.w(TAG, "Cannot roam to a different network, initiate new connection. " 1176 + "Current network ID: " + getCurrentNetworkId(ifaceName)); 1177 return connectToNetwork(ifaceName, config); 1178 } 1179 String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID(); 1180 logd("roamToNetwork" + config.getProfileKey() + " (bssid " + bssid + ")"); 1181 1182 SupplicantStaNetworkHalHidlImpl networkHandle = 1183 checkSupplicantStaNetworkAndLogFailure(ifaceName, "roamToNetwork"); 1184 if (networkHandle == null || !networkHandle.setBssid(bssid)) { 1185 loge("Failed to set new bssid on network: " + config.getProfileKey()); 1186 return false; 1187 } 1188 if (!reassociate(ifaceName)) { 1189 loge("Failed to trigger reassociate"); 1190 return false; 1191 } 1192 return true; 1193 } 1194 } 1195 1196 /** 1197 * Clean HAL cached data for |networkId| in the framework. 1198 * 1199 * @param networkId network id of the network to be removed from supplicant. 1200 */ removeNetworkCachedData(int networkId)1201 public void removeNetworkCachedData(int networkId) { 1202 synchronized (mLock) { 1203 logd("Remove cached HAL data for config id " + networkId); 1204 removePmkCacheEntry(networkId); 1205 } 1206 } 1207 1208 /** 1209 * Clear HAL cached data if MAC address is changed. 1210 * 1211 * @param networkId network id of the network to be checked. 1212 * @param curMacAddress current MAC address 1213 */ removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress)1214 public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) { 1215 synchronized (mLock) { 1216 mPmkCacheManager.remove(networkId, curMacAddress); 1217 } 1218 } 1219 1220 /** 1221 * Remove all networks from supplicant 1222 * 1223 * @param ifaceName Name of the interface. 1224 */ removeAllNetworks(@onNull String ifaceName)1225 public boolean removeAllNetworks(@NonNull String ifaceName) { 1226 synchronized (mLock) { 1227 ArrayList<Integer> networks = listNetworks(ifaceName); 1228 if (networks == null) { 1229 Log.e(TAG, "removeAllNetworks failed, got null networks"); 1230 return false; 1231 } 1232 for (int id : networks) { 1233 if (!removeNetwork(ifaceName, id)) { 1234 Log.e(TAG, "removeAllNetworks failed to remove network: " + id); 1235 return false; 1236 } 1237 } 1238 // Reset current network info. 1239 mCurrentNetworkRemoteHandles.remove(ifaceName); 1240 mCurrentNetworkLocalConfigs.remove(ifaceName); 1241 mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName); 1242 return true; 1243 } 1244 } 1245 1246 /** 1247 * Disable the current network in supplicant 1248 * 1249 * @param ifaceName Name of the interface. 1250 */ disableCurrentNetwork(@onNull String ifaceName)1251 public boolean disableCurrentNetwork(@NonNull String ifaceName) { 1252 synchronized (mLock) { 1253 SupplicantStaNetworkHalHidlImpl networkHandle = 1254 checkSupplicantStaNetworkAndLogFailure(ifaceName, "disableCurrentNetwork"); 1255 if (networkHandle == null) return false; 1256 Log.d(TAG, "Remove fallback ssids to avoid endless loop"); 1257 mCurrentNetworkFallbackSsids.remove(ifaceName); 1258 mCurrentNetworkFallbackSsidIndex.remove(ifaceName); 1259 return networkHandle.disable(); 1260 } 1261 } 1262 1263 /** 1264 * Set the currently configured network's bssid. 1265 * 1266 * @param ifaceName Name of the interface. 1267 * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX" 1268 * @return true if succeeds, false otherwise. 1269 */ setCurrentNetworkBssid(@onNull String ifaceName, String bssidStr)1270 public boolean setCurrentNetworkBssid(@NonNull String ifaceName, String bssidStr) { 1271 synchronized (mLock) { 1272 SupplicantStaNetworkHalHidlImpl networkHandle = 1273 checkSupplicantStaNetworkAndLogFailure(ifaceName, "setCurrentNetworkBssid"); 1274 if (networkHandle == null) return false; 1275 return networkHandle.setBssid(bssidStr); 1276 } 1277 } 1278 1279 /** 1280 * Get the currently configured network's WPS NFC token. 1281 * 1282 * @param ifaceName Name of the interface. 1283 * @return Hex string corresponding to the WPS NFC token. 1284 */ getCurrentNetworkWpsNfcConfigurationToken(@onNull String ifaceName)1285 public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) { 1286 synchronized (mLock) { 1287 SupplicantStaNetworkHalHidlImpl networkHandle = 1288 checkSupplicantStaNetworkAndLogFailure( 1289 ifaceName, "getCurrentNetworkWpsNfcConfigurationToken"); 1290 if (networkHandle == null) return null; 1291 return networkHandle.getWpsNfcConfigurationToken(); 1292 } 1293 } 1294 1295 /** 1296 * Get the eap anonymous identity for the currently configured network. 1297 * 1298 * @param ifaceName Name of the interface. 1299 * @return anonymous identity string if succeeds, null otherwise. 1300 */ getCurrentNetworkEapAnonymousIdentity(@onNull String ifaceName)1301 public String getCurrentNetworkEapAnonymousIdentity(@NonNull String ifaceName) { 1302 synchronized (mLock) { 1303 SupplicantStaNetworkHalHidlImpl networkHandle = 1304 checkSupplicantStaNetworkAndLogFailure( 1305 ifaceName, "getCurrentNetworkEapAnonymousIdentity"); 1306 if (networkHandle == null) return null; 1307 return networkHandle.fetchEapAnonymousIdentity(); 1308 } 1309 } 1310 1311 /** 1312 * Send the eap identity response for the currently configured network. 1313 * 1314 * @param ifaceName Name of the interface. 1315 * @param identity identity used for EAP-Identity 1316 * @param encryptedIdentity encrypted identity used for EAP-AKA/EAP-SIM 1317 * @return true if succeeds, false otherwise. 1318 */ sendCurrentNetworkEapIdentityResponse( @onNull String ifaceName, @NonNull String identity, String encryptedIdentity)1319 public boolean sendCurrentNetworkEapIdentityResponse( 1320 @NonNull String ifaceName, @NonNull String identity, String encryptedIdentity) { 1321 synchronized (mLock) { 1322 SupplicantStaNetworkHalHidlImpl networkHandle = 1323 checkSupplicantStaNetworkAndLogFailure( 1324 ifaceName, "sendCurrentNetworkEapIdentityResponse"); 1325 if (networkHandle == null) return false; 1326 return networkHandle.sendNetworkEapIdentityResponse(identity, encryptedIdentity); 1327 } 1328 } 1329 1330 /** 1331 * Send the eap sim gsm auth response for the currently configured network. 1332 * 1333 * @param ifaceName Name of the interface. 1334 * @param paramsStr String to send. 1335 * @return true if succeeds, false otherwise. 1336 */ sendCurrentNetworkEapSimGsmAuthResponse( @onNull String ifaceName, String paramsStr)1337 public boolean sendCurrentNetworkEapSimGsmAuthResponse( 1338 @NonNull String ifaceName, String paramsStr) { 1339 synchronized (mLock) { 1340 SupplicantStaNetworkHalHidlImpl networkHandle = 1341 checkSupplicantStaNetworkAndLogFailure( 1342 ifaceName, "sendCurrentNetworkEapSimGsmAuthResponse"); 1343 if (networkHandle == null) return false; 1344 return networkHandle.sendNetworkEapSimGsmAuthResponse(paramsStr); 1345 } 1346 } 1347 1348 /** 1349 * Send the eap sim gsm auth failure for the currently configured network. 1350 * 1351 * @param ifaceName Name of the interface. 1352 * @return true if succeeds, false otherwise. 1353 */ sendCurrentNetworkEapSimGsmAuthFailure(@onNull String ifaceName)1354 public boolean sendCurrentNetworkEapSimGsmAuthFailure(@NonNull String ifaceName) { 1355 synchronized (mLock) { 1356 SupplicantStaNetworkHalHidlImpl networkHandle = 1357 checkSupplicantStaNetworkAndLogFailure( 1358 ifaceName, "sendCurrentNetworkEapSimGsmAuthFailure"); 1359 if (networkHandle == null) return false; 1360 return networkHandle.sendNetworkEapSimGsmAuthFailure(); 1361 } 1362 } 1363 1364 /** 1365 * Send the eap sim umts auth response for the currently configured network. 1366 * 1367 * @param ifaceName Name of the interface. 1368 * @param paramsStr String to send. 1369 * @return true if succeeds, false otherwise. 1370 */ sendCurrentNetworkEapSimUmtsAuthResponse( @onNull String ifaceName, String paramsStr)1371 public boolean sendCurrentNetworkEapSimUmtsAuthResponse( 1372 @NonNull String ifaceName, String paramsStr) { 1373 synchronized (mLock) { 1374 SupplicantStaNetworkHalHidlImpl networkHandle = 1375 checkSupplicantStaNetworkAndLogFailure( 1376 ifaceName, "sendCurrentNetworkEapSimUmtsAuthResponse"); 1377 if (networkHandle == null) return false; 1378 return networkHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr); 1379 } 1380 } 1381 1382 /** 1383 * Send the eap sim umts auts response for the currently configured network. 1384 * 1385 * @param ifaceName Name of the interface. 1386 * @param paramsStr String to send. 1387 * @return true if succeeds, false otherwise. 1388 */ sendCurrentNetworkEapSimUmtsAutsResponse( @onNull String ifaceName, String paramsStr)1389 public boolean sendCurrentNetworkEapSimUmtsAutsResponse( 1390 @NonNull String ifaceName, String paramsStr) { 1391 synchronized (mLock) { 1392 SupplicantStaNetworkHalHidlImpl networkHandle = 1393 checkSupplicantStaNetworkAndLogFailure( 1394 ifaceName, "sendCurrentNetworkEapSimUmtsAutsResponse"); 1395 if (networkHandle == null) return false; 1396 return networkHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr); 1397 } 1398 } 1399 1400 /** 1401 * Send the eap sim umts auth failure for the currently configured network. 1402 * 1403 * @param ifaceName Name of the interface. 1404 * @return true if succeeds, false otherwise. 1405 */ sendCurrentNetworkEapSimUmtsAuthFailure(@onNull String ifaceName)1406 public boolean sendCurrentNetworkEapSimUmtsAuthFailure(@NonNull String ifaceName) { 1407 synchronized (mLock) { 1408 SupplicantStaNetworkHalHidlImpl networkHandle = 1409 checkSupplicantStaNetworkAndLogFailure( 1410 ifaceName, "sendCurrentNetworkEapSimUmtsAuthFailure"); 1411 if (networkHandle == null) return false; 1412 return networkHandle.sendNetworkEapSimUmtsAuthFailure(); 1413 } 1414 } 1415 1416 /** 1417 * Adds a new network. 1418 * 1419 * @return The ISupplicantNetwork object for the new network, or null if the call fails 1420 */ addNetwork(@onNull String ifaceName)1421 private SupplicantStaNetworkHalHidlImpl addNetwork(@NonNull String ifaceName) { 1422 synchronized (mLock) { 1423 final String methodStr = "addNetwork"; 1424 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1425 if (iface == null) return null; 1426 Mutable<ISupplicantNetwork> newNetwork = new Mutable<>(); 1427 try { 1428 iface.addNetwork((SupplicantStatus status, 1429 ISupplicantNetwork network) -> { 1430 if (checkStatusAndLogFailure(status, methodStr)) { 1431 newNetwork.value = network; 1432 } 1433 }); 1434 } catch (RemoteException e) { 1435 handleRemoteException(e, methodStr); 1436 } 1437 if (newNetwork.value != null) { 1438 return getStaNetworkMockable( 1439 ifaceName, 1440 ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder())); 1441 } else { 1442 return null; 1443 } 1444 } 1445 } 1446 1447 /** 1448 * Remove network from supplicant with network Id 1449 * 1450 * @return true if request is sent successfully, false otherwise. 1451 */ removeNetwork(@onNull String ifaceName, int id)1452 private boolean removeNetwork(@NonNull String ifaceName, int id) { 1453 synchronized (mLock) { 1454 final String methodStr = "removeNetwork"; 1455 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1456 if (iface == null) return false; 1457 try { 1458 SupplicantStatus status = iface.removeNetwork(id); 1459 return checkStatusAndLogFailure(status, methodStr); 1460 } catch (RemoteException e) { 1461 handleRemoteException(e, methodStr); 1462 return false; 1463 } 1464 } 1465 } 1466 1467 /** 1468 * Use this to mock the creation of SupplicantStaNetworkHal instance. 1469 * 1470 * @param ifaceName Name of the interface. 1471 * @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL. 1472 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 1473 * the call fails 1474 */ getStaNetworkMockable( @onNull String ifaceName, ISupplicantStaNetwork iSupplicantStaNetwork)1475 protected SupplicantStaNetworkHalHidlImpl getStaNetworkMockable( 1476 @NonNull String ifaceName, ISupplicantStaNetwork iSupplicantStaNetwork) { 1477 synchronized (mLock) { 1478 SupplicantStaNetworkHalHidlImpl network = 1479 new SupplicantStaNetworkHalHidlImpl(iSupplicantStaNetwork, ifaceName, mContext, 1480 mWifiMonitor, mWifiGlobals, 1481 getAdvancedCapabilities(ifaceName)); 1482 if (network != null) { 1483 network.enableVerboseLogging(mVerboseLoggingEnabled, mVerboseHalLoggingEnabled); 1484 } 1485 return network; 1486 } 1487 } 1488 1489 /** 1490 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 1491 * the call fails 1492 */ getNetwork(@onNull String ifaceName, int id)1493 private SupplicantStaNetworkHalHidlImpl getNetwork(@NonNull String ifaceName, int id) { 1494 synchronized (mLock) { 1495 final String methodStr = "getNetwork"; 1496 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1497 if (iface == null) return null; 1498 Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>(); 1499 try { 1500 iface.getNetwork(id, (SupplicantStatus status, ISupplicantNetwork network) -> { 1501 if (checkStatusAndLogFailure(status, methodStr)) { 1502 gotNetwork.value = network; 1503 } 1504 }); 1505 } catch (RemoteException e) { 1506 handleRemoteException(e, methodStr); 1507 } 1508 if (gotNetwork.value != null) { 1509 return getStaNetworkMockable( 1510 ifaceName, 1511 ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder())); 1512 } else { 1513 return null; 1514 } 1515 } 1516 } 1517 1518 /** See ISupplicantStaNetwork.hal for documentation */ registerCallback( ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback)1519 private boolean registerCallback( 1520 ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback) { 1521 synchronized (mLock) { 1522 final String methodStr = "registerCallback"; 1523 if (iface == null) return false; 1524 try { 1525 SupplicantStatus status = iface.registerCallback(callback); 1526 return checkStatusAndLogFailure(status, methodStr); 1527 } catch (RemoteException e) { 1528 handleRemoteException(e, methodStr); 1529 return false; 1530 } 1531 } 1532 } 1533 registerCallbackV1_1( android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface, android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback callback)1534 private boolean registerCallbackV1_1( 1535 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface, 1536 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback callback) { 1537 synchronized (mLock) { 1538 String methodStr = "registerCallback_1_1"; 1539 1540 if (iface == null) return false; 1541 try { 1542 SupplicantStatus status = iface.registerCallback_1_1(callback); 1543 return checkStatusAndLogFailure(status, methodStr); 1544 } catch (RemoteException e) { 1545 handleRemoteException(e, methodStr); 1546 return false; 1547 } 1548 } 1549 } 1550 registerCallbackV1_2( android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface iface, android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback callback)1551 private boolean registerCallbackV1_2( 1552 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface iface, 1553 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback callback) { 1554 synchronized (mLock) { 1555 String methodStr = "registerCallback_1_2"; 1556 1557 if (iface == null) return false; 1558 try { 1559 SupplicantStatus status = iface.registerCallback_1_2(callback); 1560 return checkStatusAndLogFailure(status, methodStr); 1561 } catch (RemoteException e) { 1562 handleRemoteException(e, methodStr); 1563 return false; 1564 } 1565 } 1566 } 1567 registerCallbackV1_3( android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface iface, android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback callback)1568 private boolean registerCallbackV1_3( 1569 android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface iface, 1570 android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback callback) { 1571 synchronized (mLock) { 1572 String methodStr = "registerCallback_1_3"; 1573 1574 if (iface == null) return false; 1575 try { 1576 SupplicantStatus status = iface.registerCallback_1_3(callback); 1577 return checkStatusAndLogFailure(status, methodStr); 1578 } catch (RemoteException e) { 1579 handleRemoteException(e, methodStr); 1580 return false; 1581 } 1582 } 1583 } 1584 registerCallbackV1_4( android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface iface, android.hardware.wifi.supplicant.V1_4.ISupplicantStaIfaceCallback callback)1585 private boolean registerCallbackV1_4( 1586 android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface iface, 1587 android.hardware.wifi.supplicant.V1_4.ISupplicantStaIfaceCallback callback) { 1588 synchronized (mLock) { 1589 String methodStr = "registerCallback_1_4"; 1590 1591 if (iface == null) return false; 1592 try { 1593 android.hardware.wifi.supplicant.V1_4.SupplicantStatus status = 1594 iface.registerCallback_1_4(callback); 1595 return checkStatusAndLogFailure(status, methodStr); 1596 } catch (RemoteException e) { 1597 handleRemoteException(e, methodStr); 1598 return false; 1599 } 1600 } 1601 } 1602 1603 /** 1604 * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns 1605 * null if the call fails 1606 */ listNetworks(@onNull String ifaceName)1607 private java.util.ArrayList<Integer> listNetworks(@NonNull String ifaceName) { 1608 synchronized (mLock) { 1609 final String methodStr = "listNetworks"; 1610 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1611 if (iface == null) return null; 1612 Mutable<ArrayList<Integer>> networkIdList = new Mutable<>(); 1613 try { 1614 iface.listNetworks((SupplicantStatus status, ArrayList<Integer> networkIds) -> { 1615 if (checkStatusAndLogFailure(status, methodStr)) { 1616 networkIdList.value = networkIds; 1617 } 1618 }); 1619 } catch (RemoteException e) { 1620 handleRemoteException(e, methodStr); 1621 } 1622 return networkIdList.value; 1623 } 1624 } 1625 1626 /** 1627 * Set WPS device name. 1628 * 1629 * @param ifaceName Name of the interface. 1630 * @param name String to be set. 1631 * @return true if request is sent successfully, false otherwise. 1632 */ setWpsDeviceName(@onNull String ifaceName, String name)1633 public boolean setWpsDeviceName(@NonNull String ifaceName, String name) { 1634 synchronized (mLock) { 1635 final String methodStr = "setWpsDeviceName"; 1636 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1637 if (iface == null) return false; 1638 try { 1639 SupplicantStatus status = iface.setWpsDeviceName(name); 1640 return checkStatusAndLogFailure(status, methodStr); 1641 } catch (RemoteException e) { 1642 handleRemoteException(e, methodStr); 1643 return false; 1644 } 1645 } 1646 } 1647 1648 /** 1649 * Set WPS device type. 1650 * 1651 * @param ifaceName Name of the interface. 1652 * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg> 1653 * @return true if request is sent successfully, false otherwise. 1654 */ setWpsDeviceType(@onNull String ifaceName, String typeStr)1655 public boolean setWpsDeviceType(@NonNull String ifaceName, String typeStr) { 1656 synchronized (mLock) { 1657 try { 1658 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr); 1659 if (!match.find() || match.groupCount() != 3) { 1660 Log.e(TAG, "Malformed WPS device type " + typeStr); 1661 return false; 1662 } 1663 short categ = Short.parseShort(match.group(1)); 1664 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2)); 1665 short subCateg = Short.parseShort(match.group(3)); 1666 1667 byte[] bytes = new byte[8]; 1668 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); 1669 byteBuffer.putShort(categ); 1670 byteBuffer.put(oui); 1671 byteBuffer.putShort(subCateg); 1672 return setWpsDeviceType(ifaceName, bytes); 1673 } catch (IllegalArgumentException e) { 1674 Log.e(TAG, "Illegal argument " + typeStr, e); 1675 return false; 1676 } 1677 } 1678 } 1679 setWpsDeviceType(@onNull String ifaceName, byte[ ] type)1680 private boolean setWpsDeviceType(@NonNull String ifaceName, byte[/* 8 */] type) { 1681 synchronized (mLock) { 1682 final String methodStr = "setWpsDeviceType"; 1683 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1684 if (iface == null) return false; 1685 try { 1686 SupplicantStatus status = iface.setWpsDeviceType(type); 1687 return checkStatusAndLogFailure(status, methodStr); 1688 } catch (RemoteException e) { 1689 handleRemoteException(e, methodStr); 1690 return false; 1691 } 1692 } 1693 } 1694 1695 /** 1696 * Set WPS manufacturer. 1697 * 1698 * @param ifaceName Name of the interface. 1699 * @param manufacturer String to be set. 1700 * @return true if request is sent successfully, false otherwise. 1701 */ setWpsManufacturer(@onNull String ifaceName, String manufacturer)1702 public boolean setWpsManufacturer(@NonNull String ifaceName, String manufacturer) { 1703 synchronized (mLock) { 1704 final String methodStr = "setWpsManufacturer"; 1705 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1706 if (iface == null) return false; 1707 try { 1708 SupplicantStatus status = iface.setWpsManufacturer(manufacturer); 1709 return checkStatusAndLogFailure(status, methodStr); 1710 } catch (RemoteException e) { 1711 handleRemoteException(e, methodStr); 1712 return false; 1713 } 1714 } 1715 } 1716 1717 /** 1718 * Set WPS model name. 1719 * 1720 * @param ifaceName Name of the interface. 1721 * @param modelName String to be set. 1722 * @return true if request is sent successfully, false otherwise. 1723 */ setWpsModelName(@onNull String ifaceName, String modelName)1724 public boolean setWpsModelName(@NonNull String ifaceName, String modelName) { 1725 synchronized (mLock) { 1726 final String methodStr = "setWpsModelName"; 1727 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1728 if (iface == null) return false; 1729 try { 1730 SupplicantStatus status = iface.setWpsModelName(modelName); 1731 return checkStatusAndLogFailure(status, methodStr); 1732 } catch (RemoteException e) { 1733 handleRemoteException(e, methodStr); 1734 return false; 1735 } 1736 } 1737 } 1738 1739 /** 1740 * Set WPS model number. 1741 * 1742 * @param ifaceName Name of the interface. 1743 * @param modelNumber String to be set. 1744 * @return true if request is sent successfully, false otherwise. 1745 */ setWpsModelNumber(@onNull String ifaceName, String modelNumber)1746 public boolean setWpsModelNumber(@NonNull String ifaceName, String modelNumber) { 1747 synchronized (mLock) { 1748 final String methodStr = "setWpsModelNumber"; 1749 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1750 if (iface == null) return false; 1751 try { 1752 SupplicantStatus status = iface.setWpsModelNumber(modelNumber); 1753 return checkStatusAndLogFailure(status, methodStr); 1754 } catch (RemoteException e) { 1755 handleRemoteException(e, methodStr); 1756 return false; 1757 } 1758 } 1759 } 1760 1761 /** 1762 * Set WPS serial number. 1763 * 1764 * @param ifaceName Name of the interface. 1765 * @param serialNumber String to be set. 1766 * @return true if request is sent successfully, false otherwise. 1767 */ setWpsSerialNumber(@onNull String ifaceName, String serialNumber)1768 public boolean setWpsSerialNumber(@NonNull String ifaceName, String serialNumber) { 1769 synchronized (mLock) { 1770 final String methodStr = "setWpsSerialNumber"; 1771 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1772 if (iface == null) return false; 1773 try { 1774 SupplicantStatus status = iface.setWpsSerialNumber(serialNumber); 1775 return checkStatusAndLogFailure(status, methodStr); 1776 } catch (RemoteException e) { 1777 handleRemoteException(e, methodStr); 1778 return false; 1779 } 1780 } 1781 } 1782 1783 /** 1784 * Set WPS config methods 1785 * 1786 * @param ifaceName Name of the interface. 1787 * @param configMethodsStr List of config methods. 1788 * @return true if request is sent successfully, false otherwise. 1789 */ setWpsConfigMethods(@onNull String ifaceName, String configMethodsStr)1790 public boolean setWpsConfigMethods(@NonNull String ifaceName, String configMethodsStr) { 1791 synchronized (mLock) { 1792 short configMethodsMask = 0; 1793 String[] configMethodsStrArr = configMethodsStr.split("\\s+"); 1794 for (int i = 0; i < configMethodsStrArr.length; i++) { 1795 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]); 1796 } 1797 return setWpsConfigMethods(ifaceName, configMethodsMask); 1798 } 1799 } 1800 setWpsConfigMethods(@onNull String ifaceName, short configMethods)1801 private boolean setWpsConfigMethods(@NonNull String ifaceName, short configMethods) { 1802 synchronized (mLock) { 1803 final String methodStr = "setWpsConfigMethods"; 1804 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1805 if (iface == null) return false; 1806 try { 1807 SupplicantStatus status = iface.setWpsConfigMethods(configMethods); 1808 return checkStatusAndLogFailure(status, methodStr); 1809 } catch (RemoteException e) { 1810 handleRemoteException(e, methodStr); 1811 return false; 1812 } 1813 } 1814 } 1815 1816 /** 1817 * Trigger a reassociation even if the iface is currently connected. 1818 * 1819 * @param ifaceName Name of the interface. 1820 * @return true if request is sent successfully, false otherwise. 1821 */ reassociate(@onNull String ifaceName)1822 public boolean reassociate(@NonNull String ifaceName) { 1823 synchronized (mLock) { 1824 final String methodStr = "reassociate"; 1825 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1826 if (iface == null) return false; 1827 try { 1828 SupplicantStatus status = iface.reassociate(); 1829 return checkStatusAndLogFailure(status, methodStr); 1830 } catch (RemoteException e) { 1831 handleRemoteException(e, methodStr); 1832 return false; 1833 } 1834 } 1835 } 1836 1837 /** 1838 * Trigger a reconnection if the iface is disconnected. 1839 * 1840 * @param ifaceName Name of the interface. 1841 * @return true if request is sent successfully, false otherwise. 1842 */ reconnect(@onNull String ifaceName)1843 public boolean reconnect(@NonNull String ifaceName) { 1844 synchronized (mLock) { 1845 final String methodStr = "reconnect"; 1846 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1847 if (iface == null) return false; 1848 try { 1849 SupplicantStatus status = iface.reconnect(); 1850 return checkStatusAndLogFailure(status, methodStr); 1851 } catch (RemoteException e) { 1852 handleRemoteException(e, methodStr); 1853 return false; 1854 } 1855 } 1856 } 1857 1858 /** 1859 * Trigger a disconnection from the currently connected network. 1860 * 1861 * @param ifaceName Name of the interface. 1862 * @return true if request is sent successfully, false otherwise. 1863 */ disconnect(@onNull String ifaceName)1864 public boolean disconnect(@NonNull String ifaceName) { 1865 synchronized (mLock) { 1866 final String methodStr = "disconnect"; 1867 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1868 if (iface == null) return false; 1869 try { 1870 SupplicantStatus status = iface.disconnect(); 1871 return checkStatusAndLogFailure(status, methodStr); 1872 } catch (RemoteException e) { 1873 handleRemoteException(e, methodStr); 1874 return false; 1875 } 1876 } 1877 } 1878 1879 /** 1880 * Enable or disable power save mode. 1881 * 1882 * @param ifaceName Name of the interface. 1883 * @param enable true to enable, false to disable. 1884 * @return true if request is sent successfully, false otherwise. 1885 */ setPowerSave(@onNull String ifaceName, boolean enable)1886 public boolean setPowerSave(@NonNull String ifaceName, boolean enable) { 1887 synchronized (mLock) { 1888 final String methodStr = "setPowerSave"; 1889 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1890 if (iface == null) return false; 1891 try { 1892 SupplicantStatus status = iface.setPowerSave(enable); 1893 return checkStatusAndLogFailure(status, methodStr); 1894 } catch (RemoteException e) { 1895 handleRemoteException(e, methodStr); 1896 return false; 1897 } 1898 } 1899 } 1900 1901 /** 1902 * Initiate TDLS discover with the specified AP. 1903 * 1904 * @param ifaceName Name of the interface. 1905 * @param macAddress MAC Address of the AP. 1906 * @return true if request is sent successfully, false otherwise. 1907 */ initiateTdlsDiscover(@onNull String ifaceName, String macAddress)1908 public boolean initiateTdlsDiscover(@NonNull String ifaceName, String macAddress) { 1909 synchronized (mLock) { 1910 try { 1911 return initiateTdlsDiscover( 1912 ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1913 } catch (IllegalArgumentException e) { 1914 Log.e(TAG, "Illegal argument " + macAddress, e); 1915 return false; 1916 } 1917 } 1918 } 1919 /** See ISupplicantStaIface.hal for documentation */ initiateTdlsDiscover(@onNull String ifaceName, byte[ ] macAddress)1920 private boolean initiateTdlsDiscover(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1921 synchronized (mLock) { 1922 final String methodStr = "initiateTdlsDiscover"; 1923 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1924 if (iface == null) return false; 1925 try { 1926 SupplicantStatus status = iface.initiateTdlsDiscover(macAddress); 1927 return checkStatusAndLogFailure(status, methodStr); 1928 } catch (RemoteException e) { 1929 handleRemoteException(e, methodStr); 1930 return false; 1931 } 1932 } 1933 } 1934 1935 /** 1936 * Initiate TDLS setup with the specified AP. 1937 * 1938 * @param ifaceName Name of the interface. 1939 * @param macAddress MAC Address of the AP. 1940 * @return true if request is sent successfully, false otherwise. 1941 */ initiateTdlsSetup(@onNull String ifaceName, String macAddress)1942 public boolean initiateTdlsSetup(@NonNull String ifaceName, String macAddress) { 1943 synchronized (mLock) { 1944 try { 1945 return initiateTdlsSetup(ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1946 } catch (IllegalArgumentException e) { 1947 Log.e(TAG, "Illegal argument " + macAddress, e); 1948 return false; 1949 } 1950 } 1951 } 1952 /** See ISupplicantStaIface.hal for documentation */ initiateTdlsSetup(@onNull String ifaceName, byte[ ] macAddress)1953 private boolean initiateTdlsSetup(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1954 synchronized (mLock) { 1955 final String methodStr = "initiateTdlsSetup"; 1956 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1957 if (iface == null) return false; 1958 try { 1959 SupplicantStatus status = iface.initiateTdlsSetup(macAddress); 1960 return checkStatusAndLogFailure(status, methodStr); 1961 } catch (RemoteException e) { 1962 handleRemoteException(e, methodStr); 1963 return false; 1964 } 1965 } 1966 } 1967 1968 /** 1969 * Initiate TDLS teardown with the specified AP. 1970 * @param ifaceName Name of the interface. 1971 * @param macAddress MAC Address of the AP. 1972 * @return true if request is sent successfully, false otherwise. 1973 */ initiateTdlsTeardown(@onNull String ifaceName, String macAddress)1974 public boolean initiateTdlsTeardown(@NonNull String ifaceName, String macAddress) { 1975 synchronized (mLock) { 1976 try { 1977 return initiateTdlsTeardown( 1978 ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1979 } catch (IllegalArgumentException e) { 1980 Log.e(TAG, "Illegal argument " + macAddress, e); 1981 return false; 1982 } 1983 } 1984 } 1985 1986 /** See ISupplicantStaIface.hal for documentation */ initiateTdlsTeardown(@onNull String ifaceName, byte[ ] macAddress)1987 private boolean initiateTdlsTeardown(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1988 synchronized (mLock) { 1989 final String methodStr = "initiateTdlsTeardown"; 1990 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1991 if (iface == null) return false; 1992 try { 1993 SupplicantStatus status = iface.initiateTdlsTeardown(macAddress); 1994 return checkStatusAndLogFailure(status, methodStr); 1995 } catch (RemoteException e) { 1996 handleRemoteException(e, methodStr); 1997 return false; 1998 } 1999 } 2000 } 2001 2002 /** 2003 * Request the specified ANQP elements |elements| from the specified AP |bssid|. 2004 * 2005 * @param ifaceName Name of the interface. 2006 * @param bssid BSSID of the AP 2007 * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId. 2008 * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes. 2009 * @return true if request is sent successfully, false otherwise. 2010 */ initiateAnqpQuery(@onNull String ifaceName, String bssid, ArrayList<Short> infoElements, ArrayList<Integer> hs20SubTypes)2011 public boolean initiateAnqpQuery(@NonNull String ifaceName, String bssid, 2012 ArrayList<Short> infoElements, 2013 ArrayList<Integer> hs20SubTypes) { 2014 synchronized (mLock) { 2015 try { 2016 return initiateAnqpQuery( 2017 ifaceName, 2018 NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes); 2019 } catch (IllegalArgumentException e) { 2020 Log.e(TAG, "Illegal argument " + bssid, e); 2021 return false; 2022 } 2023 } 2024 } 2025 2026 /** See ISupplicantStaIface.hal for documentation */ initiateAnqpQuery(@onNull String ifaceName, byte[ ] macAddress, java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes)2027 private boolean initiateAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress, 2028 java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) { 2029 synchronized (mLock) { 2030 final String methodStr = "initiateAnqpQuery"; 2031 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2032 if (iface == null) return false; 2033 try { 2034 SupplicantStatus status = iface.initiateAnqpQuery( 2035 macAddress, infoElements, subTypes); 2036 return checkStatusAndLogFailure(status, methodStr); 2037 } catch (RemoteException e) { 2038 handleRemoteException(e, methodStr); 2039 return false; 2040 } 2041 } 2042 } 2043 2044 /** 2045 * Request Venue URL ANQP element from the specified AP |bssid|. 2046 * 2047 * @param ifaceName Name of the interface. 2048 * @param bssid BSSID of the AP 2049 * @return true if request is sent successfully, false otherwise. 2050 */ initiateVenueUrlAnqpQuery(@onNull String ifaceName, String bssid)2051 public boolean initiateVenueUrlAnqpQuery(@NonNull String ifaceName, String bssid) { 2052 synchronized (mLock) { 2053 try { 2054 return initiateVenueUrlAnqpQuery( 2055 ifaceName, NativeUtil.macAddressToByteArray(bssid)); 2056 } catch (IllegalArgumentException e) { 2057 Log.e(TAG, "Illegal argument " + bssid, e); 2058 return false; 2059 } 2060 } 2061 } 2062 2063 /** See ISupplicantStaIface.hal for documentation */ initiateVenueUrlAnqpQuery(@onNull String ifaceName, byte[ ] macAddress)2064 private boolean initiateVenueUrlAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 2065 synchronized (mLock) { 2066 final String methodStr = "initiateVenueUrlAnqpQuery"; 2067 if (!isV1_4()) { 2068 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 2069 return false; 2070 } 2071 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2072 if (iface == null) return false; 2073 // Get a v1.4 supplicant STA Interface 2074 android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface staIfaceV14 = 2075 getStaIfaceMockableV1_4(iface); 2076 2077 if (staIfaceV14 == null) { 2078 Log.e(TAG, methodStr 2079 + ": SupplicantStaIface is null, cannot initiate Venue URL ANQP request"); 2080 return false; 2081 } 2082 try { 2083 android.hardware.wifi.supplicant.V1_4.SupplicantStatus status = 2084 staIfaceV14.initiateVenueUrlAnqpQuery(macAddress); 2085 return checkStatusAndLogFailure(status, methodStr); 2086 } catch (RemoteException e) { 2087 handleRemoteException(e, methodStr); 2088 return false; 2089 } 2090 } 2091 } 2092 2093 /** 2094 * Request the specified ANQP ICON from the specified AP |bssid|. 2095 * 2096 * @param ifaceName Name of the interface. 2097 * @param bssid BSSID of the AP 2098 * @param fileName Name of the file to request. 2099 * @return true if request is sent successfully, false otherwise. 2100 */ initiateHs20IconQuery(@onNull String ifaceName, String bssid, String fileName)2101 public boolean initiateHs20IconQuery(@NonNull String ifaceName, String bssid, String fileName) { 2102 synchronized (mLock) { 2103 try { 2104 return initiateHs20IconQuery( 2105 ifaceName, NativeUtil.macAddressToByteArray(bssid), fileName); 2106 } catch (IllegalArgumentException e) { 2107 Log.e(TAG, "Illegal argument " + bssid, e); 2108 return false; 2109 } 2110 } 2111 } 2112 2113 /** See ISupplicantStaIface.hal for documentation */ initiateHs20IconQuery(@onNull String ifaceName, byte[ ] macAddress, String fileName)2114 private boolean initiateHs20IconQuery(@NonNull String ifaceName, 2115 byte[/* 6 */] macAddress, String fileName) { 2116 synchronized (mLock) { 2117 final String methodStr = "initiateHs20IconQuery"; 2118 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2119 if (iface == null) return false; 2120 try { 2121 SupplicantStatus status = iface.initiateHs20IconQuery(macAddress, fileName); 2122 return checkStatusAndLogFailure(status, methodStr); 2123 } catch (RemoteException e) { 2124 handleRemoteException(e, methodStr); 2125 return false; 2126 } 2127 } 2128 } 2129 2130 /** 2131 * Makes a callback to HIDL to getMacAddress from supplicant 2132 * 2133 * @param ifaceName Name of the interface. 2134 * @return string containing the MAC address, or null on a failed call 2135 */ getMacAddress(@onNull String ifaceName)2136 public String getMacAddress(@NonNull String ifaceName) { 2137 synchronized (mLock) { 2138 final String methodStr = "getMacAddress"; 2139 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2140 if (iface == null) return null; 2141 Mutable<String> gotMac = new Mutable<>(); 2142 try { 2143 iface.getMacAddress((SupplicantStatus status, 2144 byte[/* 6 */] macAddr) -> { 2145 if (checkStatusAndLogFailure(status, methodStr)) { 2146 gotMac.value = NativeUtil.macAddressFromByteArray(macAddr); 2147 } 2148 }); 2149 } catch (RemoteException e) { 2150 handleRemoteException(e, methodStr); 2151 } 2152 return gotMac.value; 2153 } 2154 } 2155 2156 /** 2157 * Start using the added RX filters. 2158 * 2159 * @param ifaceName Name of the interface. 2160 * @return true if request is sent successfully, false otherwise. 2161 */ startRxFilter(@onNull String ifaceName)2162 public boolean startRxFilter(@NonNull String ifaceName) { 2163 synchronized (mLock) { 2164 final String methodStr = "startRxFilter"; 2165 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2166 if (iface == null) return false; 2167 try { 2168 SupplicantStatus status = iface.startRxFilter(); 2169 return checkStatusAndLogFailure(status, methodStr); 2170 } catch (RemoteException e) { 2171 handleRemoteException(e, methodStr); 2172 return false; 2173 } 2174 } 2175 } 2176 2177 /** 2178 * Stop using the added RX filters. 2179 * 2180 * @param ifaceName Name of the interface. 2181 * @return true if request is sent successfully, false otherwise. 2182 */ stopRxFilter(@onNull String ifaceName)2183 public boolean stopRxFilter(@NonNull String ifaceName) { 2184 synchronized (mLock) { 2185 final String methodStr = "stopRxFilter"; 2186 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2187 if (iface == null) return false; 2188 try { 2189 SupplicantStatus status = iface.stopRxFilter(); 2190 return checkStatusAndLogFailure(status, methodStr); 2191 } catch (RemoteException e) { 2192 handleRemoteException(e, methodStr); 2193 return false; 2194 } 2195 } 2196 } 2197 2198 /** 2199 * Add an RX filter. 2200 * 2201 * @param ifaceName Name of the interface. 2202 * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST} 2203 * {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values. 2204 * @return true if request is sent successfully, false otherwise. 2205 */ addRxFilter(@onNull String ifaceName, int type)2206 public boolean addRxFilter(@NonNull String ifaceName, int type) { 2207 synchronized (mLock) { 2208 byte halType; 2209 switch (type) { 2210 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST: 2211 halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST; 2212 break; 2213 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST: 2214 halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST; 2215 break; 2216 default: 2217 Log.e(TAG, "Invalid Rx Filter type: " + type); 2218 return false; 2219 } 2220 return addRxFilter(ifaceName, halType); 2221 } 2222 } 2223 addRxFilter(@onNull String ifaceName, byte type)2224 private boolean addRxFilter(@NonNull String ifaceName, byte type) { 2225 synchronized (mLock) { 2226 final String methodStr = "addRxFilter"; 2227 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2228 if (iface == null) return false; 2229 try { 2230 SupplicantStatus status = iface.addRxFilter(type); 2231 return checkStatusAndLogFailure(status, methodStr); 2232 } catch (RemoteException e) { 2233 handleRemoteException(e, methodStr); 2234 return false; 2235 } 2236 } 2237 } 2238 2239 /** 2240 * Remove an RX filter. 2241 * 2242 * @param ifaceName Name of the interface. 2243 * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST} 2244 * {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values. 2245 * @return true if request is sent successfully, false otherwise. 2246 */ removeRxFilter(@onNull String ifaceName, int type)2247 public boolean removeRxFilter(@NonNull String ifaceName, int type) { 2248 synchronized (mLock) { 2249 byte halType; 2250 switch (type) { 2251 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST: 2252 halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST; 2253 break; 2254 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST: 2255 halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST; 2256 break; 2257 default: 2258 Log.e(TAG, "Invalid Rx Filter type: " + type); 2259 return false; 2260 } 2261 return removeRxFilter(ifaceName, halType); 2262 } 2263 } 2264 removeRxFilter(@onNull String ifaceName, byte type)2265 private boolean removeRxFilter(@NonNull String ifaceName, byte type) { 2266 synchronized (mLock) { 2267 final String methodStr = "removeRxFilter"; 2268 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2269 if (iface == null) return false; 2270 try { 2271 SupplicantStatus status = iface.removeRxFilter(type); 2272 return checkStatusAndLogFailure(status, methodStr); 2273 } catch (RemoteException e) { 2274 handleRemoteException(e, methodStr); 2275 return false; 2276 } 2277 } 2278 } 2279 2280 /** 2281 * Set Bt co existense mode. 2282 * 2283 * @param ifaceName Name of the interface. 2284 * @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 2285 * {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or 2286 * {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}. 2287 * @return true if request is sent successfully, false otherwise. 2288 */ setBtCoexistenceMode(@onNull String ifaceName, int mode)2289 public boolean setBtCoexistenceMode(@NonNull String ifaceName, int mode) { 2290 synchronized (mLock) { 2291 byte halMode; 2292 switch (mode) { 2293 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_ENABLED: 2294 halMode = ISupplicantStaIface.BtCoexistenceMode.ENABLED; 2295 break; 2296 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED: 2297 halMode = ISupplicantStaIface.BtCoexistenceMode.DISABLED; 2298 break; 2299 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE: 2300 halMode = ISupplicantStaIface.BtCoexistenceMode.SENSE; 2301 break; 2302 default: 2303 Log.e(TAG, "Invalid Bt Coex mode: " + mode); 2304 return false; 2305 } 2306 return setBtCoexistenceMode(ifaceName, halMode); 2307 } 2308 } 2309 setBtCoexistenceMode(@onNull String ifaceName, byte mode)2310 private boolean setBtCoexistenceMode(@NonNull String ifaceName, byte mode) { 2311 synchronized (mLock) { 2312 final String methodStr = "setBtCoexistenceMode"; 2313 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2314 if (iface == null) return false; 2315 try { 2316 SupplicantStatus status = iface.setBtCoexistenceMode(mode); 2317 return checkStatusAndLogFailure(status, methodStr); 2318 } catch (RemoteException e) { 2319 handleRemoteException(e, methodStr); 2320 return false; 2321 } 2322 } 2323 } 2324 2325 /** Enable or disable BT coexistence mode. 2326 * 2327 * @param ifaceName Name of the interface. 2328 * @param enable true to enable, false to disable. 2329 * @return true if request is sent successfully, false otherwise. 2330 */ setBtCoexistenceScanModeEnabled(@onNull String ifaceName, boolean enable)2331 public boolean setBtCoexistenceScanModeEnabled(@NonNull String ifaceName, boolean enable) { 2332 synchronized (mLock) { 2333 final String methodStr = "setBtCoexistenceScanModeEnabled"; 2334 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2335 if (iface == null) return false; 2336 try { 2337 SupplicantStatus status = 2338 iface.setBtCoexistenceScanModeEnabled(enable); 2339 return checkStatusAndLogFailure(status, methodStr); 2340 } catch (RemoteException e) { 2341 handleRemoteException(e, methodStr); 2342 return false; 2343 } 2344 } 2345 } 2346 2347 /** 2348 * Enable or disable suspend mode optimizations. 2349 * 2350 * @param ifaceName Name of the interface. 2351 * @param enable true to enable, false otherwise. 2352 * @return true if request is sent successfully, false otherwise. 2353 */ setSuspendModeEnabled(@onNull String ifaceName, boolean enable)2354 public boolean setSuspendModeEnabled(@NonNull String ifaceName, boolean enable) { 2355 synchronized (mLock) { 2356 final String methodStr = "setSuspendModeEnabled"; 2357 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2358 if (iface == null) return false; 2359 try { 2360 SupplicantStatus status = iface.setSuspendModeEnabled(enable); 2361 return checkStatusAndLogFailure(status, methodStr); 2362 } catch (RemoteException e) { 2363 handleRemoteException(e, methodStr); 2364 return false; 2365 } 2366 } 2367 } 2368 2369 /** 2370 * Set country code. 2371 * 2372 * @param ifaceName Name of the interface. 2373 * @param codeStr 2 byte ASCII string. For ex: US, CA. 2374 * @return true if request is sent successfully, false otherwise. 2375 */ setCountryCode(@onNull String ifaceName, String codeStr)2376 public boolean setCountryCode(@NonNull String ifaceName, String codeStr) { 2377 synchronized (mLock) { 2378 if (TextUtils.isEmpty(codeStr)) return false; 2379 byte[] countryCodeBytes = NativeUtil.stringToByteArray(codeStr); 2380 if (countryCodeBytes.length != 2) return false; 2381 return setCountryCode(ifaceName, countryCodeBytes); 2382 } 2383 } 2384 2385 /** See ISupplicantStaIface.hal for documentation */ setCountryCode(@onNull String ifaceName, byte[ ] code)2386 private boolean setCountryCode(@NonNull String ifaceName, byte[/* 2 */] code) { 2387 synchronized (mLock) { 2388 final String methodStr = "setCountryCode"; 2389 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2390 if (iface == null) return false; 2391 try { 2392 SupplicantStatus status = iface.setCountryCode(code); 2393 return checkStatusAndLogFailure(status, methodStr); 2394 } catch (RemoteException e) { 2395 handleRemoteException(e, methodStr); 2396 return false; 2397 } 2398 } 2399 } 2400 2401 /** 2402 * Flush all previously configured HLPs. 2403 * 2404 * @param ifaceName Name of the interface. 2405 * @return true if request is sent successfully, false otherwise. 2406 */ flushAllHlp(@onNull String ifaceName)2407 public boolean flushAllHlp(@NonNull String ifaceName) { 2408 synchronized (mLock) { 2409 final String methodStr = "filsHlpFlushRequest"; 2410 if (isV1_3()) { 2411 ISupplicantStaIface iface = 2412 checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2413 if (iface == null) { 2414 return false; 2415 } 2416 2417 // Get a v1.3 supplicant STA Interface 2418 android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface staIfaceV13 = 2419 getStaIfaceMockableV1_3(iface); 2420 2421 if (staIfaceV13 == null) { 2422 Log.e(TAG, methodStr 2423 + ": ISupplicantStaIface is null, cannot flushAllHlp"); 2424 return false; 2425 } 2426 try { 2427 SupplicantStatus status = staIfaceV13.filsHlpFlushRequest(); 2428 return checkStatusAndLogFailure(status, methodStr); 2429 } catch (RemoteException e) { 2430 handleRemoteException(e, methodStr); 2431 return false; 2432 } 2433 } else { 2434 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 2435 return false; 2436 } 2437 } 2438 } 2439 2440 /** 2441 * Set FILS HLP packet. 2442 * 2443 * @param ifaceName Name of the interface. 2444 * @param dst Destination MAC address. 2445 * @param hlpPacket Hlp Packet data in hex. 2446 * @return true if request is sent successfully, false otherwise. 2447 */ addHlpReq(@onNull String ifaceName, byte [] dst, byte [] hlpPacket)2448 public boolean addHlpReq(@NonNull String ifaceName, byte [] dst, byte [] hlpPacket) { 2449 synchronized (mLock) { 2450 final String methodStr = "filsHlpAddRequest"; 2451 if (isV1_3()) { 2452 ISupplicantStaIface iface = 2453 checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2454 if (iface == null) { 2455 return false; 2456 } 2457 2458 // Get a v1.3 supplicant STA Interface 2459 android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface staIfaceV13 = 2460 getStaIfaceMockableV1_3(iface); 2461 2462 if (staIfaceV13 == null) { 2463 Log.e(TAG, methodStr 2464 + ": ISupplicantStaIface is null, cannot addHlpReq"); 2465 return false; 2466 } 2467 try { 2468 ArrayList<Byte> payload = NativeUtil.byteArrayToArrayList(hlpPacket); 2469 SupplicantStatus status = staIfaceV13.filsHlpAddRequest(dst, payload); 2470 return checkStatusAndLogFailure(status, methodStr); 2471 } catch (RemoteException e) { 2472 handleRemoteException(e, methodStr); 2473 return false; 2474 } 2475 } else { 2476 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 2477 return false; 2478 } 2479 } 2480 } 2481 2482 2483 /** 2484 * Start WPS pin registrar operation with the specified peer and pin. 2485 * 2486 * @param ifaceName Name of the interface. 2487 * @param bssidStr BSSID of the peer. 2488 * @param pin Pin to be used. 2489 * @return true if request is sent successfully, false otherwise. 2490 */ startWpsRegistrar(@onNull String ifaceName, String bssidStr, String pin)2491 public boolean startWpsRegistrar(@NonNull String ifaceName, String bssidStr, String pin) { 2492 synchronized (mLock) { 2493 if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) return false; 2494 try { 2495 return startWpsRegistrar( 2496 ifaceName, NativeUtil.macAddressToByteArray(bssidStr), pin); 2497 } catch (IllegalArgumentException e) { 2498 Log.e(TAG, "Illegal argument " + bssidStr, e); 2499 return false; 2500 } 2501 } 2502 } 2503 2504 /** See ISupplicantStaIface.hal for documentation */ startWpsRegistrar(@onNull String ifaceName, byte[ ] bssid, String pin)2505 private boolean startWpsRegistrar(@NonNull String ifaceName, byte[/* 6 */] bssid, String pin) { 2506 synchronized (mLock) { 2507 final String methodStr = "startWpsRegistrar"; 2508 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2509 if (iface == null) return false; 2510 try { 2511 SupplicantStatus status = iface.startWpsRegistrar(bssid, pin); 2512 return checkStatusAndLogFailure(status, methodStr); 2513 } catch (RemoteException e) { 2514 handleRemoteException(e, methodStr); 2515 return false; 2516 } 2517 } 2518 } 2519 2520 /** 2521 * Start WPS pin display operation with the specified peer. 2522 * 2523 * @param ifaceName Name of the interface. 2524 * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard. 2525 * @return true if request is sent successfully, false otherwise. 2526 */ startWpsPbc(@onNull String ifaceName, String bssidStr)2527 public boolean startWpsPbc(@NonNull String ifaceName, String bssidStr) { 2528 synchronized (mLock) { 2529 try { 2530 return startWpsPbc(ifaceName, NativeUtil.macAddressToByteArray(bssidStr)); 2531 } catch (IllegalArgumentException e) { 2532 Log.e(TAG, "Illegal argument " + bssidStr, e); 2533 return false; 2534 } 2535 } 2536 } 2537 2538 /** See ISupplicantStaIface.hal for documentation */ startWpsPbc(@onNull String ifaceName, byte[ ] bssid)2539 private boolean startWpsPbc(@NonNull String ifaceName, byte[/* 6 */] bssid) { 2540 synchronized (mLock) { 2541 final String methodStr = "startWpsPbc"; 2542 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2543 if (iface == null) return false; 2544 try { 2545 SupplicantStatus status = iface.startWpsPbc(bssid); 2546 return checkStatusAndLogFailure(status, methodStr); 2547 } catch (RemoteException e) { 2548 handleRemoteException(e, methodStr); 2549 return false; 2550 } 2551 } 2552 } 2553 2554 /** 2555 * Start WPS pin keypad operation with the specified pin. 2556 * 2557 * @param ifaceName Name of the interface. 2558 * @param pin Pin to be used. 2559 * @return true if request is sent successfully, false otherwise. 2560 */ startWpsPinKeypad(@onNull String ifaceName, String pin)2561 public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) { 2562 if (TextUtils.isEmpty(pin)) return false; 2563 synchronized (mLock) { 2564 final String methodStr = "startWpsPinKeypad"; 2565 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2566 if (iface == null) return false; 2567 try { 2568 SupplicantStatus status = iface.startWpsPinKeypad(pin); 2569 return checkStatusAndLogFailure(status, methodStr); 2570 } catch (RemoteException e) { 2571 handleRemoteException(e, methodStr); 2572 return false; 2573 } 2574 } 2575 } 2576 2577 /** 2578 * Start WPS pin display operation with the specified peer. 2579 * 2580 * @param ifaceName Name of the interface. 2581 * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard. 2582 * @return new pin generated on success, null otherwise. 2583 */ startWpsPinDisplay(@onNull String ifaceName, String bssidStr)2584 public String startWpsPinDisplay(@NonNull String ifaceName, String bssidStr) { 2585 synchronized (mLock) { 2586 try { 2587 return startWpsPinDisplay(ifaceName, NativeUtil.macAddressToByteArray(bssidStr)); 2588 } catch (IllegalArgumentException e) { 2589 Log.e(TAG, "Illegal argument " + bssidStr, e); 2590 return null; 2591 } 2592 } 2593 } 2594 2595 /** See ISupplicantStaIface.hal for documentation */ startWpsPinDisplay(@onNull String ifaceName, byte[ ] bssid)2596 private String startWpsPinDisplay(@NonNull String ifaceName, byte[/* 6 */] bssid) { 2597 synchronized (mLock) { 2598 final String methodStr = "startWpsPinDisplay"; 2599 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2600 if (iface == null) return null; 2601 final Mutable<String> gotPin = new Mutable<>(); 2602 try { 2603 iface.startWpsPinDisplay(bssid, 2604 (SupplicantStatus status, String pin) -> { 2605 if (checkStatusAndLogFailure(status, methodStr)) { 2606 gotPin.value = pin; 2607 } 2608 }); 2609 } catch (RemoteException e) { 2610 handleRemoteException(e, methodStr); 2611 } 2612 return gotPin.value; 2613 } 2614 } 2615 2616 /** 2617 * Cancels any ongoing WPS requests. 2618 * 2619 * @param ifaceName Name of the interface. 2620 * @return true if request is sent successfully, false otherwise. 2621 */ cancelWps(@onNull String ifaceName)2622 public boolean cancelWps(@NonNull String ifaceName) { 2623 synchronized (mLock) { 2624 final String methodStr = "cancelWps"; 2625 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2626 if (iface == null) return false; 2627 try { 2628 SupplicantStatus status = iface.cancelWps(); 2629 return checkStatusAndLogFailure(status, methodStr); 2630 } catch (RemoteException e) { 2631 handleRemoteException(e, methodStr); 2632 return false; 2633 } 2634 } 2635 } 2636 2637 /** 2638 * Sets whether to use external sim for SIM/USIM processing. 2639 * 2640 * @param ifaceName Name of the interface. 2641 * @param useExternalSim true to enable, false otherwise. 2642 * @return true if request is sent successfully, false otherwise. 2643 */ setExternalSim(@onNull String ifaceName, boolean useExternalSim)2644 public boolean setExternalSim(@NonNull String ifaceName, boolean useExternalSim) { 2645 synchronized (mLock) { 2646 final String methodStr = "setExternalSim"; 2647 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2648 if (iface == null) return false; 2649 try { 2650 SupplicantStatus status = iface.setExternalSim(useExternalSim); 2651 return checkStatusAndLogFailure(status, methodStr); 2652 } catch (RemoteException e) { 2653 handleRemoteException(e, methodStr); 2654 return false; 2655 } 2656 } 2657 } 2658 2659 /** See ISupplicant.hal for documentation */ enableAutoReconnect(@onNull String ifaceName, boolean enable)2660 public boolean enableAutoReconnect(@NonNull String ifaceName, boolean enable) { 2661 synchronized (mLock) { 2662 final String methodStr = "enableAutoReconnect"; 2663 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2664 if (iface == null) return false; 2665 try { 2666 SupplicantStatus status = iface.enableAutoReconnect(enable); 2667 return checkStatusAndLogFailure(status, methodStr); 2668 } catch (RemoteException e) { 2669 handleRemoteException(e, methodStr); 2670 return false; 2671 } 2672 } 2673 } 2674 2675 /** 2676 * Set the debug log level for wpa_supplicant 2677 * 2678 * @param turnOnVerbose Whether to turn on verbose logging or not. 2679 * @return true if request is sent successfully, false otherwise. 2680 */ setLogLevel(boolean turnOnVerbose)2681 public boolean setLogLevel(boolean turnOnVerbose) { 2682 synchronized (mLock) { 2683 int logLevel = turnOnVerbose 2684 ? ISupplicant.DebugLevel.DEBUG 2685 : ISupplicant.DebugLevel.INFO; 2686 return setDebugParams(logLevel, false, 2687 turnOnVerbose && mWifiGlobals.getShowKeyVerboseLoggingModeEnabled()); 2688 } 2689 } 2690 2691 /** See ISupplicant.hal for documentation */ setDebugParams(int level, boolean showTimestamp, boolean showKeys)2692 private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) { 2693 synchronized (mLock) { 2694 final String methodStr = "setDebugParams"; 2695 if (!checkSupplicantAndLogFailure(methodStr)) return false; 2696 try { 2697 SupplicantStatus status = 2698 mISupplicant.setDebugParams(level, showTimestamp, showKeys); 2699 return checkStatusAndLogFailure(status, methodStr); 2700 } catch (RemoteException e) { 2701 handleRemoteException(e, methodStr); 2702 return false; 2703 } 2704 } 2705 } 2706 2707 /** 2708 * Set concurrency priority between P2P & STA operations. 2709 * 2710 * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations, 2711 * false otherwise. 2712 * @return true if request is sent successfully, false otherwise. 2713 */ setConcurrencyPriority(boolean isStaHigherPriority)2714 public boolean setConcurrencyPriority(boolean isStaHigherPriority) { 2715 synchronized (mLock) { 2716 if (isStaHigherPriority) { 2717 return setConcurrencyPriority(IfaceType.STA); 2718 } else { 2719 return setConcurrencyPriority(IfaceType.P2P); 2720 } 2721 } 2722 } 2723 2724 /** See ISupplicant.hal for documentation */ setConcurrencyPriority(int type)2725 private boolean setConcurrencyPriority(int type) { 2726 synchronized (mLock) { 2727 final String methodStr = "setConcurrencyPriority"; 2728 if (!checkSupplicantAndLogFailure(methodStr)) return false; 2729 try { 2730 SupplicantStatus status = mISupplicant.setConcurrencyPriority(type); 2731 return checkStatusAndLogFailure(status, methodStr); 2732 } catch (RemoteException e) { 2733 handleRemoteException(e, methodStr); 2734 return false; 2735 } 2736 } 2737 } 2738 2739 /** 2740 * Returns false if Supplicant is null, and logs failure to call methodStr 2741 */ checkSupplicantAndLogFailure(final String methodStr)2742 private boolean checkSupplicantAndLogFailure(final String methodStr) { 2743 synchronized (mLock) { 2744 if (mISupplicant == null) { 2745 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null"); 2746 return false; 2747 } 2748 return true; 2749 } 2750 } 2751 2752 /** 2753 * Returns false if SupplicantStaIface is null, and logs failure to call methodStr 2754 */ checkSupplicantStaIfaceAndLogFailure( @onNull String ifaceName, final String methodStr)2755 private ISupplicantStaIface checkSupplicantStaIfaceAndLogFailure( 2756 @NonNull String ifaceName, final String methodStr) { 2757 synchronized (mLock) { 2758 ISupplicantStaIface iface = getStaIface(ifaceName); 2759 if (iface == null) { 2760 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null for iface=" 2761 + ifaceName); 2762 return null; 2763 } 2764 return iface; 2765 } 2766 } 2767 2768 /** 2769 * Returns false if SupplicantStaNetwork is null, and logs failure to call methodStr 2770 */ checkSupplicantStaNetworkAndLogFailure( @onNull String ifaceName, final String methodStr)2771 private SupplicantStaNetworkHalHidlImpl checkSupplicantStaNetworkAndLogFailure( 2772 @NonNull String ifaceName, final String methodStr) { 2773 synchronized (mLock) { 2774 SupplicantStaNetworkHalHidlImpl networkHal = getCurrentNetworkRemoteHandle(ifaceName); 2775 if (networkHal == null) { 2776 Log.e(TAG, "Can't call " + methodStr + ", SupplicantStaNetwork is null"); 2777 return null; 2778 } 2779 return networkHal; 2780 } 2781 } 2782 2783 /** 2784 * Returns true if provided status code is SUCCESS, logs debug message and returns false 2785 * otherwise 2786 */ checkStatusAndLogFailure(SupplicantStatus status, final String methodStr)2787 private boolean checkStatusAndLogFailure(SupplicantStatus status, 2788 final String methodStr) { 2789 synchronized (mLock) { 2790 if (status == null || status.code != SupplicantStatusCode.SUCCESS) { 2791 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed: " + status); 2792 return false; 2793 } else { 2794 if (mVerboseLoggingEnabled) { 2795 Log.d(TAG, "ISupplicantStaIface." + methodStr + " succeeded"); 2796 } 2797 return true; 2798 } 2799 } 2800 } 2801 2802 /** 2803 * Returns true if provided status code is SUCCESS, logs debug message and returns false 2804 * otherwise 2805 */ checkStatusAndLogFailure( android.hardware.wifi.supplicant.V1_4.SupplicantStatus status, final String methodStr)2806 private boolean checkStatusAndLogFailure( 2807 android.hardware.wifi.supplicant.V1_4.SupplicantStatus status, 2808 final String methodStr) { 2809 synchronized (mLock) { 2810 if (status == null 2811 || status.code 2812 != android.hardware.wifi.supplicant.V1_4.SupplicantStatusCode.SUCCESS) { 2813 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed: " + status); 2814 return false; 2815 } else { 2816 if (mVerboseLoggingEnabled) { 2817 Log.d(TAG, "ISupplicantStaIface." + methodStr + " succeeded"); 2818 } 2819 return true; 2820 } 2821 } 2822 } 2823 2824 /** 2825 * Helper function to log callbacks. 2826 */ logCallback(final String methodStr)2827 protected void logCallback(final String methodStr) { 2828 synchronized (mLock) { 2829 if (mVerboseLoggingEnabled) { 2830 Log.d(TAG, "ISupplicantStaIfaceCallback." + methodStr + " received"); 2831 } 2832 } 2833 } 2834 handleNoSuchElementException(NoSuchElementException e, String methodStr)2835 private void handleNoSuchElementException(NoSuchElementException e, String methodStr) { 2836 synchronized (mLock) { 2837 clearState(); 2838 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e); 2839 } 2840 } 2841 handleRemoteException(RemoteException e, String methodStr)2842 private void handleRemoteException(RemoteException e, String methodStr) { 2843 synchronized (mLock) { 2844 clearState(); 2845 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e); 2846 } 2847 } 2848 handleIllegalArgumentException(IllegalArgumentException e, String methodStr)2849 private void handleIllegalArgumentException(IllegalArgumentException e, String methodStr) { 2850 synchronized (mLock) { 2851 clearState(); 2852 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e); 2853 } 2854 } 2855 2856 /** 2857 * Converts the Wps config method string to the equivalent enum value. 2858 */ stringToWpsConfigMethod(String configMethod)2859 private static short stringToWpsConfigMethod(String configMethod) { 2860 switch (configMethod) { 2861 case "usba": 2862 return WpsConfigMethods.USBA; 2863 case "ethernet": 2864 return WpsConfigMethods.ETHERNET; 2865 case "label": 2866 return WpsConfigMethods.LABEL; 2867 case "display": 2868 return WpsConfigMethods.DISPLAY; 2869 case "int_nfc_token": 2870 return WpsConfigMethods.INT_NFC_TOKEN; 2871 case "ext_nfc_token": 2872 return WpsConfigMethods.EXT_NFC_TOKEN; 2873 case "nfc_interface": 2874 return WpsConfigMethods.NFC_INTERFACE; 2875 case "push_button": 2876 return WpsConfigMethods.PUSHBUTTON; 2877 case "keypad": 2878 return WpsConfigMethods.KEYPAD; 2879 case "virtual_push_button": 2880 return WpsConfigMethods.VIRT_PUSHBUTTON; 2881 case "physical_push_button": 2882 return WpsConfigMethods.PHY_PUSHBUTTON; 2883 case "p2ps": 2884 return WpsConfigMethods.P2PS; 2885 case "virtual_display": 2886 return WpsConfigMethods.VIRT_DISPLAY; 2887 case "physical_display": 2888 return WpsConfigMethods.PHY_DISPLAY; 2889 default: 2890 throw new IllegalArgumentException( 2891 "Invalid WPS config method: " + configMethod); 2892 } 2893 } 2894 2895 protected class SupplicantStaIfaceHalCallback extends SupplicantStaIfaceCallbackHidlImpl { SupplicantStaIfaceHalCallback(@onNull String ifaceName)2896 SupplicantStaIfaceHalCallback(@NonNull String ifaceName) { 2897 super(SupplicantStaIfaceHalHidlImpl.this, ifaceName, new Object(), mWifiMonitor, 2898 mSsidTranslator); 2899 } 2900 } 2901 2902 protected class SupplicantStaIfaceHalCallbackV1_1 extends 2903 SupplicantStaIfaceCallbackHidlV1_1Impl { SupplicantStaIfaceHalCallbackV1_1(@onNull String ifaceName)2904 SupplicantStaIfaceHalCallbackV1_1(@NonNull String ifaceName) { 2905 super(SupplicantStaIfaceHalHidlImpl.this, ifaceName, new Object(), mWifiMonitor); 2906 } 2907 } 2908 2909 protected class SupplicantStaIfaceHalCallbackV1_2 extends 2910 SupplicantStaIfaceCallbackHidlV1_2Impl { SupplicantStaIfaceHalCallbackV1_2(@onNull String ifaceName)2911 SupplicantStaIfaceHalCallbackV1_2(@NonNull String ifaceName) { 2912 super(SupplicantStaIfaceHalHidlImpl.this, ifaceName, mContext, mSsidTranslator); 2913 } 2914 } 2915 2916 protected class SupplicantStaIfaceHalCallbackV1_3 extends 2917 SupplicantStaIfaceCallbackHidlV1_3Impl { SupplicantStaIfaceHalCallbackV1_3(@onNull String ifaceName)2918 SupplicantStaIfaceHalCallbackV1_3(@NonNull String ifaceName) { 2919 super(SupplicantStaIfaceHalHidlImpl.this, ifaceName, mWifiMonitor); 2920 } 2921 } 2922 2923 protected class SupplicantStaIfaceHalCallbackV1_4 extends 2924 SupplicantStaIfaceCallbackHidlV1_4Impl { SupplicantStaIfaceHalCallbackV1_4(@onNull String ifaceName)2925 SupplicantStaIfaceHalCallbackV1_4(@NonNull String ifaceName) { 2926 super(SupplicantStaIfaceHalHidlImpl.this, ifaceName, new Object(), mWifiMonitor, 2927 mSsidTranslator); 2928 } 2929 } 2930 addPmkCacheEntry( String ifaceName, int networkId, long expirationTimeInSec, ArrayList<Byte> serializedEntry)2931 protected void addPmkCacheEntry( 2932 String ifaceName, 2933 int networkId, long expirationTimeInSec, ArrayList<Byte> serializedEntry) { 2934 String macAddressStr = getMacAddress(ifaceName); 2935 try { 2936 if (!mPmkCacheManager.add(MacAddress.fromString(macAddressStr), 2937 networkId, null, expirationTimeInSec, serializedEntry)) { 2938 Log.w(TAG, "Cannot add PMK cache for " + ifaceName); 2939 } 2940 } catch (IllegalArgumentException ex) { 2941 Log.w(TAG, "Cannot add PMK cache: " + ex); 2942 } 2943 } 2944 removePmkCacheEntry(int networkId)2945 protected void removePmkCacheEntry(int networkId) { 2946 mPmkCacheManager.remove(networkId); 2947 } 2948 logd(String s)2949 private static void logd(String s) { 2950 Log.d(TAG, s); 2951 } 2952 logi(String s)2953 private static void logi(String s) { 2954 Log.i(TAG, s); 2955 } 2956 loge(String s)2957 private static void loge(String s) { 2958 Log.e(TAG, s); 2959 } 2960 2961 /** 2962 * See comments for {@link ISupplicantStaIfaceHal#getAdvancedCapabilities(String)} 2963 * 2964 * This is a v1.2+ HAL feature. 2965 * On error, or if these features are not supported, an empty BitSet is returned. 2966 */ getAdvancedCapabilities(@onNull String ifaceName)2967 public @NonNull BitSet getAdvancedCapabilities(@NonNull String ifaceName) { 2968 final String methodStr = "getAdvancedCapabilities"; 2969 2970 BitSet advancedCapabilities = new BitSet(); 2971 int keyMgmtCapabilities = getKeyMgmtCapabilities(ifaceName); 2972 2973 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork 2974 .KeyMgmtMask.SAE) != 0) { 2975 advancedCapabilities.set(WIFI_FEATURE_WPA3_SAE); 2976 2977 if (mVerboseLoggingEnabled) { 2978 Log.v(TAG, methodStr + ": SAE supported"); 2979 } 2980 } 2981 2982 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork 2983 .KeyMgmtMask.SUITE_B_192) != 0) { 2984 advancedCapabilities.set(WIFI_FEATURE_WPA3_SUITE_B); 2985 2986 if (mVerboseLoggingEnabled) { 2987 Log.v(TAG, methodStr + ": SUITE_B supported"); 2988 } 2989 } 2990 2991 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork 2992 .KeyMgmtMask.OWE) != 0) { 2993 advancedCapabilities.set(WIFI_FEATURE_OWE); 2994 2995 if (mVerboseLoggingEnabled) { 2996 Log.v(TAG, methodStr + ": OWE supported"); 2997 } 2998 } 2999 3000 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork 3001 .KeyMgmtMask.DPP) != 0) { 3002 advancedCapabilities.set(WIFI_FEATURE_DPP); 3003 3004 if (mVerboseLoggingEnabled) { 3005 Log.v(TAG, methodStr + ": DPP supported"); 3006 } 3007 if (isV1_4()) { 3008 advancedCapabilities.set(WIFI_FEATURE_DPP_ENROLLEE_RESPONDER); 3009 if (mVerboseLoggingEnabled) { 3010 Log.v(TAG, methodStr + ": DPP ENROLLEE RESPONDER supported"); 3011 } 3012 } 3013 } 3014 3015 if (isV1_4()) { 3016 advancedCapabilities.set(WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS); 3017 advancedCapabilities.set(WIFI_FEATURE_DECORATED_IDENTITY); 3018 if (mVerboseLoggingEnabled) { 3019 Log.v(TAG, methodStr + ": Passpoint T&C supported"); 3020 Log.v(TAG, methodStr + ": RFC 7542 decorated identity supported"); 3021 } 3022 } 3023 3024 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork 3025 .KeyMgmtMask.WAPI_PSK) != 0) { 3026 advancedCapabilities.set(WIFI_FEATURE_WAPI); 3027 3028 if (mVerboseLoggingEnabled) { 3029 Log.v(TAG, methodStr + ": WAPI supported"); 3030 } 3031 } 3032 3033 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork 3034 .KeyMgmtMask.FILS_SHA256) != 0) { 3035 advancedCapabilities.set(WIFI_FEATURE_FILS_SHA256); 3036 3037 if (mVerboseLoggingEnabled) { 3038 Log.v(TAG, methodStr + ": FILS_SHA256 supported"); 3039 } 3040 } 3041 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork 3042 .KeyMgmtMask.FILS_SHA384) != 0) { 3043 advancedCapabilities.set(WIFI_FEATURE_FILS_SHA384); 3044 3045 if (mVerboseLoggingEnabled) { 3046 Log.v(TAG, methodStr + ": FILS_SHA384 supported"); 3047 } 3048 } 3049 3050 if (mVerboseLoggingEnabled) { 3051 Log.v(TAG, methodStr + ": Capability flags = " + keyMgmtCapabilities); 3052 } 3053 3054 return advancedCapabilities; 3055 } 3056 getKeyMgmtCapabilities_1_3(@onNull String ifaceName)3057 private int getKeyMgmtCapabilities_1_3(@NonNull String ifaceName) { 3058 final String methodStr = "getKeyMgmtCapabilities_1_3"; 3059 Mutable<Integer> keyMgmtMask = new Mutable<>(0); 3060 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3061 if (iface == null) { 3062 return 0; 3063 } 3064 3065 // Get a v1.3 supplicant STA Interface 3066 android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface staIfaceV13 = 3067 getStaIfaceMockableV1_3(iface); 3068 if (staIfaceV13 == null) { 3069 Log.e(TAG, methodStr 3070 + ": ISupplicantStaIface V1.3 is null, cannot get advanced capabilities"); 3071 return 0; 3072 } 3073 3074 try { 3075 // Support for new key management types; WAPI_PSK, WAPI_CERT 3076 // Requires HAL v1.3 or higher 3077 staIfaceV13.getKeyMgmtCapabilities_1_3( 3078 (SupplicantStatus statusInternal, int keyMgmtMaskInternal) -> { 3079 if (statusInternal.code == SupplicantStatusCode.SUCCESS) { 3080 keyMgmtMask.value = keyMgmtMaskInternal; 3081 } 3082 checkStatusAndLogFailure(statusInternal, methodStr); 3083 }); 3084 } catch (RemoteException e) { 3085 handleRemoteException(e, methodStr); 3086 } 3087 return keyMgmtMask.value; 3088 } 3089 getKeyMgmtCapabilities(@onNull String ifaceName)3090 private int getKeyMgmtCapabilities(@NonNull String ifaceName) { 3091 final String methodStr = "getKeyMgmtCapabilities"; 3092 Mutable<Boolean> status = new Mutable<>(false); 3093 Mutable<Integer> keyMgmtMask = new Mutable<>(0); 3094 3095 if (isV1_3()) { 3096 keyMgmtMask.value = getKeyMgmtCapabilities_1_3(ifaceName); 3097 } else if (isV1_2()) { 3098 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3099 if (iface == null) { 3100 return 0; 3101 } 3102 3103 // Get a v1.2 supplicant STA Interface 3104 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3105 getStaIfaceMockableV1_2(iface); 3106 3107 if (staIfaceV12 == null) { 3108 Log.e(TAG, methodStr 3109 + ": ISupplicantStaIface is null, cannot get advanced capabilities"); 3110 return 0; 3111 } 3112 3113 try { 3114 // Support for new key management types; SAE, SUITE_B, OWE 3115 // Requires HAL v1.2 or higher 3116 staIfaceV12.getKeyMgmtCapabilities( 3117 (SupplicantStatus statusInternal, int keyMgmtMaskInternal) -> { 3118 status.value = statusInternal.code == SupplicantStatusCode.SUCCESS; 3119 if (status.value) { 3120 keyMgmtMask.value = keyMgmtMaskInternal; 3121 } 3122 checkStatusAndLogFailure(statusInternal, methodStr); 3123 }); 3124 } catch (RemoteException e) { 3125 handleRemoteException(e, methodStr); 3126 } 3127 } else { 3128 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3129 } 3130 3131 // 0 is returned in case of an error 3132 return keyMgmtMask.value; 3133 } 3134 getWpaDriverCapabilities_1_4(@onNull String ifaceName)3135 private Mutable<Integer> getWpaDriverCapabilities_1_4(@NonNull String ifaceName) { 3136 final String methodStr = "getWpaDriverCapabilities_1_4"; 3137 Mutable<Integer> drvCapabilitiesMask = new Mutable<>(0); 3138 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3139 3140 if (null == iface) return drvCapabilitiesMask; 3141 3142 android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface staIfaceV14 = 3143 getStaIfaceMockableV1_4(iface); 3144 if (null == staIfaceV14) { 3145 Log.e(TAG, methodStr 3146 + ": SupplicantStaIface is null, cannot get wpa driver features"); 3147 return drvCapabilitiesMask; 3148 } 3149 3150 try { 3151 staIfaceV14.getWpaDriverCapabilities_1_4( 3152 (android.hardware.wifi.supplicant.V1_4.SupplicantStatus statusInternal, 3153 int drvCapabilities) -> { 3154 if (statusInternal.code 3155 == android.hardware.wifi.supplicant.V1_4 3156 .SupplicantStatusCode.SUCCESS) { 3157 drvCapabilitiesMask.value = drvCapabilities; 3158 } 3159 checkStatusAndLogFailure(statusInternal, methodStr); 3160 }); 3161 } catch (RemoteException e) { 3162 handleRemoteException(e, methodStr); 3163 } 3164 return drvCapabilitiesMask; 3165 } 3166 getWpaDriverCapabilities_1_3(@onNull String ifaceName)3167 private Mutable<Integer> getWpaDriverCapabilities_1_3(@NonNull String ifaceName) { 3168 final String methodStr = "getWpaDriverCapabilities_1_3"; 3169 Mutable<Integer> drvCapabilitiesMask = new Mutable<>(0); 3170 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3171 3172 if (null == iface) return drvCapabilitiesMask; 3173 3174 android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface staIfaceV13 = 3175 getStaIfaceMockableV1_3(iface); 3176 if (null == staIfaceV13) { 3177 Log.e(TAG, methodStr 3178 + ": SupplicantStaIface is null, cannot get wpa driver features"); 3179 return drvCapabilitiesMask; 3180 } 3181 3182 try { 3183 staIfaceV13.getWpaDriverCapabilities( 3184 (SupplicantStatus statusInternal, int drvCapabilities) -> { 3185 if (statusInternal.code == SupplicantStatusCode.SUCCESS) { 3186 drvCapabilitiesMask.value = drvCapabilities; 3187 } 3188 checkStatusAndLogFailure(statusInternal, methodStr); 3189 }); 3190 } catch (RemoteException e) { 3191 handleRemoteException(e, methodStr); 3192 } 3193 return drvCapabilitiesMask; 3194 } 3195 3196 /** 3197 * See comments for {@link ISupplicantStaIfaceHal#getWpaDriverFeatureSet(String)} 3198 */ getWpaDriverFeatureSet(@onNull String ifaceName)3199 public @NonNull BitSet getWpaDriverFeatureSet(@NonNull String ifaceName) { 3200 final String methodStr = "getWpaDriverFeatureSet"; 3201 Mutable<Integer> drvCapabilitiesMask = new Mutable<>(0); 3202 BitSet featureSet = new BitSet(); 3203 3204 if (isV1_4()) { 3205 drvCapabilitiesMask = getWpaDriverCapabilities_1_4(ifaceName); 3206 } else if (isV1_3()) { 3207 drvCapabilitiesMask = getWpaDriverCapabilities_1_3(ifaceName); 3208 } else { 3209 Log.i(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3210 return new BitSet(); 3211 } 3212 3213 if ((drvCapabilitiesMask.value & WpaDriverCapabilitiesMask.MBO) != 0) { 3214 featureSet.set(WIFI_FEATURE_MBO); 3215 if (mVerboseLoggingEnabled) { 3216 Log.v(TAG, methodStr + ": MBO supported"); 3217 } 3218 if ((drvCapabilitiesMask.value 3219 & WpaDriverCapabilitiesMask.OCE) != 0) { 3220 featureSet.set(WIFI_FEATURE_OCE); 3221 if (mVerboseLoggingEnabled) { 3222 Log.v(TAG, methodStr + ": OCE supported"); 3223 } 3224 } 3225 } 3226 3227 if ((drvCapabilitiesMask.value 3228 & android.hardware.wifi.supplicant.V1_4.WpaDriverCapabilitiesMask.SAE_PK) != 0) { 3229 featureSet.set(WIFI_FEATURE_SAE_PK); 3230 if (mVerboseLoggingEnabled) { 3231 Log.v(TAG, methodStr + ": SAE-PK supported"); 3232 } 3233 } 3234 3235 if ((drvCapabilitiesMask.value 3236 & android.hardware.wifi.supplicant.V1_4.WpaDriverCapabilitiesMask.WFD_R2) != 0) { 3237 featureSet.set(WIFI_FEATURE_WFD_R2); 3238 if (mVerboseLoggingEnabled) { 3239 Log.v(TAG, methodStr + ": WFD-R2 supported"); 3240 } 3241 } 3242 3243 return featureSet; 3244 } 3245 getWifiStandard(int technology)3246 private @WifiStandard int getWifiStandard(int technology) { 3247 switch(technology) { 3248 case WifiTechnology.HE: 3249 return ScanResult.WIFI_STANDARD_11AX; 3250 case WifiTechnology.VHT: 3251 return ScanResult.WIFI_STANDARD_11AC; 3252 case WifiTechnology.HT: 3253 return ScanResult.WIFI_STANDARD_11N; 3254 case WifiTechnology.LEGACY: 3255 return ScanResult.WIFI_STANDARD_LEGACY; 3256 default: 3257 return ScanResult.WIFI_STANDARD_UNKNOWN; 3258 } 3259 } 3260 getChannelBandwidth(int channelBandwidth)3261 private int getChannelBandwidth(int channelBandwidth) { 3262 switch(channelBandwidth) { 3263 case WifiChannelWidthInMhz.WIDTH_20: 3264 return ScanResult.CHANNEL_WIDTH_20MHZ; 3265 case WifiChannelWidthInMhz.WIDTH_40: 3266 return ScanResult.CHANNEL_WIDTH_40MHZ; 3267 case WifiChannelWidthInMhz.WIDTH_80: 3268 return ScanResult.CHANNEL_WIDTH_80MHZ; 3269 case WifiChannelWidthInMhz.WIDTH_160: 3270 return ScanResult.CHANNEL_WIDTH_160MHZ; 3271 case WifiChannelWidthInMhz.WIDTH_80P80: 3272 return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ; 3273 default: 3274 return ScanResult.CHANNEL_WIDTH_20MHZ; 3275 } 3276 } 3277 frameworkToHidlDppAkm(int dppAkm)3278 private int frameworkToHidlDppAkm(int dppAkm) { 3279 switch(dppAkm) { 3280 case SupplicantStaIfaceHal.DppAkm.PSK: 3281 return DppAkm.PSK; 3282 case SupplicantStaIfaceHal.DppAkm.PSK_SAE: 3283 return DppAkm.PSK_SAE; 3284 case SupplicantStaIfaceHal.DppAkm.SAE: 3285 return DppAkm.SAE; 3286 case SupplicantStaIfaceHal.DppAkm.DPP: 3287 return DppAkm.DPP; 3288 default: 3289 Log.e(TAG, "Invalid DppAkm received"); 3290 return -1; 3291 } 3292 } 3293 frameworkToHidlDppCurve(int dppCurve)3294 private int frameworkToHidlDppCurve(int dppCurve) { 3295 switch(dppCurve) { 3296 case SupplicantStaIfaceHal.DppCurve.PRIME256V1: 3297 return DppCurve.PRIME256V1; 3298 case SupplicantStaIfaceHal.DppCurve.SECP384R1: 3299 return DppCurve.SECP384R1; 3300 case SupplicantStaIfaceHal.DppCurve.SECP521R1: 3301 return DppCurve.SECP521R1; 3302 case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP256R1: 3303 return DppCurve.BRAINPOOLP256R1; 3304 case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP384R1: 3305 return DppCurve.BRAINPOOLP384R1; 3306 case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP512R1: 3307 return DppCurve.BRAINPOOLP512R1; 3308 default: 3309 Log.e(TAG, "Invalid DppAkm received"); 3310 return -1; 3311 } 3312 } 3313 frameworkToHidlDppNetRole(int dppNetRole)3314 private int frameworkToHidlDppNetRole(int dppNetRole) { 3315 switch(dppNetRole) { 3316 case SupplicantStaIfaceHal.DppNetRole.STA: 3317 return DppNetRole.STA; 3318 case SupplicantStaIfaceHal.DppNetRole.AP: 3319 return DppNetRole.AP; 3320 default: 3321 Log.e(TAG, "Invalid DppNetRole received"); 3322 return -1; 3323 } 3324 } 3325 3326 /** 3327 * Returns signal poll results for all Wi-Fi links of the interface. 3328 * 3329 * @param ifaceName Name of the interface. 3330 * @return Signal poll results. 3331 */ getSignalPollResults(@onNull String ifaceName)3332 public WifiSignalPollResults getSignalPollResults(@NonNull String ifaceName) { 3333 /* Signal polling is not implemented for HIDL. */ 3334 return null; 3335 } 3336 3337 3338 /** 3339 * Returns connection capabilities of the current network 3340 * 3341 * This is a v1.3+ HAL feature. 3342 * @param ifaceName Name of the interface. 3343 * @return connection capabilities of the current network 3344 */ getConnectionCapabilities(@onNull String ifaceName)3345 public WifiNative.ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) { 3346 final String methodStr = "getConnectionCapabilities"; 3347 WifiNative.ConnectionCapabilities capOut = new WifiNative.ConnectionCapabilities(); 3348 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3349 if (iface == null) { 3350 return capOut; 3351 } 3352 if (isV1_4()) { 3353 return getConnectionCapabilities_1_4(iface); 3354 } else if (isV1_3()) { 3355 return getConnectionCapabilities_1_3(iface); 3356 } else { 3357 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3358 } 3359 return capOut; 3360 } 3361 3362 /** 3363 * Returns connection MLO links info 3364 * 3365 * @param ifaceName Name of the interface. 3366 * @return null since this method is not supported on Hidl 3367 */ getConnectionMloLinksInfo(@onNull String ifaceName)3368 public WifiNative.ConnectionMloLinksInfo getConnectionMloLinksInfo(@NonNull String ifaceName) { 3369 return null; 3370 } 3371 getConnectionCapabilities_1_3( @onNull ISupplicantStaIface iface)3372 private WifiNative.ConnectionCapabilities getConnectionCapabilities_1_3( 3373 @NonNull ISupplicantStaIface iface) { 3374 final String methodStr = "getConnectionCapabilities_1_3"; 3375 WifiNative.ConnectionCapabilities capOut = new WifiNative.ConnectionCapabilities(); 3376 3377 // Get a v1.3 supplicant STA Interface 3378 android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface staIfaceV13 = 3379 getStaIfaceMockableV1_3(iface); 3380 3381 if (staIfaceV13 == null) { 3382 Log.e(TAG, methodStr 3383 + ": SupplicantStaIface is null, cannot get Connection Capabilities"); 3384 return capOut; 3385 } 3386 3387 try { 3388 staIfaceV13.getConnectionCapabilities( 3389 (SupplicantStatus statusInternal, ConnectionCapabilities cap) -> { 3390 if (statusInternal.code == SupplicantStatusCode.SUCCESS) { 3391 capOut.wifiStandard = getWifiStandard(cap.technology); 3392 capOut.channelBandwidth = getChannelBandwidth( 3393 cap.channelBandwidth); 3394 capOut.maxNumberTxSpatialStreams = cap.maxNumberTxSpatialStreams; 3395 capOut.maxNumberRxSpatialStreams = cap.maxNumberRxSpatialStreams; 3396 } 3397 checkStatusAndLogFailure(statusInternal, methodStr); 3398 }); 3399 } catch (RemoteException e) { 3400 handleRemoteException(e, methodStr); 3401 } 3402 return capOut; 3403 } 3404 getConnectionCapabilities_1_4( @onNull ISupplicantStaIface iface)3405 private WifiNative.ConnectionCapabilities getConnectionCapabilities_1_4( 3406 @NonNull ISupplicantStaIface iface) { 3407 final String methodStr = "getConnectionCapabilities_1_4"; 3408 WifiNative.ConnectionCapabilities capOut = new WifiNative.ConnectionCapabilities(); 3409 // Get a v1.4 supplicant STA Interface 3410 android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface staIfaceV14 = 3411 getStaIfaceMockableV1_4(iface); 3412 3413 if (staIfaceV14 == null) { 3414 Log.e(TAG, methodStr 3415 + ": SupplicantStaIface is null, cannot get Connection Capabilities"); 3416 return capOut; 3417 } 3418 3419 try { 3420 staIfaceV14.getConnectionCapabilities_1_4( 3421 (android.hardware.wifi.supplicant.V1_4.SupplicantStatus statusInternal, 3422 android.hardware.wifi.supplicant.V1_4.ConnectionCapabilities cap) 3423 -> { 3424 if (statusInternal.code == SupplicantStatusCode.SUCCESS) { 3425 capOut.wifiStandard = getWifiStandard(cap.V1_3.technology); 3426 capOut.channelBandwidth = getChannelBandwidth( 3427 cap.V1_3.channelBandwidth); 3428 capOut.is11bMode = (cap.legacyMode == LegacyMode.B_MODE); 3429 capOut.maxNumberTxSpatialStreams = cap.V1_3.maxNumberTxSpatialStreams; 3430 capOut.maxNumberRxSpatialStreams = cap.V1_3.maxNumberRxSpatialStreams; 3431 } 3432 checkStatusAndLogFailure(statusInternal, methodStr); 3433 }); 3434 } catch (RemoteException e) { 3435 handleRemoteException(e, methodStr); 3436 } 3437 return capOut; 3438 } 3439 /** 3440 * Adds a DPP peer URI to the URI list. 3441 * 3442 * This is a v1.2+ HAL feature. 3443 * Returns an ID to be used later to refer to this URI (>0). 3444 * On error, or if these features are not supported, -1 is returned. 3445 */ addDppPeerUri(@onNull String ifaceName, @NonNull String uri)3446 public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) { 3447 final String methodStr = "addDppPeerUri"; 3448 Mutable<Boolean> status = new Mutable<>(false); 3449 Mutable<Integer> bootstrapId = new Mutable<>(-1); 3450 3451 if (!isV1_2()) { 3452 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3453 return -1; 3454 } 3455 3456 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3457 if (iface == null) { 3458 return -1; 3459 } 3460 3461 // Get a v1.2 supplicant STA Interface 3462 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3463 getStaIfaceMockableV1_2(iface); 3464 3465 if (staIfaceV12 == null) { 3466 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3467 return -1; 3468 } 3469 3470 try { 3471 // Support for DPP (Easy connect) 3472 // Requires HAL v1.2 or higher 3473 staIfaceV12.addDppPeerUri(uri, 3474 (SupplicantStatus statusInternal, int bootstrapIdInternal) -> { 3475 status.value = statusInternal.code == SupplicantStatusCode.SUCCESS; 3476 if (status.value) { 3477 bootstrapId.value = bootstrapIdInternal; 3478 } 3479 checkStatusAndLogFailure(statusInternal, methodStr); 3480 }); 3481 } catch (RemoteException e) { 3482 handleRemoteException(e, methodStr); 3483 return -1; 3484 } 3485 3486 return bootstrapId.value; 3487 } 3488 3489 /** 3490 * Removes a DPP URI to the URI list given an ID. 3491 * 3492 * This is a v1.2+ HAL feature. 3493 * Returns true when operation is successful 3494 * On error, or if these features are not supported, false is returned. 3495 */ removeDppUri(@onNull String ifaceName, int bootstrapId)3496 public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId) { 3497 final String methodStr = "removeDppUri"; 3498 3499 if (!isV1_2()) { 3500 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3501 return false; 3502 } 3503 3504 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3505 if (iface == null) { 3506 return false; 3507 } 3508 3509 // Get a v1.2 supplicant STA Interface 3510 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3511 getStaIfaceMockableV1_2(iface); 3512 3513 if (staIfaceV12 == null) { 3514 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3515 return false; 3516 } 3517 3518 try { 3519 // Support for DPP (Easy connect) 3520 // Requires HAL v1.2 or higher 3521 SupplicantStatus status = staIfaceV12.removeDppUri(bootstrapId); 3522 return checkStatusAndLogFailure(status, methodStr); 3523 } catch (RemoteException e) { 3524 handleRemoteException(e, methodStr); 3525 } 3526 3527 return false; 3528 } 3529 3530 /** 3531 * Stops/aborts DPP Initiator request 3532 * 3533 * This is a v1.2+ HAL feature. 3534 * Returns true when operation is successful 3535 * On error, or if these features are not supported, false is returned. 3536 */ stopDppInitiator(@onNull String ifaceName)3537 public boolean stopDppInitiator(@NonNull String ifaceName) { 3538 final String methodStr = "stopDppInitiator"; 3539 3540 if (!isV1_2()) { 3541 return false; 3542 } 3543 3544 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3545 if (iface == null) { 3546 return false; 3547 } 3548 3549 // Get a v1.2 supplicant STA Interface 3550 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3551 getStaIfaceMockableV1_2(iface); 3552 3553 if (staIfaceV12 == null) { 3554 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3555 return false; 3556 } 3557 3558 try { 3559 // Support for DPP (Easy connect) 3560 // Requires HAL v1.2 or higher 3561 SupplicantStatus status = staIfaceV12.stopDppInitiator(); 3562 return checkStatusAndLogFailure(status, methodStr); 3563 } catch (RemoteException e) { 3564 handleRemoteException(e, methodStr); 3565 } 3566 3567 return false; 3568 } 3569 3570 /** 3571 * Starts DPP Configurator-Initiator request 3572 * 3573 * This is a v1.2+ HAL feature. 3574 * Returns true when operation is successful 3575 * On error, or if these features are not supported, false is returned. 3576 */ startDppConfiguratorInitiator(@onNull String ifaceName, int peerBootstrapId, int ownBootstrapId, @NonNull String ssid, String password, String psk, int netRole, int securityAkm, byte[] privEckey)3577 public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId, 3578 int ownBootstrapId, @NonNull String ssid, String password, String psk, 3579 int netRole, int securityAkm, byte[] privEckey) { 3580 final String methodStr = "startDppConfiguratorInitiator"; 3581 3582 if (!isV1_2()) { 3583 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3584 return false; 3585 } 3586 3587 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3588 if (iface == null) { 3589 return false; 3590 } 3591 3592 // Get a v1.2 supplicant STA Interface 3593 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3594 getStaIfaceMockableV1_2(iface); 3595 3596 if (staIfaceV12 == null) { 3597 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3598 return false; 3599 } 3600 3601 try { 3602 // Support for DPP (Easy connect) 3603 // Requires HAL v1.2 or higher 3604 SupplicantStatus status = staIfaceV12.startDppConfiguratorInitiator(peerBootstrapId, 3605 ownBootstrapId, ssid, password != null ? password : "", psk != null ? psk : "", 3606 frameworkToHidlDppNetRole(netRole), frameworkToHidlDppAkm(securityAkm)); 3607 return checkStatusAndLogFailure(status, methodStr); 3608 } catch (RemoteException e) { 3609 handleRemoteException(e, methodStr); 3610 } 3611 3612 return false; 3613 } 3614 3615 /** 3616 * Starts DPP Enrollee-Initiator request 3617 * 3618 * This is a v1.2+ HAL feature. 3619 * Returns true when operation is successful 3620 * On error, or if these features are not supported, false is returned. 3621 */ startDppEnrolleeInitiator(@onNull String ifaceName, int peerBootstrapId, int ownBootstrapId)3622 public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId, 3623 int ownBootstrapId) { 3624 final String methodStr = "startDppEnrolleeInitiator"; 3625 3626 if (!isV1_2()) { 3627 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3628 return false; 3629 } 3630 3631 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3632 if (iface == null) { 3633 return false; 3634 } 3635 3636 // Get a v1.2 supplicant STA Interface 3637 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3638 getStaIfaceMockableV1_2(iface); 3639 3640 if (staIfaceV12 == null) { 3641 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3642 return false; 3643 } 3644 3645 try { 3646 // Support for DPP (Easy connect) 3647 // Requires HAL v1.2 or higher 3648 SupplicantStatus status = staIfaceV12.startDppEnrolleeInitiator(peerBootstrapId, 3649 ownBootstrapId); 3650 return checkStatusAndLogFailure(status, methodStr); 3651 } catch (RemoteException e) { 3652 handleRemoteException(e, methodStr); 3653 } 3654 3655 return false; 3656 } 3657 3658 /** 3659 * Generate a DPP QR code based boot strap info 3660 * 3661 * This is a v1.4+ HAL feature. 3662 * Returns DppResponderBootstrapInfo; 3663 */ generateDppBootstrapInfoForResponder( @onNull String ifaceName, String macAddress, @NonNull String deviceInfo, int dppCurve)3664 public WifiNative.DppBootstrapQrCodeInfo generateDppBootstrapInfoForResponder( 3665 @NonNull String ifaceName, String macAddress, @NonNull String deviceInfo, 3666 int dppCurve) { 3667 final String methodStr = "generateDppBootstrapInfoForResponder"; 3668 Mutable<Boolean> status = new Mutable<>(false); 3669 WifiNative.DppBootstrapQrCodeInfo bootstrapInfoOut = 3670 new WifiNative.DppBootstrapQrCodeInfo(); 3671 3672 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3673 if (iface == null) { 3674 return bootstrapInfoOut; 3675 } 3676 3677 // Get a v1.4 supplicant STA Interface 3678 android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface staIfaceV14 = 3679 getStaIfaceMockableV1_4(iface); 3680 3681 if (staIfaceV14 == null) { 3682 Log.e(TAG, methodStr + ": SupplicantStaIface V1.4 is null"); 3683 return bootstrapInfoOut; 3684 } 3685 3686 try { 3687 // Support for DPP Responder 3688 // Requires HAL v1.4 or higher 3689 staIfaceV14.generateDppBootstrapInfoForResponder( 3690 NativeUtil.macAddressToByteArray(macAddress), deviceInfo, 3691 frameworkToHidlDppCurve(dppCurve), 3692 (android.hardware.wifi.supplicant.V1_4.SupplicantStatus statusInternal, 3693 android.hardware.wifi.supplicant.V1_4 3694 .DppResponderBootstrapInfo info) -> { 3695 if (statusInternal.code == SupplicantStatusCode.SUCCESS) { 3696 bootstrapInfoOut.bootstrapId = info.bootstrapId; 3697 bootstrapInfoOut.listenChannel = info.listenChannel; 3698 bootstrapInfoOut.uri = info.uri; 3699 } 3700 checkStatusAndLogFailure(statusInternal, methodStr); 3701 }); 3702 } catch (RemoteException e) { 3703 handleRemoteException(e, methodStr); 3704 return bootstrapInfoOut; 3705 } 3706 3707 return bootstrapInfoOut; 3708 } 3709 3710 /** 3711 * Starts DPP Enrollee-Responder request 3712 * 3713 * This is a v1.4+ HAL feature. 3714 * Returns true when operation is successful 3715 * On error, or if these features are not supported, false is returned. 3716 */ startDppEnrolleeResponder(@onNull String ifaceName, int listenChannel)3717 public boolean startDppEnrolleeResponder(@NonNull String ifaceName, int listenChannel) { 3718 final String methodStr = "startDppEnrolleeResponder"; 3719 3720 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3721 if (iface == null) { 3722 return false; 3723 } 3724 3725 // Get a v1.4 supplicant STA Interface 3726 android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface staIfaceV14 = 3727 getStaIfaceMockableV1_4(iface); 3728 3729 if (staIfaceV14 == null) { 3730 Log.e(TAG, methodStr + ": ISupplicantStaIface V1.4 is null"); 3731 return false; 3732 } 3733 3734 try { 3735 // Support for DPP Responder 3736 // Requires HAL v1.4 or higher 3737 android.hardware.wifi.supplicant.V1_4.SupplicantStatus status = 3738 staIfaceV14.startDppEnrolleeResponder(listenChannel); 3739 return checkStatusAndLogFailure(status, methodStr); 3740 } catch (RemoteException e) { 3741 handleRemoteException(e, methodStr); 3742 } 3743 3744 return false; 3745 } 3746 3747 /** 3748 * Stops/aborts DPP Responder request. 3749 * 3750 * This is a v1.4+ HAL feature. 3751 * Returns true when operation is successful 3752 * On error, or if these features are not supported, false is returned. 3753 */ stopDppResponder(@onNull String ifaceName, int ownBootstrapId)3754 public boolean stopDppResponder(@NonNull String ifaceName, int ownBootstrapId) { 3755 final String methodStr = "stopDppResponder"; 3756 3757 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3758 if (iface == null) { 3759 return false; 3760 } 3761 3762 // Get a v1.4 supplicant STA Interface 3763 android.hardware.wifi.supplicant.V1_4.ISupplicantStaIface staIfaceV14 = 3764 getStaIfaceMockableV1_4(iface); 3765 3766 if (staIfaceV14 == null) { 3767 Log.e(TAG, methodStr + ": ISupplicantStaIface V1.4 is null"); 3768 return false; 3769 } 3770 3771 try { 3772 // Support for DPP Responder 3773 // Requires HAL v1.4 or higher 3774 android.hardware.wifi.supplicant.V1_4.SupplicantStatus status = 3775 staIfaceV14.stopDppResponder(ownBootstrapId); 3776 return checkStatusAndLogFailure(status, methodStr); 3777 } catch (RemoteException e) { 3778 handleRemoteException(e, methodStr); 3779 } 3780 3781 return false; 3782 } 3783 3784 3785 /** 3786 * Register callbacks for DPP events. 3787 * 3788 * @param dppCallback DPP callback object. 3789 */ registerDppCallback(DppEventCallback dppCallback)3790 public void registerDppCallback(DppEventCallback dppCallback) { 3791 mDppCallback = dppCallback; 3792 } 3793 getDppCallback()3794 protected DppEventCallback getDppCallback() { 3795 return mDppCallback; 3796 } 3797 3798 /** 3799 * Set MBO cellular data availability. 3800 * 3801 * @param ifaceName Name of the interface. 3802 * @param available true means cellular data available, false otherwise. 3803 * @return None. 3804 */ setMboCellularDataStatus(@onNull String ifaceName, boolean available)3805 public boolean setMboCellularDataStatus(@NonNull String ifaceName, boolean available) { 3806 final String methodStr = "setMboCellularDataStatus"; 3807 3808 if (isV1_3()) { 3809 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3810 if (iface == null) { 3811 return false; 3812 } 3813 3814 // Get a v1.3 supplicant STA Interface 3815 android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface staIfaceV13 = 3816 getStaIfaceMockableV1_3(iface); 3817 if (staIfaceV13 == null) { 3818 Log.e(TAG, methodStr 3819 + ": SupplicantStaIface is null, cannot update cell status"); 3820 return false; 3821 } 3822 3823 try { 3824 SupplicantStatus status = staIfaceV13.setMboCellularDataStatus(available); 3825 return checkStatusAndLogFailure(status, methodStr); 3826 } catch (RemoteException e) { 3827 handleRemoteException(e, methodStr); 3828 } 3829 } else { 3830 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3831 return false; 3832 } 3833 3834 return false; 3835 } 3836 3837 /** 3838 * Check if we've roamed to a linked network and make the linked network the current network 3839 * if we have. 3840 * 3841 * @param ifaceName Name of the interface. 3842 * @param newNetworkId Network id of the new network we've roamed to. If fromFramework is 3843 * {@code true}, this will be a framework network id. Otherwise, this will 3844 * be a remote network id. 3845 * @param fromFramework {@code true} if the network id is a framework network id, {@code false} 3846 if the network id is a remote network id. 3847 * @return true if we've roamed to a linked network, false if not. 3848 */ updateOnLinkedNetworkRoaming( @onNull String ifaceName, int newNetworkId, boolean fromFramework)3849 public boolean updateOnLinkedNetworkRoaming( 3850 @NonNull String ifaceName, int newNetworkId, boolean fromFramework) { 3851 synchronized (mLock) { 3852 List<Pair<SupplicantStaNetworkHalHidlImpl, WifiConfiguration>> linkedNetworkHandles = 3853 mLinkedNetworkLocalAndRemoteConfigs.get(ifaceName); 3854 SupplicantStaNetworkHalHidlImpl currentHandle = 3855 getCurrentNetworkRemoteHandle(ifaceName); 3856 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 3857 if (linkedNetworkHandles == null || currentHandle == null || currentConfig == null) { 3858 return false; 3859 } 3860 if (fromFramework ? currentConfig.networkId == newNetworkId 3861 : currentHandle.getNetworkId() == newNetworkId) { 3862 return false; 3863 } 3864 for (Pair<SupplicantStaNetworkHalHidlImpl, WifiConfiguration> pair 3865 : linkedNetworkHandles) { 3866 if (fromFramework ? pair.second.networkId == newNetworkId 3867 : pair.first.getNetworkId() == newNetworkId) { 3868 Log.i(TAG, "Roamed to linked network, " 3869 + "make linked network as current network"); 3870 mCurrentNetworkRemoteHandles.put(ifaceName, pair.first); 3871 mCurrentNetworkLocalConfigs.put(ifaceName, pair.second); 3872 return true; 3873 } 3874 } 3875 return false; 3876 } 3877 } 3878 3879 /** 3880 * Updates the linked networks for the current network and sends them to the supplicant. 3881 * 3882 * @param ifaceName Name of the interface. 3883 * @param networkId network id of the network to link the configurations to. 3884 * @param linkedConfigurations Map of config profile key to config for linking. 3885 * @return true if networks were successfully linked, false otherwise. 3886 */ updateLinkedNetworks(@onNull String ifaceName, int networkId, Map<String, WifiConfiguration> linkedConfigurations)3887 public boolean updateLinkedNetworks(@NonNull String ifaceName, int networkId, 3888 Map<String, WifiConfiguration> linkedConfigurations) { 3889 synchronized (mLock) { 3890 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 3891 SupplicantStaNetworkHalHidlImpl currentHandle = 3892 getCurrentNetworkRemoteHandle(ifaceName); 3893 3894 if (currentConfig == null || currentHandle == null) { 3895 Log.e(TAG, "current network not configured yet."); 3896 return false; 3897 } 3898 3899 if (networkId != currentConfig.networkId) { 3900 Log.e(TAG, "current config network id is not matching"); 3901 return false; 3902 } 3903 3904 final int remoteNetworkId = currentHandle.getNetworkId(); 3905 if (remoteNetworkId == -1) { 3906 Log.e(TAG, "current handle getNetworkId failed"); 3907 return false; 3908 } 3909 3910 if (!removeAllNetworksExcept(ifaceName, remoteNetworkId)) { 3911 Log.e(TAG, "couldn't remove non-current supplicant networks"); 3912 return false; 3913 } 3914 3915 mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName); 3916 3917 if (linkedConfigurations == null || linkedConfigurations.size() == 0) { 3918 Log.i(TAG, "cleared linked networks"); 3919 return true; 3920 } 3921 3922 List<Pair<SupplicantStaNetworkHalHidlImpl, WifiConfiguration>> linkedNetworkHandles = 3923 new ArrayList<>(); 3924 linkedNetworkHandles.add(new Pair(currentHandle, currentConfig)); 3925 for (String linkedNetwork : linkedConfigurations.keySet()) { 3926 Log.i(TAG, "add linked network: " + linkedNetwork); 3927 Pair<SupplicantStaNetworkHalHidlImpl, WifiConfiguration> pair = 3928 addNetworkAndSaveConfig(ifaceName, linkedConfigurations.get(linkedNetwork)); 3929 if (pair == null) { 3930 Log.e(TAG, "failed to add/save linked network: " + linkedNetwork); 3931 return false; 3932 } 3933 pair.first.enable(true); 3934 linkedNetworkHandles.add(pair); 3935 } 3936 3937 mLinkedNetworkLocalAndRemoteConfigs.put(ifaceName, linkedNetworkHandles); 3938 3939 return true; 3940 } 3941 } 3942 3943 /** 3944 * Remove all networks except the supplied network ID from supplicant 3945 * 3946 * @param ifaceName Name of the interface 3947 * @param networkId network id to keep 3948 */ removeAllNetworksExcept(@onNull String ifaceName, int networkId)3949 private boolean removeAllNetworksExcept(@NonNull String ifaceName, int networkId) { 3950 synchronized (mLock) { 3951 List<Integer> networks = listNetworks(ifaceName); 3952 if (networks == null) { 3953 Log.e(TAG, "removeAllNetworksExcept failed, got null networks"); 3954 return false; 3955 } 3956 for (int id : networks) { 3957 if (networkId == id) { 3958 continue; 3959 } 3960 if (!removeNetwork(ifaceName, id)) { 3961 Log.e(TAG, "removeAllNetworksExcept failed to remove network: " + id); 3962 return false; 3963 } 3964 } 3965 return true; 3966 } 3967 } 3968 3969 /** 3970 * Gets the security params of the current network associated with this interface 3971 * 3972 * @param ifaceName Name of the interface 3973 * @return Security params of the current network associated with the interface 3974 */ getCurrentNetworkSecurityParams(@onNull String ifaceName)3975 public SecurityParams getCurrentNetworkSecurityParams(@NonNull String ifaceName) { 3976 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 3977 3978 if (currentConfig == null) { 3979 return null; 3980 } 3981 3982 return currentConfig.getNetworkSelectionStatus().getCandidateSecurityParams(); 3983 } 3984 } 3985