SupplicantStaIfaceHal.java revision 511c6a204fefd7d295cb3728e6d4665106a29ae7
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.content.Context; 30import android.hardware.wifi.supplicant.V1_0.ISupplicant; 31import android.hardware.wifi.supplicant.V1_0.ISupplicantIface; 32import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork; 33import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface; 34import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback; 35import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork; 36import android.hardware.wifi.supplicant.V1_0.IfaceType; 37import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; 38import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; 39import android.hardware.wifi.supplicant.V1_0.WpsConfigMethods; 40import android.hidl.manager.V1_0.IServiceManager; 41import android.hidl.manager.V1_0.IServiceNotification; 42import android.net.IpConfiguration; 43import android.net.wifi.SupplicantState; 44import android.net.wifi.WifiConfiguration; 45import android.net.wifi.WifiSsid; 46import android.os.RemoteException; 47import android.util.Log; 48import android.util.SparseArray; 49 50import com.android.server.wifi.hotspot2.AnqpEvent; 51import com.android.server.wifi.hotspot2.IconEvent; 52import com.android.server.wifi.hotspot2.WnmData; 53import com.android.server.wifi.hotspot2.anqp.ANQPElement; 54import com.android.server.wifi.hotspot2.anqp.ANQPParser; 55import com.android.server.wifi.hotspot2.anqp.Constants; 56import com.android.server.wifi.util.NativeUtil; 57 58import java.io.IOException; 59import java.nio.BufferUnderflowException; 60import java.nio.ByteBuffer; 61import java.nio.ByteOrder; 62import java.util.ArrayList; 63import java.util.HashMap; 64import java.util.List; 65import java.util.Map; 66import java.util.regex.Matcher; 67import java.util.regex.Pattern; 68 69/** 70 * Hal calls for bring up/shut down of the supplicant daemon and for 71 * sending requests to the supplicant daemon 72 */ 73public class SupplicantStaIfaceHal { 74 private static final String TAG = "SupplicantStaIfaceHal"; 75 private static final String SERVICE_MANAGER_NAME = "manager"; 76 /** 77 * Regex pattern for extracting the wps device type bytes. 78 * Matches a strings like the following: "<categ>-<OUI>-<subcateg>"; 79 */ 80 private static final Pattern WPS_DEVICE_TYPE_PATTERN = 81 Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$"); 82 83 private boolean mVerboseLoggingEnabled = false; 84 private IServiceManager mIServiceManager = null; 85 // Supplicant HAL interface objects 86 private ISupplicant mISupplicant; 87 private ISupplicantStaIface mISupplicantStaIface; 88 private String mIfaceName; 89 // Currently configured network in wpa_supplicant 90 private SupplicantStaNetworkHal mCurrentNetwork; 91 // Currently configured network's framework network Id. 92 private int mFrameworkNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 93 private final Object mLock = new Object(); 94 private final Context mContext; 95 private final WifiMonitor mWifiMonitor; 96 97 public SupplicantStaIfaceHal(Context context, WifiMonitor monitor) { 98 mContext = context; 99 mWifiMonitor = monitor; 100 } 101 102 /** 103 * Enable/Disable verbose logging. 104 * 105 * @param enable true to enable, false to disable. 106 */ 107 void enableVerboseLogging(boolean enable) { 108 mVerboseLoggingEnabled = enable; 109 } 110 111 /** 112 * Registers a service notification for the ISupplicant service, which triggers intialization of 113 * the ISupplicantStaIface 114 * @return true if the service notification was successfully registered 115 */ 116 public boolean initialize() { 117 if (mVerboseLoggingEnabled) Log.i(TAG, "Registering ISupplicant service ready callback."); 118 synchronized (mLock) { 119 mISupplicant = null; 120 mISupplicantStaIface = null; 121 if (mIServiceManager != null) { 122 // Already have an IServiceManager and serviceNotification registered, don't 123 // don't register another. 124 return true; 125 } 126 try { 127 mIServiceManager = getServiceManagerMockable(); 128 if (mIServiceManager == null) { 129 Log.e(TAG, "Failed to get HIDL Service Manager"); 130 return false; 131 } 132 if (!mIServiceManager.linkToDeath(cookie -> { 133 Log.wtf(TAG, "IServiceManager died: cookie=" + cookie); 134 synchronized (mLock) { 135 supplicantServiceDiedHandler(); 136 mIServiceManager = null; // Will need to register a new ServiceNotification 137 } 138 }, 0)) { 139 Log.wtf(TAG, "Error on linkToDeath on IServiceManager"); 140 supplicantServiceDiedHandler(); 141 mIServiceManager = null; // Will need to register a new ServiceNotification 142 return false; 143 } 144 IServiceNotification serviceNotificationCb = new IServiceNotification.Stub() { 145 public void onRegistration(String fqName, String name, boolean preexisting) { 146 synchronized (mLock) { 147 if (mVerboseLoggingEnabled) { 148 Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName 149 + ", " + name + " preexisting=" + preexisting); 150 } 151 if (!initSupplicantService() || !initSupplicantStaIface()) { 152 Log.e(TAG, "initalizing ISupplicantIfaces failed."); 153 supplicantServiceDiedHandler(); 154 } else { 155 Log.i(TAG, "Completed initialization of ISupplicant interfaces."); 156 } 157 } 158 } 159 }; 160 /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it 161 exists */ 162 if (!mIServiceManager.registerForNotifications(ISupplicant.kInterfaceName, 163 "", serviceNotificationCb)) { 164 Log.e(TAG, "Failed to register for notifications to " 165 + ISupplicant.kInterfaceName); 166 mIServiceManager = null; // Will need to register a new ServiceNotification 167 return false; 168 } 169 } catch (RemoteException e) { 170 Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: " 171 + e); 172 supplicantServiceDiedHandler(); 173 } 174 return true; 175 } 176 } 177 178 private boolean initSupplicantService() { 179 synchronized (mLock) { 180 try { 181 mISupplicant = getSupplicantMockable(); 182 } catch (RemoteException e) { 183 Log.e(TAG, "ISupplicant.getService exception: " + e); 184 return false; 185 } 186 if (mISupplicant == null) { 187 Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup"); 188 return false; 189 } 190 } 191 return true; 192 } 193 194 private boolean initSupplicantStaIface() { 195 synchronized (mLock) { 196 /** List all supplicant Ifaces */ 197 final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>(); 198 try { 199 mISupplicant.listInterfaces((SupplicantStatus status, 200 ArrayList<ISupplicant.IfaceInfo> ifaces) -> { 201 if (status.code != SupplicantStatusCode.SUCCESS) { 202 Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code); 203 return; 204 } 205 supplicantIfaces.addAll(ifaces); 206 }); 207 } catch (RemoteException e) { 208 Log.e(TAG, "ISupplicant.listInterfaces exception: " + e); 209 return false; 210 } 211 if (supplicantIfaces.size() == 0) { 212 Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup."); 213 return false; 214 } 215 Mutable<ISupplicantIface> supplicantIface = new Mutable<>(); 216 Mutable<String> ifaceName = new Mutable<>(); 217 for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) { 218 if (ifaceInfo.type == IfaceType.STA) { 219 try { 220 mISupplicant.getInterface(ifaceInfo, 221 (SupplicantStatus status, ISupplicantIface iface) -> { 222 if (status.code != SupplicantStatusCode.SUCCESS) { 223 Log.e(TAG, "Failed to get ISupplicantIface " + status.code); 224 return; 225 } 226 supplicantIface.value = iface; 227 }); 228 } catch (RemoteException e) { 229 Log.e(TAG, "ISupplicant.getInterface exception: " + e); 230 return false; 231 } 232 ifaceName.value = ifaceInfo.name; 233 break; 234 } 235 } 236 if (supplicantIface.value == null) { 237 Log.e(TAG, "initSupplicantStaIface got null iface"); 238 return false; 239 } 240 mISupplicantStaIface = getStaIfaceMockable(supplicantIface.value); 241 mIfaceName = ifaceName.value; 242 if (!registerCallback(new SupplicantStaIfaceHalCallback())) { 243 return false; 244 } 245 return true; 246 } 247 } 248 249 private void supplicantServiceDiedHandler() { 250 synchronized (mLock) { 251 mISupplicant = null; 252 mISupplicantStaIface = null; 253 mWifiMonitor.broadcastSupplicantDisconnectionEvent(mIfaceName); 254 } 255 } 256 257 /** 258 * Signals whether Initialization completed successfully. Only necessary for testing, is not 259 * needed to guard calls etc. 260 */ 261 public boolean isInitializationComplete() { 262 return mISupplicantStaIface != null; 263 } 264 265 /** 266 * Wrapper functions to access static HAL methods, created to be mockable in unit tests 267 */ 268 protected IServiceManager getServiceManagerMockable() throws RemoteException { 269 return IServiceManager.getService(SERVICE_MANAGER_NAME); 270 } 271 272 protected ISupplicant getSupplicantMockable() throws RemoteException { 273 return ISupplicant.getService(); 274 } 275 276 protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) { 277 return ISupplicantStaIface.asInterface(iface.asBinder()); 278 } 279 280 /** 281 * Add a network configuration to wpa_supplicant. 282 * 283 * @param config Config corresponding to the network. 284 * @return SupplicantStaNetwork of the added network in wpa_supplicant. 285 */ 286 private SupplicantStaNetworkHal addNetwork(WifiConfiguration config) { 287 logi("addSupplicantStaNetwork via HIDL"); 288 if (config == null) { 289 loge("Cannot add NULL network!"); 290 return null; 291 } 292 SupplicantStaNetworkHal network = addNetwork(); 293 if (network == null) { 294 loge("Failed to add a network!"); 295 return null; 296 } 297 if (!network.saveWifiConfiguration(config)) { 298 loge("Failed to save variables for: " + config.configKey()); 299 if (!removeAllNetworks()) { 300 loge("Failed to remove all networks on failure."); 301 } 302 return null; 303 } 304 return network; 305 } 306 307 /** 308 * Add the provided network configuration to wpa_supplicant and initiate connection to it. 309 * This method does the following: 310 * 1. Triggers disconnect command to wpa_supplicant (if |shouldDisconnect| is true). 311 * 2. Remove any existing network in wpa_supplicant. 312 * 3. Add a new network to wpa_supplicant. 313 * 4. Save the provided configuration to wpa_supplicant. 314 * 5. Select the new network in wpa_supplicant. 315 * 316 * @param config WifiConfiguration parameters for the provided network. 317 * @param shouldDisconnect whether to trigger a disconnection or not. 318 * @return {@code true} if it succeeds, {@code false} otherwise 319 */ 320 public boolean connectToNetwork(WifiConfiguration config, boolean shouldDisconnect) { 321 mFrameworkNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 322 mCurrentNetwork = null; 323 logd("connectToNetwork " + config.configKey() 324 + " (shouldDisconnect " + shouldDisconnect + ")"); 325 if (shouldDisconnect && !disconnect()) { 326 loge("Failed to trigger disconnect"); 327 return false; 328 } 329 if (!removeAllNetworks()) { 330 loge("Failed to remove existing networks"); 331 return false; 332 } 333 mCurrentNetwork = addNetwork(config); 334 if (mCurrentNetwork == null) { 335 loge("Failed to add/save network configuration: " + config.configKey()); 336 return false; 337 } 338 if (!mCurrentNetwork.select()) { 339 loge("Failed to select network configuration: " + config.configKey()); 340 return false; 341 } 342 mFrameworkNetworkId = config.networkId; 343 return true; 344 } 345 346 /** 347 * Initiates roaming to the already configured network in wpa_supplicant. If the network 348 * configuration provided does not match the already configured network, then this triggers 349 * a new connection attempt (instead of roam). 350 * 1. First check if we're attempting to connect to the same network as we currently have 351 * configured. 352 * 2. Set the new bssid for the network in wpa_supplicant. 353 * 3. Trigger reassociate command to wpa_supplicant. 354 * 355 * @param config WifiConfiguration parameters for the provided network. 356 * @return {@code true} if it succeeds, {@code false} otherwise 357 */ 358 public boolean roamToNetwork(WifiConfiguration config) { 359 if (mFrameworkNetworkId != config.networkId || mCurrentNetwork == null) { 360 Log.w(TAG, "Cannot roam to a different network, initiate new connection. " 361 + "Current network ID: " + mFrameworkNetworkId); 362 return connectToNetwork(config, false); 363 } 364 String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID(); 365 logd("roamToNetwork" + config.configKey() + " (bssid " + bssid + ")"); 366 if (!mCurrentNetwork.setBssid(bssid)) { 367 loge("Failed to set new bssid on network: " + config.configKey()); 368 return false; 369 } 370 if (!reassociate()) { 371 loge("Failed to trigger reassociate"); 372 return false; 373 } 374 return true; 375 } 376 377 /** 378 * Load all the configured networks from wpa_supplicant. 379 * 380 * @param configs Map of configuration key to configuration objects corresponding to all 381 * the networks. 382 * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf 383 * @return true if succeeds, false otherwise. 384 */ 385 public boolean loadNetworks(Map<String, WifiConfiguration> configs, 386 SparseArray<Map<String, String>> networkExtras) { 387 List<Integer> networkIds = listNetworks(); 388 if (networkIds == null) { 389 Log.e(TAG, "Failed to list networks"); 390 return false; 391 } 392 for (Integer networkId : networkIds) { 393 SupplicantStaNetworkHal network = getNetwork(networkId); 394 if (network == null) { 395 Log.e(TAG, "Failed to get network with ID: " + networkId); 396 return false; 397 } 398 WifiConfiguration config = new WifiConfiguration(); 399 Map<String, String> networkExtra = new HashMap<>(); 400 if (!network.loadWifiConfiguration(config, networkExtra)) { 401 Log.e(TAG, "Failed to load wifi configuration for network with ID: " + networkId); 402 return false; 403 } 404 // Set the default IP assignments. 405 config.setIpAssignment(IpConfiguration.IpAssignment.DHCP); 406 config.setProxySettings(IpConfiguration.ProxySettings.NONE); 407 408 networkExtras.put(networkId, networkExtra); 409 String configKey = networkExtra.get(SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY); 410 final WifiConfiguration duplicateConfig = configs.put(configKey, config); 411 if (duplicateConfig != null) { 412 // The network is already known. Overwrite the duplicate entry. 413 Log.i(TAG, "Replacing duplicate network: " + duplicateConfig.networkId); 414 removeNetwork(duplicateConfig.networkId); 415 networkExtras.remove(duplicateConfig.networkId); 416 } 417 } 418 return true; 419 } 420 421 /** 422 * Remove all networks from supplicant 423 */ 424 public boolean removeAllNetworks() { 425 synchronized (mLock) { 426 ArrayList<Integer> networks = listNetworks(); 427 if (networks == null) { 428 Log.e(TAG, "removeAllNetworks failed, got null networks"); 429 return false; 430 } 431 for (int id : networks) { 432 if (!removeNetwork(id)) { 433 Log.e(TAG, "removeAllNetworks failed to remove network: " + id); 434 return false; 435 } 436 } 437 } 438 return true; 439 } 440 441 /** 442 * Set the currently configured network's bssid. 443 * 444 * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX" 445 * @return true if succeeds, false otherwise. 446 */ 447 public boolean setCurrentNetworkBssid(String bssidStr) { 448 if (mCurrentNetwork == null) return false; 449 return mCurrentNetwork.setBssid(bssidStr); 450 } 451 452 /** 453 * Get the currently configured network's WPS NFC token. 454 * 455 * @return Hex string corresponding to the WPS NFC token. 456 */ 457 public String getCurrentNetworkWpsNfcConfigurationToken() { 458 if (mCurrentNetwork == null) return null; 459 return mCurrentNetwork.getWpsNfcConfigurationToken(); 460 } 461 462 /** 463 * Send the eap identity response for the currently configured network. 464 * 465 * @param identityStr String to send. 466 * @return true if succeeds, false otherwise. 467 */ 468 public boolean sendCurrentNetworkEapIdentityResponse(String identityStr) { 469 if (mCurrentNetwork == null) return false; 470 return mCurrentNetwork.sendNetworkEapIdentityResponse(identityStr); 471 } 472 473 /** 474 * Send the eap sim gsm auth response for the currently configured network. 475 * 476 * @param paramsStr String to send. 477 * @return true if succeeds, false otherwise. 478 */ 479 public boolean sendCurrentNetworkEapSimGsmAuthResponse(String paramsStr) { 480 if (mCurrentNetwork == null) return false; 481 return mCurrentNetwork.sendNetworkEapSimGsmAuthResponse(paramsStr); 482 } 483 484 /** 485 * Send the eap sim gsm auth failure for the currently configured network. 486 * 487 * @return true if succeeds, false otherwise. 488 */ 489 public boolean sendCurrentNetworkEapSimGsmAuthFailure() { 490 if (mCurrentNetwork == null) return false; 491 return mCurrentNetwork.sendNetworkEapSimGsmAuthFailure(); 492 } 493 494 /** 495 * Send the eap sim umts auth response for the currently configured network. 496 * 497 * @param paramsStr String to send. 498 * @return true if succeeds, false otherwise. 499 */ 500 public boolean sendCurrentNetworkEapSimUmtsAuthResponse(String paramsStr) { 501 if (mCurrentNetwork == null) return false; 502 return mCurrentNetwork.sendNetworkEapSimUmtsAuthResponse(paramsStr); 503 } 504 505 /** 506 * Send the eap sim umts auts response for the currently configured network. 507 * 508 * @param paramsStr String to send. 509 * @return true if succeeds, false otherwise. 510 */ 511 public boolean sendCurrentNetworkEapSimUmtsAutsResponse(String paramsStr) { 512 if (mCurrentNetwork == null) return false; 513 return mCurrentNetwork.sendNetworkEapSimUmtsAutsResponse(paramsStr); 514 } 515 516 /** 517 * Send the eap sim umts auth failure for the currently configured network. 518 * 519 * @return true if succeeds, false otherwise. 520 */ 521 public boolean sendCurrentNetworkEapSimUmtsAuthFailure() { 522 if (mCurrentNetwork == null) return false; 523 return mCurrentNetwork.sendNetworkEapSimUmtsAuthFailure(); 524 } 525 526 /** 527 * Adds a new network. 528 * 529 * @return The ISupplicantNetwork object for the new network, or null if the call fails 530 */ 531 private SupplicantStaNetworkHal addNetwork() { 532 synchronized (mLock) { 533 final String methodStr = "addNetwork"; 534 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 535 Mutable<ISupplicantNetwork> newNetwork = new Mutable<>(); 536 try { 537 mISupplicantStaIface.addNetwork((SupplicantStatus status, 538 ISupplicantNetwork network) -> { 539 if (checkStatusAndLogFailure(status, methodStr)) { 540 newNetwork.value = network; 541 } 542 }); 543 } catch (RemoteException e) { 544 handleRemoteException(e, methodStr); 545 } 546 if (newNetwork.value != null) { 547 return getStaNetworkMockable( 548 ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder())); 549 } else { 550 return null; 551 } 552 } 553 } 554 555 /** 556 * Remove network from supplicant with network Id 557 * 558 * @return true if request is sent successfully, false otherwise. 559 */ 560 private boolean removeNetwork(int id) { 561 synchronized (mLock) { 562 final String methodStr = "removeNetwork"; 563 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 564 try { 565 SupplicantStatus status = mISupplicantStaIface.removeNetwork(id); 566 return checkStatusAndLogFailure(status, methodStr); 567 } catch (RemoteException e) { 568 handleRemoteException(e, methodStr); 569 return false; 570 } 571 } 572 } 573 574 /** 575 * Use this to mock the creation of SupplicantStaNetworkHal instance. 576 * 577 * @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL. 578 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 579 * the call fails 580 */ 581 protected SupplicantStaNetworkHal getStaNetworkMockable( 582 ISupplicantStaNetwork iSupplicantStaNetwork) { 583 SupplicantStaNetworkHal network = 584 new SupplicantStaNetworkHal(iSupplicantStaNetwork, mIfaceName, mContext, 585 mWifiMonitor); 586 if (network != null) { 587 network.enableVerboseLogging(mVerboseLoggingEnabled); 588 } 589 return network; 590 } 591 592 /** 593 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 594 * the call fails 595 */ 596 private SupplicantStaNetworkHal getNetwork(int id) { 597 synchronized (mLock) { 598 final String methodStr = "getNetwork"; 599 Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>(); 600 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 601 try { 602 mISupplicantStaIface.getNetwork(id, (SupplicantStatus status, 603 ISupplicantNetwork network) -> { 604 if (checkStatusAndLogFailure(status, methodStr)) { 605 gotNetwork.value = network; 606 } 607 }); 608 } catch (RemoteException e) { 609 handleRemoteException(e, methodStr); 610 } 611 if (gotNetwork.value != null) { 612 return getStaNetworkMockable( 613 ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder())); 614 } else { 615 return null; 616 } 617 } 618 } 619 620 /** See ISupplicantStaNetwork.hal for documentation */ 621 private boolean registerCallback(ISupplicantStaIfaceCallback callback) { 622 synchronized (mLock) { 623 final String methodStr = "registerCallback"; 624 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 625 try { 626 SupplicantStatus status = mISupplicantStaIface.registerCallback(callback); 627 return checkStatusAndLogFailure(status, methodStr); 628 } catch (RemoteException e) { 629 handleRemoteException(e, methodStr); 630 return false; 631 } 632 } 633 } 634 635 /** 636 * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns 637 * null if the call fails 638 */ 639 private java.util.ArrayList<Integer> listNetworks() { 640 synchronized (mLock) { 641 final String methodStr = "listNetworks"; 642 Mutable<ArrayList<Integer>> networkIdList = new Mutable<>(); 643 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 644 try { 645 mISupplicantStaIface.listNetworks((SupplicantStatus status, 646 java.util.ArrayList<Integer> networkIds) -> { 647 if (checkStatusAndLogFailure(status, methodStr)) { 648 networkIdList.value = networkIds; 649 } 650 }); 651 } catch (RemoteException e) { 652 handleRemoteException(e, methodStr); 653 } 654 return networkIdList.value; 655 } 656 } 657 658 /** 659 * Set WPS device name. 660 * 661 * @param name String to be set. 662 * @return true if request is sent successfully, false otherwise. 663 */ 664 public boolean setWpsDeviceName(String name) { 665 synchronized (mLock) { 666 final String methodStr = "setWpsDeviceName"; 667 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 668 try { 669 SupplicantStatus status = mISupplicantStaIface.setWpsDeviceName(name); 670 return checkStatusAndLogFailure(status, methodStr); 671 } catch (RemoteException e) { 672 handleRemoteException(e, methodStr); 673 return false; 674 } 675 } 676 } 677 678 /** 679 * Set WPS device type. 680 * 681 * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg> 682 * @return true if request is sent successfully, false otherwise. 683 */ 684 public boolean setWpsDeviceType(String typeStr) { 685 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr); 686 if (!match.find() || match.groupCount() != 3) { 687 Log.e(TAG, "Malformed WPS device type " + typeStr); 688 return false; 689 } 690 short categ = Short.parseShort(match.group(1)); 691 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2)); 692 short subCateg = Short.parseShort(match.group(3)); 693 694 byte[] bytes = new byte[8]; 695 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); 696 byteBuffer.putShort(categ); 697 byteBuffer.put(oui); 698 byteBuffer.putShort(subCateg); 699 return setWpsDeviceType(bytes); 700 } 701 702 private boolean setWpsDeviceType(byte[/* 8 */] type) { 703 synchronized (mLock) { 704 final String methodStr = "setWpsDeviceType"; 705 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 706 try { 707 SupplicantStatus status = mISupplicantStaIface.setWpsDeviceType(type); 708 return checkStatusAndLogFailure(status, methodStr); 709 } catch (RemoteException e) { 710 handleRemoteException(e, methodStr); 711 return false; 712 } 713 } 714 } 715 716 /** 717 * Set WPS manufacturer. 718 * 719 * @param manufacturer String to be set. 720 * @return true if request is sent successfully, false otherwise. 721 */ 722 public boolean setWpsManufacturer(String manufacturer) { 723 synchronized (mLock) { 724 final String methodStr = "setWpsManufacturer"; 725 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 726 try { 727 SupplicantStatus status = mISupplicantStaIface.setWpsManufacturer(manufacturer); 728 return checkStatusAndLogFailure(status, methodStr); 729 } catch (RemoteException e) { 730 handleRemoteException(e, methodStr); 731 return false; 732 } 733 } 734 } 735 736 /** 737 * Set WPS model name. 738 * 739 * @param modelName String to be set. 740 * @return true if request is sent successfully, false otherwise. 741 */ 742 public boolean setWpsModelName(String modelName) { 743 synchronized (mLock) { 744 final String methodStr = "setWpsModelName"; 745 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 746 try { 747 SupplicantStatus status = mISupplicantStaIface.setWpsModelName(modelName); 748 return checkStatusAndLogFailure(status, methodStr); 749 } catch (RemoteException e) { 750 handleRemoteException(e, methodStr); 751 return false; 752 } 753 } 754 } 755 756 /** 757 * Set WPS model number. 758 * 759 * @param modelNumber String to be set. 760 * @return true if request is sent successfully, false otherwise. 761 */ 762 public boolean setWpsModelNumber(String modelNumber) { 763 synchronized (mLock) { 764 final String methodStr = "setWpsModelNumber"; 765 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 766 try { 767 SupplicantStatus status = mISupplicantStaIface.setWpsModelNumber(modelNumber); 768 return checkStatusAndLogFailure(status, methodStr); 769 } catch (RemoteException e) { 770 handleRemoteException(e, methodStr); 771 return false; 772 } 773 } 774 } 775 776 /** 777 * Set WPS serial number. 778 * 779 * @param serialNumber String to be set. 780 * @return true if request is sent successfully, false otherwise. 781 */ 782 public boolean setWpsSerialNumber(String serialNumber) { 783 synchronized (mLock) { 784 final String methodStr = "setWpsSerialNumber"; 785 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 786 try { 787 SupplicantStatus status = mISupplicantStaIface.setWpsSerialNumber(serialNumber); 788 return checkStatusAndLogFailure(status, methodStr); 789 } catch (RemoteException e) { 790 handleRemoteException(e, methodStr); 791 return false; 792 } 793 } 794 } 795 796 /** 797 * Set WPS config methods 798 * 799 * @param configMethodsStr List of config methods. 800 * @return true if request is sent successfully, false otherwise. 801 */ 802 public boolean setWpsConfigMethods(String configMethodsStr) { 803 short configMethodsMask = 0; 804 String[] configMethodsStrArr = configMethodsStr.split("\\s+"); 805 for (int i = 0; i < configMethodsStrArr.length; i++) { 806 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]); 807 } 808 return setWpsConfigMethods(configMethodsMask); 809 } 810 811 private boolean setWpsConfigMethods(short configMethods) { 812 synchronized (mLock) { 813 final String methodStr = "setWpsConfigMethods"; 814 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 815 try { 816 SupplicantStatus status = mISupplicantStaIface.setWpsConfigMethods(configMethods); 817 return checkStatusAndLogFailure(status, methodStr); 818 } catch (RemoteException e) { 819 handleRemoteException(e, methodStr); 820 return false; 821 } 822 } 823 } 824 825 /** 826 * Trigger a reassociation even if the iface is currently connected. 827 * 828 * @return true if request is sent successfully, false otherwise. 829 */ 830 public boolean reassociate() { 831 synchronized (mLock) { 832 final String methodStr = "reassociate"; 833 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 834 try { 835 SupplicantStatus status = mISupplicantStaIface.reassociate(); 836 return checkStatusAndLogFailure(status, methodStr); 837 } catch (RemoteException e) { 838 handleRemoteException(e, methodStr); 839 return false; 840 } 841 } 842 } 843 844 /** 845 * Trigger a reconnection if the iface is disconnected. 846 * 847 * @return true if request is sent successfully, false otherwise. 848 */ 849 public boolean reconnect() { 850 synchronized (mLock) { 851 final String methodStr = "reconnect"; 852 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 853 try { 854 SupplicantStatus status = mISupplicantStaIface.reconnect(); 855 return checkStatusAndLogFailure(status, methodStr); 856 } catch (RemoteException e) { 857 handleRemoteException(e, methodStr); 858 return false; 859 } 860 } 861 } 862 863 /** 864 * Trigger a disconnection from the currently connected network. 865 * 866 * @return true if request is sent successfully, false otherwise. 867 */ 868 public boolean disconnect() { 869 synchronized (mLock) { 870 final String methodStr = "disconnect"; 871 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 872 try { 873 SupplicantStatus status = mISupplicantStaIface.disconnect(); 874 return checkStatusAndLogFailure(status, methodStr); 875 } catch (RemoteException e) { 876 handleRemoteException(e, methodStr); 877 return false; 878 } 879 } 880 } 881 882 /** 883 * Enable or disable power save mode. 884 * 885 * @param enable true to enable, false to disable. 886 * @return true if request is sent successfully, false otherwise. 887 */ 888 public boolean setPowerSave(boolean enable) { 889 synchronized (mLock) { 890 final String methodStr = "setPowerSave"; 891 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 892 try { 893 SupplicantStatus status = mISupplicantStaIface.setPowerSave(enable); 894 return checkStatusAndLogFailure(status, methodStr); 895 } catch (RemoteException e) { 896 handleRemoteException(e, methodStr); 897 return false; 898 } 899 } 900 } 901 902 /** 903 * Initiate TDLS discover with the specified AP. 904 * 905 * @param macAddress MAC Address of the AP. 906 * @return true if request is sent successfully, false otherwise. 907 */ 908 public boolean initiateTdlsDiscover(String macAddress) { 909 return initiateTdlsDiscover(NativeUtil.macAddressToByteArray(macAddress)); 910 } 911 /** See ISupplicantStaIface.hal for documentation */ 912 private boolean initiateTdlsDiscover(byte[/* 6 */] macAddress) { 913 synchronized (mLock) { 914 final String methodStr = "initiateTdlsDiscover"; 915 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 916 try { 917 SupplicantStatus status = mISupplicantStaIface.initiateTdlsDiscover(macAddress); 918 return checkStatusAndLogFailure(status, methodStr); 919 } catch (RemoteException e) { 920 handleRemoteException(e, methodStr); 921 return false; 922 } 923 } 924 } 925 926 /** 927 * Initiate TDLS setup with the specified AP. 928 * 929 * @param macAddress MAC Address of the AP. 930 * @return true if request is sent successfully, false otherwise. 931 */ 932 public boolean initiateTdlsSetup(String macAddress) { 933 return initiateTdlsSetup(NativeUtil.macAddressToByteArray(macAddress)); 934 } 935 /** See ISupplicantStaIface.hal for documentation */ 936 private boolean initiateTdlsSetup(byte[/* 6 */] macAddress) { 937 synchronized (mLock) { 938 final String methodStr = "initiateTdlsSetup"; 939 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 940 try { 941 SupplicantStatus status = mISupplicantStaIface.initiateTdlsSetup(macAddress); 942 return checkStatusAndLogFailure(status, methodStr); 943 } catch (RemoteException e) { 944 handleRemoteException(e, methodStr); 945 return false; 946 } 947 } 948 } 949 950 /** 951 * Initiate TDLS teardown with the specified AP. 952 * @param macAddress MAC Address of the AP. 953 * @return true if request is sent successfully, false otherwise. 954 */ 955 public boolean initiateTdlsTeardown(String macAddress) { 956 return initiateTdlsTeardown(NativeUtil.macAddressToByteArray(macAddress)); 957 } 958 959 /** See ISupplicantStaIface.hal for documentation */ 960 private boolean initiateTdlsTeardown(byte[/* 6 */] macAddress) { 961 synchronized (mLock) { 962 final String methodStr = "initiateTdlsTeardown"; 963 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 964 try { 965 SupplicantStatus status = mISupplicantStaIface.initiateTdlsTeardown(macAddress); 966 return checkStatusAndLogFailure(status, methodStr); 967 } catch (RemoteException e) { 968 handleRemoteException(e, methodStr); 969 return false; 970 } 971 } 972 } 973 974 /** 975 * Request the specified ANQP elements |elements| from the specified AP |bssid|. 976 * 977 * @param bssid BSSID of the AP 978 * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId. 979 * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes. 980 * @return true if request is sent successfully, false otherwise. 981 */ 982 public boolean initiateAnqpQuery(String bssid, ArrayList<Short> infoElements, 983 ArrayList<Integer> hs20SubTypes) { 984 return initiateAnqpQuery( 985 NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes); 986 } 987 988 /** See ISupplicantStaIface.hal for documentation */ 989 private boolean initiateAnqpQuery(byte[/* 6 */] macAddress, 990 java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) { 991 synchronized (mLock) { 992 final String methodStr = "initiateAnqpQuery"; 993 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 994 try { 995 SupplicantStatus status = mISupplicantStaIface.initiateAnqpQuery(macAddress, 996 infoElements, subTypes); 997 return checkStatusAndLogFailure(status, methodStr); 998 } catch (RemoteException e) { 999 handleRemoteException(e, methodStr); 1000 return false; 1001 } 1002 } 1003 } 1004 1005 /** 1006 * Request the specified ANQP ICON from the specified AP |bssid|. 1007 * 1008 * @param bssid BSSID of the AP 1009 * @param fileName Name of the file to request. 1010 * @return true if request is sent successfully, false otherwise. 1011 */ 1012 public boolean initiateHs20IconQuery(String bssid, String fileName) { 1013 return initiateHs20IconQuery(NativeUtil.macAddressToByteArray(bssid), fileName); 1014 } 1015 1016 /** See ISupplicantStaIface.hal for documentation */ 1017 private boolean initiateHs20IconQuery(byte[/* 6 */] macAddress, String fileName) { 1018 synchronized (mLock) { 1019 final String methodStr = "initiateHs20IconQuery"; 1020 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1021 try { 1022 SupplicantStatus status = mISupplicantStaIface.initiateHs20IconQuery(macAddress, 1023 fileName); 1024 return checkStatusAndLogFailure(status, methodStr); 1025 } catch (RemoteException e) { 1026 handleRemoteException(e, methodStr); 1027 return false; 1028 } 1029 } 1030 } 1031 1032 /** 1033 * Makes a callback to HIDL to getMacAddress from supplicant 1034 * 1035 * @return string containing the MAC address, or null on a failed call 1036 */ 1037 public String getMacAddress() { 1038 synchronized (mLock) { 1039 final String methodStr = "getMacAddress"; 1040 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 1041 Mutable<String> gotMac = new Mutable<>(); 1042 try { 1043 mISupplicantStaIface.getMacAddress((SupplicantStatus status, 1044 byte[/* 6 */] macAddr) -> { 1045 if (checkStatusAndLogFailure(status, methodStr)) { 1046 gotMac.value = NativeUtil.macAddressFromByteArray(macAddr); 1047 } 1048 }); 1049 } catch (RemoteException e) { 1050 handleRemoteException(e, methodStr); 1051 } 1052 return gotMac.value; 1053 } 1054 } 1055 1056 /** 1057 * Start using the added RX filters. 1058 * 1059 * @return true if request is sent successfully, false otherwise. 1060 */ 1061 public boolean startRxFilter() { 1062 synchronized (mLock) { 1063 final String methodStr = "startRxFilter"; 1064 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1065 try { 1066 SupplicantStatus status = mISupplicantStaIface.startRxFilter(); 1067 return checkStatusAndLogFailure(status, methodStr); 1068 } catch (RemoteException e) { 1069 handleRemoteException(e, methodStr); 1070 return false; 1071 } 1072 } 1073 } 1074 1075 /** 1076 * Stop using the added RX filters. 1077 * 1078 * @return true if request is sent successfully, false otherwise. 1079 */ 1080 public boolean stopRxFilter() { 1081 synchronized (mLock) { 1082 final String methodStr = "stopRxFilter"; 1083 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1084 try { 1085 SupplicantStatus status = mISupplicantStaIface.stopRxFilter(); 1086 return checkStatusAndLogFailure(status, methodStr); 1087 } catch (RemoteException e) { 1088 handleRemoteException(e, methodStr); 1089 return false; 1090 } 1091 } 1092 } 1093 1094 public static final byte RX_FILTER_TYPE_V4_MULTICAST = 1095 ISupplicantStaIface.RxFilterType.V6_MULTICAST; 1096 public static final byte RX_FILTER_TYPE_V6_MULTICAST = 1097 ISupplicantStaIface.RxFilterType.V6_MULTICAST; 1098 /** 1099 * Add an RX filter. 1100 * 1101 * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or 1102 * {@link #RX_FILTER_TYPE_V6_MULTICAST} values. 1103 * @return true if request is sent successfully, false otherwise. 1104 */ 1105 public boolean addRxFilter(byte type) { 1106 synchronized (mLock) { 1107 final String methodStr = "addRxFilter"; 1108 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1109 try { 1110 SupplicantStatus status = mISupplicantStaIface.addRxFilter(type); 1111 return checkStatusAndLogFailure(status, methodStr); 1112 } catch (RemoteException e) { 1113 handleRemoteException(e, methodStr); 1114 return false; 1115 } 1116 } 1117 } 1118 1119 /** 1120 * Remove an RX filter. 1121 * 1122 * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or 1123 * {@link #RX_FILTER_TYPE_V6_MULTICAST} values. 1124 * @return true if request is sent successfully, false otherwise. 1125 */ 1126 public boolean removeRxFilter(byte type) { 1127 synchronized (mLock) { 1128 final String methodStr = "removeRxFilter"; 1129 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1130 try { 1131 SupplicantStatus status = mISupplicantStaIface.removeRxFilter(type); 1132 return checkStatusAndLogFailure(status, methodStr); 1133 } catch (RemoteException e) { 1134 handleRemoteException(e, methodStr); 1135 return false; 1136 } 1137 } 1138 } 1139 1140 public static final byte BT_COEX_MODE_ENABLED = ISupplicantStaIface.BtCoexistenceMode.ENABLED; 1141 public static final byte BT_COEX_MODE_DISABLED = ISupplicantStaIface.BtCoexistenceMode.DISABLED; 1142 public static final byte BT_COEX_MODE_SENSE = ISupplicantStaIface.BtCoexistenceMode.SENSE; 1143 /** 1144 * Set Bt co existense mode. 1145 * 1146 * @param mode one of the above {@link #BT_COEX_MODE_ENABLED}, {@link #BT_COEX_MODE_DISABLED} 1147 * or {@link #BT_COEX_MODE_SENSE} values. 1148 * @return true if request is sent successfully, false otherwise. 1149 */ 1150 public boolean setBtCoexistenceMode(byte mode) { 1151 synchronized (mLock) { 1152 final String methodStr = "setBtCoexistenceMode"; 1153 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1154 try { 1155 SupplicantStatus status = mISupplicantStaIface.setBtCoexistenceMode(mode); 1156 return checkStatusAndLogFailure(status, methodStr); 1157 } catch (RemoteException e) { 1158 handleRemoteException(e, methodStr); 1159 return false; 1160 } 1161 } 1162 } 1163 1164 /** Enable or disable BT coexistence mode. 1165 * 1166 * @param enable true to enable, false to disable. 1167 * @return true if request is sent successfully, false otherwise. 1168 */ 1169 public boolean setBtCoexistenceScanModeEnabled(boolean enable) { 1170 synchronized (mLock) { 1171 final String methodStr = "setBtCoexistenceScanModeEnabled"; 1172 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1173 try { 1174 SupplicantStatus status = 1175 mISupplicantStaIface.setBtCoexistenceScanModeEnabled(enable); 1176 return checkStatusAndLogFailure(status, methodStr); 1177 } catch (RemoteException e) { 1178 handleRemoteException(e, methodStr); 1179 return false; 1180 } 1181 } 1182 } 1183 1184 /** 1185 * Enable or disable suspend mode optimizations. 1186 * 1187 * @param enable true to enable, false otherwise. 1188 * @return true if request is sent successfully, false otherwise. 1189 */ 1190 public boolean setSuspendModeEnabled(boolean enable) { 1191 synchronized (mLock) { 1192 final String methodStr = "setSuspendModeEnabled"; 1193 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1194 try { 1195 SupplicantStatus status = mISupplicantStaIface.setSuspendModeEnabled(enable); 1196 return checkStatusAndLogFailure(status, methodStr); 1197 } catch (RemoteException e) { 1198 handleRemoteException(e, methodStr); 1199 return false; 1200 } 1201 } 1202 } 1203 1204 /** 1205 * Set country code. 1206 * 1207 * @param codeStr 2 byte ASCII string. For ex: US, CA. 1208 * @return true if request is sent successfully, false otherwise. 1209 */ 1210 public boolean setCountryCode(String codeStr) { 1211 return setCountryCode(NativeUtil.stringToByteArray(codeStr)); 1212 } 1213 1214 /** See ISupplicantStaIface.hal for documentation */ 1215 private boolean setCountryCode(byte[/* 2 */] code) { 1216 synchronized (mLock) { 1217 final String methodStr = "setCountryCode"; 1218 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1219 try { 1220 SupplicantStatus status = mISupplicantStaIface.setCountryCode(code); 1221 return checkStatusAndLogFailure(status, methodStr); 1222 } catch (RemoteException e) { 1223 handleRemoteException(e, methodStr); 1224 return false; 1225 } 1226 } 1227 } 1228 1229 /** 1230 * Start WPS pin registrar operation with the specified peer and pin. 1231 * 1232 * @param bssidStr BSSID of the peer. 1233 * @param pin Pin to be used. 1234 * @return true if request is sent successfully, false otherwise. 1235 */ 1236 public boolean startWpsRegistrar(String bssidStr, String pin) { 1237 return startWpsRegistrar(NativeUtil.macAddressToByteArray(bssidStr), pin); 1238 } 1239 1240 /** See ISupplicantStaIface.hal for documentation */ 1241 private boolean startWpsRegistrar(byte[/* 6 */] bssid, String pin) { 1242 synchronized (mLock) { 1243 final String methodStr = "startWpsRegistrar"; 1244 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1245 try { 1246 SupplicantStatus status = mISupplicantStaIface.startWpsRegistrar(bssid, pin); 1247 return checkStatusAndLogFailure(status, methodStr); 1248 } catch (RemoteException e) { 1249 handleRemoteException(e, methodStr); 1250 return false; 1251 } 1252 } 1253 } 1254 1255 /** 1256 * Start WPS pin display operation with the specified peer. 1257 * 1258 * @param bssidStr BSSID of the peer. 1259 * @return true if request is sent successfully, false otherwise. 1260 */ 1261 public boolean startWpsPbc(String bssidStr) { 1262 return startWpsPbc(NativeUtil.macAddressToByteArray(bssidStr)); 1263 } 1264 1265 /** See ISupplicantStaIface.hal for documentation */ 1266 private boolean startWpsPbc(byte[/* 6 */] bssid) { 1267 synchronized (mLock) { 1268 final String methodStr = "startWpsPbc"; 1269 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1270 try { 1271 SupplicantStatus status = mISupplicantStaIface.startWpsPbc(bssid); 1272 return checkStatusAndLogFailure(status, methodStr); 1273 } catch (RemoteException e) { 1274 handleRemoteException(e, methodStr); 1275 return false; 1276 } 1277 } 1278 } 1279 1280 /** 1281 * Start WPS pin keypad operation with the specified pin. 1282 * 1283 * @param pin Pin to be used. 1284 * @return true if request is sent successfully, false otherwise. 1285 */ 1286 public boolean startWpsPinKeypad(String pin) { 1287 synchronized (mLock) { 1288 final String methodStr = "startWpsPinKeypad"; 1289 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1290 try { 1291 SupplicantStatus status = mISupplicantStaIface.startWpsPinKeypad(pin); 1292 return checkStatusAndLogFailure(status, methodStr); 1293 } catch (RemoteException e) { 1294 handleRemoteException(e, methodStr); 1295 return false; 1296 } 1297 } 1298 } 1299 1300 /** 1301 * Start WPS pin display operation with the specified peer. 1302 * 1303 * @param bssidStr BSSID of the peer. 1304 * @return new pin generated on success, null otherwise. 1305 */ 1306 public String startWpsPinDisplay(String bssidStr) { 1307 return startWpsPinDisplay(NativeUtil.macAddressToByteArray(bssidStr)); 1308 } 1309 1310 /** See ISupplicantStaIface.hal for documentation */ 1311 private String startWpsPinDisplay(byte[/* 6 */] bssid) { 1312 synchronized (mLock) { 1313 final String methodStr = "startWpsPinDisplay"; 1314 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 1315 final Mutable<String> gotPin = new Mutable<>(); 1316 try { 1317 mISupplicantStaIface.startWpsPinDisplay(bssid, 1318 (SupplicantStatus status, String pin) -> { 1319 if (checkStatusAndLogFailure(status, methodStr)) { 1320 gotPin.value = pin; 1321 } 1322 }); 1323 } catch (RemoteException e) { 1324 handleRemoteException(e, methodStr); 1325 } 1326 return gotPin.value; 1327 } 1328 } 1329 1330 /** 1331 * Cancels any ongoing WPS requests. 1332 * 1333 * @return true if request is sent successfully, false otherwise. 1334 */ 1335 public boolean cancelWps() { 1336 synchronized (mLock) { 1337 final String methodStr = "cancelWps"; 1338 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1339 try { 1340 SupplicantStatus status = mISupplicantStaIface.cancelWps(); 1341 return checkStatusAndLogFailure(status, methodStr); 1342 } catch (RemoteException e) { 1343 handleRemoteException(e, methodStr); 1344 return false; 1345 } 1346 } 1347 } 1348 1349 /** 1350 * Sets whether to use external sim for SIM/USIM processing. 1351 * 1352 * @param useExternalSim true to enable, false otherwise. 1353 * @return true if request is sent successfully, false otherwise. 1354 */ 1355 public boolean setExternalSim(boolean useExternalSim) { 1356 synchronized (mLock) { 1357 final String methodStr = "setExternalSim"; 1358 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 1359 try { 1360 SupplicantStatus status = mISupplicantStaIface.setExternalSim(useExternalSim); 1361 return checkStatusAndLogFailure(status, methodStr); 1362 } catch (RemoteException e) { 1363 handleRemoteException(e, methodStr); 1364 return false; 1365 } 1366 } 1367 } 1368 1369 public static final int LOG_LEVEL_EXCESSIVE = ISupplicant.DebugLevel.EXCESSIVE; 1370 public static final int LOG_LEVEL_MSGDUMP = ISupplicant.DebugLevel.MSGDUMP; 1371 public static final int LOG_LEVEL_DEBUG = ISupplicant.DebugLevel.DEBUG; 1372 public static final int LOG_LEVEL_INFO = ISupplicant.DebugLevel.INFO; 1373 public static final int LOG_LEVEL_WARNING = ISupplicant.DebugLevel.WARNING; 1374 public static final int LOG_LEVEL_ERROR = ISupplicant.DebugLevel.ERROR; 1375 /** 1376 * Set the debug log level for wpa_supplicant 1377 * @param level One of the above {@link #LOG_LEVEL_EXCESSIVE} - {@link #LOG_LEVEL_ERROR} value. 1378 * @return true if request is sent successfully, false otherwise. 1379 */ 1380 public boolean setLogLevel(int level) { 1381 return setDebugParams(level, false, false); 1382 } 1383 1384 /** See ISupplicant.hal for documentation */ 1385 private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) { 1386 synchronized (mLock) { 1387 final String methodStr = "setDebugParams"; 1388 if (!checkSupplicantAndLogFailure(methodStr)) return false; 1389 try { 1390 SupplicantStatus status = 1391 mISupplicant.setDebugParams(level, showTimestamp, showKeys); 1392 return checkStatusAndLogFailure(status, methodStr); 1393 } catch (RemoteException e) { 1394 handleRemoteException(e, methodStr); 1395 return false; 1396 } 1397 } 1398 } 1399 1400 /** 1401 * Set concurrency priority between P2P & STA operations. 1402 * 1403 * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations, 1404 * false otherwise. 1405 * @return true if request is sent successfully, false otherwise. 1406 */ 1407 public boolean setConcurrencyPriority(boolean isStaHigherPriority) { 1408 if (isStaHigherPriority) { 1409 return setConcurrencyPriority(IfaceType.STA); 1410 } else { 1411 return setConcurrencyPriority(IfaceType.P2P); 1412 } 1413 } 1414 1415 /** See ISupplicant.hal for documentation */ 1416 private boolean setConcurrencyPriority(int type) { 1417 synchronized (mLock) { 1418 final String methodStr = "setConcurrencyPriority"; 1419 if (!checkSupplicantAndLogFailure(methodStr)) return false; 1420 try { 1421 SupplicantStatus status = mISupplicant.setConcurrencyPriority(type); 1422 return checkStatusAndLogFailure(status, methodStr); 1423 } catch (RemoteException e) { 1424 handleRemoteException(e, methodStr); 1425 return false; 1426 } 1427 } 1428 } 1429 1430 /** 1431 * Returns false if Supplicant is null, and logs failure to call methodStr 1432 */ 1433 private boolean checkSupplicantAndLogFailure(final String methodStr) { 1434 if (mISupplicant == null) { 1435 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null"); 1436 return false; 1437 } 1438 return true; 1439 } 1440 1441 /** 1442 * Returns false if SupplicantStaIface is null, and logs failure to call methodStr 1443 */ 1444 private boolean checkSupplicantStaIfaceAndLogFailure(final String methodStr) { 1445 if (mISupplicantStaIface == null) { 1446 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null"); 1447 return false; 1448 } 1449 return true; 1450 } 1451 1452 /** 1453 * Returns true if provided status code is SUCCESS, logs debug message and returns false 1454 * otherwise 1455 */ 1456 private boolean checkStatusAndLogFailure(SupplicantStatus status, 1457 final String methodStr) { 1458 if (status.code != SupplicantStatusCode.SUCCESS) { 1459 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed: " 1460 + supplicantStatusCodeToString(status.code) + ", " + status.debugMessage); 1461 return false; 1462 } else { 1463 if (mVerboseLoggingEnabled) { 1464 Log.i(TAG, "ISupplicantStaIface." + methodStr + " succeeded"); 1465 } 1466 return true; 1467 } 1468 } 1469 1470 private void handleRemoteException(RemoteException e, String methodStr) { 1471 supplicantServiceDiedHandler(); 1472 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e); 1473 } 1474 1475 /** 1476 * Converts SupplicantStatus code values to strings for debug logging 1477 * TODO(b/34811152) Remove this, or make it more break resistance 1478 */ 1479 public static String supplicantStatusCodeToString(int code) { 1480 switch (code) { 1481 case 0: 1482 return "SUCCESS"; 1483 case 1: 1484 return "FAILURE_UNKNOWN"; 1485 case 2: 1486 return "FAILURE_ARGS_INVALID"; 1487 case 3: 1488 return "FAILURE_IFACE_INVALID"; 1489 case 4: 1490 return "FAILURE_IFACE_UNKNOWN"; 1491 case 5: 1492 return "FAILURE_IFACE_EXISTS"; 1493 case 6: 1494 return "FAILURE_IFACE_DISABLED"; 1495 case 7: 1496 return "FAILURE_IFACE_NOT_DISCONNECTED"; 1497 case 8: 1498 return "FAILURE_NETWORK_INVALID"; 1499 case 9: 1500 return "FAILURE_NETWORK_UNKNOWN"; 1501 default: 1502 return "??? UNKNOWN_CODE"; 1503 } 1504 } 1505 1506 1507 /** 1508 * Converts the Wps config method string to the equivalent enum value. 1509 */ 1510 private static short stringToWpsConfigMethod(String configMethod) { 1511 switch (configMethod) { 1512 case "usba": 1513 return WpsConfigMethods.USBA; 1514 case "ethernet": 1515 return WpsConfigMethods.ETHERNET; 1516 case "label": 1517 return WpsConfigMethods.LABEL; 1518 case "display": 1519 return WpsConfigMethods.DISPLAY; 1520 case "int_nfc_token": 1521 return WpsConfigMethods.INT_NFC_TOKEN; 1522 case "ext_nfc_token": 1523 return WpsConfigMethods.EXT_NFC_TOKEN; 1524 case "nfc_interface": 1525 return WpsConfigMethods.NFC_INTERFACE; 1526 case "push_button": 1527 return WpsConfigMethods.PUSHBUTTON; 1528 case "keypad": 1529 return WpsConfigMethods.KEYPAD; 1530 case "virtual_push_button": 1531 return WpsConfigMethods.VIRT_PUSHBUTTON; 1532 case "physical_push_button": 1533 return WpsConfigMethods.PHY_PUSHBUTTON; 1534 case "p2ps": 1535 return WpsConfigMethods.P2PS; 1536 case "virtual_display": 1537 return WpsConfigMethods.VIRT_DISPLAY; 1538 case "physical_display": 1539 return WpsConfigMethods.PHY_DISPLAY; 1540 default: 1541 throw new IllegalArgumentException( 1542 "Invalid WPS config method: " + configMethod); 1543 } 1544 } 1545 1546 /** 1547 * Converts the supplicant state received from HIDL to the equivalent framework state. 1548 */ 1549 private static SupplicantState supplicantHidlStateToFrameworkState(int state) { 1550 switch (state) { 1551 case ISupplicantStaIfaceCallback.State.DISCONNECTED: 1552 return SupplicantState.DISCONNECTED; 1553 case ISupplicantStaIfaceCallback.State.IFACE_DISABLED: 1554 return SupplicantState.INTERFACE_DISABLED; 1555 case ISupplicantStaIfaceCallback.State.INACTIVE: 1556 return SupplicantState.INACTIVE; 1557 case ISupplicantStaIfaceCallback.State.SCANNING: 1558 return SupplicantState.SCANNING; 1559 case ISupplicantStaIfaceCallback.State.AUTHENTICATING: 1560 return SupplicantState.AUTHENTICATING; 1561 case ISupplicantStaIfaceCallback.State.ASSOCIATING: 1562 return SupplicantState.ASSOCIATING; 1563 case ISupplicantStaIfaceCallback.State.ASSOCIATED: 1564 return SupplicantState.ASSOCIATED; 1565 case ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE: 1566 return SupplicantState.FOUR_WAY_HANDSHAKE; 1567 case ISupplicantStaIfaceCallback.State.GROUP_HANDSHAKE: 1568 return SupplicantState.GROUP_HANDSHAKE; 1569 case ISupplicantStaIfaceCallback.State.COMPLETED: 1570 return SupplicantState.COMPLETED; 1571 default: 1572 throw new IllegalArgumentException("Invalid state: " + state); 1573 } 1574 } 1575 1576 private static class Mutable<E> { 1577 public E value; 1578 1579 Mutable() { 1580 value = null; 1581 } 1582 1583 Mutable(E value) { 1584 this.value = value; 1585 } 1586 } 1587 1588 private class SupplicantStaIfaceHalCallback extends ISupplicantStaIfaceCallback.Stub { 1589 /** 1590 * Parses the provided payload into an ANQP element. 1591 * 1592 * @param infoID Element type. 1593 * @param payload Raw payload bytes. 1594 * @return AnqpElement instance on success, null on failure. 1595 */ 1596 private ANQPElement parseAnqpElement(Constants.ANQPElementType infoID, 1597 ArrayList<Byte> payload) { 1598 try { 1599 return Constants.getANQPElementID(infoID) != null 1600 ? ANQPParser.parseElement( 1601 infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload))) 1602 : ANQPParser.parseHS20Element( 1603 infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload))); 1604 } catch (IOException | BufferUnderflowException e) { 1605 Log.e(TAG, "Failed parsing ANQP element payload: " + infoID, e); 1606 return null; 1607 } 1608 } 1609 1610 /** 1611 * Parse the ANQP element data and add to the provided elements map if successful. 1612 * 1613 * @param elementsMap Map to add the parsed out element to. 1614 * @param infoID Element type. 1615 * @param payload Raw payload bytes. 1616 */ 1617 private void addAnqpElementToMap(Map<Constants.ANQPElementType, ANQPElement> elementsMap, 1618 Constants.ANQPElementType infoID, 1619 ArrayList<Byte> payload) { 1620 if (payload == null || payload.isEmpty()) return; 1621 ANQPElement element = parseAnqpElement(infoID, payload); 1622 if (element != null) { 1623 elementsMap.put(infoID, element); 1624 } 1625 } 1626 1627 /** 1628 * Helper utility to convert the bssid bytes to long. 1629 */ 1630 private Long toLongBssid(byte[] bssidBytes) { 1631 try { 1632 return ByteBufferReader.readInteger( 1633 ByteBuffer.wrap(bssidBytes), ByteOrder.BIG_ENDIAN, bssidBytes.length); 1634 } catch (BufferUnderflowException | IllegalArgumentException e) { 1635 return 0L; 1636 } 1637 } 1638 1639 @Override 1640 public void onNetworkAdded(int id) { 1641 } 1642 1643 @Override 1644 public void onNetworkRemoved(int id) { 1645 } 1646 1647 @Override 1648 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id, 1649 ArrayList<Byte> ssid) { 1650 SupplicantState newSupplicantState = supplicantHidlStateToFrameworkState(newState); 1651 WifiSsid wifiSsid = 1652 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid)); 1653 String bssidStr = NativeUtil.macAddressFromByteArray(bssid); 1654 mWifiMonitor.broadcastSupplicantStateChangeEvent( 1655 mIfaceName, mFrameworkNetworkId, wifiSsid, bssidStr, newSupplicantState); 1656 if (newSupplicantState == SupplicantState.ASSOCIATED) { 1657 mWifiMonitor.broadcastAssociationSuccesfulEvent(mIfaceName, bssidStr); 1658 } else if (newSupplicantState == SupplicantState.COMPLETED) { 1659 mWifiMonitor.broadcastNetworkConnectionEvent( 1660 mIfaceName, mFrameworkNetworkId, bssidStr); 1661 } 1662 } 1663 1664 @Override 1665 public void onAnqpQueryDone(byte[/* 6 */] bssid, 1666 ISupplicantStaIfaceCallback.AnqpData data, 1667 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) { 1668 Map<Constants.ANQPElementType, ANQPElement> elementsMap = new HashMap<>(); 1669 addAnqpElementToMap(elementsMap, ANQPVenueName, data.venueName); 1670 addAnqpElementToMap(elementsMap, ANQPRoamingConsortium, data.roamingConsortium); 1671 addAnqpElementToMap(elementsMap, ANQPIPAddrAvailability, data.ipAddrTypeAvailability); 1672 addAnqpElementToMap(elementsMap, ANQPNAIRealm, data.naiRealm); 1673 addAnqpElementToMap(elementsMap, ANQP3GPPNetwork, data.anqp3gppCellularNetwork); 1674 addAnqpElementToMap(elementsMap, ANQPDomName, data.domainName); 1675 addAnqpElementToMap(elementsMap, HSFriendlyName, hs20Data.operatorFriendlyName); 1676 addAnqpElementToMap(elementsMap, HSWANMetrics, hs20Data.wanMetrics); 1677 addAnqpElementToMap(elementsMap, HSConnCapability, hs20Data.connectionCapability); 1678 addAnqpElementToMap(elementsMap, HSOSUProviders, hs20Data.osuProvidersList); 1679 mWifiMonitor.broadcastAnqpDoneEvent( 1680 mIfaceName, new AnqpEvent(toLongBssid(bssid), elementsMap)); 1681 } 1682 1683 @Override 1684 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName, 1685 ArrayList<Byte> data) { 1686 mWifiMonitor.broadcastIconDoneEvent( 1687 mIfaceName, 1688 new IconEvent(toLongBssid(bssid), fileName, data.size(), 1689 NativeUtil.byteArrayFromArrayList(data))); 1690 } 1691 1692 @Override 1693 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, byte osuMethod, String url) { 1694 mWifiMonitor.broadcastWnmEvent( 1695 mIfaceName, new WnmData(toLongBssid(bssid), url, osuMethod)); 1696 } 1697 1698 @Override 1699 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode, 1700 int reAuthDelayInSec, String url) { 1701 mWifiMonitor.broadcastWnmEvent( 1702 mIfaceName, 1703 new WnmData(toLongBssid(bssid), url, reasonCode == WnmData.ESS, 1704 reAuthDelayInSec)); 1705 } 1706 1707 @Override 1708 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, int reasonCode) { 1709 mWifiMonitor.broadcastNetworkDisconnectionEvent( 1710 mIfaceName, locallyGenerated ? 1 : 0, reasonCode, 1711 NativeUtil.macAddressFromByteArray(bssid)); 1712 } 1713 1714 @Override 1715 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode) { 1716 // TODO(b/35464954): Need to figure out when to trigger 1717 // |WifiMonitor.AUTHENTICATION_FAILURE_REASON_WRONG_PSWD| 1718 mWifiMonitor.broadcastAssociationRejectionEvent(mIfaceName, statusCode, 1719 NativeUtil.macAddressFromByteArray(bssid)); 1720 } 1721 1722 @Override 1723 public void onAuthenticationTimeout(byte[/* 6 */] bssid) { 1724 mWifiMonitor.broadcastAuthenticationFailureEvent( 1725 mIfaceName, WifiMonitor.AUTHENTICATION_FAILURE_REASON_TIMEOUT); 1726 } 1727 1728 @Override 1729 public void onEapFailure() { 1730 mWifiMonitor.broadcastAuthenticationFailureEvent( 1731 mIfaceName, WifiMonitor.AUTHENTICATION_FAILURE_REASON_EAP_FAILURE); 1732 } 1733 1734 @Override 1735 public void onWpsEventSuccess() { 1736 mWifiMonitor.broadcastWpsSuccessEvent(mIfaceName); 1737 } 1738 1739 @Override 1740 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) { 1741 if (configError == WpsConfigError.MSG_TIMEOUT 1742 && errorInd == WpsErrorIndication.NO_ERROR) { 1743 mWifiMonitor.broadcastWpsTimeoutEvent(mIfaceName); 1744 } else { 1745 mWifiMonitor.broadcastWpsFailEvent(mIfaceName, configError, errorInd); 1746 } 1747 } 1748 1749 @Override 1750 public void onWpsEventPbcOverlap() { 1751 mWifiMonitor.broadcastWpsOverlapEvent(mIfaceName); 1752 } 1753 1754 @Override 1755 public void onExtRadioWorkStart(int id) { 1756 } 1757 1758 @Override 1759 public void onExtRadioWorkTimeout(int id) { 1760 } 1761 } 1762 1763 private void logd(String s) { 1764 Log.d(TAG, s); 1765 } 1766 1767 private void logi(String s) { 1768 Log.i(TAG, s); 1769 } 1770 1771 private void loge(String s) { 1772 Log.e(TAG, s); 1773 } 1774} 1775