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