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