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 */ 16package com.android.server.wifi; 17 18import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQP3GPPNetwork; 19import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPDomName; 20import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPIPAddrAvailability; 21import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPNAIRealm; 22import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPRoamingConsortium; 23import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPVenueName; 24import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSConnCapability; 25import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSFriendlyName; 26import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSOSUProviders; 27import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSWANMetrics; 28 29import android.annotation.NonNull; 30import android.content.Context; 31import android.hardware.wifi.supplicant.V1_0.ISupplicant; 32import android.hardware.wifi.supplicant.V1_0.ISupplicantIface; 33import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork; 34import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface; 35import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback; 36import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback.BssidChangeReason; 37import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork; 38import android.hardware.wifi.supplicant.V1_0.IfaceType; 39import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; 40import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; 41import android.hardware.wifi.supplicant.V1_0.WpsConfigMethods; 42import android.hidl.manager.V1_0.IServiceManager; 43import android.hidl.manager.V1_0.IServiceNotification; 44import android.net.IpConfiguration; 45import android.net.wifi.SupplicantState; 46import android.net.wifi.WifiConfiguration; 47import android.net.wifi.WifiManager; 48import android.net.wifi.WifiSsid; 49import android.os.HidlSupport.Mutable; 50import android.os.HwRemoteBinder; 51import android.os.RemoteException; 52import android.text.TextUtils; 53import android.util.Log; 54import android.util.Pair; 55import android.util.SparseArray; 56 57import com.android.server.wifi.WifiNative.SupplicantDeathEventHandler; 58import com.android.server.wifi.hotspot2.AnqpEvent; 59import com.android.server.wifi.hotspot2.IconEvent; 60import com.android.server.wifi.hotspot2.WnmData; 61import com.android.server.wifi.hotspot2.anqp.ANQPElement; 62import com.android.server.wifi.hotspot2.anqp.ANQPParser; 63import com.android.server.wifi.hotspot2.anqp.Constants; 64import com.android.server.wifi.util.NativeUtil; 65 66import java.io.IOException; 67import java.nio.BufferUnderflowException; 68import java.nio.ByteBuffer; 69import java.nio.ByteOrder; 70import java.util.ArrayList; 71import java.util.HashMap; 72import java.util.List; 73import java.util.Map; 74import java.util.NoSuchElementException; 75import java.util.Objects; 76import java.util.regex.Matcher; 77import java.util.regex.Pattern; 78 79import javax.annotation.concurrent.ThreadSafe; 80 81/** 82 * Hal calls for bring up/shut down of the supplicant daemon and for 83 * sending requests to the supplicant daemon 84 * To maintain thread-safety, the locking protocol is that every non-static method (regardless of 85 * access level) acquires mLock. 86 */ 87@ThreadSafe 88public class SupplicantStaIfaceHal { 89 private static final String TAG = "SupplicantStaIfaceHal"; 90 /** 91 * Regex pattern for extracting the wps device type bytes. 92 * Matches a strings like the following: "<categ>-<OUI>-<subcateg>"; 93 */ 94 private static final Pattern WPS_DEVICE_TYPE_PATTERN = 95 Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$"); 96 97 private final Object mLock = new Object(); 98 private boolean mVerboseLoggingEnabled = false; 99 100 // Supplicant HAL interface objects 101 private IServiceManager mIServiceManager = null; 102 private ISupplicant mISupplicant; 103 private HashMap<String, ISupplicantStaIface> mISupplicantStaIfaces = new HashMap<>(); 104 private HashMap<String, ISupplicantStaIfaceCallback> mISupplicantStaIfaceCallbacks = 105 new HashMap<>(); 106 private HashMap<String, SupplicantStaNetworkHal> mCurrentNetworkRemoteHandles = new HashMap<>(); 107 private HashMap<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>(); 108 private SupplicantDeathEventHandler mDeathEventHandler; 109 private final Context mContext; 110 private final WifiMonitor mWifiMonitor; 111 112 private final IServiceNotification mServiceNotificationCallback = 113 new IServiceNotification.Stub() { 114 public void onRegistration(String fqName, String name, boolean preexisting) { 115 synchronized (mLock) { 116 if (mVerboseLoggingEnabled) { 117 Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName 118 + ", " + name + " preexisting=" + preexisting); 119 } 120 if (!initSupplicantService()) { 121 Log.e(TAG, "initalizing ISupplicant failed."); 122 supplicantServiceDiedHandler(); 123 } else { 124 Log.i(TAG, "Completed initialization of ISupplicant."); 125 } 126 } 127 } 128 }; 129 private final HwRemoteBinder.DeathRecipient mServiceManagerDeathRecipient = 130 cookie -> { 131 synchronized (mLock) { 132 Log.w(TAG, "IServiceManager died: cookie=" + cookie); 133 supplicantServiceDiedHandler(); 134 mIServiceManager = null; // Will need to register a new ServiceNotification 135 } 136 }; 137 private final HwRemoteBinder.DeathRecipient mSupplicantDeathRecipient = 138 cookie -> { 139 synchronized (mLock) { 140 Log.w(TAG, "ISupplicant died: cookie=" + cookie); 141 supplicantServiceDiedHandler(); 142 } 143 }; 144 145 146 public SupplicantStaIfaceHal(Context context, WifiMonitor monitor) { 147 mContext = context; 148 mWifiMonitor = monitor; 149 } 150 151 /** 152 * Enable/Disable verbose logging. 153 * 154 * @param enable true to enable, false to disable. 155 */ 156 void enableVerboseLogging(boolean enable) { 157 synchronized (mLock) { 158 mVerboseLoggingEnabled = enable; 159 } 160 } 161 162 private boolean linkToServiceManagerDeath() { 163 synchronized (mLock) { 164 if (mIServiceManager == null) return false; 165 try { 166 if (!mIServiceManager.linkToDeath(mServiceManagerDeathRecipient, 0)) { 167 Log.wtf(TAG, "Error on linkToDeath on IServiceManager"); 168 supplicantServiceDiedHandler(); 169 mIServiceManager = null; // Will need to register a new ServiceNotification 170 return false; 171 } 172 } catch (RemoteException e) { 173 Log.e(TAG, "IServiceManager.linkToDeath exception", e); 174 return false; 175 } 176 return true; 177 } 178 } 179 180 /** 181 * Registers a service notification for the ISupplicant service, which triggers intialization of 182 * the ISupplicantStaIface 183 * @return true if the service notification was successfully registered 184 */ 185 public boolean initialize() { 186 synchronized (mLock) { 187 if (mVerboseLoggingEnabled) { 188 Log.i(TAG, "Registering ISupplicant service ready callback."); 189 } 190 mISupplicant = null; 191 mISupplicantStaIfaces.clear(); 192 if (mIServiceManager != null) { 193 // Already have an IServiceManager and serviceNotification registered, don't 194 // don't register another. 195 return true; 196 } 197 try { 198 mIServiceManager = getServiceManagerMockable(); 199 if (mIServiceManager == null) { 200 Log.e(TAG, "Failed to get HIDL Service Manager"); 201 return false; 202 } 203 if (!linkToServiceManagerDeath()) { 204 return false; 205 } 206 /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it 207 exists */ 208 if (!mIServiceManager.registerForNotifications( 209 ISupplicant.kInterfaceName, "", mServiceNotificationCallback)) { 210 Log.e(TAG, "Failed to register for notifications to " 211 + ISupplicant.kInterfaceName); 212 mIServiceManager = null; // Will need to register a new ServiceNotification 213 return false; 214 } 215 } catch (RemoteException e) { 216 Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: " 217 + e); 218 supplicantServiceDiedHandler(); 219 } 220 return true; 221 } 222 } 223 224 private boolean linkToSupplicantDeath() { 225 synchronized (mLock) { 226 if (mISupplicant == null) return false; 227 try { 228 if (!mISupplicant.linkToDeath(mSupplicantDeathRecipient, 0)) { 229 Log.wtf(TAG, "Error on linkToDeath on ISupplicant"); 230 supplicantServiceDiedHandler(); 231 return false; 232 } 233 } catch (RemoteException e) { 234 Log.e(TAG, "ISupplicant.linkToDeath exception", e); 235 return false; 236 } 237 return true; 238 } 239 } 240 241 private boolean initSupplicantService() { 242 synchronized (mLock) { 243 try { 244 mISupplicant = getSupplicantMockable(); 245 } catch (RemoteException e) { 246 Log.e(TAG, "ISupplicant.getService exception: " + e); 247 return false; 248 } 249 if (mISupplicant == null) { 250 Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup"); 251 return false; 252 } 253 if (!linkToSupplicantDeath()) { 254 return false; 255 } 256 } 257 return true; 258 } 259 260 private int getCurrentNetworkId(@NonNull String ifaceName) { 261 synchronized (mLock) { 262 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 263 if (currentConfig == null) { 264 return WifiConfiguration.INVALID_NETWORK_ID; 265 } 266 return currentConfig.networkId; 267 } 268 } 269 270 /** 271 * Setup a STA interface for the specified iface name. 272 * 273 * @param ifaceName Name of the interface. 274 * @return true on success, false otherwise. 275 */ 276 public boolean setupIface(@NonNull String ifaceName) { 277 final String methodStr = "setupIface"; 278 if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) != null) return false; 279 ISupplicantIface ifaceHwBinder; 280 if (isV1_1()) { 281 ifaceHwBinder = addIfaceV1_1(ifaceName); 282 } else { 283 ifaceHwBinder = getIfaceV1_0(ifaceName); 284 } 285 if (ifaceHwBinder == null) { 286 Log.e(TAG, "setupIface got null iface"); 287 return false; 288 } 289 SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName); 290 291 if (isV1_1()) { 292 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface = 293 getStaIfaceMockableV1_1(ifaceHwBinder); 294 SupplicantStaIfaceHalCallbackV1_1 callbackV1_1 = 295 new SupplicantStaIfaceHalCallbackV1_1(ifaceName, callback); 296 297 if (!registerCallbackV1_1(iface, callbackV1_1)) { 298 return false; 299 } 300 mISupplicantStaIfaces.put(ifaceName, iface); 301 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV1_1); 302 } else { 303 ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder); 304 305 if (!registerCallback(iface, callback)) { 306 return false; 307 } 308 mISupplicantStaIfaces.put(ifaceName, iface); 309 mISupplicantStaIfaceCallbacks.put(ifaceName, callback); 310 } 311 return true; 312 } 313 314 /** 315 * Get a STA interface for the specified iface name. 316 * 317 * @param ifaceName Name of the interface. 318 * @return true on success, false otherwise. 319 */ 320 private ISupplicantIface getIfaceV1_0(@NonNull String ifaceName) { 321 synchronized (mLock) { 322 /** List all supplicant Ifaces */ 323 final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>(); 324 try { 325 mISupplicant.listInterfaces((SupplicantStatus status, 326 ArrayList<ISupplicant.IfaceInfo> ifaces) -> { 327 if (status.code != SupplicantStatusCode.SUCCESS) { 328 Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code); 329 return; 330 } 331 supplicantIfaces.addAll(ifaces); 332 }); 333 } catch (RemoteException e) { 334 Log.e(TAG, "ISupplicant.listInterfaces exception: " + e); 335 handleRemoteException(e, "listInterfaces"); 336 return null; 337 } 338 if (supplicantIfaces.size() == 0) { 339 Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup."); 340 return null; 341 } 342 Mutable<ISupplicantIface> supplicantIface = new Mutable<>(); 343 for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) { 344 if (ifaceInfo.type == IfaceType.STA && ifaceName.equals(ifaceInfo.name)) { 345 try { 346 mISupplicant.getInterface(ifaceInfo, 347 (SupplicantStatus status, ISupplicantIface iface) -> { 348 if (status.code != SupplicantStatusCode.SUCCESS) { 349 Log.e(TAG, "Failed to get ISupplicantIface " + status.code); 350 return; 351 } 352 supplicantIface.value = iface; 353 }); 354 } catch (RemoteException e) { 355 Log.e(TAG, "ISupplicant.getInterface exception: " + e); 356 handleRemoteException(e, "getInterface"); 357 return null; 358 } 359 break; 360 } 361 } 362 return supplicantIface.value; 363 } 364 } 365 366 /** 367 * Create a STA interface for the specified iface name. 368 * 369 * @param ifaceName Name of the interface. 370 * @return true on success, false otherwise. 371 */ 372 private ISupplicantIface addIfaceV1_1(@NonNull String ifaceName) { 373 synchronized (mLock) { 374 ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo(); 375 ifaceInfo.name = ifaceName; 376 ifaceInfo.type = IfaceType.STA; 377 Mutable<ISupplicantIface> supplicantIface = new Mutable<>(); 378 try { 379 getSupplicantMockableV1_1().addInterface(ifaceInfo, 380 (SupplicantStatus status, ISupplicantIface iface) -> { 381 if (status.code != SupplicantStatusCode.SUCCESS 382 && status.code != SupplicantStatusCode.FAILURE_IFACE_EXISTS) { 383 Log.e(TAG, "Failed to create ISupplicantIface " + status.code); 384 return; 385 } 386 supplicantIface.value = iface; 387 }); 388 } catch (RemoteException e) { 389 Log.e(TAG, "ISupplicant.addInterface exception: " + e); 390 handleRemoteException(e, "addInterface"); 391 return null; 392 } 393 return supplicantIface.value; 394 } 395 } 396 397 /** 398 * Teardown a STA interface for the specified iface name. 399 * 400 * @param ifaceName Name of the interface. 401 * @return true on success, false otherwise. 402 */ 403 public boolean teardownIface(@NonNull String ifaceName) { 404 synchronized (mLock) { 405 final String methodStr = "teardownIface"; 406 if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) == null) return false; 407 if (isV1_1()) { 408 if (!removeIfaceV1_1(ifaceName)) { 409 Log.e(TAG, "Failed to remove iface = " + ifaceName); 410 return false; 411 } 412 } 413 if (mISupplicantStaIfaces.remove(ifaceName) == null) { 414 Log.e(TAG, "Trying to teardown unknown inteface"); 415 return false; 416 } 417 mISupplicantStaIfaceCallbacks.remove(ifaceName); 418 return true; 419 } 420 } 421 422 /** 423 * Remove a STA interface for the specified iface name. 424 * 425 * @param ifaceName Name of the interface. 426 * @return true on success, false otherwise. 427 */ 428 private boolean removeIfaceV1_1(@NonNull String ifaceName) { 429 synchronized (mLock) { 430 try { 431 ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo(); 432 ifaceInfo.name = ifaceName; 433 ifaceInfo.type = IfaceType.STA; 434 SupplicantStatus status = getSupplicantMockableV1_1().removeInterface(ifaceInfo); 435 if (status.code != SupplicantStatusCode.SUCCESS) { 436 Log.e(TAG, "Failed to remove iface " + status.code); 437 return false; 438 } 439 } catch (RemoteException e) { 440 Log.e(TAG, "ISupplicant.removeInterface exception: " + e); 441 handleRemoteException(e, "removeInterface"); 442 return false; 443 } 444 return true; 445 } 446 } 447 448 /** 449 * Registers a death notification for supplicant. 450 * @return Returns true on success. 451 */ 452 public boolean registerDeathHandler(@NonNull SupplicantDeathEventHandler handler) { 453 if (mDeathEventHandler != null) { 454 Log.e(TAG, "Death handler already present"); 455 } 456 mDeathEventHandler = handler; 457 return true; 458 } 459 460 /** 461 * Deregisters a death notification for supplicant. 462 * @return Returns true on success. 463 */ 464 public boolean deregisterDeathHandler() { 465 if (mDeathEventHandler == null) { 466 Log.e(TAG, "No Death handler present"); 467 } 468 mDeathEventHandler = null; 469 return true; 470 } 471 472 473 private void clearState() { 474 synchronized (mLock) { 475 mISupplicant = null; 476 mISupplicantStaIfaces.clear(); 477 mCurrentNetworkLocalConfigs.clear(); 478 mCurrentNetworkRemoteHandles.clear(); 479 } 480 } 481 482 private void supplicantServiceDiedHandler() { 483 synchronized (mLock) { 484 for (String ifaceName : mISupplicantStaIfaces.keySet()) { 485 mWifiMonitor.broadcastSupplicantDisconnectionEvent(ifaceName); 486 } 487 clearState(); 488 if (mDeathEventHandler != null) { 489 mDeathEventHandler.onDeath(); 490 } 491 } 492 } 493 494 /** 495 * Signals whether Initialization completed successfully. 496 */ 497 public boolean isInitializationStarted() { 498 synchronized (mLock) { 499 return mIServiceManager != null; 500 } 501 } 502 503 /** 504 * Signals whether Initialization completed successfully. 505 */ 506 public boolean isInitializationComplete() { 507 synchronized (mLock) { 508 return mISupplicant != null; 509 } 510 } 511 512 /** 513 * Terminate the supplicant daemon. 514 */ 515 public void terminate() { 516 synchronized (mLock) { 517 final String methodStr = "terminate"; 518 if (!checkSupplicantAndLogFailure(methodStr)) return; 519 try { 520 if (isV1_1()) { 521 getSupplicantMockableV1_1().terminate(); 522 } 523 } catch (RemoteException e) { 524 handleRemoteException(e, methodStr); 525 } 526 } 527 } 528 529 /** 530 * Wrapper functions to access static HAL methods, created to be mockable in unit tests 531 */ 532 protected IServiceManager getServiceManagerMockable() throws RemoteException { 533 synchronized (mLock) { 534 return IServiceManager.getService(); 535 } 536 } 537 538 protected ISupplicant getSupplicantMockable() throws RemoteException { 539 synchronized (mLock) { 540 try { 541 return ISupplicant.getService(); 542 } catch (NoSuchElementException e) { 543 Log.e(TAG, "Failed to get ISupplicant", e); 544 return null; 545 } 546 } 547 } 548 549 protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1() 550 throws RemoteException { 551 synchronized (mLock) { 552 try { 553 return android.hardware.wifi.supplicant.V1_1.ISupplicant.castFrom( 554 ISupplicant.getService()); 555 } catch (NoSuchElementException e) { 556 Log.e(TAG, "Failed to get ISupplicant", e); 557 return null; 558 } 559 } 560 } 561 562 protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) { 563 synchronized (mLock) { 564 return ISupplicantStaIface.asInterface(iface.asBinder()); 565 } 566 } 567 568 protected android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface 569 getStaIfaceMockableV1_1(ISupplicantIface iface) { 570 synchronized (mLock) { 571 return android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface. 572 asInterface(iface.asBinder()); 573 } 574 } 575 576 /** 577 * Check if the device is running V1_1 supplicant service. 578 * @return 579 */ 580 private boolean isV1_1() { 581 synchronized (mLock) { 582 try { 583 return (getSupplicantMockableV1_1() != null); 584 } catch (RemoteException e) { 585 Log.e(TAG, "ISupplicant.getService exception: " + e); 586 handleRemoteException(e, "getSupplicantMockable"); 587 return false; 588 } 589 } 590 } 591 592 /** 593 * Helper method to look up the network object for the specified iface. 594 */ 595 private ISupplicantStaIface getStaIface(@NonNull String ifaceName) { 596 return mISupplicantStaIfaces.get(ifaceName); 597 } 598 599 /** 600 * Helper method to look up the network object for the specified iface. 601 */ 602 private SupplicantStaNetworkHal getCurrentNetworkRemoteHandle(@NonNull String ifaceName) { 603 return mCurrentNetworkRemoteHandles.get(ifaceName); 604 } 605 606 /** 607 * Helper method to look up the network config or the specified iface. 608 */ 609 private WifiConfiguration getCurrentNetworkLocalConfig(@NonNull String ifaceName) { 610 return mCurrentNetworkLocalConfigs.get(ifaceName); 611 } 612 613 /** 614 * Add a network configuration to wpa_supplicant. 615 * 616 * @param config Config corresponding to the network. 617 * @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects 618 * for the current network. 619 */ 620 private Pair<SupplicantStaNetworkHal, WifiConfiguration> 621 addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) { 622 synchronized (mLock) { 623 logi("addSupplicantStaNetwork via HIDL"); 624 if (config == null) { 625 loge("Cannot add NULL network!"); 626 return null; 627 } 628 SupplicantStaNetworkHal network = addNetwork(ifaceName); 629 if (network == null) { 630 loge("Failed to add a network!"); 631 return null; 632 } 633 boolean saveSuccess = false; 634 try { 635 saveSuccess = network.saveWifiConfiguration(config); 636 } catch (IllegalArgumentException e) { 637 Log.e(TAG, "Exception while saving config params: " + config, e); 638 } 639 if (!saveSuccess) { 640 loge("Failed to save variables for: " + config.configKey()); 641 if (!removeAllNetworks(ifaceName)) { 642 loge("Failed to remove all networks on failure."); 643 } 644 return null; 645 } 646 return new Pair(network, new WifiConfiguration(config)); 647 } 648 } 649 650 /** 651 * Add the provided network configuration to wpa_supplicant and initiate connection to it. 652 * This method does the following: 653 * 1. If |config| is different to the current supplicant network, removes all supplicant 654 * networks and saves |config|. 655 * 2. Select the new network in wpa_supplicant. 656 * 657 * @param ifaceName Name of the interface. 658 * @param config WifiConfiguration parameters for the provided network. 659 * @return {@code true} if it succeeds, {@code false} otherwise 660 */ 661 public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) { 662 synchronized (mLock) { 663 logd("connectToNetwork " + config.configKey()); 664 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 665 if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) { 666 String networkSelectionBSSID = config.getNetworkSelectionStatus() 667 .getNetworkSelectionBSSID(); 668 String networkSelectionBSSIDCurrent = 669 currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID(); 670 if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) { 671 logd("Network is already saved, will not trigger remove and add operation."); 672 } else { 673 logd("Network is already saved, but need to update BSSID."); 674 if (!setCurrentNetworkBssid( 675 ifaceName, 676 config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) { 677 loge("Failed to set current network BSSID."); 678 return false; 679 } 680 mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config)); 681 } 682 } else { 683 mCurrentNetworkRemoteHandles.remove(ifaceName); 684 mCurrentNetworkLocalConfigs.remove(ifaceName); 685 if (!removeAllNetworks(ifaceName)) { 686 loge("Failed to remove existing networks"); 687 return false; 688 } 689 Pair<SupplicantStaNetworkHal, WifiConfiguration> pair = 690 addNetworkAndSaveConfig(ifaceName, config); 691 if (pair == null) { 692 loge("Failed to add/save network configuration: " + config.configKey()); 693 return false; 694 } 695 mCurrentNetworkRemoteHandles.put(ifaceName, pair.first); 696 mCurrentNetworkLocalConfigs.put(ifaceName, pair.second); 697 } 698 SupplicantStaNetworkHal networkHandle = 699 checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork"); 700 if (networkHandle == null || !networkHandle.select()) { 701 loge("Failed to select network configuration: " + config.configKey()); 702 return false; 703 } 704 return true; 705 } 706 } 707 708 /** 709 * Initiates roaming to the already configured network in wpa_supplicant. If the network 710 * configuration provided does not match the already configured network, then this triggers 711 * a new connection attempt (instead of roam). 712 * 1. First check if we're attempting to connect to the same network as we currently have 713 * configured. 714 * 2. Set the new bssid for the network in wpa_supplicant. 715 * 3. Trigger reassociate command to wpa_supplicant. 716 * 717 * @param ifaceName Name of the interface. 718 * @param config WifiConfiguration parameters for the provided network. 719 * @return {@code true} if it succeeds, {@code false} otherwise 720 */ 721 public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration config) { 722 synchronized (mLock) { 723 if (getCurrentNetworkId(ifaceName) != config.networkId) { 724 Log.w(TAG, "Cannot roam to a different network, initiate new connection. " 725 + "Current network ID: " + getCurrentNetworkId(ifaceName)); 726 return connectToNetwork(ifaceName, config); 727 } 728 String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID(); 729 logd("roamToNetwork" + config.configKey() + " (bssid " + bssid + ")"); 730 731 SupplicantStaNetworkHal networkHandle = 732 checkSupplicantStaNetworkAndLogFailure(ifaceName, "roamToNetwork"); 733 if (networkHandle == null || !networkHandle.setBssid(bssid)) { 734 loge("Failed to set new bssid on network: " + config.configKey()); 735 return false; 736 } 737 if (!reassociate(ifaceName)) { 738 loge("Failed to trigger reassociate"); 739 return false; 740 } 741 return true; 742 } 743 } 744 745 /** 746 * Load all the configured networks from wpa_supplicant. 747 * 748 * @param ifaceName Name of the interface. 749 * @param configs Map of configuration key to configuration objects corresponding to all 750 * the networks. 751 * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf 752 * @return true if succeeds, false otherwise. 753 */ 754 public boolean loadNetworks(@NonNull String ifaceName, Map<String, WifiConfiguration> configs, 755 SparseArray<Map<String, String>> networkExtras) { 756 synchronized (mLock) { 757 List<Integer> networkIds = listNetworks(ifaceName); 758 if (networkIds == null) { 759 Log.e(TAG, "Failed to list networks"); 760 return false; 761 } 762 for (Integer networkId : networkIds) { 763 SupplicantStaNetworkHal network = getNetwork(ifaceName, networkId); 764 if (network == null) { 765 Log.e(TAG, "Failed to get network with ID: " + networkId); 766 return false; 767 } 768 WifiConfiguration config = new WifiConfiguration(); 769 Map<String, String> networkExtra = new HashMap<>(); 770 boolean loadSuccess = false; 771 try { 772 loadSuccess = network.loadWifiConfiguration(config, networkExtra); 773 } catch (IllegalArgumentException e) { 774 Log.wtf(TAG, "Exception while loading config params: " + config, e); 775 } 776 if (!loadSuccess) { 777 Log.e(TAG, "Failed to load wifi configuration for network with ID: " + networkId 778 + ". Skipping..."); 779 continue; 780 } 781 // Set the default IP assignments. 782 config.setIpAssignment(IpConfiguration.IpAssignment.DHCP); 783 config.setProxySettings(IpConfiguration.ProxySettings.NONE); 784 785 networkExtras.put(networkId, networkExtra); 786 String configKey = 787 networkExtra.get(SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY); 788 final WifiConfiguration duplicateConfig = configs.put(configKey, config); 789 if (duplicateConfig != null) { 790 // The network is already known. Overwrite the duplicate entry. 791 Log.i(TAG, "Replacing duplicate network: " + duplicateConfig.networkId); 792 removeNetwork(ifaceName, duplicateConfig.networkId); 793 networkExtras.remove(duplicateConfig.networkId); 794 } 795 } 796 return true; 797 } 798 } 799 800 /** 801 * Remove the request |networkId| from supplicant if it's the current network, 802 * if the current configured network matches |networkId|. 803 * 804 * @param ifaceName Name of the interface. 805 * @param networkId network id of the network to be removed from supplicant. 806 */ 807 public void removeNetworkIfCurrent(@NonNull String ifaceName, int networkId) { 808 synchronized (mLock) { 809 if (getCurrentNetworkId(ifaceName) == networkId) { 810 // Currently we only save 1 network in supplicant. 811 removeAllNetworks(ifaceName); 812 } 813 } 814 } 815 816 /** 817 * Remove all networks from supplicant 818 * 819 * @param ifaceName Name of the interface. 820 */ 821 public boolean removeAllNetworks(@NonNull String ifaceName) { 822 synchronized (mLock) { 823 ArrayList<Integer> networks = listNetworks(ifaceName); 824 if (networks == null) { 825 Log.e(TAG, "removeAllNetworks failed, got null networks"); 826 return false; 827 } 828 for (int id : networks) { 829 if (!removeNetwork(ifaceName, id)) { 830 Log.e(TAG, "removeAllNetworks failed to remove network: " + id); 831 return false; 832 } 833 } 834 // Reset current network info. Probably not needed once we add support to remove/reset 835 // current network on receiving disconnection event from supplicant (b/32898136). 836 mCurrentNetworkRemoteHandles.remove(ifaceName); 837 mCurrentNetworkLocalConfigs.remove(ifaceName); 838 return true; 839 } 840 } 841 842 /** 843 * Set the currently configured network's bssid. 844 * 845 * @param ifaceName Name of the interface. 846 * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX" 847 * @return true if succeeds, false otherwise. 848 */ 849 public boolean setCurrentNetworkBssid(@NonNull String ifaceName, String bssidStr) { 850 synchronized (mLock) { 851 SupplicantStaNetworkHal networkHandle = 852 checkSupplicantStaNetworkAndLogFailure(ifaceName, "setCurrentNetworkBssid"); 853 if (networkHandle == null) return false; 854 return networkHandle.setBssid(bssidStr); 855 } 856 } 857 858 /** 859 * Get the currently configured network's WPS NFC token. 860 * 861 * @param ifaceName Name of the interface. 862 * @return Hex string corresponding to the WPS NFC token. 863 */ 864 public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) { 865 synchronized (mLock) { 866 SupplicantStaNetworkHal networkHandle = 867 checkSupplicantStaNetworkAndLogFailure( 868 ifaceName, "getCurrentNetworkWpsNfcConfigurationToken"); 869 if (networkHandle == null) return null; 870 return networkHandle.getWpsNfcConfigurationToken(); 871 } 872 } 873 874 /** 875 * Get the eap anonymous identity for the currently configured network. 876 * 877 * @param ifaceName Name of the interface. 878 * @return anonymous identity string if succeeds, null otherwise. 879 */ 880 public String getCurrentNetworkEapAnonymousIdentity(@NonNull String ifaceName) { 881 synchronized (mLock) { 882 SupplicantStaNetworkHal networkHandle = 883 checkSupplicantStaNetworkAndLogFailure( 884 ifaceName, "getCurrentNetworkEapAnonymousIdentity"); 885 if (networkHandle == null) return null; 886 return networkHandle.fetchEapAnonymousIdentity(); 887 } 888 } 889 890 /** 891 * Send the eap identity response for the currently configured network. 892 * 893 * @param ifaceName Name of the interface. 894 * @param identity identity used for EAP-Identity 895 * @param encryptedIdentity encrypted identity used for EAP-AKA/EAP-SIM 896 * @return true if succeeds, false otherwise. 897 */ 898 public boolean sendCurrentNetworkEapIdentityResponse( 899 @NonNull String ifaceName, @NonNull String identity, String encryptedIdentity) { 900 synchronized (mLock) { 901 SupplicantStaNetworkHal networkHandle = 902 checkSupplicantStaNetworkAndLogFailure( 903 ifaceName, "sendCurrentNetworkEapIdentityResponse"); 904 if (networkHandle == null) return false; 905 return networkHandle.sendNetworkEapIdentityResponse(identity, encryptedIdentity); 906 } 907 } 908 909 /** 910 * Send the eap sim gsm auth response for the currently configured network. 911 * 912 * @param ifaceName Name of the interface. 913 * @param paramsStr String to send. 914 * @return true if succeeds, false otherwise. 915 */ 916 public boolean sendCurrentNetworkEapSimGsmAuthResponse( 917 @NonNull String ifaceName, String paramsStr) { 918 synchronized (mLock) { 919 SupplicantStaNetworkHal networkHandle = 920 checkSupplicantStaNetworkAndLogFailure( 921 ifaceName, "sendCurrentNetworkEapSimGsmAuthResponse"); 922 if (networkHandle == null) return false; 923 return networkHandle.sendNetworkEapSimGsmAuthResponse(paramsStr); 924 } 925 } 926 927 /** 928 * Send the eap sim gsm auth failure for the currently configured network. 929 * 930 * @param ifaceName Name of the interface. 931 * @return true if succeeds, false otherwise. 932 */ 933 public boolean sendCurrentNetworkEapSimGsmAuthFailure(@NonNull String ifaceName) { 934 synchronized (mLock) { 935 SupplicantStaNetworkHal networkHandle = 936 checkSupplicantStaNetworkAndLogFailure( 937 ifaceName, "sendCurrentNetworkEapSimGsmAuthFailure"); 938 if (networkHandle == null) return false; 939 return networkHandle.sendNetworkEapSimGsmAuthFailure(); 940 } 941 } 942 943 /** 944 * Send the eap sim umts auth response for the currently configured network. 945 * 946 * @param ifaceName Name of the interface. 947 * @param paramsStr String to send. 948 * @return true if succeeds, false otherwise. 949 */ 950 public boolean sendCurrentNetworkEapSimUmtsAuthResponse( 951 @NonNull String ifaceName, String paramsStr) { 952 synchronized (mLock) { 953 SupplicantStaNetworkHal networkHandle = 954 checkSupplicantStaNetworkAndLogFailure( 955 ifaceName, "sendCurrentNetworkEapSimUmtsAuthResponse"); 956 if (networkHandle == null) return false; 957 return networkHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr); 958 } 959 } 960 961 /** 962 * Send the eap sim umts auts response for the currently configured network. 963 * 964 * @param ifaceName Name of the interface. 965 * @param paramsStr String to send. 966 * @return true if succeeds, false otherwise. 967 */ 968 public boolean sendCurrentNetworkEapSimUmtsAutsResponse( 969 @NonNull String ifaceName, String paramsStr) { 970 synchronized (mLock) { 971 SupplicantStaNetworkHal networkHandle = 972 checkSupplicantStaNetworkAndLogFailure( 973 ifaceName, "sendCurrentNetworkEapSimUmtsAutsResponse"); 974 if (networkHandle == null) return false; 975 return networkHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr); 976 } 977 } 978 979 /** 980 * Send the eap sim umts auth failure for the currently configured network. 981 * 982 * @param ifaceName Name of the interface. 983 * @return true if succeeds, false otherwise. 984 */ 985 public boolean sendCurrentNetworkEapSimUmtsAuthFailure(@NonNull String ifaceName) { 986 synchronized (mLock) { 987 SupplicantStaNetworkHal networkHandle = 988 checkSupplicantStaNetworkAndLogFailure( 989 ifaceName, "sendCurrentNetworkEapSimUmtsAuthFailure"); 990 if (networkHandle == null) return false; 991 return networkHandle.sendNetworkEapSimUmtsAuthFailure(); 992 } 993 } 994 995 /** 996 * Adds a new network. 997 * 998 * @return The ISupplicantNetwork object for the new network, or null if the call fails 999 */ 1000 private SupplicantStaNetworkHal addNetwork(@NonNull String ifaceName) { 1001 synchronized (mLock) { 1002 final String methodStr = "addNetwork"; 1003 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1004 if (iface == null) return null; 1005 Mutable<ISupplicantNetwork> newNetwork = new Mutable<>(); 1006 try { 1007 iface.addNetwork((SupplicantStatus status, 1008 ISupplicantNetwork network) -> { 1009 if (checkStatusAndLogFailure(status, methodStr)) { 1010 newNetwork.value = network; 1011 } 1012 }); 1013 } catch (RemoteException e) { 1014 handleRemoteException(e, methodStr); 1015 } 1016 if (newNetwork.value != null) { 1017 return getStaNetworkMockable( 1018 ifaceName, 1019 ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder())); 1020 } else { 1021 return null; 1022 } 1023 } 1024 } 1025 1026 /** 1027 * Remove network from supplicant with network Id 1028 * 1029 * @return true if request is sent successfully, false otherwise. 1030 */ 1031 private boolean removeNetwork(@NonNull String ifaceName, int id) { 1032 synchronized (mLock) { 1033 final String methodStr = "removeNetwork"; 1034 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1035 if (iface == null) return false; 1036 try { 1037 SupplicantStatus status = iface.removeNetwork(id); 1038 return checkStatusAndLogFailure(status, methodStr); 1039 } catch (RemoteException e) { 1040 handleRemoteException(e, methodStr); 1041 return false; 1042 } 1043 } 1044 } 1045 1046 /** 1047 * Use this to mock the creation of SupplicantStaNetworkHal instance. 1048 * 1049 * @param ifaceName Name of the interface. 1050 * @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL. 1051 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 1052 * the call fails 1053 */ 1054 protected SupplicantStaNetworkHal getStaNetworkMockable( 1055 @NonNull String ifaceName, ISupplicantStaNetwork iSupplicantStaNetwork) { 1056 synchronized (mLock) { 1057 SupplicantStaNetworkHal network = 1058 new SupplicantStaNetworkHal(iSupplicantStaNetwork, ifaceName, mContext, 1059 mWifiMonitor); 1060 if (network != null) { 1061 network.enableVerboseLogging(mVerboseLoggingEnabled); 1062 } 1063 return network; 1064 } 1065 } 1066 1067 /** 1068 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 1069 * the call fails 1070 */ 1071 private SupplicantStaNetworkHal getNetwork(@NonNull String ifaceName, int id) { 1072 synchronized (mLock) { 1073 final String methodStr = "getNetwork"; 1074 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1075 if (iface == null) return null; 1076 Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>(); 1077 try { 1078 iface.getNetwork(id, (SupplicantStatus status, ISupplicantNetwork network) -> { 1079 if (checkStatusAndLogFailure(status, methodStr)) { 1080 gotNetwork.value = network; 1081 } 1082 }); 1083 } catch (RemoteException e) { 1084 handleRemoteException(e, methodStr); 1085 } 1086 if (gotNetwork.value != null) { 1087 return getStaNetworkMockable( 1088 ifaceName, 1089 ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder())); 1090 } else { 1091 return null; 1092 } 1093 } 1094 } 1095 1096 /** See ISupplicantStaNetwork.hal for documentation */ 1097 private boolean registerCallback( 1098 ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback) { 1099 synchronized (mLock) { 1100 final String methodStr = "registerCallback"; 1101 if (iface == null) return false; 1102 try { 1103 SupplicantStatus status = iface.registerCallback(callback); 1104 return checkStatusAndLogFailure(status, methodStr); 1105 } catch (RemoteException e) { 1106 handleRemoteException(e, methodStr); 1107 return false; 1108 } 1109 } 1110 } 1111 1112 private boolean registerCallbackV1_1( 1113 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface, 1114 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback callback) { 1115 synchronized (mLock) { 1116 String methodStr = "registerCallback_1_1"; 1117 1118 if (iface == null) return false; 1119 try { 1120 SupplicantStatus status = iface.registerCallback_1_1(callback); 1121 return checkStatusAndLogFailure(status, methodStr); 1122 } catch (RemoteException e) { 1123 handleRemoteException(e, methodStr); 1124 return false; 1125 } 1126 } 1127 } 1128 1129 /** 1130 * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns 1131 * null if the call fails 1132 */ 1133 private java.util.ArrayList<Integer> listNetworks(@NonNull String ifaceName) { 1134 synchronized (mLock) { 1135 final String methodStr = "listNetworks"; 1136 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1137 if (iface == null) return null; 1138 Mutable<ArrayList<Integer>> networkIdList = new Mutable<>(); 1139 try { 1140 iface.listNetworks((SupplicantStatus status, ArrayList<Integer> networkIds) -> { 1141 if (checkStatusAndLogFailure(status, methodStr)) { 1142 networkIdList.value = networkIds; 1143 } 1144 }); 1145 } catch (RemoteException e) { 1146 handleRemoteException(e, methodStr); 1147 } 1148 return networkIdList.value; 1149 } 1150 } 1151 1152 /** 1153 * Set WPS device name. 1154 * 1155 * @param ifaceName Name of the interface. 1156 * @param name String to be set. 1157 * @return true if request is sent successfully, false otherwise. 1158 */ 1159 public boolean setWpsDeviceName(@NonNull String ifaceName, String name) { 1160 synchronized (mLock) { 1161 final String methodStr = "setWpsDeviceName"; 1162 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1163 if (iface == null) return false; 1164 try { 1165 SupplicantStatus status = iface.setWpsDeviceName(name); 1166 return checkStatusAndLogFailure(status, methodStr); 1167 } catch (RemoteException e) { 1168 handleRemoteException(e, methodStr); 1169 return false; 1170 } 1171 } 1172 } 1173 1174 /** 1175 * Set WPS device type. 1176 * 1177 * @param ifaceName Name of the interface. 1178 * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg> 1179 * @return true if request is sent successfully, false otherwise. 1180 */ 1181 public boolean setWpsDeviceType(@NonNull String ifaceName, String typeStr) { 1182 synchronized (mLock) { 1183 try { 1184 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr); 1185 if (!match.find() || match.groupCount() != 3) { 1186 Log.e(TAG, "Malformed WPS device type " + typeStr); 1187 return false; 1188 } 1189 short categ = Short.parseShort(match.group(1)); 1190 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2)); 1191 short subCateg = Short.parseShort(match.group(3)); 1192 1193 byte[] bytes = new byte[8]; 1194 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); 1195 byteBuffer.putShort(categ); 1196 byteBuffer.put(oui); 1197 byteBuffer.putShort(subCateg); 1198 return setWpsDeviceType(ifaceName, bytes); 1199 } catch (IllegalArgumentException e) { 1200 Log.e(TAG, "Illegal argument " + typeStr, e); 1201 return false; 1202 } 1203 } 1204 } 1205 1206 private boolean setWpsDeviceType(@NonNull String ifaceName, byte[/* 8 */] type) { 1207 synchronized (mLock) { 1208 final String methodStr = "setWpsDeviceType"; 1209 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1210 if (iface == null) return false; 1211 try { 1212 SupplicantStatus status = iface.setWpsDeviceType(type); 1213 return checkStatusAndLogFailure(status, methodStr); 1214 } catch (RemoteException e) { 1215 handleRemoteException(e, methodStr); 1216 return false; 1217 } 1218 } 1219 } 1220 1221 /** 1222 * Set WPS manufacturer. 1223 * 1224 * @param ifaceName Name of the interface. 1225 * @param manufacturer String to be set. 1226 * @return true if request is sent successfully, false otherwise. 1227 */ 1228 public boolean setWpsManufacturer(@NonNull String ifaceName, String manufacturer) { 1229 synchronized (mLock) { 1230 final String methodStr = "setWpsManufacturer"; 1231 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1232 if (iface == null) return false; 1233 try { 1234 SupplicantStatus status = iface.setWpsManufacturer(manufacturer); 1235 return checkStatusAndLogFailure(status, methodStr); 1236 } catch (RemoteException e) { 1237 handleRemoteException(e, methodStr); 1238 return false; 1239 } 1240 } 1241 } 1242 1243 /** 1244 * Set WPS model name. 1245 * 1246 * @param ifaceName Name of the interface. 1247 * @param modelName String to be set. 1248 * @return true if request is sent successfully, false otherwise. 1249 */ 1250 public boolean setWpsModelName(@NonNull String ifaceName, String modelName) { 1251 synchronized (mLock) { 1252 final String methodStr = "setWpsModelName"; 1253 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1254 if (iface == null) return false; 1255 try { 1256 SupplicantStatus status = iface.setWpsModelName(modelName); 1257 return checkStatusAndLogFailure(status, methodStr); 1258 } catch (RemoteException e) { 1259 handleRemoteException(e, methodStr); 1260 return false; 1261 } 1262 } 1263 } 1264 1265 /** 1266 * Set WPS model number. 1267 * 1268 * @param ifaceName Name of the interface. 1269 * @param modelNumber String to be set. 1270 * @return true if request is sent successfully, false otherwise. 1271 */ 1272 public boolean setWpsModelNumber(@NonNull String ifaceName, String modelNumber) { 1273 synchronized (mLock) { 1274 final String methodStr = "setWpsModelNumber"; 1275 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1276 if (iface == null) return false; 1277 try { 1278 SupplicantStatus status = iface.setWpsModelNumber(modelNumber); 1279 return checkStatusAndLogFailure(status, methodStr); 1280 } catch (RemoteException e) { 1281 handleRemoteException(e, methodStr); 1282 return false; 1283 } 1284 } 1285 } 1286 1287 /** 1288 * Set WPS serial number. 1289 * 1290 * @param ifaceName Name of the interface. 1291 * @param serialNumber String to be set. 1292 * @return true if request is sent successfully, false otherwise. 1293 */ 1294 public boolean setWpsSerialNumber(@NonNull String ifaceName, String serialNumber) { 1295 synchronized (mLock) { 1296 final String methodStr = "setWpsSerialNumber"; 1297 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1298 if (iface == null) return false; 1299 try { 1300 SupplicantStatus status = iface.setWpsSerialNumber(serialNumber); 1301 return checkStatusAndLogFailure(status, methodStr); 1302 } catch (RemoteException e) { 1303 handleRemoteException(e, methodStr); 1304 return false; 1305 } 1306 } 1307 } 1308 1309 /** 1310 * Set WPS config methods 1311 * 1312 * @param ifaceName Name of the interface. 1313 * @param configMethodsStr List of config methods. 1314 * @return true if request is sent successfully, false otherwise. 1315 */ 1316 public boolean setWpsConfigMethods(@NonNull String ifaceName, String configMethodsStr) { 1317 synchronized (mLock) { 1318 short configMethodsMask = 0; 1319 String[] configMethodsStrArr = configMethodsStr.split("\\s+"); 1320 for (int i = 0; i < configMethodsStrArr.length; i++) { 1321 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]); 1322 } 1323 return setWpsConfigMethods(ifaceName, configMethodsMask); 1324 } 1325 } 1326 1327 private boolean setWpsConfigMethods(@NonNull String ifaceName, short configMethods) { 1328 synchronized (mLock) { 1329 final String methodStr = "setWpsConfigMethods"; 1330 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1331 if (iface == null) return false; 1332 try { 1333 SupplicantStatus status = iface.setWpsConfigMethods(configMethods); 1334 return checkStatusAndLogFailure(status, methodStr); 1335 } catch (RemoteException e) { 1336 handleRemoteException(e, methodStr); 1337 return false; 1338 } 1339 } 1340 } 1341 1342 /** 1343 * Trigger a reassociation even if the iface is currently connected. 1344 * 1345 * @param ifaceName Name of the interface. 1346 * @return true if request is sent successfully, false otherwise. 1347 */ 1348 public boolean reassociate(@NonNull String ifaceName) { 1349 synchronized (mLock) { 1350 final String methodStr = "reassociate"; 1351 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1352 if (iface == null) return false; 1353 try { 1354 SupplicantStatus status = iface.reassociate(); 1355 return checkStatusAndLogFailure(status, methodStr); 1356 } catch (RemoteException e) { 1357 handleRemoteException(e, methodStr); 1358 return false; 1359 } 1360 } 1361 } 1362 1363 /** 1364 * Trigger a reconnection if the iface is disconnected. 1365 * 1366 * @param ifaceName Name of the interface. 1367 * @return true if request is sent successfully, false otherwise. 1368 */ 1369 public boolean reconnect(@NonNull String ifaceName) { 1370 synchronized (mLock) { 1371 final String methodStr = "reconnect"; 1372 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1373 if (iface == null) return false; 1374 try { 1375 SupplicantStatus status = iface.reconnect(); 1376 return checkStatusAndLogFailure(status, methodStr); 1377 } catch (RemoteException e) { 1378 handleRemoteException(e, methodStr); 1379 return false; 1380 } 1381 } 1382 } 1383 1384 /** 1385 * Trigger a disconnection from the currently connected network. 1386 * 1387 * @param ifaceName Name of the interface. 1388 * @return true if request is sent successfully, false otherwise. 1389 */ 1390 public boolean disconnect(@NonNull String ifaceName) { 1391 synchronized (mLock) { 1392 final String methodStr = "disconnect"; 1393 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1394 if (iface == null) return false; 1395 try { 1396 SupplicantStatus status = iface.disconnect(); 1397 return checkStatusAndLogFailure(status, methodStr); 1398 } catch (RemoteException e) { 1399 handleRemoteException(e, methodStr); 1400 return false; 1401 } 1402 } 1403 } 1404 1405 /** 1406 * Enable or disable power save mode. 1407 * 1408 * @param ifaceName Name of the interface. 1409 * @param enable true to enable, false to disable. 1410 * @return true if request is sent successfully, false otherwise. 1411 */ 1412 public boolean setPowerSave(@NonNull String ifaceName, boolean enable) { 1413 synchronized (mLock) { 1414 final String methodStr = "setPowerSave"; 1415 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1416 if (iface == null) return false; 1417 try { 1418 SupplicantStatus status = iface.setPowerSave(enable); 1419 return checkStatusAndLogFailure(status, methodStr); 1420 } catch (RemoteException e) { 1421 handleRemoteException(e, methodStr); 1422 return false; 1423 } 1424 } 1425 } 1426 1427 /** 1428 * Initiate TDLS discover with the specified AP. 1429 * 1430 * @param ifaceName Name of the interface. 1431 * @param macAddress MAC Address of the AP. 1432 * @return true if request is sent successfully, false otherwise. 1433 */ 1434 public boolean initiateTdlsDiscover(@NonNull String ifaceName, String macAddress) { 1435 synchronized (mLock) { 1436 try { 1437 return initiateTdlsDiscover( 1438 ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1439 } catch (IllegalArgumentException e) { 1440 Log.e(TAG, "Illegal argument " + macAddress, e); 1441 return false; 1442 } 1443 } 1444 } 1445 /** See ISupplicantStaIface.hal for documentation */ 1446 private boolean initiateTdlsDiscover(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1447 synchronized (mLock) { 1448 final String methodStr = "initiateTdlsDiscover"; 1449 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1450 if (iface == null) return false; 1451 try { 1452 SupplicantStatus status = iface.initiateTdlsDiscover(macAddress); 1453 return checkStatusAndLogFailure(status, methodStr); 1454 } catch (RemoteException e) { 1455 handleRemoteException(e, methodStr); 1456 return false; 1457 } 1458 } 1459 } 1460 1461 /** 1462 * Initiate TDLS setup with the specified AP. 1463 * 1464 * @param ifaceName Name of the interface. 1465 * @param macAddress MAC Address of the AP. 1466 * @return true if request is sent successfully, false otherwise. 1467 */ 1468 public boolean initiateTdlsSetup(@NonNull String ifaceName, String macAddress) { 1469 synchronized (mLock) { 1470 try { 1471 return initiateTdlsSetup(ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1472 } catch (IllegalArgumentException e) { 1473 Log.e(TAG, "Illegal argument " + macAddress, e); 1474 return false; 1475 } 1476 } 1477 } 1478 /** See ISupplicantStaIface.hal for documentation */ 1479 private boolean initiateTdlsSetup(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1480 synchronized (mLock) { 1481 final String methodStr = "initiateTdlsSetup"; 1482 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1483 if (iface == null) return false; 1484 try { 1485 SupplicantStatus status = iface.initiateTdlsSetup(macAddress); 1486 return checkStatusAndLogFailure(status, methodStr); 1487 } catch (RemoteException e) { 1488 handleRemoteException(e, methodStr); 1489 return false; 1490 } 1491 } 1492 } 1493 1494 /** 1495 * Initiate TDLS teardown with the specified AP. 1496 * @param ifaceName Name of the interface. 1497 * @param macAddress MAC Address of the AP. 1498 * @return true if request is sent successfully, false otherwise. 1499 */ 1500 public boolean initiateTdlsTeardown(@NonNull String ifaceName, String macAddress) { 1501 synchronized (mLock) { 1502 try { 1503 return initiateTdlsTeardown( 1504 ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1505 } catch (IllegalArgumentException e) { 1506 Log.e(TAG, "Illegal argument " + macAddress, e); 1507 return false; 1508 } 1509 } 1510 } 1511 1512 /** See ISupplicantStaIface.hal for documentation */ 1513 private boolean initiateTdlsTeardown(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1514 synchronized (mLock) { 1515 final String methodStr = "initiateTdlsTeardown"; 1516 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1517 if (iface == null) return false; 1518 try { 1519 SupplicantStatus status = iface.initiateTdlsTeardown(macAddress); 1520 return checkStatusAndLogFailure(status, methodStr); 1521 } catch (RemoteException e) { 1522 handleRemoteException(e, methodStr); 1523 return false; 1524 } 1525 } 1526 } 1527 1528 /** 1529 * Request the specified ANQP elements |elements| from the specified AP |bssid|. 1530 * 1531 * @param ifaceName Name of the interface. 1532 * @param bssid BSSID of the AP 1533 * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId. 1534 * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes. 1535 * @return true if request is sent successfully, false otherwise. 1536 */ 1537 public boolean initiateAnqpQuery(@NonNull String ifaceName, String bssid, 1538 ArrayList<Short> infoElements, 1539 ArrayList<Integer> hs20SubTypes) { 1540 synchronized (mLock) { 1541 try { 1542 return initiateAnqpQuery( 1543 ifaceName, 1544 NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes); 1545 } catch (IllegalArgumentException e) { 1546 Log.e(TAG, "Illegal argument " + bssid, e); 1547 return false; 1548 } 1549 } 1550 } 1551 1552 /** See ISupplicantStaIface.hal for documentation */ 1553 private boolean initiateAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress, 1554 java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) { 1555 synchronized (mLock) { 1556 final String methodStr = "initiateAnqpQuery"; 1557 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1558 if (iface == null) return false; 1559 try { 1560 SupplicantStatus status = iface.initiateAnqpQuery( 1561 macAddress, infoElements, subTypes); 1562 return checkStatusAndLogFailure(status, methodStr); 1563 } catch (RemoteException e) { 1564 handleRemoteException(e, methodStr); 1565 return false; 1566 } 1567 } 1568 } 1569 1570 /** 1571 * Request the specified ANQP ICON from the specified AP |bssid|. 1572 * 1573 * @param ifaceName Name of the interface. 1574 * @param bssid BSSID of the AP 1575 * @param fileName Name of the file to request. 1576 * @return true if request is sent successfully, false otherwise. 1577 */ 1578 public boolean initiateHs20IconQuery(@NonNull String ifaceName, String bssid, String fileName) { 1579 synchronized (mLock) { 1580 try { 1581 return initiateHs20IconQuery( 1582 ifaceName, NativeUtil.macAddressToByteArray(bssid), fileName); 1583 } catch (IllegalArgumentException e) { 1584 Log.e(TAG, "Illegal argument " + bssid, e); 1585 return false; 1586 } 1587 } 1588 } 1589 1590 /** See ISupplicantStaIface.hal for documentation */ 1591 private boolean initiateHs20IconQuery(@NonNull String ifaceName, 1592 byte[/* 6 */] macAddress, String fileName) { 1593 synchronized (mLock) { 1594 final String methodStr = "initiateHs20IconQuery"; 1595 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1596 if (iface == null) return false; 1597 try { 1598 SupplicantStatus status = iface.initiateHs20IconQuery(macAddress, fileName); 1599 return checkStatusAndLogFailure(status, methodStr); 1600 } catch (RemoteException e) { 1601 handleRemoteException(e, methodStr); 1602 return false; 1603 } 1604 } 1605 } 1606 1607 /** 1608 * Makes a callback to HIDL to getMacAddress from supplicant 1609 * 1610 * @param ifaceName Name of the interface. 1611 * @return string containing the MAC address, or null on a failed call 1612 */ 1613 public String getMacAddress(@NonNull String ifaceName) { 1614 synchronized (mLock) { 1615 final String methodStr = "getMacAddress"; 1616 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1617 if (iface == null) return null; 1618 Mutable<String> gotMac = new Mutable<>(); 1619 try { 1620 iface.getMacAddress((SupplicantStatus status, 1621 byte[/* 6 */] macAddr) -> { 1622 if (checkStatusAndLogFailure(status, methodStr)) { 1623 gotMac.value = NativeUtil.macAddressFromByteArray(macAddr); 1624 } 1625 }); 1626 } catch (RemoteException e) { 1627 handleRemoteException(e, methodStr); 1628 } 1629 return gotMac.value; 1630 } 1631 } 1632 1633 /** 1634 * Start using the added RX filters. 1635 * 1636 * @param ifaceName Name of the interface. 1637 * @return true if request is sent successfully, false otherwise. 1638 */ 1639 public boolean startRxFilter(@NonNull String ifaceName) { 1640 synchronized (mLock) { 1641 final String methodStr = "startRxFilter"; 1642 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1643 if (iface == null) return false; 1644 try { 1645 SupplicantStatus status = iface.startRxFilter(); 1646 return checkStatusAndLogFailure(status, methodStr); 1647 } catch (RemoteException e) { 1648 handleRemoteException(e, methodStr); 1649 return false; 1650 } 1651 } 1652 } 1653 1654 /** 1655 * Stop using the added RX filters. 1656 * 1657 * @param ifaceName Name of the interface. 1658 * @return true if request is sent successfully, false otherwise. 1659 */ 1660 public boolean stopRxFilter(@NonNull String ifaceName) { 1661 synchronized (mLock) { 1662 final String methodStr = "stopRxFilter"; 1663 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1664 if (iface == null) return false; 1665 try { 1666 SupplicantStatus status = iface.stopRxFilter(); 1667 return checkStatusAndLogFailure(status, methodStr); 1668 } catch (RemoteException e) { 1669 handleRemoteException(e, methodStr); 1670 return false; 1671 } 1672 } 1673 } 1674 1675 /** 1676 * Add an RX filter. 1677 * 1678 * @param ifaceName Name of the interface. 1679 * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST} 1680 * {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values. 1681 * @return true if request is sent successfully, false otherwise. 1682 */ 1683 public boolean addRxFilter(@NonNull String ifaceName, int type) { 1684 synchronized (mLock) { 1685 byte halType; 1686 switch (type) { 1687 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST: 1688 halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST; 1689 break; 1690 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST: 1691 halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST; 1692 break; 1693 default: 1694 Log.e(TAG, "Invalid Rx Filter type: " + type); 1695 return false; 1696 } 1697 return addRxFilter(ifaceName, halType); 1698 } 1699 } 1700 1701 private boolean addRxFilter(@NonNull String ifaceName, byte type) { 1702 synchronized (mLock) { 1703 final String methodStr = "addRxFilter"; 1704 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1705 if (iface == null) return false; 1706 try { 1707 SupplicantStatus status = iface.addRxFilter(type); 1708 return checkStatusAndLogFailure(status, methodStr); 1709 } catch (RemoteException e) { 1710 handleRemoteException(e, methodStr); 1711 return false; 1712 } 1713 } 1714 } 1715 1716 /** 1717 * Remove an RX filter. 1718 * 1719 * @param ifaceName Name of the interface. 1720 * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST} 1721 * {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values. 1722 * @return true if request is sent successfully, false otherwise. 1723 */ 1724 public boolean removeRxFilter(@NonNull String ifaceName, int type) { 1725 synchronized (mLock) { 1726 byte halType; 1727 switch (type) { 1728 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST: 1729 halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST; 1730 break; 1731 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST: 1732 halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST; 1733 break; 1734 default: 1735 Log.e(TAG, "Invalid Rx Filter type: " + type); 1736 return false; 1737 } 1738 return removeRxFilter(ifaceName, halType); 1739 } 1740 } 1741 1742 private boolean removeRxFilter(@NonNull String ifaceName, byte type) { 1743 synchronized (mLock) { 1744 final String methodStr = "removeRxFilter"; 1745 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1746 if (iface == null) return false; 1747 try { 1748 SupplicantStatus status = iface.removeRxFilter(type); 1749 return checkStatusAndLogFailure(status, methodStr); 1750 } catch (RemoteException e) { 1751 handleRemoteException(e, methodStr); 1752 return false; 1753 } 1754 } 1755 } 1756 1757 /** 1758 * Set Bt co existense mode. 1759 * 1760 * @param ifaceName Name of the interface. 1761 * @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 1762 * {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or 1763 * {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}. 1764 * @return true if request is sent successfully, false otherwise. 1765 */ 1766 public boolean setBtCoexistenceMode(@NonNull String ifaceName, int mode) { 1767 synchronized (mLock) { 1768 byte halMode; 1769 switch (mode) { 1770 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_ENABLED: 1771 halMode = ISupplicantStaIface.BtCoexistenceMode.ENABLED; 1772 break; 1773 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED: 1774 halMode = ISupplicantStaIface.BtCoexistenceMode.DISABLED; 1775 break; 1776 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE: 1777 halMode = ISupplicantStaIface.BtCoexistenceMode.SENSE; 1778 break; 1779 default: 1780 Log.e(TAG, "Invalid Bt Coex mode: " + mode); 1781 return false; 1782 } 1783 return setBtCoexistenceMode(ifaceName, halMode); 1784 } 1785 } 1786 1787 private boolean setBtCoexistenceMode(@NonNull String ifaceName, byte mode) { 1788 synchronized (mLock) { 1789 final String methodStr = "setBtCoexistenceMode"; 1790 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1791 if (iface == null) return false; 1792 try { 1793 SupplicantStatus status = iface.setBtCoexistenceMode(mode); 1794 return checkStatusAndLogFailure(status, methodStr); 1795 } catch (RemoteException e) { 1796 handleRemoteException(e, methodStr); 1797 return false; 1798 } 1799 } 1800 } 1801 1802 /** Enable or disable BT coexistence mode. 1803 * 1804 * @param ifaceName Name of the interface. 1805 * @param enable true to enable, false to disable. 1806 * @return true if request is sent successfully, false otherwise. 1807 */ 1808 public boolean setBtCoexistenceScanModeEnabled(@NonNull String ifaceName, boolean enable) { 1809 synchronized (mLock) { 1810 final String methodStr = "setBtCoexistenceScanModeEnabled"; 1811 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1812 if (iface == null) return false; 1813 try { 1814 SupplicantStatus status = 1815 iface.setBtCoexistenceScanModeEnabled(enable); 1816 return checkStatusAndLogFailure(status, methodStr); 1817 } catch (RemoteException e) { 1818 handleRemoteException(e, methodStr); 1819 return false; 1820 } 1821 } 1822 } 1823 1824 /** 1825 * Enable or disable suspend mode optimizations. 1826 * 1827 * @param ifaceName Name of the interface. 1828 * @param enable true to enable, false otherwise. 1829 * @return true if request is sent successfully, false otherwise. 1830 */ 1831 public boolean setSuspendModeEnabled(@NonNull String ifaceName, boolean enable) { 1832 synchronized (mLock) { 1833 final String methodStr = "setSuspendModeEnabled"; 1834 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1835 if (iface == null) return false; 1836 try { 1837 SupplicantStatus status = iface.setSuspendModeEnabled(enable); 1838 return checkStatusAndLogFailure(status, methodStr); 1839 } catch (RemoteException e) { 1840 handleRemoteException(e, methodStr); 1841 return false; 1842 } 1843 } 1844 } 1845 1846 /** 1847 * Set country code. 1848 * 1849 * @param ifaceName Name of the interface. 1850 * @param codeStr 2 byte ASCII string. For ex: US, CA. 1851 * @return true if request is sent successfully, false otherwise. 1852 */ 1853 public boolean setCountryCode(@NonNull String ifaceName, String codeStr) { 1854 synchronized (mLock) { 1855 if (TextUtils.isEmpty(codeStr)) return false; 1856 return setCountryCode(ifaceName, NativeUtil.stringToByteArray(codeStr)); 1857 } 1858 } 1859 1860 /** See ISupplicantStaIface.hal for documentation */ 1861 private boolean setCountryCode(@NonNull String ifaceName, byte[/* 2 */] code) { 1862 synchronized (mLock) { 1863 final String methodStr = "setCountryCode"; 1864 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1865 if (iface == null) return false; 1866 try { 1867 SupplicantStatus status = iface.setCountryCode(code); 1868 return checkStatusAndLogFailure(status, methodStr); 1869 } catch (RemoteException e) { 1870 handleRemoteException(e, methodStr); 1871 return false; 1872 } 1873 } 1874 } 1875 1876 /** 1877 * Start WPS pin registrar operation with the specified peer and pin. 1878 * 1879 * @param ifaceName Name of the interface. 1880 * @param bssidStr BSSID of the peer. 1881 * @param pin Pin to be used. 1882 * @return true if request is sent successfully, false otherwise. 1883 */ 1884 public boolean startWpsRegistrar(@NonNull String ifaceName, String bssidStr, String pin) { 1885 synchronized (mLock) { 1886 if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) return false; 1887 try { 1888 return startWpsRegistrar( 1889 ifaceName, NativeUtil.macAddressToByteArray(bssidStr), pin); 1890 } catch (IllegalArgumentException e) { 1891 Log.e(TAG, "Illegal argument " + bssidStr, e); 1892 return false; 1893 } 1894 } 1895 } 1896 1897 /** See ISupplicantStaIface.hal for documentation */ 1898 private boolean startWpsRegistrar(@NonNull String ifaceName, byte[/* 6 */] bssid, String pin) { 1899 synchronized (mLock) { 1900 final String methodStr = "startWpsRegistrar"; 1901 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1902 if (iface == null) return false; 1903 try { 1904 SupplicantStatus status = iface.startWpsRegistrar(bssid, pin); 1905 return checkStatusAndLogFailure(status, methodStr); 1906 } catch (RemoteException e) { 1907 handleRemoteException(e, methodStr); 1908 return false; 1909 } 1910 } 1911 } 1912 1913 /** 1914 * Start WPS pin display operation with the specified peer. 1915 * 1916 * @param ifaceName Name of the interface. 1917 * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard. 1918 * @return true if request is sent successfully, false otherwise. 1919 */ 1920 public boolean startWpsPbc(@NonNull String ifaceName, String bssidStr) { 1921 synchronized (mLock) { 1922 try { 1923 return startWpsPbc(ifaceName, NativeUtil.macAddressToByteArray(bssidStr)); 1924 } catch (IllegalArgumentException e) { 1925 Log.e(TAG, "Illegal argument " + bssidStr, e); 1926 return false; 1927 } 1928 } 1929 } 1930 1931 /** See ISupplicantStaIface.hal for documentation */ 1932 private boolean startWpsPbc(@NonNull String ifaceName, byte[/* 6 */] bssid) { 1933 synchronized (mLock) { 1934 final String methodStr = "startWpsPbc"; 1935 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1936 if (iface == null) return false; 1937 try { 1938 SupplicantStatus status = iface.startWpsPbc(bssid); 1939 return checkStatusAndLogFailure(status, methodStr); 1940 } catch (RemoteException e) { 1941 handleRemoteException(e, methodStr); 1942 return false; 1943 } 1944 } 1945 } 1946 1947 /** 1948 * Start WPS pin keypad operation with the specified pin. 1949 * 1950 * @param ifaceName Name of the interface. 1951 * @param pin Pin to be used. 1952 * @return true if request is sent successfully, false otherwise. 1953 */ 1954 public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) { 1955 if (TextUtils.isEmpty(pin)) return false; 1956 synchronized (mLock) { 1957 final String methodStr = "startWpsPinKeypad"; 1958 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1959 if (iface == null) return false; 1960 try { 1961 SupplicantStatus status = iface.startWpsPinKeypad(pin); 1962 return checkStatusAndLogFailure(status, methodStr); 1963 } catch (RemoteException e) { 1964 handleRemoteException(e, methodStr); 1965 return false; 1966 } 1967 } 1968 } 1969 1970 /** 1971 * Start WPS pin display operation with the specified peer. 1972 * 1973 * @param ifaceName Name of the interface. 1974 * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard. 1975 * @return new pin generated on success, null otherwise. 1976 */ 1977 public String startWpsPinDisplay(@NonNull String ifaceName, String bssidStr) { 1978 synchronized (mLock) { 1979 try { 1980 return startWpsPinDisplay(ifaceName, NativeUtil.macAddressToByteArray(bssidStr)); 1981 } catch (IllegalArgumentException e) { 1982 Log.e(TAG, "Illegal argument " + bssidStr, e); 1983 return null; 1984 } 1985 } 1986 } 1987 1988 /** See ISupplicantStaIface.hal for documentation */ 1989 private String startWpsPinDisplay(@NonNull String ifaceName, byte[/* 6 */] bssid) { 1990 synchronized (mLock) { 1991 final String methodStr = "startWpsPinDisplay"; 1992 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1993 if (iface == null) return null; 1994 final Mutable<String> gotPin = new Mutable<>(); 1995 try { 1996 iface.startWpsPinDisplay(bssid, 1997 (SupplicantStatus status, String pin) -> { 1998 if (checkStatusAndLogFailure(status, methodStr)) { 1999 gotPin.value = pin; 2000 } 2001 }); 2002 } catch (RemoteException e) { 2003 handleRemoteException(e, methodStr); 2004 } 2005 return gotPin.value; 2006 } 2007 } 2008 2009 /** 2010 * Cancels any ongoing WPS requests. 2011 * 2012 * @param ifaceName Name of the interface. 2013 * @return true if request is sent successfully, false otherwise. 2014 */ 2015 public boolean cancelWps(@NonNull String ifaceName) { 2016 synchronized (mLock) { 2017 final String methodStr = "cancelWps"; 2018 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2019 if (iface == null) return false; 2020 try { 2021 SupplicantStatus status = iface.cancelWps(); 2022 return checkStatusAndLogFailure(status, methodStr); 2023 } catch (RemoteException e) { 2024 handleRemoteException(e, methodStr); 2025 return false; 2026 } 2027 } 2028 } 2029 2030 /** 2031 * Sets whether to use external sim for SIM/USIM processing. 2032 * 2033 * @param ifaceName Name of the interface. 2034 * @param useExternalSim true to enable, false otherwise. 2035 * @return true if request is sent successfully, false otherwise. 2036 */ 2037 public boolean setExternalSim(@NonNull String ifaceName, boolean useExternalSim) { 2038 synchronized (mLock) { 2039 final String methodStr = "setExternalSim"; 2040 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2041 if (iface == null) return false; 2042 try { 2043 SupplicantStatus status = iface.setExternalSim(useExternalSim); 2044 return checkStatusAndLogFailure(status, methodStr); 2045 } catch (RemoteException e) { 2046 handleRemoteException(e, methodStr); 2047 return false; 2048 } 2049 } 2050 } 2051 2052 /** See ISupplicant.hal for documentation */ 2053 public boolean enableAutoReconnect(@NonNull String ifaceName, boolean enable) { 2054 synchronized (mLock) { 2055 final String methodStr = "enableAutoReconnect"; 2056 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2057 if (iface == null) return false; 2058 try { 2059 SupplicantStatus status = iface.enableAutoReconnect(enable); 2060 return checkStatusAndLogFailure(status, methodStr); 2061 } catch (RemoteException e) { 2062 handleRemoteException(e, methodStr); 2063 return false; 2064 } 2065 } 2066 } 2067 2068 /** 2069 * Set the debug log level for wpa_supplicant 2070 * 2071 * @param turnOnVerbose Whether to turn on verbose logging or not. 2072 * @return true if request is sent successfully, false otherwise. 2073 */ 2074 public boolean setLogLevel(boolean turnOnVerbose) { 2075 synchronized (mLock) { 2076 int logLevel = turnOnVerbose 2077 ? ISupplicant.DebugLevel.DEBUG 2078 : ISupplicant.DebugLevel.INFO; 2079 return setDebugParams(logLevel, false, false); 2080 } 2081 } 2082 2083 /** See ISupplicant.hal for documentation */ 2084 private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) { 2085 synchronized (mLock) { 2086 final String methodStr = "setDebugParams"; 2087 if (!checkSupplicantAndLogFailure(methodStr)) return false; 2088 try { 2089 SupplicantStatus status = 2090 mISupplicant.setDebugParams(level, showTimestamp, showKeys); 2091 return checkStatusAndLogFailure(status, methodStr); 2092 } catch (RemoteException e) { 2093 handleRemoteException(e, methodStr); 2094 return false; 2095 } 2096 } 2097 } 2098 2099 /** 2100 * Set concurrency priority between P2P & STA operations. 2101 * 2102 * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations, 2103 * false otherwise. 2104 * @return true if request is sent successfully, false otherwise. 2105 */ 2106 public boolean setConcurrencyPriority(boolean isStaHigherPriority) { 2107 synchronized (mLock) { 2108 if (isStaHigherPriority) { 2109 return setConcurrencyPriority(IfaceType.STA); 2110 } else { 2111 return setConcurrencyPriority(IfaceType.P2P); 2112 } 2113 } 2114 } 2115 2116 /** See ISupplicant.hal for documentation */ 2117 private boolean setConcurrencyPriority(int type) { 2118 synchronized (mLock) { 2119 final String methodStr = "setConcurrencyPriority"; 2120 if (!checkSupplicantAndLogFailure(methodStr)) return false; 2121 try { 2122 SupplicantStatus status = mISupplicant.setConcurrencyPriority(type); 2123 return checkStatusAndLogFailure(status, methodStr); 2124 } catch (RemoteException e) { 2125 handleRemoteException(e, methodStr); 2126 return false; 2127 } 2128 } 2129 } 2130 2131 /** 2132 * Returns false if Supplicant is null, and logs failure to call methodStr 2133 */ 2134 private boolean checkSupplicantAndLogFailure(final String methodStr) { 2135 synchronized (mLock) { 2136 if (mISupplicant == null) { 2137 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null"); 2138 return false; 2139 } 2140 return true; 2141 } 2142 } 2143 2144 /** 2145 * Returns false if SupplicantStaIface is null, and logs failure to call methodStr 2146 */ 2147 private ISupplicantStaIface checkSupplicantStaIfaceAndLogFailure( 2148 @NonNull String ifaceName, final String methodStr) { 2149 synchronized (mLock) { 2150 ISupplicantStaIface iface = getStaIface(ifaceName); 2151 if (iface == null) { 2152 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null"); 2153 return null; 2154 } 2155 return iface; 2156 } 2157 } 2158 2159 /** 2160 * Returns false if SupplicantStaNetwork is null, and logs failure to call methodStr 2161 */ 2162 private SupplicantStaNetworkHal checkSupplicantStaNetworkAndLogFailure( 2163 @NonNull String ifaceName, final String methodStr) { 2164 synchronized (mLock) { 2165 SupplicantStaNetworkHal networkHal = getCurrentNetworkRemoteHandle(ifaceName); 2166 if (networkHal == null) { 2167 Log.e(TAG, "Can't call " + methodStr + ", SupplicantStaNetwork is null"); 2168 return null; 2169 } 2170 return networkHal; 2171 } 2172 } 2173 2174 /** 2175 * Returns true if provided status code is SUCCESS, logs debug message and returns false 2176 * otherwise 2177 */ 2178 private boolean checkStatusAndLogFailure(SupplicantStatus status, 2179 final String methodStr) { 2180 synchronized (mLock) { 2181 if (status.code != SupplicantStatusCode.SUCCESS) { 2182 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed: " + status); 2183 return false; 2184 } else { 2185 if (mVerboseLoggingEnabled) { 2186 Log.d(TAG, "ISupplicantStaIface." + methodStr + " succeeded"); 2187 } 2188 return true; 2189 } 2190 } 2191 } 2192 2193 /** 2194 * Helper function to log callbacks. 2195 */ 2196 private void logCallback(final String methodStr) { 2197 synchronized (mLock) { 2198 if (mVerboseLoggingEnabled) { 2199 Log.d(TAG, "ISupplicantStaIfaceCallback." + methodStr + " received"); 2200 } 2201 } 2202 } 2203 2204 2205 private void handleRemoteException(RemoteException e, String methodStr) { 2206 synchronized (mLock) { 2207 clearState(); 2208 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e); 2209 } 2210 } 2211 2212 /** 2213 * Converts the Wps config method string to the equivalent enum value. 2214 */ 2215 private static short stringToWpsConfigMethod(String configMethod) { 2216 switch (configMethod) { 2217 case "usba": 2218 return WpsConfigMethods.USBA; 2219 case "ethernet": 2220 return WpsConfigMethods.ETHERNET; 2221 case "label": 2222 return WpsConfigMethods.LABEL; 2223 case "display": 2224 return WpsConfigMethods.DISPLAY; 2225 case "int_nfc_token": 2226 return WpsConfigMethods.INT_NFC_TOKEN; 2227 case "ext_nfc_token": 2228 return WpsConfigMethods.EXT_NFC_TOKEN; 2229 case "nfc_interface": 2230 return WpsConfigMethods.NFC_INTERFACE; 2231 case "push_button": 2232 return WpsConfigMethods.PUSHBUTTON; 2233 case "keypad": 2234 return WpsConfigMethods.KEYPAD; 2235 case "virtual_push_button": 2236 return WpsConfigMethods.VIRT_PUSHBUTTON; 2237 case "physical_push_button": 2238 return WpsConfigMethods.PHY_PUSHBUTTON; 2239 case "p2ps": 2240 return WpsConfigMethods.P2PS; 2241 case "virtual_display": 2242 return WpsConfigMethods.VIRT_DISPLAY; 2243 case "physical_display": 2244 return WpsConfigMethods.PHY_DISPLAY; 2245 default: 2246 throw new IllegalArgumentException( 2247 "Invalid WPS config method: " + configMethod); 2248 } 2249 } 2250 2251 /** 2252 * Converts the supplicant state received from HIDL to the equivalent framework state. 2253 */ 2254 private static SupplicantState supplicantHidlStateToFrameworkState(int state) { 2255 switch (state) { 2256 case ISupplicantStaIfaceCallback.State.DISCONNECTED: 2257 return SupplicantState.DISCONNECTED; 2258 case ISupplicantStaIfaceCallback.State.IFACE_DISABLED: 2259 return SupplicantState.INTERFACE_DISABLED; 2260 case ISupplicantStaIfaceCallback.State.INACTIVE: 2261 return SupplicantState.INACTIVE; 2262 case ISupplicantStaIfaceCallback.State.SCANNING: 2263 return SupplicantState.SCANNING; 2264 case ISupplicantStaIfaceCallback.State.AUTHENTICATING: 2265 return SupplicantState.AUTHENTICATING; 2266 case ISupplicantStaIfaceCallback.State.ASSOCIATING: 2267 return SupplicantState.ASSOCIATING; 2268 case ISupplicantStaIfaceCallback.State.ASSOCIATED: 2269 return SupplicantState.ASSOCIATED; 2270 case ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE: 2271 return SupplicantState.FOUR_WAY_HANDSHAKE; 2272 case ISupplicantStaIfaceCallback.State.GROUP_HANDSHAKE: 2273 return SupplicantState.GROUP_HANDSHAKE; 2274 case ISupplicantStaIfaceCallback.State.COMPLETED: 2275 return SupplicantState.COMPLETED; 2276 default: 2277 throw new IllegalArgumentException("Invalid state: " + state); 2278 } 2279 } 2280 2281 private class SupplicantStaIfaceHalCallback extends ISupplicantStaIfaceCallback.Stub { 2282 private String mIfaceName; 2283 private boolean mStateIsFourway = false; // Used to help check for PSK password mismatch 2284 2285 SupplicantStaIfaceHalCallback(@NonNull String ifaceName) { 2286 mIfaceName = ifaceName; 2287 } 2288 2289 /** 2290 * Parses the provided payload into an ANQP element. 2291 * 2292 * @param infoID Element type. 2293 * @param payload Raw payload bytes. 2294 * @return AnqpElement instance on success, null on failure. 2295 */ 2296 private ANQPElement parseAnqpElement(Constants.ANQPElementType infoID, 2297 ArrayList<Byte> payload) { 2298 synchronized (mLock) { 2299 try { 2300 return Constants.getANQPElementID(infoID) != null 2301 ? ANQPParser.parseElement( 2302 infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload))) 2303 : ANQPParser.parseHS20Element( 2304 infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload))); 2305 } catch (IOException | BufferUnderflowException e) { 2306 Log.e(TAG, "Failed parsing ANQP element payload: " + infoID, e); 2307 return null; 2308 } 2309 } 2310 } 2311 2312 /** 2313 * Parse the ANQP element data and add to the provided elements map if successful. 2314 * 2315 * @param elementsMap Map to add the parsed out element to. 2316 * @param infoID Element type. 2317 * @param payload Raw payload bytes. 2318 */ 2319 private void addAnqpElementToMap(Map<Constants.ANQPElementType, ANQPElement> elementsMap, 2320 Constants.ANQPElementType infoID, 2321 ArrayList<Byte> payload) { 2322 synchronized (mLock) { 2323 if (payload == null || payload.isEmpty()) return; 2324 ANQPElement element = parseAnqpElement(infoID, payload); 2325 if (element != null) { 2326 elementsMap.put(infoID, element); 2327 } 2328 } 2329 } 2330 2331 @Override 2332 public void onNetworkAdded(int id) { 2333 synchronized (mLock) { 2334 logCallback("onNetworkAdded"); 2335 } 2336 } 2337 2338 @Override 2339 public void onNetworkRemoved(int id) { 2340 synchronized (mLock) { 2341 logCallback("onNetworkRemoved"); 2342 } 2343 } 2344 2345 @Override 2346 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id, 2347 ArrayList<Byte> ssid) { 2348 synchronized (mLock) { 2349 logCallback("onStateChanged"); 2350 SupplicantState newSupplicantState = supplicantHidlStateToFrameworkState(newState); 2351 WifiSsid wifiSsid = 2352 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid)); 2353 String bssidStr = NativeUtil.macAddressFromByteArray(bssid); 2354 mStateIsFourway = (newState == ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE); 2355 if (newSupplicantState == SupplicantState.COMPLETED) { 2356 mWifiMonitor.broadcastNetworkConnectionEvent( 2357 mIfaceName, getCurrentNetworkId(mIfaceName), bssidStr); 2358 } 2359 mWifiMonitor.broadcastSupplicantStateChangeEvent( 2360 mIfaceName, getCurrentNetworkId(mIfaceName), wifiSsid, 2361 bssidStr, newSupplicantState); 2362 } 2363 } 2364 2365 @Override 2366 public void onAnqpQueryDone(byte[/* 6 */] bssid, 2367 ISupplicantStaIfaceCallback.AnqpData data, 2368 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) { 2369 synchronized (mLock) { 2370 logCallback("onAnqpQueryDone"); 2371 Map<Constants.ANQPElementType, ANQPElement> elementsMap = new HashMap<>(); 2372 addAnqpElementToMap(elementsMap, ANQPVenueName, data.venueName); 2373 addAnqpElementToMap(elementsMap, ANQPRoamingConsortium, data.roamingConsortium); 2374 addAnqpElementToMap( 2375 elementsMap, ANQPIPAddrAvailability, data.ipAddrTypeAvailability); 2376 addAnqpElementToMap(elementsMap, ANQPNAIRealm, data.naiRealm); 2377 addAnqpElementToMap(elementsMap, ANQP3GPPNetwork, data.anqp3gppCellularNetwork); 2378 addAnqpElementToMap(elementsMap, ANQPDomName, data.domainName); 2379 addAnqpElementToMap(elementsMap, HSFriendlyName, hs20Data.operatorFriendlyName); 2380 addAnqpElementToMap(elementsMap, HSWANMetrics, hs20Data.wanMetrics); 2381 addAnqpElementToMap(elementsMap, HSConnCapability, hs20Data.connectionCapability); 2382 addAnqpElementToMap(elementsMap, HSOSUProviders, hs20Data.osuProvidersList); 2383 mWifiMonitor.broadcastAnqpDoneEvent( 2384 mIfaceName, new AnqpEvent(NativeUtil.macAddressToLong(bssid), elementsMap)); 2385 } 2386 } 2387 2388 @Override 2389 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName, 2390 ArrayList<Byte> data) { 2391 synchronized (mLock) { 2392 logCallback("onHs20IconQueryDone"); 2393 mWifiMonitor.broadcastIconDoneEvent( 2394 mIfaceName, 2395 new IconEvent(NativeUtil.macAddressToLong(bssid), fileName, data.size(), 2396 NativeUtil.byteArrayFromArrayList(data))); 2397 } 2398 } 2399 2400 @Override 2401 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, byte osuMethod, String url) { 2402 synchronized (mLock) { 2403 logCallback("onHs20SubscriptionRemediation"); 2404 mWifiMonitor.broadcastWnmEvent( 2405 mIfaceName, 2406 new WnmData(NativeUtil.macAddressToLong(bssid), url, osuMethod)); 2407 } 2408 } 2409 2410 @Override 2411 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode, 2412 int reAuthDelayInSec, String url) { 2413 synchronized (mLock) { 2414 logCallback("onHs20DeauthImminentNotice"); 2415 mWifiMonitor.broadcastWnmEvent( 2416 mIfaceName, 2417 new WnmData(NativeUtil.macAddressToLong(bssid), url, 2418 reasonCode == WnmData.ESS, reAuthDelayInSec)); 2419 } 2420 } 2421 2422 @Override 2423 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, int reasonCode) { 2424 synchronized (mLock) { 2425 logCallback("onDisconnected"); 2426 if (mVerboseLoggingEnabled) { 2427 Log.e(TAG, "onDisconnected 4way=" + mStateIsFourway 2428 + " locallyGenerated=" + locallyGenerated 2429 + " reasonCode=" + reasonCode); 2430 } 2431 if (mStateIsFourway 2432 && (!locallyGenerated || reasonCode != ReasonCode.IE_IN_4WAY_DIFFERS)) { 2433 mWifiMonitor.broadcastAuthenticationFailureEvent( 2434 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD, -1); 2435 } 2436 mWifiMonitor.broadcastNetworkDisconnectionEvent( 2437 mIfaceName, locallyGenerated ? 1 : 0, reasonCode, 2438 NativeUtil.macAddressFromByteArray(bssid)); 2439 } 2440 } 2441 2442 @Override 2443 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode, boolean timedOut) { 2444 synchronized (mLock) { 2445 logCallback("onAssociationRejected"); 2446 mWifiMonitor.broadcastAssociationRejectionEvent(mIfaceName, statusCode, timedOut, 2447 NativeUtil.macAddressFromByteArray(bssid)); 2448 } 2449 } 2450 2451 @Override 2452 public void onAuthenticationTimeout(byte[/* 6 */] bssid) { 2453 synchronized (mLock) { 2454 logCallback("onAuthenticationTimeout"); 2455 mWifiMonitor.broadcastAuthenticationFailureEvent( 2456 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_TIMEOUT, -1); 2457 } 2458 } 2459 2460 @Override 2461 public void onBssidChanged(byte reason, byte[/* 6 */] bssid) { 2462 synchronized (mLock) { 2463 logCallback("onBssidChanged"); 2464 if (reason == BssidChangeReason.ASSOC_START) { 2465 mWifiMonitor.broadcastTargetBssidEvent( 2466 mIfaceName, NativeUtil.macAddressFromByteArray(bssid)); 2467 } else if (reason == BssidChangeReason.ASSOC_COMPLETE) { 2468 mWifiMonitor.broadcastAssociatedBssidEvent( 2469 mIfaceName, NativeUtil.macAddressFromByteArray(bssid)); 2470 } 2471 } 2472 } 2473 2474 @Override 2475 public void onEapFailure() { 2476 synchronized (mLock) { 2477 logCallback("onEapFailure"); 2478 mWifiMonitor.broadcastAuthenticationFailureEvent( 2479 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE, -1); 2480 } 2481 } 2482 2483 @Override 2484 public void onWpsEventSuccess() { 2485 logCallback("onWpsEventSuccess"); 2486 synchronized (mLock) { 2487 mWifiMonitor.broadcastWpsSuccessEvent(mIfaceName); 2488 } 2489 } 2490 2491 @Override 2492 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) { 2493 synchronized (mLock) { 2494 logCallback("onWpsEventFail"); 2495 if (configError == WpsConfigError.MSG_TIMEOUT 2496 && errorInd == WpsErrorIndication.NO_ERROR) { 2497 mWifiMonitor.broadcastWpsTimeoutEvent(mIfaceName); 2498 } else { 2499 mWifiMonitor.broadcastWpsFailEvent(mIfaceName, configError, errorInd); 2500 } 2501 } 2502 } 2503 2504 @Override 2505 public void onWpsEventPbcOverlap() { 2506 synchronized (mLock) { 2507 logCallback("onWpsEventPbcOverlap"); 2508 mWifiMonitor.broadcastWpsOverlapEvent(mIfaceName); 2509 } 2510 } 2511 2512 @Override 2513 public void onExtRadioWorkStart(int id) { 2514 synchronized (mLock) { 2515 logCallback("onExtRadioWorkStart"); 2516 } 2517 } 2518 2519 @Override 2520 public void onExtRadioWorkTimeout(int id) { 2521 synchronized (mLock) { 2522 logCallback("onExtRadioWorkTimeout"); 2523 } 2524 } 2525 } 2526 2527 private class SupplicantStaIfaceHalCallbackV1_1 extends 2528 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback.Stub { 2529 private String mIfaceName; 2530 private SupplicantStaIfaceHalCallback mCallbackV1_0; 2531 2532 SupplicantStaIfaceHalCallbackV1_1(@NonNull String ifaceName, 2533 @NonNull SupplicantStaIfaceHalCallback callback) { 2534 mIfaceName = ifaceName; 2535 mCallbackV1_0 = callback; 2536 } 2537 2538 @Override 2539 public void onNetworkAdded(int id) { 2540 mCallbackV1_0.onNetworkAdded(id); 2541 } 2542 2543 @Override 2544 public void onNetworkRemoved(int id) { 2545 mCallbackV1_0.onNetworkRemoved(id); 2546 } 2547 2548 @Override 2549 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id, 2550 ArrayList<Byte> ssid) { 2551 mCallbackV1_0.onStateChanged(newState, bssid, id, ssid); 2552 } 2553 2554 @Override 2555 public void onAnqpQueryDone(byte[/* 6 */] bssid, 2556 ISupplicantStaIfaceCallback.AnqpData data, 2557 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) { 2558 mCallbackV1_0.onAnqpQueryDone(bssid, data, hs20Data); 2559 } 2560 2561 @Override 2562 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName, 2563 ArrayList<Byte> data) { 2564 mCallbackV1_0.onHs20IconQueryDone(bssid, fileName, data); 2565 } 2566 2567 @Override 2568 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, 2569 byte osuMethod, String url) { 2570 mCallbackV1_0.onHs20SubscriptionRemediation(bssid, osuMethod, url); 2571 } 2572 2573 @Override 2574 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode, 2575 int reAuthDelayInSec, String url) { 2576 mCallbackV1_0.onHs20DeauthImminentNotice(bssid, reasonCode, reAuthDelayInSec, url); 2577 } 2578 2579 @Override 2580 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, 2581 int reasonCode) { 2582 mCallbackV1_0.onDisconnected(bssid, locallyGenerated, reasonCode); 2583 } 2584 2585 @Override 2586 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode, 2587 boolean timedOut) { 2588 mCallbackV1_0.onAssociationRejected(bssid, statusCode, timedOut); 2589 } 2590 2591 @Override 2592 public void onAuthenticationTimeout(byte[/* 6 */] bssid) { 2593 mCallbackV1_0.onAuthenticationTimeout(bssid); 2594 } 2595 2596 @Override 2597 public void onBssidChanged(byte reason, byte[/* 6 */] bssid) { 2598 mCallbackV1_0.onBssidChanged(reason, bssid); 2599 } 2600 2601 @Override 2602 public void onEapFailure() { 2603 mCallbackV1_0.onEapFailure(); 2604 } 2605 2606 @Override 2607 public void onEapFailure_1_1(int code) { 2608 synchronized (mLock) { 2609 logCallback("onEapFailure_1_1"); 2610 mWifiMonitor.broadcastAuthenticationFailureEvent( 2611 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE, code); 2612 } 2613 } 2614 2615 @Override 2616 public void onWpsEventSuccess() { 2617 mCallbackV1_0.onWpsEventSuccess(); 2618 } 2619 2620 @Override 2621 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) { 2622 mCallbackV1_0.onWpsEventFail(bssid, configError, errorInd); 2623 } 2624 2625 @Override 2626 public void onWpsEventPbcOverlap() { 2627 mCallbackV1_0.onWpsEventPbcOverlap(); 2628 } 2629 2630 @Override 2631 public void onExtRadioWorkStart(int id) { 2632 mCallbackV1_0.onExtRadioWorkStart(id); 2633 } 2634 2635 @Override 2636 public void onExtRadioWorkTimeout(int id) { 2637 mCallbackV1_0.onExtRadioWorkTimeout(id); 2638 } 2639 } 2640 2641 private static void logd(String s) { 2642 Log.d(TAG, s); 2643 } 2644 2645 private static void logi(String s) { 2646 Log.i(TAG, s); 2647 } 2648 2649 private static void loge(String s) { 2650 Log.e(TAG, s); 2651 } 2652} 2653