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