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