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