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