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