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 */ 16 package com.android.server.wifi; 17 18 import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP; 19 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE; 20 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE; 21 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B; 22 23 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQP3GPPNetwork; 24 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPDomName; 25 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPIPAddrAvailability; 26 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPNAIRealm; 27 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPRoamingConsortium; 28 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPVenueName; 29 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSConnCapability; 30 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSFriendlyName; 31 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSOSUProviders; 32 import static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSWANMetrics; 33 34 import android.annotation.NonNull; 35 import android.content.Context; 36 import android.hardware.wifi.supplicant.V1_0.ISupplicant; 37 import android.hardware.wifi.supplicant.V1_0.ISupplicantIface; 38 import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork; 39 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface; 40 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback; 41 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork; 42 import android.hardware.wifi.supplicant.V1_0.IfaceType; 43 import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; 44 import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; 45 import android.hardware.wifi.supplicant.V1_0.WpsConfigMethods; 46 import android.hardware.wifi.supplicant.V1_2.DppAkm; 47 import android.hardware.wifi.supplicant.V1_2.DppFailureCode; 48 import android.hidl.manager.V1_0.IServiceManager; 49 import android.hidl.manager.V1_0.IServiceNotification; 50 import android.net.IpConfiguration; 51 import android.net.wifi.SupplicantState; 52 import android.net.wifi.WifiConfiguration; 53 import android.net.wifi.WifiManager; 54 import android.net.wifi.WifiSsid; 55 import android.os.Handler; 56 import android.os.HidlSupport.Mutable; 57 import android.os.HwRemoteBinder; 58 import android.os.Looper; 59 import android.os.Process; 60 import android.os.RemoteException; 61 import android.text.TextUtils; 62 import android.util.Log; 63 import android.util.MutableBoolean; 64 import android.util.MutableInt; 65 import android.util.Pair; 66 import android.util.SparseArray; 67 68 import com.android.internal.annotations.VisibleForTesting; 69 import com.android.server.wifi.WifiNative.DppEventCallback; 70 import com.android.server.wifi.WifiNative.SupplicantDeathEventHandler; 71 import com.android.server.wifi.hotspot2.AnqpEvent; 72 import com.android.server.wifi.hotspot2.IconEvent; 73 import com.android.server.wifi.hotspot2.WnmData; 74 import com.android.server.wifi.hotspot2.anqp.ANQPElement; 75 import com.android.server.wifi.hotspot2.anqp.ANQPParser; 76 import com.android.server.wifi.hotspot2.anqp.Constants; 77 import com.android.server.wifi.util.NativeUtil; 78 79 import java.io.IOException; 80 import java.nio.BufferUnderflowException; 81 import java.nio.ByteBuffer; 82 import java.nio.ByteOrder; 83 import java.util.ArrayList; 84 import java.util.HashMap; 85 import java.util.List; 86 import java.util.Map; 87 import java.util.NoSuchElementException; 88 import java.util.Objects; 89 import java.util.regex.Matcher; 90 import java.util.regex.Pattern; 91 92 import javax.annotation.concurrent.ThreadSafe; 93 94 /** 95 * Hal calls for bring up/shut down of the supplicant daemon and for 96 * sending requests to the supplicant daemon 97 * To maintain thread-safety, the locking protocol is that every non-static method (regardless of 98 * access level) acquires mLock. 99 */ 100 @ThreadSafe 101 public class SupplicantStaIfaceHal { 102 private static final String TAG = "SupplicantStaIfaceHal"; 103 @VisibleForTesting 104 public static final String HAL_INSTANCE_NAME = "default"; 105 @VisibleForTesting 106 public static final String INIT_START_PROPERTY = "ctl.start"; 107 @VisibleForTesting 108 public static final String INIT_STOP_PROPERTY = "ctl.stop"; 109 @VisibleForTesting 110 public static final String INIT_SERVICE_NAME = "wpa_supplicant"; 111 /** 112 * Regex pattern for extracting the wps device type bytes. 113 * Matches a strings like the following: "<categ>-<OUI>-<subcateg>"; 114 */ 115 private static final Pattern WPS_DEVICE_TYPE_PATTERN = 116 Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$"); 117 118 private final Object mLock = new Object(); 119 private boolean mVerboseLoggingEnabled = false; 120 121 // Supplicant HAL interface objects 122 private IServiceManager mIServiceManager = null; 123 private ISupplicant mISupplicant; 124 private HashMap<String, ISupplicantStaIface> mISupplicantStaIfaces = new HashMap<>(); 125 private HashMap<String, ISupplicantStaIfaceCallback> mISupplicantStaIfaceCallbacks = 126 new HashMap<>(); 127 private HashMap<String, SupplicantStaNetworkHal> mCurrentNetworkRemoteHandles = new HashMap<>(); 128 private HashMap<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>(); 129 private SupplicantDeathEventHandler mDeathEventHandler; 130 private ServiceManagerDeathRecipient mServiceManagerDeathRecipient; 131 private SupplicantDeathRecipient mSupplicantDeathRecipient; 132 // Death recipient cookie registered for current supplicant instance. 133 private long mDeathRecipientCookie = 0; 134 private final Context mContext; 135 private final WifiMonitor mWifiMonitor; 136 private final PropertyService mPropertyService; 137 private final Handler mEventHandler; 138 private DppEventCallback mDppCallback = null; 139 140 private final IServiceNotification mServiceNotificationCallback = 141 new IServiceNotification.Stub() { 142 public void onRegistration(String fqName, String name, boolean preexisting) { 143 synchronized (mLock) { 144 if (mVerboseLoggingEnabled) { 145 Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName 146 + ", " + name + " preexisting=" + preexisting); 147 } 148 if (!initSupplicantService()) { 149 Log.e(TAG, "initalizing ISupplicant failed."); 150 supplicantServiceDiedHandler(mDeathRecipientCookie); 151 } else { 152 Log.i(TAG, "Completed initialization of ISupplicant."); 153 } 154 } 155 } 156 }; 157 private class ServiceManagerDeathRecipient implements HwRemoteBinder.DeathRecipient { 158 @Override serviceDied(long cookie)159 public void serviceDied(long cookie) { 160 mEventHandler.post(() -> { 161 synchronized (mLock) { 162 Log.w(TAG, "IServiceManager died: cookie=" + cookie); 163 supplicantServiceDiedHandler(mDeathRecipientCookie); 164 mIServiceManager = null; // Will need to register a new ServiceNotification 165 } 166 }); 167 } 168 } 169 private class SupplicantDeathRecipient implements HwRemoteBinder.DeathRecipient { 170 @Override serviceDied(long cookie)171 public void serviceDied(long cookie) { 172 mEventHandler.post(() -> { 173 synchronized (mLock) { 174 Log.w(TAG, "ISupplicant died: cookie=" + cookie); 175 supplicantServiceDiedHandler(cookie); 176 } 177 }); 178 } 179 } 180 SupplicantStaIfaceHal(Context context, WifiMonitor monitor, PropertyService propertyService, Looper looper)181 public SupplicantStaIfaceHal(Context context, WifiMonitor monitor, 182 PropertyService propertyService, Looper looper) { 183 mContext = context; 184 mWifiMonitor = monitor; 185 mPropertyService = propertyService; 186 mEventHandler = new Handler(looper); 187 188 mServiceManagerDeathRecipient = new ServiceManagerDeathRecipient(); 189 mSupplicantDeathRecipient = new SupplicantDeathRecipient(); 190 } 191 192 /** 193 * Enable/Disable verbose logging. 194 * 195 * @param enable true to enable, false to disable. 196 */ enableVerboseLogging(boolean enable)197 void enableVerboseLogging(boolean enable) { 198 synchronized (mLock) { 199 mVerboseLoggingEnabled = enable; 200 } 201 } 202 linkToServiceManagerDeath()203 private boolean linkToServiceManagerDeath() { 204 synchronized (mLock) { 205 if (mIServiceManager == null) return false; 206 try { 207 if (!mIServiceManager.linkToDeath(mServiceManagerDeathRecipient, 0)) { 208 Log.wtf(TAG, "Error on linkToDeath on IServiceManager"); 209 supplicantServiceDiedHandler(mDeathRecipientCookie); 210 mIServiceManager = null; // Will need to register a new ServiceNotification 211 return false; 212 } 213 } catch (RemoteException e) { 214 Log.e(TAG, "IServiceManager.linkToDeath exception", e); 215 return false; 216 } 217 return true; 218 } 219 } 220 221 /** 222 * Registers a service notification for the ISupplicant service, which triggers initialization 223 * of the ISupplicantStaIface 224 * @return true if the service notification was successfully registered 225 */ initialize()226 public boolean initialize() { 227 synchronized (mLock) { 228 if (mVerboseLoggingEnabled) { 229 Log.i(TAG, "Registering ISupplicant service ready callback."); 230 } 231 mISupplicant = null; 232 mISupplicantStaIfaces.clear(); 233 if (mIServiceManager != null) { 234 // Already have an IServiceManager and serviceNotification registered, don't 235 // don't register another. 236 return true; 237 } 238 try { 239 mIServiceManager = getServiceManagerMockable(); 240 if (mIServiceManager == null) { 241 Log.e(TAG, "Failed to get HIDL Service Manager"); 242 return false; 243 } 244 if (!linkToServiceManagerDeath()) { 245 return false; 246 } 247 /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it 248 exists */ 249 if (!mIServiceManager.registerForNotifications( 250 ISupplicant.kInterfaceName, "", mServiceNotificationCallback)) { 251 Log.e(TAG, "Failed to register for notifications to " 252 + ISupplicant.kInterfaceName); 253 mIServiceManager = null; // Will need to register a new ServiceNotification 254 return false; 255 } 256 } catch (RemoteException e) { 257 Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: " 258 + e); 259 supplicantServiceDiedHandler(mDeathRecipientCookie); 260 } 261 return true; 262 } 263 } 264 linkToSupplicantDeath()265 private boolean linkToSupplicantDeath() { 266 synchronized (mLock) { 267 if (mISupplicant == null) return false; 268 try { 269 if (!mISupplicant.linkToDeath(mSupplicantDeathRecipient, ++mDeathRecipientCookie)) { 270 Log.wtf(TAG, "Error on linkToDeath on ISupplicant"); 271 supplicantServiceDiedHandler(mDeathRecipientCookie); 272 return false; 273 } 274 } catch (RemoteException e) { 275 Log.e(TAG, "ISupplicant.linkToDeath exception", e); 276 return false; 277 } 278 return true; 279 } 280 } 281 initSupplicantService()282 private boolean initSupplicantService() { 283 synchronized (mLock) { 284 try { 285 mISupplicant = getSupplicantMockable(); 286 } catch (RemoteException e) { 287 Log.e(TAG, "ISupplicant.getService exception: " + e); 288 return false; 289 } catch (NoSuchElementException e) { 290 Log.e(TAG, "ISupplicant.getService exception: " + e); 291 return false; 292 } 293 if (mISupplicant == null) { 294 Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup"); 295 return false; 296 } 297 if (!linkToSupplicantDeath()) { 298 return false; 299 } 300 } 301 return true; 302 } 303 getCurrentNetworkId(@onNull String ifaceName)304 private int getCurrentNetworkId(@NonNull String ifaceName) { 305 synchronized (mLock) { 306 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 307 if (currentConfig == null) { 308 return WifiConfiguration.INVALID_NETWORK_ID; 309 } 310 return currentConfig.networkId; 311 } 312 } 313 314 /** 315 * Setup a STA interface for the specified iface name. 316 * 317 * @param ifaceName Name of the interface. 318 * @return true on success, false otherwise. 319 */ setupIface(@onNull String ifaceName)320 public boolean setupIface(@NonNull String ifaceName) { 321 final String methodStr = "setupIface"; 322 if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) != null) return false; 323 ISupplicantIface ifaceHwBinder; 324 325 if (isV1_1()) { 326 ifaceHwBinder = addIfaceV1_1(ifaceName); 327 } else { 328 ifaceHwBinder = getIfaceV1_0(ifaceName); 329 } 330 if (ifaceHwBinder == null) { 331 Log.e(TAG, "setupIface got null iface"); 332 return false; 333 } 334 SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName); 335 336 if (isV1_2()) { 337 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface iface = 338 getStaIfaceMockableV1_2(ifaceHwBinder); 339 340 SupplicantStaIfaceHalCallbackV1_1 callbackV11 = 341 new SupplicantStaIfaceHalCallbackV1_1(ifaceName, callback); 342 343 SupplicantStaIfaceHalCallbackV1_2 callbackV12 = 344 new SupplicantStaIfaceHalCallbackV1_2(callbackV11); 345 346 if (!registerCallbackV1_2(iface, callbackV12)) { 347 return false; 348 } 349 mISupplicantStaIfaces.put(ifaceName, iface); 350 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV11); 351 } else if (isV1_1()) { 352 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface = 353 getStaIfaceMockableV1_1(ifaceHwBinder); 354 SupplicantStaIfaceHalCallbackV1_1 callbackV1_1 = 355 new SupplicantStaIfaceHalCallbackV1_1(ifaceName, callback); 356 357 if (!registerCallbackV1_1(iface, callbackV1_1)) { 358 return false; 359 } 360 mISupplicantStaIfaces.put(ifaceName, iface); 361 mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV1_1); 362 } else { 363 ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder); 364 365 if (!registerCallback(iface, callback)) { 366 return false; 367 } 368 mISupplicantStaIfaces.put(ifaceName, iface); 369 mISupplicantStaIfaceCallbacks.put(ifaceName, callback); 370 } 371 return true; 372 } 373 374 /** 375 * Get a STA interface for the specified iface name. 376 * 377 * @param ifaceName Name of the interface. 378 * @return true on success, false otherwise. 379 */ getIfaceV1_0(@onNull String ifaceName)380 private ISupplicantIface getIfaceV1_0(@NonNull String ifaceName) { 381 synchronized (mLock) { 382 if (mISupplicant == null) { 383 return null; 384 } 385 386 /** List all supplicant Ifaces */ 387 final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>(); 388 try { 389 mISupplicant.listInterfaces((SupplicantStatus status, 390 ArrayList<ISupplicant.IfaceInfo> ifaces) -> { 391 if (status.code != SupplicantStatusCode.SUCCESS) { 392 Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code); 393 return; 394 } 395 supplicantIfaces.addAll(ifaces); 396 }); 397 } catch (RemoteException e) { 398 Log.e(TAG, "ISupplicant.listInterfaces exception: " + e); 399 handleRemoteException(e, "listInterfaces"); 400 return null; 401 } 402 if (supplicantIfaces.size() == 0) { 403 Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup."); 404 return null; 405 } 406 Mutable<ISupplicantIface> supplicantIface = new Mutable<>(); 407 for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) { 408 if (ifaceInfo.type == IfaceType.STA && ifaceName.equals(ifaceInfo.name)) { 409 try { 410 mISupplicant.getInterface(ifaceInfo, 411 (SupplicantStatus status, ISupplicantIface iface) -> { 412 if (status.code != SupplicantStatusCode.SUCCESS) { 413 Log.e(TAG, "Failed to get ISupplicantIface " + status.code); 414 return; 415 } 416 supplicantIface.value = iface; 417 }); 418 } catch (RemoteException e) { 419 Log.e(TAG, "ISupplicant.getInterface exception: " + e); 420 handleRemoteException(e, "getInterface"); 421 return null; 422 } 423 break; 424 } 425 } 426 return supplicantIface.value; 427 } 428 } 429 430 /** 431 * Create a STA interface for the specified iface name. 432 * 433 * @param ifaceName Name of the interface. 434 * @return true on success, false otherwise. 435 */ addIfaceV1_1(@onNull String ifaceName)436 private ISupplicantIface addIfaceV1_1(@NonNull String ifaceName) { 437 synchronized (mLock) { 438 ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo(); 439 ifaceInfo.name = ifaceName; 440 ifaceInfo.type = IfaceType.STA; 441 Mutable<ISupplicantIface> supplicantIface = new Mutable<>(); 442 try { 443 getSupplicantMockableV1_1().addInterface(ifaceInfo, 444 (SupplicantStatus status, ISupplicantIface iface) -> { 445 if (status.code != SupplicantStatusCode.SUCCESS 446 && status.code != SupplicantStatusCode.FAILURE_IFACE_EXISTS) { 447 Log.e(TAG, "Failed to create ISupplicantIface " + status.code); 448 return; 449 } 450 supplicantIface.value = iface; 451 }); 452 } catch (RemoteException e) { 453 Log.e(TAG, "ISupplicant.addInterface exception: " + e); 454 handleRemoteException(e, "addInterface"); 455 return null; 456 } catch (NoSuchElementException e) { 457 Log.e(TAG, "ISupplicant.addInterface exception: " + e); 458 handleNoSuchElementException(e, "addInterface"); 459 return null; 460 } 461 return supplicantIface.value; 462 } 463 } 464 465 /** 466 * Teardown a STA interface for the specified iface name. 467 * 468 * @param ifaceName Name of the interface. 469 * @return true on success, false otherwise. 470 */ teardownIface(@onNull String ifaceName)471 public boolean teardownIface(@NonNull String ifaceName) { 472 synchronized (mLock) { 473 final String methodStr = "teardownIface"; 474 if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) == null) return false; 475 if (isV1_1()) { 476 if (!removeIfaceV1_1(ifaceName)) { 477 Log.e(TAG, "Failed to remove iface = " + ifaceName); 478 return false; 479 } 480 } 481 if (mISupplicantStaIfaces.remove(ifaceName) == null) { 482 Log.e(TAG, "Trying to teardown unknown inteface"); 483 return false; 484 } 485 mISupplicantStaIfaceCallbacks.remove(ifaceName); 486 return true; 487 } 488 } 489 490 /** 491 * Remove a STA interface for the specified iface name. 492 * 493 * @param ifaceName Name of the interface. 494 * @return true on success, false otherwise. 495 */ removeIfaceV1_1(@onNull String ifaceName)496 private boolean removeIfaceV1_1(@NonNull String ifaceName) { 497 synchronized (mLock) { 498 try { 499 ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo(); 500 ifaceInfo.name = ifaceName; 501 ifaceInfo.type = IfaceType.STA; 502 SupplicantStatus status = getSupplicantMockableV1_1().removeInterface(ifaceInfo); 503 if (status.code != SupplicantStatusCode.SUCCESS) { 504 Log.e(TAG, "Failed to remove iface " + status.code); 505 return false; 506 } 507 } catch (RemoteException e) { 508 Log.e(TAG, "ISupplicant.removeInterface exception: " + e); 509 handleRemoteException(e, "removeInterface"); 510 return false; 511 } catch (NoSuchElementException e) { 512 Log.e(TAG, "ISupplicant.removeInterface exception: " + e); 513 handleNoSuchElementException(e, "removeInterface"); 514 return false; 515 } 516 return true; 517 } 518 } 519 520 /** 521 * Registers a death notification for supplicant. 522 * @return Returns true on success. 523 */ registerDeathHandler(@onNull SupplicantDeathEventHandler handler)524 public boolean registerDeathHandler(@NonNull SupplicantDeathEventHandler handler) { 525 if (mDeathEventHandler != null) { 526 Log.e(TAG, "Death handler already present"); 527 } 528 mDeathEventHandler = handler; 529 return true; 530 } 531 532 /** 533 * Deregisters a death notification for supplicant. 534 * @return Returns true on success. 535 */ deregisterDeathHandler()536 public boolean deregisterDeathHandler() { 537 if (mDeathEventHandler == null) { 538 Log.e(TAG, "No Death handler present"); 539 } 540 mDeathEventHandler = null; 541 return true; 542 } 543 544 clearState()545 private void clearState() { 546 synchronized (mLock) { 547 mISupplicant = null; 548 mISupplicantStaIfaces.clear(); 549 mCurrentNetworkLocalConfigs.clear(); 550 mCurrentNetworkRemoteHandles.clear(); 551 } 552 } 553 supplicantServiceDiedHandler(long cookie)554 private void supplicantServiceDiedHandler(long cookie) { 555 synchronized (mLock) { 556 if (mDeathRecipientCookie != cookie) { 557 Log.i(TAG, "Ignoring stale death recipient notification"); 558 return; 559 } 560 for (String ifaceName : mISupplicantStaIfaces.keySet()) { 561 mWifiMonitor.broadcastSupplicantDisconnectionEvent(ifaceName); 562 } 563 clearState(); 564 if (mDeathEventHandler != null) { 565 mDeathEventHandler.onDeath(); 566 } 567 } 568 } 569 570 /** 571 * Signals whether Initialization completed successfully. 572 */ isInitializationStarted()573 public boolean isInitializationStarted() { 574 synchronized (mLock) { 575 return mIServiceManager != null; 576 } 577 } 578 579 /** 580 * Signals whether Initialization completed successfully. 581 */ isInitializationComplete()582 public boolean isInitializationComplete() { 583 synchronized (mLock) { 584 return mISupplicant != null; 585 } 586 } 587 588 589 /** 590 * Start the supplicant daemon for V1_1 service. 591 * 592 * @return true on success, false otherwise. 593 */ startDaemon_V1_1()594 private boolean startDaemon_V1_1() { 595 synchronized (mLock) { 596 try { 597 // This should startup supplicant daemon using the lazy start HAL mechanism. 598 getSupplicantMockableV1_1(); 599 } catch (RemoteException e) { 600 Log.e(TAG, "Exception while trying to start supplicant: " 601 + e); 602 supplicantServiceDiedHandler(mDeathRecipientCookie); 603 return false; 604 } catch (NoSuchElementException e) { 605 // We're starting the daemon, so expect |NoSuchElementException|. 606 Log.d(TAG, "Successfully triggered start of supplicant using HIDL"); 607 } 608 return true; 609 } 610 } 611 612 /** 613 * Start the supplicant daemon. 614 * 615 * @return true on success, false otherwise. 616 */ startDaemon()617 public boolean startDaemon() { 618 synchronized (mLock) { 619 if (isV1_1()) { 620 Log.i(TAG, "Starting supplicant using HIDL"); 621 return startDaemon_V1_1(); 622 } else { 623 Log.i(TAG, "Starting supplicant using init"); 624 mPropertyService.set(INIT_START_PROPERTY, INIT_SERVICE_NAME); 625 return true; 626 } 627 } 628 } 629 630 /** 631 * Terminate the supplicant daemon for V1_1 service. 632 */ terminate_V1_1()633 private void terminate_V1_1() { 634 synchronized (mLock) { 635 final String methodStr = "terminate"; 636 if (!checkSupplicantAndLogFailure(methodStr)) return; 637 try { 638 getSupplicantMockableV1_1().terminate(); 639 } catch (RemoteException e) { 640 handleRemoteException(e, methodStr); 641 } catch (NoSuchElementException e) { 642 handleNoSuchElementException(e, methodStr); 643 } 644 } 645 } 646 647 /** 648 * Terminate the supplicant daemon. 649 */ terminate()650 public void terminate() { 651 synchronized (mLock) { 652 if (isV1_1()) { 653 Log.i(TAG, "Terminating supplicant using HIDL"); 654 terminate_V1_1(); 655 } else { 656 Log.i(TAG, "Terminating supplicant using init"); 657 mPropertyService.set(INIT_STOP_PROPERTY, INIT_SERVICE_NAME); 658 } 659 } 660 } 661 662 /** 663 * Wrapper functions to access static HAL methods, created to be mockable in unit tests 664 */ getServiceManagerMockable()665 protected IServiceManager getServiceManagerMockable() throws RemoteException { 666 synchronized (mLock) { 667 return IServiceManager.getService(); 668 } 669 } 670 getSupplicantMockable()671 protected ISupplicant getSupplicantMockable() throws RemoteException, NoSuchElementException { 672 synchronized (mLock) { 673 return ISupplicant.getService(); 674 } 675 } 676 getSupplicantMockableV1_1()677 protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1() 678 throws RemoteException, NoSuchElementException { 679 synchronized (mLock) { 680 return android.hardware.wifi.supplicant.V1_1.ISupplicant.castFrom( 681 ISupplicant.getService()); 682 } 683 } 684 getSupplicantMockableV1_2()685 protected android.hardware.wifi.supplicant.V1_2.ISupplicant getSupplicantMockableV1_2() 686 throws RemoteException, NoSuchElementException { 687 synchronized (mLock) { 688 return android.hardware.wifi.supplicant.V1_2.ISupplicant.castFrom( 689 ISupplicant.getService()); 690 } 691 } 692 getStaIfaceMockable(ISupplicantIface iface)693 protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) { 694 synchronized (mLock) { 695 return ISupplicantStaIface.asInterface(iface.asBinder()); 696 } 697 } 698 699 protected android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface getStaIfaceMockableV1_1(ISupplicantIface iface)700 getStaIfaceMockableV1_1(ISupplicantIface iface) { 701 synchronized (mLock) { 702 return android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface 703 .asInterface(iface.asBinder()); 704 } 705 } 706 707 protected android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface getStaIfaceMockableV1_2(ISupplicantIface iface)708 getStaIfaceMockableV1_2(ISupplicantIface iface) { 709 synchronized (mLock) { 710 return android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface 711 .asInterface(iface.asBinder()); 712 } 713 } 714 715 /** 716 * Uses the IServiceManager to check if the device is running V1_1 of the HAL from the VINTF for 717 * the device. 718 * @return true if supported, false otherwise. 719 */ isV1_1()720 private boolean isV1_1() { 721 return checkHalVersionByInterfaceName( 722 android.hardware.wifi.supplicant.V1_1.ISupplicant.kInterfaceName); 723 } 724 725 /** 726 * Uses the IServiceManager to check if the device is running V1_2 of the HAL from the VINTF for 727 * the device. 728 * @return true if supported, false otherwise. 729 */ isV1_2()730 private boolean isV1_2() { 731 return checkHalVersionByInterfaceName( 732 android.hardware.wifi.supplicant.V1_2.ISupplicant.kInterfaceName); 733 } 734 checkHalVersionByInterfaceName(String interfaceName)735 private boolean checkHalVersionByInterfaceName(String interfaceName) { 736 if (interfaceName == null) { 737 return false; 738 } 739 synchronized (mLock) { 740 if (mIServiceManager == null) { 741 Log.e(TAG, "checkHalVersionByInterfaceName: called but mServiceManager is null"); 742 return false; 743 } 744 try { 745 return (mIServiceManager.getTransport( 746 interfaceName, 747 HAL_INSTANCE_NAME) 748 != IServiceManager.Transport.EMPTY); 749 } catch (RemoteException e) { 750 Log.e(TAG, "Exception while operating on IServiceManager: " + e); 751 handleRemoteException(e, "getTransport"); 752 return false; 753 } 754 } 755 } 756 757 /** 758 * Helper method to look up the network object for the specified iface. 759 */ getStaIface(@onNull String ifaceName)760 private ISupplicantStaIface getStaIface(@NonNull String ifaceName) { 761 return mISupplicantStaIfaces.get(ifaceName); 762 } 763 764 /** 765 * Helper method to look up the network object for the specified iface. 766 */ getCurrentNetworkRemoteHandle(@onNull String ifaceName)767 private SupplicantStaNetworkHal getCurrentNetworkRemoteHandle(@NonNull String ifaceName) { 768 return mCurrentNetworkRemoteHandles.get(ifaceName); 769 } 770 771 /** 772 * Helper method to look up the network config or the specified iface. 773 */ getCurrentNetworkLocalConfig(@onNull String ifaceName)774 private WifiConfiguration getCurrentNetworkLocalConfig(@NonNull String ifaceName) { 775 return mCurrentNetworkLocalConfigs.get(ifaceName); 776 } 777 778 /** 779 * Add a network configuration to wpa_supplicant. 780 * 781 * @param config Config corresponding to the network. 782 * @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects 783 * for the current network. 784 */ 785 private Pair<SupplicantStaNetworkHal, WifiConfiguration> addNetworkAndSaveConfig(@onNull String ifaceName, WifiConfiguration config)786 addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) { 787 synchronized (mLock) { 788 logi("addSupplicantStaNetwork via HIDL"); 789 if (config == null) { 790 loge("Cannot add NULL network!"); 791 return null; 792 } 793 SupplicantStaNetworkHal network = addNetwork(ifaceName); 794 if (network == null) { 795 loge("Failed to add a network!"); 796 return null; 797 } 798 boolean saveSuccess = false; 799 try { 800 saveSuccess = network.saveWifiConfiguration(config); 801 } catch (IllegalArgumentException e) { 802 Log.e(TAG, "Exception while saving config params: " + config, e); 803 } 804 if (!saveSuccess) { 805 loge("Failed to save variables for: " + config.configKey()); 806 if (!removeAllNetworks(ifaceName)) { 807 loge("Failed to remove all networks on failure."); 808 } 809 return null; 810 } 811 return new Pair(network, new WifiConfiguration(config)); 812 } 813 } 814 815 /** 816 * Add the provided network configuration to wpa_supplicant and initiate connection to it. 817 * This method does the following: 818 * 1. If |config| is different to the current supplicant network, removes all supplicant 819 * networks and saves |config|. 820 * 2. Select the new network in wpa_supplicant. 821 * 822 * @param ifaceName Name of the interface. 823 * @param config WifiConfiguration parameters for the provided network. 824 * @return {@code true} if it succeeds, {@code false} otherwise 825 */ connectToNetwork(@onNull String ifaceName, @NonNull WifiConfiguration config)826 public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) { 827 synchronized (mLock) { 828 logd("connectToNetwork " + config.configKey()); 829 WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); 830 if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) { 831 String networkSelectionBSSID = config.getNetworkSelectionStatus() 832 .getNetworkSelectionBSSID(); 833 String networkSelectionBSSIDCurrent = 834 currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID(); 835 if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) { 836 logd("Network is already saved, will not trigger remove and add operation."); 837 } else { 838 logd("Network is already saved, but need to update BSSID."); 839 if (!setCurrentNetworkBssid( 840 ifaceName, 841 config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) { 842 loge("Failed to set current network BSSID."); 843 return false; 844 } 845 mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config)); 846 } 847 } else { 848 mCurrentNetworkRemoteHandles.remove(ifaceName); 849 mCurrentNetworkLocalConfigs.remove(ifaceName); 850 if (!removeAllNetworks(ifaceName)) { 851 loge("Failed to remove existing networks"); 852 return false; 853 } 854 Pair<SupplicantStaNetworkHal, WifiConfiguration> pair = 855 addNetworkAndSaveConfig(ifaceName, config); 856 if (pair == null) { 857 loge("Failed to add/save network configuration: " + config.configKey()); 858 return false; 859 } 860 mCurrentNetworkRemoteHandles.put(ifaceName, pair.first); 861 mCurrentNetworkLocalConfigs.put(ifaceName, pair.second); 862 } 863 SupplicantStaNetworkHal networkHandle = 864 checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork"); 865 if (networkHandle == null || !networkHandle.select()) { 866 loge("Failed to select network configuration: " + config.configKey()); 867 return false; 868 } 869 return true; 870 } 871 } 872 873 /** 874 * Initiates roaming to the already configured network in wpa_supplicant. If the network 875 * configuration provided does not match the already configured network, then this triggers 876 * a new connection attempt (instead of roam). 877 * 1. First check if we're attempting to connect to the same network as we currently have 878 * configured. 879 * 2. Set the new bssid for the network in wpa_supplicant. 880 * 3. Trigger reassociate command to wpa_supplicant. 881 * 882 * @param ifaceName Name of the interface. 883 * @param config WifiConfiguration parameters for the provided network. 884 * @return {@code true} if it succeeds, {@code false} otherwise 885 */ roamToNetwork(@onNull String ifaceName, WifiConfiguration config)886 public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration config) { 887 synchronized (mLock) { 888 if (getCurrentNetworkId(ifaceName) != config.networkId) { 889 Log.w(TAG, "Cannot roam to a different network, initiate new connection. " 890 + "Current network ID: " + getCurrentNetworkId(ifaceName)); 891 return connectToNetwork(ifaceName, config); 892 } 893 String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID(); 894 logd("roamToNetwork" + config.configKey() + " (bssid " + bssid + ")"); 895 896 SupplicantStaNetworkHal networkHandle = 897 checkSupplicantStaNetworkAndLogFailure(ifaceName, "roamToNetwork"); 898 if (networkHandle == null || !networkHandle.setBssid(bssid)) { 899 loge("Failed to set new bssid on network: " + config.configKey()); 900 return false; 901 } 902 if (!reassociate(ifaceName)) { 903 loge("Failed to trigger reassociate"); 904 return false; 905 } 906 return true; 907 } 908 } 909 910 /** 911 * Load all the configured networks from wpa_supplicant. 912 * 913 * @param ifaceName Name of the interface. 914 * @param configs Map of configuration key to configuration objects corresponding to all 915 * the networks. 916 * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf 917 * @return true if succeeds, false otherwise. 918 */ loadNetworks(@onNull String ifaceName, Map<String, WifiConfiguration> configs, SparseArray<Map<String, String>> networkExtras)919 public boolean loadNetworks(@NonNull String ifaceName, Map<String, WifiConfiguration> configs, 920 SparseArray<Map<String, String>> networkExtras) { 921 synchronized (mLock) { 922 List<Integer> networkIds = listNetworks(ifaceName); 923 if (networkIds == null) { 924 Log.e(TAG, "Failed to list networks"); 925 return false; 926 } 927 for (Integer networkId : networkIds) { 928 SupplicantStaNetworkHal network = getNetwork(ifaceName, networkId); 929 if (network == null) { 930 Log.e(TAG, "Failed to get network with ID: " + networkId); 931 return false; 932 } 933 WifiConfiguration config = new WifiConfiguration(); 934 Map<String, String> networkExtra = new HashMap<>(); 935 boolean loadSuccess = false; 936 try { 937 loadSuccess = network.loadWifiConfiguration(config, networkExtra); 938 } catch (IllegalArgumentException e) { 939 Log.wtf(TAG, "Exception while loading config params: " + config, e); 940 } 941 if (!loadSuccess) { 942 Log.e(TAG, "Failed to load wifi configuration for network with ID: " + networkId 943 + ". Skipping..."); 944 continue; 945 } 946 // Set the default IP assignments. 947 config.setIpAssignment(IpConfiguration.IpAssignment.DHCP); 948 config.setProxySettings(IpConfiguration.ProxySettings.NONE); 949 950 networkExtras.put(networkId, networkExtra); 951 String configKey = 952 networkExtra.get(SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY); 953 final WifiConfiguration duplicateConfig = configs.put(configKey, config); 954 if (duplicateConfig != null) { 955 // The network is already known. Overwrite the duplicate entry. 956 Log.i(TAG, "Replacing duplicate network: " + duplicateConfig.networkId); 957 removeNetwork(ifaceName, duplicateConfig.networkId); 958 networkExtras.remove(duplicateConfig.networkId); 959 } 960 } 961 return true; 962 } 963 } 964 965 /** 966 * Remove the request |networkId| from supplicant if it's the current network, 967 * if the current configured network matches |networkId|. 968 * 969 * @param ifaceName Name of the interface. 970 * @param networkId network id of the network to be removed from supplicant. 971 */ removeNetworkIfCurrent(@onNull String ifaceName, int networkId)972 public void removeNetworkIfCurrent(@NonNull String ifaceName, int networkId) { 973 synchronized (mLock) { 974 if (getCurrentNetworkId(ifaceName) == networkId) { 975 // Currently we only save 1 network in supplicant. 976 removeAllNetworks(ifaceName); 977 } 978 } 979 } 980 981 /** 982 * Remove all networks from supplicant 983 * 984 * @param ifaceName Name of the interface. 985 */ removeAllNetworks(@onNull String ifaceName)986 public boolean removeAllNetworks(@NonNull String ifaceName) { 987 synchronized (mLock) { 988 ArrayList<Integer> networks = listNetworks(ifaceName); 989 if (networks == null) { 990 Log.e(TAG, "removeAllNetworks failed, got null networks"); 991 return false; 992 } 993 for (int id : networks) { 994 if (!removeNetwork(ifaceName, id)) { 995 Log.e(TAG, "removeAllNetworks failed to remove network: " + id); 996 return false; 997 } 998 } 999 // Reset current network info. Probably not needed once we add support to remove/reset 1000 // current network on receiving disconnection event from supplicant (b/32898136). 1001 mCurrentNetworkRemoteHandles.remove(ifaceName); 1002 mCurrentNetworkLocalConfigs.remove(ifaceName); 1003 return true; 1004 } 1005 } 1006 1007 /** 1008 * Set the currently configured network's bssid. 1009 * 1010 * @param ifaceName Name of the interface. 1011 * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX" 1012 * @return true if succeeds, false otherwise. 1013 */ setCurrentNetworkBssid(@onNull String ifaceName, String bssidStr)1014 public boolean setCurrentNetworkBssid(@NonNull String ifaceName, String bssidStr) { 1015 synchronized (mLock) { 1016 SupplicantStaNetworkHal networkHandle = 1017 checkSupplicantStaNetworkAndLogFailure(ifaceName, "setCurrentNetworkBssid"); 1018 if (networkHandle == null) return false; 1019 return networkHandle.setBssid(bssidStr); 1020 } 1021 } 1022 1023 /** 1024 * Get the currently configured network's WPS NFC token. 1025 * 1026 * @param ifaceName Name of the interface. 1027 * @return Hex string corresponding to the WPS NFC token. 1028 */ getCurrentNetworkWpsNfcConfigurationToken(@onNull String ifaceName)1029 public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) { 1030 synchronized (mLock) { 1031 SupplicantStaNetworkHal networkHandle = 1032 checkSupplicantStaNetworkAndLogFailure( 1033 ifaceName, "getCurrentNetworkWpsNfcConfigurationToken"); 1034 if (networkHandle == null) return null; 1035 return networkHandle.getWpsNfcConfigurationToken(); 1036 } 1037 } 1038 1039 /** 1040 * Get the eap anonymous identity for the currently configured network. 1041 * 1042 * @param ifaceName Name of the interface. 1043 * @return anonymous identity string if succeeds, null otherwise. 1044 */ getCurrentNetworkEapAnonymousIdentity(@onNull String ifaceName)1045 public String getCurrentNetworkEapAnonymousIdentity(@NonNull String ifaceName) { 1046 synchronized (mLock) { 1047 SupplicantStaNetworkHal networkHandle = 1048 checkSupplicantStaNetworkAndLogFailure( 1049 ifaceName, "getCurrentNetworkEapAnonymousIdentity"); 1050 if (networkHandle == null) return null; 1051 return networkHandle.fetchEapAnonymousIdentity(); 1052 } 1053 } 1054 1055 /** 1056 * Send the eap identity response for the currently configured network. 1057 * 1058 * @param ifaceName Name of the interface. 1059 * @param identity identity used for EAP-Identity 1060 * @param encryptedIdentity encrypted identity used for EAP-AKA/EAP-SIM 1061 * @return true if succeeds, false otherwise. 1062 */ sendCurrentNetworkEapIdentityResponse( @onNull String ifaceName, @NonNull String identity, String encryptedIdentity)1063 public boolean sendCurrentNetworkEapIdentityResponse( 1064 @NonNull String ifaceName, @NonNull String identity, String encryptedIdentity) { 1065 synchronized (mLock) { 1066 SupplicantStaNetworkHal networkHandle = 1067 checkSupplicantStaNetworkAndLogFailure( 1068 ifaceName, "sendCurrentNetworkEapIdentityResponse"); 1069 if (networkHandle == null) return false; 1070 return networkHandle.sendNetworkEapIdentityResponse(identity, encryptedIdentity); 1071 } 1072 } 1073 1074 /** 1075 * Send the eap sim gsm auth response for the currently configured network. 1076 * 1077 * @param ifaceName Name of the interface. 1078 * @param paramsStr String to send. 1079 * @return true if succeeds, false otherwise. 1080 */ sendCurrentNetworkEapSimGsmAuthResponse( @onNull String ifaceName, String paramsStr)1081 public boolean sendCurrentNetworkEapSimGsmAuthResponse( 1082 @NonNull String ifaceName, String paramsStr) { 1083 synchronized (mLock) { 1084 SupplicantStaNetworkHal networkHandle = 1085 checkSupplicantStaNetworkAndLogFailure( 1086 ifaceName, "sendCurrentNetworkEapSimGsmAuthResponse"); 1087 if (networkHandle == null) return false; 1088 return networkHandle.sendNetworkEapSimGsmAuthResponse(paramsStr); 1089 } 1090 } 1091 1092 /** 1093 * Send the eap sim gsm auth failure for the currently configured network. 1094 * 1095 * @param ifaceName Name of the interface. 1096 * @return true if succeeds, false otherwise. 1097 */ sendCurrentNetworkEapSimGsmAuthFailure(@onNull String ifaceName)1098 public boolean sendCurrentNetworkEapSimGsmAuthFailure(@NonNull String ifaceName) { 1099 synchronized (mLock) { 1100 SupplicantStaNetworkHal networkHandle = 1101 checkSupplicantStaNetworkAndLogFailure( 1102 ifaceName, "sendCurrentNetworkEapSimGsmAuthFailure"); 1103 if (networkHandle == null) return false; 1104 return networkHandle.sendNetworkEapSimGsmAuthFailure(); 1105 } 1106 } 1107 1108 /** 1109 * Send the eap sim umts auth response for the currently configured network. 1110 * 1111 * @param ifaceName Name of the interface. 1112 * @param paramsStr String to send. 1113 * @return true if succeeds, false otherwise. 1114 */ sendCurrentNetworkEapSimUmtsAuthResponse( @onNull String ifaceName, String paramsStr)1115 public boolean sendCurrentNetworkEapSimUmtsAuthResponse( 1116 @NonNull String ifaceName, String paramsStr) { 1117 synchronized (mLock) { 1118 SupplicantStaNetworkHal networkHandle = 1119 checkSupplicantStaNetworkAndLogFailure( 1120 ifaceName, "sendCurrentNetworkEapSimUmtsAuthResponse"); 1121 if (networkHandle == null) return false; 1122 return networkHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr); 1123 } 1124 } 1125 1126 /** 1127 * Send the eap sim umts auts response for the currently configured network. 1128 * 1129 * @param ifaceName Name of the interface. 1130 * @param paramsStr String to send. 1131 * @return true if succeeds, false otherwise. 1132 */ sendCurrentNetworkEapSimUmtsAutsResponse( @onNull String ifaceName, String paramsStr)1133 public boolean sendCurrentNetworkEapSimUmtsAutsResponse( 1134 @NonNull String ifaceName, String paramsStr) { 1135 synchronized (mLock) { 1136 SupplicantStaNetworkHal networkHandle = 1137 checkSupplicantStaNetworkAndLogFailure( 1138 ifaceName, "sendCurrentNetworkEapSimUmtsAutsResponse"); 1139 if (networkHandle == null) return false; 1140 return networkHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr); 1141 } 1142 } 1143 1144 /** 1145 * Send the eap sim umts auth failure for the currently configured network. 1146 * 1147 * @param ifaceName Name of the interface. 1148 * @return true if succeeds, false otherwise. 1149 */ sendCurrentNetworkEapSimUmtsAuthFailure(@onNull String ifaceName)1150 public boolean sendCurrentNetworkEapSimUmtsAuthFailure(@NonNull String ifaceName) { 1151 synchronized (mLock) { 1152 SupplicantStaNetworkHal networkHandle = 1153 checkSupplicantStaNetworkAndLogFailure( 1154 ifaceName, "sendCurrentNetworkEapSimUmtsAuthFailure"); 1155 if (networkHandle == null) return false; 1156 return networkHandle.sendNetworkEapSimUmtsAuthFailure(); 1157 } 1158 } 1159 1160 /** 1161 * Adds a new network. 1162 * 1163 * @return The ISupplicantNetwork object for the new network, or null if the call fails 1164 */ addNetwork(@onNull String ifaceName)1165 private SupplicantStaNetworkHal addNetwork(@NonNull String ifaceName) { 1166 synchronized (mLock) { 1167 final String methodStr = "addNetwork"; 1168 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1169 if (iface == null) return null; 1170 Mutable<ISupplicantNetwork> newNetwork = new Mutable<>(); 1171 try { 1172 iface.addNetwork((SupplicantStatus status, 1173 ISupplicantNetwork network) -> { 1174 if (checkStatusAndLogFailure(status, methodStr)) { 1175 newNetwork.value = network; 1176 } 1177 }); 1178 } catch (RemoteException e) { 1179 handleRemoteException(e, methodStr); 1180 } 1181 if (newNetwork.value != null) { 1182 return getStaNetworkMockable( 1183 ifaceName, 1184 ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder())); 1185 } else { 1186 return null; 1187 } 1188 } 1189 } 1190 1191 /** 1192 * Remove network from supplicant with network Id 1193 * 1194 * @return true if request is sent successfully, false otherwise. 1195 */ removeNetwork(@onNull String ifaceName, int id)1196 private boolean removeNetwork(@NonNull String ifaceName, int id) { 1197 synchronized (mLock) { 1198 final String methodStr = "removeNetwork"; 1199 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1200 if (iface == null) return false; 1201 try { 1202 SupplicantStatus status = iface.removeNetwork(id); 1203 return checkStatusAndLogFailure(status, methodStr); 1204 } catch (RemoteException e) { 1205 handleRemoteException(e, methodStr); 1206 return false; 1207 } 1208 } 1209 } 1210 1211 /** 1212 * Use this to mock the creation of SupplicantStaNetworkHal instance. 1213 * 1214 * @param ifaceName Name of the interface. 1215 * @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL. 1216 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 1217 * the call fails 1218 */ getStaNetworkMockable( @onNull String ifaceName, ISupplicantStaNetwork iSupplicantStaNetwork)1219 protected SupplicantStaNetworkHal getStaNetworkMockable( 1220 @NonNull String ifaceName, ISupplicantStaNetwork iSupplicantStaNetwork) { 1221 synchronized (mLock) { 1222 SupplicantStaNetworkHal network = 1223 new SupplicantStaNetworkHal(iSupplicantStaNetwork, ifaceName, mContext, 1224 mWifiMonitor); 1225 if (network != null) { 1226 network.enableVerboseLogging(mVerboseLoggingEnabled); 1227 } 1228 return network; 1229 } 1230 } 1231 1232 /** 1233 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 1234 * the call fails 1235 */ getNetwork(@onNull String ifaceName, int id)1236 private SupplicantStaNetworkHal getNetwork(@NonNull String ifaceName, int id) { 1237 synchronized (mLock) { 1238 final String methodStr = "getNetwork"; 1239 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1240 if (iface == null) return null; 1241 Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>(); 1242 try { 1243 iface.getNetwork(id, (SupplicantStatus status, ISupplicantNetwork network) -> { 1244 if (checkStatusAndLogFailure(status, methodStr)) { 1245 gotNetwork.value = network; 1246 } 1247 }); 1248 } catch (RemoteException e) { 1249 handleRemoteException(e, methodStr); 1250 } 1251 if (gotNetwork.value != null) { 1252 return getStaNetworkMockable( 1253 ifaceName, 1254 ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder())); 1255 } else { 1256 return null; 1257 } 1258 } 1259 } 1260 1261 /** See ISupplicantStaNetwork.hal for documentation */ registerCallback( ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback)1262 private boolean registerCallback( 1263 ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback) { 1264 synchronized (mLock) { 1265 final String methodStr = "registerCallback"; 1266 if (iface == null) return false; 1267 try { 1268 SupplicantStatus status = iface.registerCallback(callback); 1269 return checkStatusAndLogFailure(status, methodStr); 1270 } catch (RemoteException e) { 1271 handleRemoteException(e, methodStr); 1272 return false; 1273 } 1274 } 1275 } 1276 registerCallbackV1_1( android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface, android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback callback)1277 private boolean registerCallbackV1_1( 1278 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface, 1279 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback callback) { 1280 synchronized (mLock) { 1281 String methodStr = "registerCallback_1_1"; 1282 1283 if (iface == null) return false; 1284 try { 1285 SupplicantStatus status = iface.registerCallback_1_1(callback); 1286 return checkStatusAndLogFailure(status, methodStr); 1287 } catch (RemoteException e) { 1288 handleRemoteException(e, methodStr); 1289 return false; 1290 } 1291 } 1292 } 1293 registerCallbackV1_2( android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface iface, android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback callback)1294 private boolean registerCallbackV1_2( 1295 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface iface, 1296 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback callback) { 1297 synchronized (mLock) { 1298 String methodStr = "registerCallback_1_2"; 1299 1300 if (iface == null) return false; 1301 try { 1302 SupplicantStatus status = iface.registerCallback_1_2(callback); 1303 return checkStatusAndLogFailure(status, methodStr); 1304 } catch (RemoteException e) { 1305 handleRemoteException(e, methodStr); 1306 return false; 1307 } 1308 } 1309 } 1310 1311 /** 1312 * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns 1313 * null if the call fails 1314 */ listNetworks(@onNull String ifaceName)1315 private java.util.ArrayList<Integer> listNetworks(@NonNull String ifaceName) { 1316 synchronized (mLock) { 1317 final String methodStr = "listNetworks"; 1318 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1319 if (iface == null) return null; 1320 Mutable<ArrayList<Integer>> networkIdList = new Mutable<>(); 1321 try { 1322 iface.listNetworks((SupplicantStatus status, ArrayList<Integer> networkIds) -> { 1323 if (checkStatusAndLogFailure(status, methodStr)) { 1324 networkIdList.value = networkIds; 1325 } 1326 }); 1327 } catch (RemoteException e) { 1328 handleRemoteException(e, methodStr); 1329 } 1330 return networkIdList.value; 1331 } 1332 } 1333 1334 /** 1335 * Set WPS device name. 1336 * 1337 * @param ifaceName Name of the interface. 1338 * @param name String to be set. 1339 * @return true if request is sent successfully, false otherwise. 1340 */ setWpsDeviceName(@onNull String ifaceName, String name)1341 public boolean setWpsDeviceName(@NonNull String ifaceName, String name) { 1342 synchronized (mLock) { 1343 final String methodStr = "setWpsDeviceName"; 1344 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1345 if (iface == null) return false; 1346 try { 1347 SupplicantStatus status = iface.setWpsDeviceName(name); 1348 return checkStatusAndLogFailure(status, methodStr); 1349 } catch (RemoteException e) { 1350 handleRemoteException(e, methodStr); 1351 return false; 1352 } 1353 } 1354 } 1355 1356 /** 1357 * Set WPS device type. 1358 * 1359 * @param ifaceName Name of the interface. 1360 * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg> 1361 * @return true if request is sent successfully, false otherwise. 1362 */ setWpsDeviceType(@onNull String ifaceName, String typeStr)1363 public boolean setWpsDeviceType(@NonNull String ifaceName, String typeStr) { 1364 synchronized (mLock) { 1365 try { 1366 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr); 1367 if (!match.find() || match.groupCount() != 3) { 1368 Log.e(TAG, "Malformed WPS device type " + typeStr); 1369 return false; 1370 } 1371 short categ = Short.parseShort(match.group(1)); 1372 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2)); 1373 short subCateg = Short.parseShort(match.group(3)); 1374 1375 byte[] bytes = new byte[8]; 1376 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); 1377 byteBuffer.putShort(categ); 1378 byteBuffer.put(oui); 1379 byteBuffer.putShort(subCateg); 1380 return setWpsDeviceType(ifaceName, bytes); 1381 } catch (IllegalArgumentException e) { 1382 Log.e(TAG, "Illegal argument " + typeStr, e); 1383 return false; 1384 } 1385 } 1386 } 1387 setWpsDeviceType(@onNull String ifaceName, byte[ ] type)1388 private boolean setWpsDeviceType(@NonNull String ifaceName, byte[/* 8 */] type) { 1389 synchronized (mLock) { 1390 final String methodStr = "setWpsDeviceType"; 1391 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1392 if (iface == null) return false; 1393 try { 1394 SupplicantStatus status = iface.setWpsDeviceType(type); 1395 return checkStatusAndLogFailure(status, methodStr); 1396 } catch (RemoteException e) { 1397 handleRemoteException(e, methodStr); 1398 return false; 1399 } 1400 } 1401 } 1402 1403 /** 1404 * Set WPS manufacturer. 1405 * 1406 * @param ifaceName Name of the interface. 1407 * @param manufacturer String to be set. 1408 * @return true if request is sent successfully, false otherwise. 1409 */ setWpsManufacturer(@onNull String ifaceName, String manufacturer)1410 public boolean setWpsManufacturer(@NonNull String ifaceName, String manufacturer) { 1411 synchronized (mLock) { 1412 final String methodStr = "setWpsManufacturer"; 1413 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1414 if (iface == null) return false; 1415 try { 1416 SupplicantStatus status = iface.setWpsManufacturer(manufacturer); 1417 return checkStatusAndLogFailure(status, methodStr); 1418 } catch (RemoteException e) { 1419 handleRemoteException(e, methodStr); 1420 return false; 1421 } 1422 } 1423 } 1424 1425 /** 1426 * Set WPS model name. 1427 * 1428 * @param ifaceName Name of the interface. 1429 * @param modelName String to be set. 1430 * @return true if request is sent successfully, false otherwise. 1431 */ setWpsModelName(@onNull String ifaceName, String modelName)1432 public boolean setWpsModelName(@NonNull String ifaceName, String modelName) { 1433 synchronized (mLock) { 1434 final String methodStr = "setWpsModelName"; 1435 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1436 if (iface == null) return false; 1437 try { 1438 SupplicantStatus status = iface.setWpsModelName(modelName); 1439 return checkStatusAndLogFailure(status, methodStr); 1440 } catch (RemoteException e) { 1441 handleRemoteException(e, methodStr); 1442 return false; 1443 } 1444 } 1445 } 1446 1447 /** 1448 * Set WPS model number. 1449 * 1450 * @param ifaceName Name of the interface. 1451 * @param modelNumber String to be set. 1452 * @return true if request is sent successfully, false otherwise. 1453 */ setWpsModelNumber(@onNull String ifaceName, String modelNumber)1454 public boolean setWpsModelNumber(@NonNull String ifaceName, String modelNumber) { 1455 synchronized (mLock) { 1456 final String methodStr = "setWpsModelNumber"; 1457 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1458 if (iface == null) return false; 1459 try { 1460 SupplicantStatus status = iface.setWpsModelNumber(modelNumber); 1461 return checkStatusAndLogFailure(status, methodStr); 1462 } catch (RemoteException e) { 1463 handleRemoteException(e, methodStr); 1464 return false; 1465 } 1466 } 1467 } 1468 1469 /** 1470 * Set WPS serial number. 1471 * 1472 * @param ifaceName Name of the interface. 1473 * @param serialNumber String to be set. 1474 * @return true if request is sent successfully, false otherwise. 1475 */ setWpsSerialNumber(@onNull String ifaceName, String serialNumber)1476 public boolean setWpsSerialNumber(@NonNull String ifaceName, String serialNumber) { 1477 synchronized (mLock) { 1478 final String methodStr = "setWpsSerialNumber"; 1479 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1480 if (iface == null) return false; 1481 try { 1482 SupplicantStatus status = iface.setWpsSerialNumber(serialNumber); 1483 return checkStatusAndLogFailure(status, methodStr); 1484 } catch (RemoteException e) { 1485 handleRemoteException(e, methodStr); 1486 return false; 1487 } 1488 } 1489 } 1490 1491 /** 1492 * Set WPS config methods 1493 * 1494 * @param ifaceName Name of the interface. 1495 * @param configMethodsStr List of config methods. 1496 * @return true if request is sent successfully, false otherwise. 1497 */ setWpsConfigMethods(@onNull String ifaceName, String configMethodsStr)1498 public boolean setWpsConfigMethods(@NonNull String ifaceName, String configMethodsStr) { 1499 synchronized (mLock) { 1500 short configMethodsMask = 0; 1501 String[] configMethodsStrArr = configMethodsStr.split("\\s+"); 1502 for (int i = 0; i < configMethodsStrArr.length; i++) { 1503 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]); 1504 } 1505 return setWpsConfigMethods(ifaceName, configMethodsMask); 1506 } 1507 } 1508 setWpsConfigMethods(@onNull String ifaceName, short configMethods)1509 private boolean setWpsConfigMethods(@NonNull String ifaceName, short configMethods) { 1510 synchronized (mLock) { 1511 final String methodStr = "setWpsConfigMethods"; 1512 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1513 if (iface == null) return false; 1514 try { 1515 SupplicantStatus status = iface.setWpsConfigMethods(configMethods); 1516 return checkStatusAndLogFailure(status, methodStr); 1517 } catch (RemoteException e) { 1518 handleRemoteException(e, methodStr); 1519 return false; 1520 } 1521 } 1522 } 1523 1524 /** 1525 * Trigger a reassociation even if the iface is currently connected. 1526 * 1527 * @param ifaceName Name of the interface. 1528 * @return true if request is sent successfully, false otherwise. 1529 */ reassociate(@onNull String ifaceName)1530 public boolean reassociate(@NonNull String ifaceName) { 1531 synchronized (mLock) { 1532 final String methodStr = "reassociate"; 1533 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1534 if (iface == null) return false; 1535 try { 1536 SupplicantStatus status = iface.reassociate(); 1537 return checkStatusAndLogFailure(status, methodStr); 1538 } catch (RemoteException e) { 1539 handleRemoteException(e, methodStr); 1540 return false; 1541 } 1542 } 1543 } 1544 1545 /** 1546 * Trigger a reconnection if the iface is disconnected. 1547 * 1548 * @param ifaceName Name of the interface. 1549 * @return true if request is sent successfully, false otherwise. 1550 */ reconnect(@onNull String ifaceName)1551 public boolean reconnect(@NonNull String ifaceName) { 1552 synchronized (mLock) { 1553 final String methodStr = "reconnect"; 1554 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1555 if (iface == null) return false; 1556 try { 1557 SupplicantStatus status = iface.reconnect(); 1558 return checkStatusAndLogFailure(status, methodStr); 1559 } catch (RemoteException e) { 1560 handleRemoteException(e, methodStr); 1561 return false; 1562 } 1563 } 1564 } 1565 1566 /** 1567 * Trigger a disconnection from the currently connected network. 1568 * 1569 * @param ifaceName Name of the interface. 1570 * @return true if request is sent successfully, false otherwise. 1571 */ disconnect(@onNull String ifaceName)1572 public boolean disconnect(@NonNull String ifaceName) { 1573 synchronized (mLock) { 1574 final String methodStr = "disconnect"; 1575 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1576 if (iface == null) return false; 1577 try { 1578 SupplicantStatus status = iface.disconnect(); 1579 return checkStatusAndLogFailure(status, methodStr); 1580 } catch (RemoteException e) { 1581 handleRemoteException(e, methodStr); 1582 return false; 1583 } 1584 } 1585 } 1586 1587 /** 1588 * Enable or disable power save mode. 1589 * 1590 * @param ifaceName Name of the interface. 1591 * @param enable true to enable, false to disable. 1592 * @return true if request is sent successfully, false otherwise. 1593 */ setPowerSave(@onNull String ifaceName, boolean enable)1594 public boolean setPowerSave(@NonNull String ifaceName, boolean enable) { 1595 synchronized (mLock) { 1596 final String methodStr = "setPowerSave"; 1597 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1598 if (iface == null) return false; 1599 try { 1600 SupplicantStatus status = iface.setPowerSave(enable); 1601 return checkStatusAndLogFailure(status, methodStr); 1602 } catch (RemoteException e) { 1603 handleRemoteException(e, methodStr); 1604 return false; 1605 } 1606 } 1607 } 1608 1609 /** 1610 * Initiate TDLS discover with the specified AP. 1611 * 1612 * @param ifaceName Name of the interface. 1613 * @param macAddress MAC Address of the AP. 1614 * @return true if request is sent successfully, false otherwise. 1615 */ initiateTdlsDiscover(@onNull String ifaceName, String macAddress)1616 public boolean initiateTdlsDiscover(@NonNull String ifaceName, String macAddress) { 1617 synchronized (mLock) { 1618 try { 1619 return initiateTdlsDiscover( 1620 ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1621 } catch (IllegalArgumentException e) { 1622 Log.e(TAG, "Illegal argument " + macAddress, e); 1623 return false; 1624 } 1625 } 1626 } 1627 /** See ISupplicantStaIface.hal for documentation */ initiateTdlsDiscover(@onNull String ifaceName, byte[ ] macAddress)1628 private boolean initiateTdlsDiscover(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1629 synchronized (mLock) { 1630 final String methodStr = "initiateTdlsDiscover"; 1631 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1632 if (iface == null) return false; 1633 try { 1634 SupplicantStatus status = iface.initiateTdlsDiscover(macAddress); 1635 return checkStatusAndLogFailure(status, methodStr); 1636 } catch (RemoteException e) { 1637 handleRemoteException(e, methodStr); 1638 return false; 1639 } 1640 } 1641 } 1642 1643 /** 1644 * Initiate TDLS setup with the specified AP. 1645 * 1646 * @param ifaceName Name of the interface. 1647 * @param macAddress MAC Address of the AP. 1648 * @return true if request is sent successfully, false otherwise. 1649 */ initiateTdlsSetup(@onNull String ifaceName, String macAddress)1650 public boolean initiateTdlsSetup(@NonNull String ifaceName, String macAddress) { 1651 synchronized (mLock) { 1652 try { 1653 return initiateTdlsSetup(ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1654 } catch (IllegalArgumentException e) { 1655 Log.e(TAG, "Illegal argument " + macAddress, e); 1656 return false; 1657 } 1658 } 1659 } 1660 /** See ISupplicantStaIface.hal for documentation */ initiateTdlsSetup(@onNull String ifaceName, byte[ ] macAddress)1661 private boolean initiateTdlsSetup(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1662 synchronized (mLock) { 1663 final String methodStr = "initiateTdlsSetup"; 1664 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1665 if (iface == null) return false; 1666 try { 1667 SupplicantStatus status = iface.initiateTdlsSetup(macAddress); 1668 return checkStatusAndLogFailure(status, methodStr); 1669 } catch (RemoteException e) { 1670 handleRemoteException(e, methodStr); 1671 return false; 1672 } 1673 } 1674 } 1675 1676 /** 1677 * Initiate TDLS teardown with the specified AP. 1678 * @param ifaceName Name of the interface. 1679 * @param macAddress MAC Address of the AP. 1680 * @return true if request is sent successfully, false otherwise. 1681 */ initiateTdlsTeardown(@onNull String ifaceName, String macAddress)1682 public boolean initiateTdlsTeardown(@NonNull String ifaceName, String macAddress) { 1683 synchronized (mLock) { 1684 try { 1685 return initiateTdlsTeardown( 1686 ifaceName, NativeUtil.macAddressToByteArray(macAddress)); 1687 } catch (IllegalArgumentException e) { 1688 Log.e(TAG, "Illegal argument " + macAddress, e); 1689 return false; 1690 } 1691 } 1692 } 1693 1694 /** See ISupplicantStaIface.hal for documentation */ initiateTdlsTeardown(@onNull String ifaceName, byte[ ] macAddress)1695 private boolean initiateTdlsTeardown(@NonNull String ifaceName, byte[/* 6 */] macAddress) { 1696 synchronized (mLock) { 1697 final String methodStr = "initiateTdlsTeardown"; 1698 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1699 if (iface == null) return false; 1700 try { 1701 SupplicantStatus status = iface.initiateTdlsTeardown(macAddress); 1702 return checkStatusAndLogFailure(status, methodStr); 1703 } catch (RemoteException e) { 1704 handleRemoteException(e, methodStr); 1705 return false; 1706 } 1707 } 1708 } 1709 1710 /** 1711 * Request the specified ANQP elements |elements| from the specified AP |bssid|. 1712 * 1713 * @param ifaceName Name of the interface. 1714 * @param bssid BSSID of the AP 1715 * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId. 1716 * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes. 1717 * @return true if request is sent successfully, false otherwise. 1718 */ initiateAnqpQuery(@onNull String ifaceName, String bssid, ArrayList<Short> infoElements, ArrayList<Integer> hs20SubTypes)1719 public boolean initiateAnqpQuery(@NonNull String ifaceName, String bssid, 1720 ArrayList<Short> infoElements, 1721 ArrayList<Integer> hs20SubTypes) { 1722 synchronized (mLock) { 1723 try { 1724 return initiateAnqpQuery( 1725 ifaceName, 1726 NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes); 1727 } catch (IllegalArgumentException e) { 1728 Log.e(TAG, "Illegal argument " + bssid, e); 1729 return false; 1730 } 1731 } 1732 } 1733 1734 /** See ISupplicantStaIface.hal for documentation */ initiateAnqpQuery(@onNull String ifaceName, byte[ ] macAddress, java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes)1735 private boolean initiateAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress, 1736 java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) { 1737 synchronized (mLock) { 1738 final String methodStr = "initiateAnqpQuery"; 1739 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1740 if (iface == null) return false; 1741 try { 1742 SupplicantStatus status = iface.initiateAnqpQuery( 1743 macAddress, infoElements, subTypes); 1744 return checkStatusAndLogFailure(status, methodStr); 1745 } catch (RemoteException e) { 1746 handleRemoteException(e, methodStr); 1747 return false; 1748 } 1749 } 1750 } 1751 1752 /** 1753 * Request the specified ANQP ICON from the specified AP |bssid|. 1754 * 1755 * @param ifaceName Name of the interface. 1756 * @param bssid BSSID of the AP 1757 * @param fileName Name of the file to request. 1758 * @return true if request is sent successfully, false otherwise. 1759 */ initiateHs20IconQuery(@onNull String ifaceName, String bssid, String fileName)1760 public boolean initiateHs20IconQuery(@NonNull String ifaceName, String bssid, String fileName) { 1761 synchronized (mLock) { 1762 try { 1763 return initiateHs20IconQuery( 1764 ifaceName, NativeUtil.macAddressToByteArray(bssid), fileName); 1765 } catch (IllegalArgumentException e) { 1766 Log.e(TAG, "Illegal argument " + bssid, e); 1767 return false; 1768 } 1769 } 1770 } 1771 1772 /** See ISupplicantStaIface.hal for documentation */ initiateHs20IconQuery(@onNull String ifaceName, byte[ ] macAddress, String fileName)1773 private boolean initiateHs20IconQuery(@NonNull String ifaceName, 1774 byte[/* 6 */] macAddress, String fileName) { 1775 synchronized (mLock) { 1776 final String methodStr = "initiateHs20IconQuery"; 1777 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1778 if (iface == null) return false; 1779 try { 1780 SupplicantStatus status = iface.initiateHs20IconQuery(macAddress, fileName); 1781 return checkStatusAndLogFailure(status, methodStr); 1782 } catch (RemoteException e) { 1783 handleRemoteException(e, methodStr); 1784 return false; 1785 } 1786 } 1787 } 1788 1789 /** 1790 * Makes a callback to HIDL to getMacAddress from supplicant 1791 * 1792 * @param ifaceName Name of the interface. 1793 * @return string containing the MAC address, or null on a failed call 1794 */ getMacAddress(@onNull String ifaceName)1795 public String getMacAddress(@NonNull String ifaceName) { 1796 synchronized (mLock) { 1797 final String methodStr = "getMacAddress"; 1798 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1799 if (iface == null) return null; 1800 Mutable<String> gotMac = new Mutable<>(); 1801 try { 1802 iface.getMacAddress((SupplicantStatus status, 1803 byte[/* 6 */] macAddr) -> { 1804 if (checkStatusAndLogFailure(status, methodStr)) { 1805 gotMac.value = NativeUtil.macAddressFromByteArray(macAddr); 1806 } 1807 }); 1808 } catch (RemoteException e) { 1809 handleRemoteException(e, methodStr); 1810 } 1811 return gotMac.value; 1812 } 1813 } 1814 1815 /** 1816 * Start using the added RX filters. 1817 * 1818 * @param ifaceName Name of the interface. 1819 * @return true if request is sent successfully, false otherwise. 1820 */ startRxFilter(@onNull String ifaceName)1821 public boolean startRxFilter(@NonNull String ifaceName) { 1822 synchronized (mLock) { 1823 final String methodStr = "startRxFilter"; 1824 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1825 if (iface == null) return false; 1826 try { 1827 SupplicantStatus status = iface.startRxFilter(); 1828 return checkStatusAndLogFailure(status, methodStr); 1829 } catch (RemoteException e) { 1830 handleRemoteException(e, methodStr); 1831 return false; 1832 } 1833 } 1834 } 1835 1836 /** 1837 * Stop using the added RX filters. 1838 * 1839 * @param ifaceName Name of the interface. 1840 * @return true if request is sent successfully, false otherwise. 1841 */ stopRxFilter(@onNull String ifaceName)1842 public boolean stopRxFilter(@NonNull String ifaceName) { 1843 synchronized (mLock) { 1844 final String methodStr = "stopRxFilter"; 1845 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1846 if (iface == null) return false; 1847 try { 1848 SupplicantStatus status = iface.stopRxFilter(); 1849 return checkStatusAndLogFailure(status, methodStr); 1850 } catch (RemoteException e) { 1851 handleRemoteException(e, methodStr); 1852 return false; 1853 } 1854 } 1855 } 1856 1857 /** 1858 * Add an RX filter. 1859 * 1860 * @param ifaceName Name of the interface. 1861 * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST} 1862 * {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values. 1863 * @return true if request is sent successfully, false otherwise. 1864 */ addRxFilter(@onNull String ifaceName, int type)1865 public boolean addRxFilter(@NonNull String ifaceName, int type) { 1866 synchronized (mLock) { 1867 byte halType; 1868 switch (type) { 1869 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST: 1870 halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST; 1871 break; 1872 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST: 1873 halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST; 1874 break; 1875 default: 1876 Log.e(TAG, "Invalid Rx Filter type: " + type); 1877 return false; 1878 } 1879 return addRxFilter(ifaceName, halType); 1880 } 1881 } 1882 addRxFilter(@onNull String ifaceName, byte type)1883 private boolean addRxFilter(@NonNull String ifaceName, byte type) { 1884 synchronized (mLock) { 1885 final String methodStr = "addRxFilter"; 1886 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1887 if (iface == null) return false; 1888 try { 1889 SupplicantStatus status = iface.addRxFilter(type); 1890 return checkStatusAndLogFailure(status, methodStr); 1891 } catch (RemoteException e) { 1892 handleRemoteException(e, methodStr); 1893 return false; 1894 } 1895 } 1896 } 1897 1898 /** 1899 * Remove an RX filter. 1900 * 1901 * @param ifaceName Name of the interface. 1902 * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST} 1903 * {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values. 1904 * @return true if request is sent successfully, false otherwise. 1905 */ removeRxFilter(@onNull String ifaceName, int type)1906 public boolean removeRxFilter(@NonNull String ifaceName, int type) { 1907 synchronized (mLock) { 1908 byte halType; 1909 switch (type) { 1910 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST: 1911 halType = ISupplicantStaIface.RxFilterType.V4_MULTICAST; 1912 break; 1913 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST: 1914 halType = ISupplicantStaIface.RxFilterType.V6_MULTICAST; 1915 break; 1916 default: 1917 Log.e(TAG, "Invalid Rx Filter type: " + type); 1918 return false; 1919 } 1920 return removeRxFilter(ifaceName, halType); 1921 } 1922 } 1923 removeRxFilter(@onNull String ifaceName, byte type)1924 private boolean removeRxFilter(@NonNull String ifaceName, byte type) { 1925 synchronized (mLock) { 1926 final String methodStr = "removeRxFilter"; 1927 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1928 if (iface == null) return false; 1929 try { 1930 SupplicantStatus status = iface.removeRxFilter(type); 1931 return checkStatusAndLogFailure(status, methodStr); 1932 } catch (RemoteException e) { 1933 handleRemoteException(e, methodStr); 1934 return false; 1935 } 1936 } 1937 } 1938 1939 /** 1940 * Set Bt co existense mode. 1941 * 1942 * @param ifaceName Name of the interface. 1943 * @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 1944 * {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or 1945 * {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}. 1946 * @return true if request is sent successfully, false otherwise. 1947 */ setBtCoexistenceMode(@onNull String ifaceName, int mode)1948 public boolean setBtCoexistenceMode(@NonNull String ifaceName, int mode) { 1949 synchronized (mLock) { 1950 byte halMode; 1951 switch (mode) { 1952 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_ENABLED: 1953 halMode = ISupplicantStaIface.BtCoexistenceMode.ENABLED; 1954 break; 1955 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED: 1956 halMode = ISupplicantStaIface.BtCoexistenceMode.DISABLED; 1957 break; 1958 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE: 1959 halMode = ISupplicantStaIface.BtCoexistenceMode.SENSE; 1960 break; 1961 default: 1962 Log.e(TAG, "Invalid Bt Coex mode: " + mode); 1963 return false; 1964 } 1965 return setBtCoexistenceMode(ifaceName, halMode); 1966 } 1967 } 1968 setBtCoexistenceMode(@onNull String ifaceName, byte mode)1969 private boolean setBtCoexistenceMode(@NonNull String ifaceName, byte mode) { 1970 synchronized (mLock) { 1971 final String methodStr = "setBtCoexistenceMode"; 1972 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1973 if (iface == null) return false; 1974 try { 1975 SupplicantStatus status = iface.setBtCoexistenceMode(mode); 1976 return checkStatusAndLogFailure(status, methodStr); 1977 } catch (RemoteException e) { 1978 handleRemoteException(e, methodStr); 1979 return false; 1980 } 1981 } 1982 } 1983 1984 /** Enable or disable BT coexistence mode. 1985 * 1986 * @param ifaceName Name of the interface. 1987 * @param enable true to enable, false to disable. 1988 * @return true if request is sent successfully, false otherwise. 1989 */ setBtCoexistenceScanModeEnabled(@onNull String ifaceName, boolean enable)1990 public boolean setBtCoexistenceScanModeEnabled(@NonNull String ifaceName, boolean enable) { 1991 synchronized (mLock) { 1992 final String methodStr = "setBtCoexistenceScanModeEnabled"; 1993 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 1994 if (iface == null) return false; 1995 try { 1996 SupplicantStatus status = 1997 iface.setBtCoexistenceScanModeEnabled(enable); 1998 return checkStatusAndLogFailure(status, methodStr); 1999 } catch (RemoteException e) { 2000 handleRemoteException(e, methodStr); 2001 return false; 2002 } 2003 } 2004 } 2005 2006 /** 2007 * Enable or disable suspend mode optimizations. 2008 * 2009 * @param ifaceName Name of the interface. 2010 * @param enable true to enable, false otherwise. 2011 * @return true if request is sent successfully, false otherwise. 2012 */ setSuspendModeEnabled(@onNull String ifaceName, boolean enable)2013 public boolean setSuspendModeEnabled(@NonNull String ifaceName, boolean enable) { 2014 synchronized (mLock) { 2015 final String methodStr = "setSuspendModeEnabled"; 2016 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2017 if (iface == null) return false; 2018 try { 2019 SupplicantStatus status = iface.setSuspendModeEnabled(enable); 2020 return checkStatusAndLogFailure(status, methodStr); 2021 } catch (RemoteException e) { 2022 handleRemoteException(e, methodStr); 2023 return false; 2024 } 2025 } 2026 } 2027 2028 /** 2029 * Set country code. 2030 * 2031 * @param ifaceName Name of the interface. 2032 * @param codeStr 2 byte ASCII string. For ex: US, CA. 2033 * @return true if request is sent successfully, false otherwise. 2034 */ setCountryCode(@onNull String ifaceName, String codeStr)2035 public boolean setCountryCode(@NonNull String ifaceName, String codeStr) { 2036 synchronized (mLock) { 2037 if (TextUtils.isEmpty(codeStr)) return false; 2038 byte[] countryCodeBytes = NativeUtil.stringToByteArray(codeStr); 2039 if (countryCodeBytes.length != 2) return false; 2040 return setCountryCode(ifaceName, countryCodeBytes); 2041 } 2042 } 2043 2044 /** See ISupplicantStaIface.hal for documentation */ setCountryCode(@onNull String ifaceName, byte[ ] code)2045 private boolean setCountryCode(@NonNull String ifaceName, byte[/* 2 */] code) { 2046 synchronized (mLock) { 2047 final String methodStr = "setCountryCode"; 2048 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2049 if (iface == null) return false; 2050 try { 2051 SupplicantStatus status = iface.setCountryCode(code); 2052 return checkStatusAndLogFailure(status, methodStr); 2053 } catch (RemoteException e) { 2054 handleRemoteException(e, methodStr); 2055 return false; 2056 } 2057 } 2058 } 2059 2060 /** 2061 * Start WPS pin registrar operation with the specified peer and pin. 2062 * 2063 * @param ifaceName Name of the interface. 2064 * @param bssidStr BSSID of the peer. 2065 * @param pin Pin to be used. 2066 * @return true if request is sent successfully, false otherwise. 2067 */ startWpsRegistrar(@onNull String ifaceName, String bssidStr, String pin)2068 public boolean startWpsRegistrar(@NonNull String ifaceName, String bssidStr, String pin) { 2069 synchronized (mLock) { 2070 if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) return false; 2071 try { 2072 return startWpsRegistrar( 2073 ifaceName, NativeUtil.macAddressToByteArray(bssidStr), pin); 2074 } catch (IllegalArgumentException e) { 2075 Log.e(TAG, "Illegal argument " + bssidStr, e); 2076 return false; 2077 } 2078 } 2079 } 2080 2081 /** See ISupplicantStaIface.hal for documentation */ startWpsRegistrar(@onNull String ifaceName, byte[ ] bssid, String pin)2082 private boolean startWpsRegistrar(@NonNull String ifaceName, byte[/* 6 */] bssid, String pin) { 2083 synchronized (mLock) { 2084 final String methodStr = "startWpsRegistrar"; 2085 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2086 if (iface == null) return false; 2087 try { 2088 SupplicantStatus status = iface.startWpsRegistrar(bssid, pin); 2089 return checkStatusAndLogFailure(status, methodStr); 2090 } catch (RemoteException e) { 2091 handleRemoteException(e, methodStr); 2092 return false; 2093 } 2094 } 2095 } 2096 2097 /** 2098 * Start WPS pin display operation with the specified peer. 2099 * 2100 * @param ifaceName Name of the interface. 2101 * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard. 2102 * @return true if request is sent successfully, false otherwise. 2103 */ startWpsPbc(@onNull String ifaceName, String bssidStr)2104 public boolean startWpsPbc(@NonNull String ifaceName, String bssidStr) { 2105 synchronized (mLock) { 2106 try { 2107 return startWpsPbc(ifaceName, NativeUtil.macAddressToByteArray(bssidStr)); 2108 } catch (IllegalArgumentException e) { 2109 Log.e(TAG, "Illegal argument " + bssidStr, e); 2110 return false; 2111 } 2112 } 2113 } 2114 2115 /** See ISupplicantStaIface.hal for documentation */ startWpsPbc(@onNull String ifaceName, byte[ ] bssid)2116 private boolean startWpsPbc(@NonNull String ifaceName, byte[/* 6 */] bssid) { 2117 synchronized (mLock) { 2118 final String methodStr = "startWpsPbc"; 2119 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2120 if (iface == null) return false; 2121 try { 2122 SupplicantStatus status = iface.startWpsPbc(bssid); 2123 return checkStatusAndLogFailure(status, methodStr); 2124 } catch (RemoteException e) { 2125 handleRemoteException(e, methodStr); 2126 return false; 2127 } 2128 } 2129 } 2130 2131 /** 2132 * Start WPS pin keypad operation with the specified pin. 2133 * 2134 * @param ifaceName Name of the interface. 2135 * @param pin Pin to be used. 2136 * @return true if request is sent successfully, false otherwise. 2137 */ startWpsPinKeypad(@onNull String ifaceName, String pin)2138 public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) { 2139 if (TextUtils.isEmpty(pin)) return false; 2140 synchronized (mLock) { 2141 final String methodStr = "startWpsPinKeypad"; 2142 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2143 if (iface == null) return false; 2144 try { 2145 SupplicantStatus status = iface.startWpsPinKeypad(pin); 2146 return checkStatusAndLogFailure(status, methodStr); 2147 } catch (RemoteException e) { 2148 handleRemoteException(e, methodStr); 2149 return false; 2150 } 2151 } 2152 } 2153 2154 /** 2155 * Start WPS pin display operation with the specified peer. 2156 * 2157 * @param ifaceName Name of the interface. 2158 * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard. 2159 * @return new pin generated on success, null otherwise. 2160 */ startWpsPinDisplay(@onNull String ifaceName, String bssidStr)2161 public String startWpsPinDisplay(@NonNull String ifaceName, String bssidStr) { 2162 synchronized (mLock) { 2163 try { 2164 return startWpsPinDisplay(ifaceName, NativeUtil.macAddressToByteArray(bssidStr)); 2165 } catch (IllegalArgumentException e) { 2166 Log.e(TAG, "Illegal argument " + bssidStr, e); 2167 return null; 2168 } 2169 } 2170 } 2171 2172 /** See ISupplicantStaIface.hal for documentation */ startWpsPinDisplay(@onNull String ifaceName, byte[ ] bssid)2173 private String startWpsPinDisplay(@NonNull String ifaceName, byte[/* 6 */] bssid) { 2174 synchronized (mLock) { 2175 final String methodStr = "startWpsPinDisplay"; 2176 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2177 if (iface == null) return null; 2178 final Mutable<String> gotPin = new Mutable<>(); 2179 try { 2180 iface.startWpsPinDisplay(bssid, 2181 (SupplicantStatus status, String pin) -> { 2182 if (checkStatusAndLogFailure(status, methodStr)) { 2183 gotPin.value = pin; 2184 } 2185 }); 2186 } catch (RemoteException e) { 2187 handleRemoteException(e, methodStr); 2188 } 2189 return gotPin.value; 2190 } 2191 } 2192 2193 /** 2194 * Cancels any ongoing WPS requests. 2195 * 2196 * @param ifaceName Name of the interface. 2197 * @return true if request is sent successfully, false otherwise. 2198 */ cancelWps(@onNull String ifaceName)2199 public boolean cancelWps(@NonNull String ifaceName) { 2200 synchronized (mLock) { 2201 final String methodStr = "cancelWps"; 2202 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2203 if (iface == null) return false; 2204 try { 2205 SupplicantStatus status = iface.cancelWps(); 2206 return checkStatusAndLogFailure(status, methodStr); 2207 } catch (RemoteException e) { 2208 handleRemoteException(e, methodStr); 2209 return false; 2210 } 2211 } 2212 } 2213 2214 /** 2215 * Sets whether to use external sim for SIM/USIM processing. 2216 * 2217 * @param ifaceName Name of the interface. 2218 * @param useExternalSim true to enable, false otherwise. 2219 * @return true if request is sent successfully, false otherwise. 2220 */ setExternalSim(@onNull String ifaceName, boolean useExternalSim)2221 public boolean setExternalSim(@NonNull String ifaceName, boolean useExternalSim) { 2222 synchronized (mLock) { 2223 final String methodStr = "setExternalSim"; 2224 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2225 if (iface == null) return false; 2226 try { 2227 SupplicantStatus status = iface.setExternalSim(useExternalSim); 2228 return checkStatusAndLogFailure(status, methodStr); 2229 } catch (RemoteException e) { 2230 handleRemoteException(e, methodStr); 2231 return false; 2232 } 2233 } 2234 } 2235 2236 /** See ISupplicant.hal for documentation */ enableAutoReconnect(@onNull String ifaceName, boolean enable)2237 public boolean enableAutoReconnect(@NonNull String ifaceName, boolean enable) { 2238 synchronized (mLock) { 2239 final String methodStr = "enableAutoReconnect"; 2240 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 2241 if (iface == null) return false; 2242 try { 2243 SupplicantStatus status = iface.enableAutoReconnect(enable); 2244 return checkStatusAndLogFailure(status, methodStr); 2245 } catch (RemoteException e) { 2246 handleRemoteException(e, methodStr); 2247 return false; 2248 } 2249 } 2250 } 2251 2252 /** 2253 * Set the debug log level for wpa_supplicant 2254 * 2255 * @param turnOnVerbose Whether to turn on verbose logging or not. 2256 * @return true if request is sent successfully, false otherwise. 2257 */ setLogLevel(boolean turnOnVerbose)2258 public boolean setLogLevel(boolean turnOnVerbose) { 2259 synchronized (mLock) { 2260 int logLevel = turnOnVerbose 2261 ? ISupplicant.DebugLevel.DEBUG 2262 : ISupplicant.DebugLevel.INFO; 2263 return setDebugParams(logLevel, false, false); 2264 } 2265 } 2266 2267 /** See ISupplicant.hal for documentation */ setDebugParams(int level, boolean showTimestamp, boolean showKeys)2268 private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) { 2269 synchronized (mLock) { 2270 final String methodStr = "setDebugParams"; 2271 if (!checkSupplicantAndLogFailure(methodStr)) return false; 2272 try { 2273 SupplicantStatus status = 2274 mISupplicant.setDebugParams(level, showTimestamp, showKeys); 2275 return checkStatusAndLogFailure(status, methodStr); 2276 } catch (RemoteException e) { 2277 handleRemoteException(e, methodStr); 2278 return false; 2279 } 2280 } 2281 } 2282 2283 /** 2284 * Set concurrency priority between P2P & STA operations. 2285 * 2286 * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations, 2287 * false otherwise. 2288 * @return true if request is sent successfully, false otherwise. 2289 */ setConcurrencyPriority(boolean isStaHigherPriority)2290 public boolean setConcurrencyPriority(boolean isStaHigherPriority) { 2291 synchronized (mLock) { 2292 if (isStaHigherPriority) { 2293 return setConcurrencyPriority(IfaceType.STA); 2294 } else { 2295 return setConcurrencyPriority(IfaceType.P2P); 2296 } 2297 } 2298 } 2299 2300 /** See ISupplicant.hal for documentation */ setConcurrencyPriority(int type)2301 private boolean setConcurrencyPriority(int type) { 2302 synchronized (mLock) { 2303 final String methodStr = "setConcurrencyPriority"; 2304 if (!checkSupplicantAndLogFailure(methodStr)) return false; 2305 try { 2306 SupplicantStatus status = mISupplicant.setConcurrencyPriority(type); 2307 return checkStatusAndLogFailure(status, methodStr); 2308 } catch (RemoteException e) { 2309 handleRemoteException(e, methodStr); 2310 return false; 2311 } 2312 } 2313 } 2314 2315 /** 2316 * Returns false if Supplicant is null, and logs failure to call methodStr 2317 */ checkSupplicantAndLogFailure(final String methodStr)2318 private boolean checkSupplicantAndLogFailure(final String methodStr) { 2319 synchronized (mLock) { 2320 if (mISupplicant == null) { 2321 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null"); 2322 return false; 2323 } 2324 return true; 2325 } 2326 } 2327 2328 /** 2329 * Returns false if SupplicantStaIface is null, and logs failure to call methodStr 2330 */ checkSupplicantStaIfaceAndLogFailure( @onNull String ifaceName, final String methodStr)2331 private ISupplicantStaIface checkSupplicantStaIfaceAndLogFailure( 2332 @NonNull String ifaceName, final String methodStr) { 2333 synchronized (mLock) { 2334 ISupplicantStaIface iface = getStaIface(ifaceName); 2335 if (iface == null) { 2336 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null"); 2337 return null; 2338 } 2339 return iface; 2340 } 2341 } 2342 2343 /** 2344 * Returns false if SupplicantStaNetwork is null, and logs failure to call methodStr 2345 */ checkSupplicantStaNetworkAndLogFailure( @onNull String ifaceName, final String methodStr)2346 private SupplicantStaNetworkHal checkSupplicantStaNetworkAndLogFailure( 2347 @NonNull String ifaceName, final String methodStr) { 2348 synchronized (mLock) { 2349 SupplicantStaNetworkHal networkHal = getCurrentNetworkRemoteHandle(ifaceName); 2350 if (networkHal == null) { 2351 Log.e(TAG, "Can't call " + methodStr + ", SupplicantStaNetwork is null"); 2352 return null; 2353 } 2354 return networkHal; 2355 } 2356 } 2357 2358 /** 2359 * Returns true if provided status code is SUCCESS, logs debug message and returns false 2360 * otherwise 2361 */ checkStatusAndLogFailure(SupplicantStatus status, final String methodStr)2362 private boolean checkStatusAndLogFailure(SupplicantStatus status, 2363 final String methodStr) { 2364 synchronized (mLock) { 2365 if (status.code != SupplicantStatusCode.SUCCESS) { 2366 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed: " + status); 2367 return false; 2368 } else { 2369 if (mVerboseLoggingEnabled) { 2370 Log.d(TAG, "ISupplicantStaIface." + methodStr + " succeeded"); 2371 } 2372 return true; 2373 } 2374 } 2375 } 2376 2377 /** 2378 * Helper function to log callbacks. 2379 */ logCallback(final String methodStr)2380 private void logCallback(final String methodStr) { 2381 synchronized (mLock) { 2382 if (mVerboseLoggingEnabled) { 2383 Log.d(TAG, "ISupplicantStaIfaceCallback." + methodStr + " received"); 2384 } 2385 } 2386 } 2387 handleNoSuchElementException(NoSuchElementException e, String methodStr)2388 private void handleNoSuchElementException(NoSuchElementException e, String methodStr) { 2389 synchronized (mLock) { 2390 clearState(); 2391 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e); 2392 } 2393 } 2394 handleRemoteException(RemoteException e, String methodStr)2395 private void handleRemoteException(RemoteException e, String methodStr) { 2396 synchronized (mLock) { 2397 clearState(); 2398 Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with exception", e); 2399 } 2400 } 2401 2402 /** 2403 * Converts the Wps config method string to the equivalent enum value. 2404 */ stringToWpsConfigMethod(String configMethod)2405 private static short stringToWpsConfigMethod(String configMethod) { 2406 switch (configMethod) { 2407 case "usba": 2408 return WpsConfigMethods.USBA; 2409 case "ethernet": 2410 return WpsConfigMethods.ETHERNET; 2411 case "label": 2412 return WpsConfigMethods.LABEL; 2413 case "display": 2414 return WpsConfigMethods.DISPLAY; 2415 case "int_nfc_token": 2416 return WpsConfigMethods.INT_NFC_TOKEN; 2417 case "ext_nfc_token": 2418 return WpsConfigMethods.EXT_NFC_TOKEN; 2419 case "nfc_interface": 2420 return WpsConfigMethods.NFC_INTERFACE; 2421 case "push_button": 2422 return WpsConfigMethods.PUSHBUTTON; 2423 case "keypad": 2424 return WpsConfigMethods.KEYPAD; 2425 case "virtual_push_button": 2426 return WpsConfigMethods.VIRT_PUSHBUTTON; 2427 case "physical_push_button": 2428 return WpsConfigMethods.PHY_PUSHBUTTON; 2429 case "p2ps": 2430 return WpsConfigMethods.P2PS; 2431 case "virtual_display": 2432 return WpsConfigMethods.VIRT_DISPLAY; 2433 case "physical_display": 2434 return WpsConfigMethods.PHY_DISPLAY; 2435 default: 2436 throw new IllegalArgumentException( 2437 "Invalid WPS config method: " + configMethod); 2438 } 2439 } 2440 2441 /** 2442 * Converts the supplicant state received from HIDL to the equivalent framework state. 2443 */ supplicantHidlStateToFrameworkState(int state)2444 private static SupplicantState supplicantHidlStateToFrameworkState(int state) { 2445 switch (state) { 2446 case ISupplicantStaIfaceCallback.State.DISCONNECTED: 2447 return SupplicantState.DISCONNECTED; 2448 case ISupplicantStaIfaceCallback.State.IFACE_DISABLED: 2449 return SupplicantState.INTERFACE_DISABLED; 2450 case ISupplicantStaIfaceCallback.State.INACTIVE: 2451 return SupplicantState.INACTIVE; 2452 case ISupplicantStaIfaceCallback.State.SCANNING: 2453 return SupplicantState.SCANNING; 2454 case ISupplicantStaIfaceCallback.State.AUTHENTICATING: 2455 return SupplicantState.AUTHENTICATING; 2456 case ISupplicantStaIfaceCallback.State.ASSOCIATING: 2457 return SupplicantState.ASSOCIATING; 2458 case ISupplicantStaIfaceCallback.State.ASSOCIATED: 2459 return SupplicantState.ASSOCIATED; 2460 case ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE: 2461 return SupplicantState.FOUR_WAY_HANDSHAKE; 2462 case ISupplicantStaIfaceCallback.State.GROUP_HANDSHAKE: 2463 return SupplicantState.GROUP_HANDSHAKE; 2464 case ISupplicantStaIfaceCallback.State.COMPLETED: 2465 return SupplicantState.COMPLETED; 2466 default: 2467 throw new IllegalArgumentException("Invalid state: " + state); 2468 } 2469 } 2470 2471 private class SupplicantStaIfaceHalCallback extends ISupplicantStaIfaceCallback.Stub { 2472 private String mIfaceName; 2473 private boolean mStateIsFourway = false; // Used to help check for PSK password mismatch 2474 SupplicantStaIfaceHalCallback(@onNull String ifaceName)2475 SupplicantStaIfaceHalCallback(@NonNull String ifaceName) { 2476 mIfaceName = ifaceName; 2477 } 2478 2479 /** 2480 * Parses the provided payload into an ANQP element. 2481 * 2482 * @param infoID Element type. 2483 * @param payload Raw payload bytes. 2484 * @return AnqpElement instance on success, null on failure. 2485 */ parseAnqpElement(Constants.ANQPElementType infoID, ArrayList<Byte> payload)2486 private ANQPElement parseAnqpElement(Constants.ANQPElementType infoID, 2487 ArrayList<Byte> payload) { 2488 synchronized (mLock) { 2489 try { 2490 return Constants.getANQPElementID(infoID) != null 2491 ? ANQPParser.parseElement( 2492 infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload))) 2493 : ANQPParser.parseHS20Element( 2494 infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload))); 2495 } catch (IOException | BufferUnderflowException e) { 2496 Log.e(TAG, "Failed parsing ANQP element payload: " + infoID, e); 2497 return null; 2498 } 2499 } 2500 } 2501 2502 /** 2503 * Parse the ANQP element data and add to the provided elements map if successful. 2504 * 2505 * @param elementsMap Map to add the parsed out element to. 2506 * @param infoID Element type. 2507 * @param payload Raw payload bytes. 2508 */ addAnqpElementToMap(Map<Constants.ANQPElementType, ANQPElement> elementsMap, Constants.ANQPElementType infoID, ArrayList<Byte> payload)2509 private void addAnqpElementToMap(Map<Constants.ANQPElementType, ANQPElement> elementsMap, 2510 Constants.ANQPElementType infoID, 2511 ArrayList<Byte> payload) { 2512 synchronized (mLock) { 2513 if (payload == null || payload.isEmpty()) return; 2514 ANQPElement element = parseAnqpElement(infoID, payload); 2515 if (element != null) { 2516 elementsMap.put(infoID, element); 2517 } 2518 } 2519 } 2520 2521 @Override onNetworkAdded(int id)2522 public void onNetworkAdded(int id) { 2523 synchronized (mLock) { 2524 logCallback("onNetworkAdded"); 2525 } 2526 } 2527 2528 @Override onNetworkRemoved(int id)2529 public void onNetworkRemoved(int id) { 2530 synchronized (mLock) { 2531 logCallback("onNetworkRemoved"); 2532 // Reset 4way handshake state since network has been removed. 2533 mStateIsFourway = false; 2534 } 2535 } 2536 2537 @Override onStateChanged(int newState, byte[ ] bssid, int id, ArrayList<Byte> ssid)2538 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id, 2539 ArrayList<Byte> ssid) { 2540 synchronized (mLock) { 2541 logCallback("onStateChanged"); 2542 SupplicantState newSupplicantState = supplicantHidlStateToFrameworkState(newState); 2543 WifiSsid wifiSsid = 2544 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid)); 2545 String bssidStr = NativeUtil.macAddressFromByteArray(bssid); 2546 mStateIsFourway = (newState == ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE); 2547 if (newSupplicantState == SupplicantState.COMPLETED) { 2548 mWifiMonitor.broadcastNetworkConnectionEvent( 2549 mIfaceName, getCurrentNetworkId(mIfaceName), bssidStr); 2550 } 2551 mWifiMonitor.broadcastSupplicantStateChangeEvent( 2552 mIfaceName, getCurrentNetworkId(mIfaceName), wifiSsid, 2553 bssidStr, newSupplicantState); 2554 } 2555 } 2556 2557 @Override onAnqpQueryDone(byte[ ] bssid, ISupplicantStaIfaceCallback.AnqpData data, ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data)2558 public void onAnqpQueryDone(byte[/* 6 */] bssid, 2559 ISupplicantStaIfaceCallback.AnqpData data, 2560 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) { 2561 synchronized (mLock) { 2562 logCallback("onAnqpQueryDone"); 2563 Map<Constants.ANQPElementType, ANQPElement> elementsMap = new HashMap<>(); 2564 addAnqpElementToMap(elementsMap, ANQPVenueName, data.venueName); 2565 addAnqpElementToMap(elementsMap, ANQPRoamingConsortium, data.roamingConsortium); 2566 addAnqpElementToMap( 2567 elementsMap, ANQPIPAddrAvailability, data.ipAddrTypeAvailability); 2568 addAnqpElementToMap(elementsMap, ANQPNAIRealm, data.naiRealm); 2569 addAnqpElementToMap(elementsMap, ANQP3GPPNetwork, data.anqp3gppCellularNetwork); 2570 addAnqpElementToMap(elementsMap, ANQPDomName, data.domainName); 2571 addAnqpElementToMap(elementsMap, HSFriendlyName, hs20Data.operatorFriendlyName); 2572 addAnqpElementToMap(elementsMap, HSWANMetrics, hs20Data.wanMetrics); 2573 addAnqpElementToMap(elementsMap, HSConnCapability, hs20Data.connectionCapability); 2574 addAnqpElementToMap(elementsMap, HSOSUProviders, hs20Data.osuProvidersList); 2575 mWifiMonitor.broadcastAnqpDoneEvent( 2576 mIfaceName, new AnqpEvent(NativeUtil.macAddressToLong(bssid), elementsMap)); 2577 } 2578 } 2579 2580 @Override onHs20IconQueryDone(byte[ ] bssid, String fileName, ArrayList<Byte> data)2581 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName, 2582 ArrayList<Byte> data) { 2583 synchronized (mLock) { 2584 logCallback("onHs20IconQueryDone"); 2585 mWifiMonitor.broadcastIconDoneEvent( 2586 mIfaceName, 2587 new IconEvent(NativeUtil.macAddressToLong(bssid), fileName, data.size(), 2588 NativeUtil.byteArrayFromArrayList(data))); 2589 } 2590 } 2591 2592 @Override onHs20SubscriptionRemediation(byte[ ] bssid, byte osuMethod, String url)2593 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, byte osuMethod, String url) { 2594 synchronized (mLock) { 2595 logCallback("onHs20SubscriptionRemediation"); 2596 mWifiMonitor.broadcastWnmEvent( 2597 mIfaceName, 2598 new WnmData(NativeUtil.macAddressToLong(bssid), url, osuMethod)); 2599 } 2600 } 2601 2602 @Override onHs20DeauthImminentNotice(byte[ ] bssid, int reasonCode, int reAuthDelayInSec, String url)2603 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode, 2604 int reAuthDelayInSec, String url) { 2605 synchronized (mLock) { 2606 logCallback("onHs20DeauthImminentNotice"); 2607 mWifiMonitor.broadcastWnmEvent( 2608 mIfaceName, 2609 new WnmData(NativeUtil.macAddressToLong(bssid), url, 2610 reasonCode == WnmData.ESS, reAuthDelayInSec)); 2611 } 2612 } 2613 2614 @Override onDisconnected(byte[ ] bssid, boolean locallyGenerated, int reasonCode)2615 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, int reasonCode) { 2616 synchronized (mLock) { 2617 logCallback("onDisconnected"); 2618 if (mVerboseLoggingEnabled) { 2619 Log.e(TAG, "onDisconnected 4way=" + mStateIsFourway 2620 + " locallyGenerated=" + locallyGenerated 2621 + " reasonCode=" + reasonCode); 2622 } 2623 if (mStateIsFourway 2624 && (!locallyGenerated || reasonCode != ReasonCode.IE_IN_4WAY_DIFFERS)) { 2625 mWifiMonitor.broadcastAuthenticationFailureEvent( 2626 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD, -1); 2627 } 2628 mWifiMonitor.broadcastNetworkDisconnectionEvent( 2629 mIfaceName, locallyGenerated ? 1 : 0, reasonCode, 2630 NativeUtil.macAddressFromByteArray(bssid)); 2631 } 2632 } 2633 2634 @Override onAssociationRejected(byte[ ] bssid, int statusCode, boolean timedOut)2635 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode, boolean timedOut) { 2636 synchronized (mLock) { 2637 logCallback("onAssociationRejected"); 2638 2639 if (statusCode == StatusCode.UNSPECIFIED_FAILURE) { 2640 WifiConfiguration curConfiguration = getCurrentNetworkLocalConfig(mIfaceName); 2641 2642 if (curConfiguration != null 2643 && curConfiguration.allowedKeyManagement 2644 .get(WifiConfiguration.KeyMgmt.SAE)) { 2645 // Special handling for WPA3-Personal networks. If the password is 2646 // incorrect, the AP will send association rejection, with status code 1 2647 // (unspecified failure). In SAE networks, the password authentication 2648 // is not related to the 4-way handshake. In this case, we will send an 2649 // authentication failure event up. 2650 logCallback("SAE incorrect password"); 2651 mWifiMonitor.broadcastAuthenticationFailureEvent( 2652 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD, -1); 2653 } 2654 } 2655 mWifiMonitor.broadcastAssociationRejectionEvent(mIfaceName, statusCode, timedOut, 2656 NativeUtil.macAddressFromByteArray(bssid)); 2657 } 2658 } 2659 2660 @Override onAuthenticationTimeout(byte[ ] bssid)2661 public void onAuthenticationTimeout(byte[/* 6 */] bssid) { 2662 synchronized (mLock) { 2663 logCallback("onAuthenticationTimeout"); 2664 mWifiMonitor.broadcastAuthenticationFailureEvent( 2665 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_TIMEOUT, -1); 2666 } 2667 } 2668 2669 @Override onBssidChanged(byte reason, byte[ ] bssid)2670 public void onBssidChanged(byte reason, byte[/* 6 */] bssid) { 2671 synchronized (mLock) { 2672 logCallback("onBssidChanged"); 2673 if (reason == BssidChangeReason.ASSOC_START) { 2674 mWifiMonitor.broadcastTargetBssidEvent( 2675 mIfaceName, NativeUtil.macAddressFromByteArray(bssid)); 2676 } else if (reason == BssidChangeReason.ASSOC_COMPLETE) { 2677 mWifiMonitor.broadcastAssociatedBssidEvent( 2678 mIfaceName, NativeUtil.macAddressFromByteArray(bssid)); 2679 } 2680 } 2681 } 2682 2683 @Override onEapFailure()2684 public void onEapFailure() { 2685 synchronized (mLock) { 2686 logCallback("onEapFailure"); 2687 mWifiMonitor.broadcastAuthenticationFailureEvent( 2688 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE, -1); 2689 } 2690 } 2691 2692 @Override onWpsEventSuccess()2693 public void onWpsEventSuccess() { 2694 logCallback("onWpsEventSuccess"); 2695 synchronized (mLock) { 2696 mWifiMonitor.broadcastWpsSuccessEvent(mIfaceName); 2697 } 2698 } 2699 2700 @Override onWpsEventFail(byte[ ] bssid, short configError, short errorInd)2701 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) { 2702 synchronized (mLock) { 2703 logCallback("onWpsEventFail"); 2704 if (configError == WpsConfigError.MSG_TIMEOUT 2705 && errorInd == WpsErrorIndication.NO_ERROR) { 2706 mWifiMonitor.broadcastWpsTimeoutEvent(mIfaceName); 2707 } else { 2708 mWifiMonitor.broadcastWpsFailEvent(mIfaceName, configError, errorInd); 2709 } 2710 } 2711 } 2712 2713 @Override onWpsEventPbcOverlap()2714 public void onWpsEventPbcOverlap() { 2715 synchronized (mLock) { 2716 logCallback("onWpsEventPbcOverlap"); 2717 mWifiMonitor.broadcastWpsOverlapEvent(mIfaceName); 2718 } 2719 } 2720 2721 @Override onExtRadioWorkStart(int id)2722 public void onExtRadioWorkStart(int id) { 2723 synchronized (mLock) { 2724 logCallback("onExtRadioWorkStart"); 2725 } 2726 } 2727 2728 @Override onExtRadioWorkTimeout(int id)2729 public void onExtRadioWorkTimeout(int id) { 2730 synchronized (mLock) { 2731 logCallback("onExtRadioWorkTimeout"); 2732 } 2733 } 2734 } 2735 2736 private class SupplicantStaIfaceHalCallbackV1_1 extends 2737 android.hardware.wifi.supplicant.V1_1.ISupplicantStaIfaceCallback.Stub { 2738 private String mIfaceName; 2739 private SupplicantStaIfaceHalCallback mCallbackV1_0; 2740 SupplicantStaIfaceHalCallbackV1_1(@onNull String ifaceName, @NonNull SupplicantStaIfaceHalCallback callback)2741 SupplicantStaIfaceHalCallbackV1_1(@NonNull String ifaceName, 2742 @NonNull SupplicantStaIfaceHalCallback callback) { 2743 mIfaceName = ifaceName; 2744 mCallbackV1_0 = callback; 2745 } 2746 2747 @Override onNetworkAdded(int id)2748 public void onNetworkAdded(int id) { 2749 mCallbackV1_0.onNetworkAdded(id); 2750 } 2751 2752 @Override onNetworkRemoved(int id)2753 public void onNetworkRemoved(int id) { 2754 mCallbackV1_0.onNetworkRemoved(id); 2755 } 2756 2757 @Override onStateChanged(int newState, byte[ ] bssid, int id, ArrayList<Byte> ssid)2758 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id, 2759 ArrayList<Byte> ssid) { 2760 mCallbackV1_0.onStateChanged(newState, bssid, id, ssid); 2761 } 2762 2763 @Override onAnqpQueryDone(byte[ ] bssid, ISupplicantStaIfaceCallback.AnqpData data, ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data)2764 public void onAnqpQueryDone(byte[/* 6 */] bssid, 2765 ISupplicantStaIfaceCallback.AnqpData data, 2766 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) { 2767 mCallbackV1_0.onAnqpQueryDone(bssid, data, hs20Data); 2768 } 2769 2770 @Override onHs20IconQueryDone(byte[ ] bssid, String fileName, ArrayList<Byte> data)2771 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName, 2772 ArrayList<Byte> data) { 2773 mCallbackV1_0.onHs20IconQueryDone(bssid, fileName, data); 2774 } 2775 2776 @Override onHs20SubscriptionRemediation(byte[ ] bssid, byte osuMethod, String url)2777 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, 2778 byte osuMethod, String url) { 2779 mCallbackV1_0.onHs20SubscriptionRemediation(bssid, osuMethod, url); 2780 } 2781 2782 @Override onHs20DeauthImminentNotice(byte[ ] bssid, int reasonCode, int reAuthDelayInSec, String url)2783 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode, 2784 int reAuthDelayInSec, String url) { 2785 mCallbackV1_0.onHs20DeauthImminentNotice(bssid, reasonCode, reAuthDelayInSec, url); 2786 } 2787 2788 @Override onDisconnected(byte[ ] bssid, boolean locallyGenerated, int reasonCode)2789 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, 2790 int reasonCode) { 2791 mCallbackV1_0.onDisconnected(bssid, locallyGenerated, reasonCode); 2792 } 2793 2794 @Override onAssociationRejected(byte[ ] bssid, int statusCode, boolean timedOut)2795 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode, 2796 boolean timedOut) { 2797 mCallbackV1_0.onAssociationRejected(bssid, statusCode, timedOut); 2798 } 2799 2800 @Override onAuthenticationTimeout(byte[ ] bssid)2801 public void onAuthenticationTimeout(byte[/* 6 */] bssid) { 2802 mCallbackV1_0.onAuthenticationTimeout(bssid); 2803 } 2804 2805 @Override onBssidChanged(byte reason, byte[ ] bssid)2806 public void onBssidChanged(byte reason, byte[/* 6 */] bssid) { 2807 mCallbackV1_0.onBssidChanged(reason, bssid); 2808 } 2809 2810 @Override onEapFailure()2811 public void onEapFailure() { 2812 mCallbackV1_0.onEapFailure(); 2813 } 2814 2815 @Override onEapFailure_1_1(int code)2816 public void onEapFailure_1_1(int code) { 2817 synchronized (mLock) { 2818 logCallback("onEapFailure_1_1"); 2819 mWifiMonitor.broadcastAuthenticationFailureEvent( 2820 mIfaceName, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE, code); 2821 } 2822 } 2823 2824 @Override onWpsEventSuccess()2825 public void onWpsEventSuccess() { 2826 mCallbackV1_0.onWpsEventSuccess(); 2827 } 2828 2829 @Override onWpsEventFail(byte[ ] bssid, short configError, short errorInd)2830 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) { 2831 mCallbackV1_0.onWpsEventFail(bssid, configError, errorInd); 2832 } 2833 2834 @Override onWpsEventPbcOverlap()2835 public void onWpsEventPbcOverlap() { 2836 mCallbackV1_0.onWpsEventPbcOverlap(); 2837 } 2838 2839 @Override onExtRadioWorkStart(int id)2840 public void onExtRadioWorkStart(int id) { 2841 mCallbackV1_0.onExtRadioWorkStart(id); 2842 } 2843 2844 @Override onExtRadioWorkTimeout(int id)2845 public void onExtRadioWorkTimeout(int id) { 2846 mCallbackV1_0.onExtRadioWorkTimeout(id); 2847 } 2848 } 2849 2850 private class SupplicantStaIfaceHalCallbackV1_2 extends 2851 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback.Stub { 2852 private SupplicantStaIfaceHalCallbackV1_1 mCallbackV1_1; 2853 SupplicantStaIfaceHalCallbackV1_2( @onNull SupplicantStaIfaceHalCallbackV1_1 callback)2854 SupplicantStaIfaceHalCallbackV1_2( 2855 @NonNull SupplicantStaIfaceHalCallbackV1_1 callback) { 2856 mCallbackV1_1 = callback; 2857 } 2858 2859 @Override onNetworkAdded(int id)2860 public void onNetworkAdded(int id) { 2861 mCallbackV1_1.onNetworkAdded(id); 2862 } 2863 2864 @Override onNetworkRemoved(int id)2865 public void onNetworkRemoved(int id) { 2866 mCallbackV1_1.onNetworkRemoved(id); 2867 } 2868 2869 @Override onStateChanged(int newState, byte[ ] bssid, int id, ArrayList<Byte> ssid)2870 public void onStateChanged(int newState, byte[/* 6 */] bssid, int id, 2871 ArrayList<Byte> ssid) { 2872 mCallbackV1_1.onStateChanged(newState, bssid, id, ssid); 2873 } 2874 2875 @Override onAnqpQueryDone(byte[ ] bssid, ISupplicantStaIfaceCallback.AnqpData data, ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data)2876 public void onAnqpQueryDone(byte[/* 6 */] bssid, 2877 ISupplicantStaIfaceCallback.AnqpData data, 2878 ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) { 2879 mCallbackV1_1.onAnqpQueryDone(bssid, data, hs20Data); 2880 } 2881 2882 @Override onHs20IconQueryDone(byte[ ] bssid, String fileName, ArrayList<Byte> data)2883 public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName, 2884 ArrayList<Byte> data) { 2885 mCallbackV1_1.onHs20IconQueryDone(bssid, fileName, data); 2886 } 2887 2888 @Override onHs20SubscriptionRemediation(byte[ ] bssid, byte osuMethod, String url)2889 public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, 2890 byte osuMethod, String url) { 2891 mCallbackV1_1.onHs20SubscriptionRemediation(bssid, osuMethod, url); 2892 } 2893 2894 @Override onHs20DeauthImminentNotice(byte[ ] bssid, int reasonCode, int reAuthDelayInSec, String url)2895 public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode, 2896 int reAuthDelayInSec, String url) { 2897 mCallbackV1_1.onHs20DeauthImminentNotice(bssid, reasonCode, reAuthDelayInSec, url); 2898 } 2899 2900 @Override onDisconnected(byte[ ] bssid, boolean locallyGenerated, int reasonCode)2901 public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, 2902 int reasonCode) { 2903 mCallbackV1_1.onDisconnected(bssid, locallyGenerated, reasonCode); 2904 } 2905 2906 @Override onAssociationRejected(byte[ ] bssid, int statusCode, boolean timedOut)2907 public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode, 2908 boolean timedOut) { 2909 mCallbackV1_1.onAssociationRejected(bssid, statusCode, timedOut); 2910 } 2911 2912 @Override onAuthenticationTimeout(byte[ ] bssid)2913 public void onAuthenticationTimeout(byte[/* 6 */] bssid) { 2914 mCallbackV1_1.onAuthenticationTimeout(bssid); 2915 } 2916 2917 @Override onBssidChanged(byte reason, byte[ ] bssid)2918 public void onBssidChanged(byte reason, byte[/* 6 */] bssid) { 2919 mCallbackV1_1.onBssidChanged(reason, bssid); 2920 } 2921 2922 @Override onEapFailure()2923 public void onEapFailure() { 2924 mCallbackV1_1.onEapFailure(); 2925 } 2926 2927 @Override onEapFailure_1_1(int code)2928 public void onEapFailure_1_1(int code) { 2929 mCallbackV1_1.onEapFailure_1_1(code); 2930 } 2931 2932 @Override onWpsEventSuccess()2933 public void onWpsEventSuccess() { 2934 mCallbackV1_1.onWpsEventSuccess(); 2935 } 2936 2937 @Override onWpsEventFail(byte[ ] bssid, short configError, short errorInd)2938 public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) { 2939 mCallbackV1_1.onWpsEventFail(bssid, configError, errorInd); 2940 } 2941 2942 @Override onWpsEventPbcOverlap()2943 public void onWpsEventPbcOverlap() { 2944 mCallbackV1_1.onWpsEventPbcOverlap(); 2945 } 2946 2947 @Override onExtRadioWorkStart(int id)2948 public void onExtRadioWorkStart(int id) { 2949 mCallbackV1_1.onExtRadioWorkStart(id); 2950 } 2951 2952 @Override onExtRadioWorkTimeout(int id)2953 public void onExtRadioWorkTimeout(int id) { 2954 mCallbackV1_1.onExtRadioWorkTimeout(id); 2955 } 2956 2957 @Override onDppSuccessConfigReceived(ArrayList<Byte> ssid, String password, byte[] psk, int securityAkm)2958 public void onDppSuccessConfigReceived(ArrayList<Byte> ssid, String password, 2959 byte[] psk, int securityAkm) { 2960 if (mDppCallback == null) { 2961 loge("onDppSuccessConfigReceived callback is null"); 2962 return; 2963 } 2964 2965 WifiConfiguration newWifiConfiguration = new WifiConfiguration(); 2966 2967 // Set up SSID 2968 WifiSsid wifiSsid = 2969 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid)); 2970 2971 newWifiConfiguration.SSID = "\"" + wifiSsid.toString() + "\""; 2972 2973 // Set up password or PSK 2974 if (password != null) { 2975 newWifiConfiguration.preSharedKey = "\"" + password + "\""; 2976 } else if (psk != null) { 2977 newWifiConfiguration.preSharedKey = psk.toString(); 2978 } 2979 2980 // Set up key management: SAE or PSK 2981 if (securityAkm == DppAkm.SAE || securityAkm == DppAkm.PSK_SAE) { 2982 newWifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE); 2983 newWifiConfiguration.requirePMF = true; 2984 } else if (securityAkm == DppAkm.PSK) { 2985 newWifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); 2986 } else { 2987 // No other AKMs are currently supported 2988 onDppFailure(DppFailureCode.NOT_SUPPORTED); 2989 return; 2990 } 2991 2992 // Set up default values 2993 newWifiConfiguration.creatorName = mContext.getPackageManager() 2994 .getNameForUid(Process.WIFI_UID); 2995 newWifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 2996 newWifiConfiguration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); 2997 newWifiConfiguration.allowedProtocols.set(WifiConfiguration.Protocol.RSN); 2998 newWifiConfiguration.status = WifiConfiguration.Status.ENABLED; 2999 3000 mDppCallback.onSuccessConfigReceived(newWifiConfiguration); 3001 } 3002 3003 @Override onDppSuccessConfigSent()3004 public void onDppSuccessConfigSent() { 3005 if (mDppCallback != null) { 3006 mDppCallback.onSuccessConfigSent(); 3007 } else { 3008 loge("onSuccessConfigSent callback is null"); 3009 } 3010 } 3011 3012 @Override onDppProgress(int code)3013 public void onDppProgress(int code) { 3014 if (mDppCallback != null) { 3015 mDppCallback.onProgress(code); 3016 } else { 3017 loge("onDppProgress callback is null"); 3018 } 3019 } 3020 3021 @Override onDppFailure(int code)3022 public void onDppFailure(int code) { 3023 if (mDppCallback != null) { 3024 mDppCallback.onFailure(code); 3025 } else { 3026 loge("onDppFailure callback is null"); 3027 } 3028 } 3029 } 3030 logd(String s)3031 private static void logd(String s) { 3032 Log.d(TAG, s); 3033 } 3034 logi(String s)3035 private static void logi(String s) { 3036 Log.i(TAG, s); 3037 } 3038 loge(String s)3039 private static void loge(String s) { 3040 Log.e(TAG, s); 3041 } 3042 3043 /** 3044 * Returns a bitmask of advanced key management capabilities: WPA3 SAE/SUITE B and OWE 3045 * Bitmask used is: 3046 * - WIFI_FEATURE_WPA3_SAE 3047 * - WIFI_FEATURE_WPA3_SUITE_B 3048 * - WIFI_FEATURE_OWE 3049 * 3050 * This is a v1.2+ HAL feature. 3051 * On error, or if these features are not supported, 0 is returned. 3052 */ getAdvancedKeyMgmtCapabilities(@onNull String ifaceName)3053 public int getAdvancedKeyMgmtCapabilities(@NonNull String ifaceName) { 3054 final String methodStr = "getAdvancedKeyMgmtCapabilities"; 3055 3056 int advancedCapabilities = 0; 3057 int keyMgmtCapabilities = getKeyMgmtCapabilities(ifaceName); 3058 3059 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork 3060 .KeyMgmtMask.SAE) != 0) { 3061 advancedCapabilities |= WIFI_FEATURE_WPA3_SAE; 3062 3063 if (mVerboseLoggingEnabled) { 3064 Log.v(TAG, methodStr + ": SAE supported"); 3065 } 3066 } 3067 3068 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork 3069 .KeyMgmtMask.SUITE_B_192) != 0) { 3070 advancedCapabilities |= WIFI_FEATURE_WPA3_SUITE_B; 3071 3072 if (mVerboseLoggingEnabled) { 3073 Log.v(TAG, methodStr + ": SUITE_B supported"); 3074 } 3075 } 3076 3077 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork 3078 .KeyMgmtMask.OWE) != 0) { 3079 advancedCapabilities |= WIFI_FEATURE_OWE; 3080 3081 if (mVerboseLoggingEnabled) { 3082 Log.v(TAG, methodStr + ": OWE supported"); 3083 } 3084 } 3085 3086 if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_2.ISupplicantStaNetwork 3087 .KeyMgmtMask.DPP) != 0) { 3088 advancedCapabilities |= WIFI_FEATURE_DPP; 3089 3090 if (mVerboseLoggingEnabled) { 3091 Log.v(TAG, methodStr + ": DPP supported"); 3092 } 3093 } 3094 3095 if (mVerboseLoggingEnabled) { 3096 Log.v(TAG, methodStr + ": Capability flags = " + keyMgmtCapabilities); 3097 } 3098 3099 return advancedCapabilities; 3100 } 3101 getKeyMgmtCapabilities(@onNull String ifaceName)3102 private int getKeyMgmtCapabilities(@NonNull String ifaceName) { 3103 final String methodStr = "getKeyMgmtCapabilities"; 3104 MutableBoolean status = new MutableBoolean(false); 3105 MutableInt keyMgmtMask = new MutableInt(0); 3106 3107 if (isV1_2()) { 3108 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3109 if (iface == null) { 3110 return 0; 3111 } 3112 3113 // Get a v1.2 supplicant STA Interface 3114 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3115 getStaIfaceMockableV1_2(iface); 3116 3117 if (staIfaceV12 == null) { 3118 Log.e(TAG, methodStr 3119 + ": ISupplicantStaIface is null, cannot get advanced capabilities"); 3120 return 0; 3121 } 3122 3123 try { 3124 // Support for new key management types; SAE, SUITE_B, OWE 3125 // Requires HAL v1.2 or higher 3126 staIfaceV12.getKeyMgmtCapabilities( 3127 (SupplicantStatus statusInternal, int keyMgmtMaskInternal) -> { 3128 status.value = statusInternal.code == SupplicantStatusCode.SUCCESS; 3129 if (status.value) { 3130 keyMgmtMask.value = keyMgmtMaskInternal; 3131 } 3132 checkStatusAndLogFailure(statusInternal, methodStr); 3133 }); 3134 } catch (RemoteException e) { 3135 handleRemoteException(e, methodStr); 3136 } 3137 } else { 3138 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3139 } 3140 3141 // 0 is returned in case of an error 3142 return keyMgmtMask.value; 3143 } 3144 3145 /** 3146 * Adds a DPP peer URI to the URI list. 3147 * 3148 * This is a v1.2+ HAL feature. 3149 * Returns an ID to be used later to refer to this URI (>0). 3150 * On error, or if these features are not supported, -1 is returned. 3151 */ addDppPeerUri(@onNull String ifaceName, @NonNull String uri)3152 public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) { 3153 final String methodStr = "addDppPeerUri"; 3154 MutableBoolean status = new MutableBoolean(false); 3155 MutableInt bootstrapId = new MutableInt(-1); 3156 3157 if (!isV1_2()) { 3158 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3159 return -1; 3160 } 3161 3162 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3163 if (iface == null) { 3164 return -1; 3165 } 3166 3167 // Get a v1.2 supplicant STA Interface 3168 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3169 getStaIfaceMockableV1_2(iface); 3170 3171 if (staIfaceV12 == null) { 3172 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3173 return -1; 3174 } 3175 3176 try { 3177 // Support for DPP (Easy connect) 3178 // Requires HAL v1.2 or higher 3179 staIfaceV12.addDppPeerUri(uri, 3180 (SupplicantStatus statusInternal, int bootstrapIdInternal) -> { 3181 status.value = statusInternal.code == SupplicantStatusCode.SUCCESS; 3182 if (status.value) { 3183 bootstrapId.value = bootstrapIdInternal; 3184 } 3185 checkStatusAndLogFailure(statusInternal, methodStr); 3186 }); 3187 } catch (RemoteException e) { 3188 handleRemoteException(e, methodStr); 3189 return -1; 3190 } 3191 3192 return bootstrapId.value; 3193 } 3194 3195 /** 3196 * Removes a DPP URI to the URI list given an ID. 3197 * 3198 * This is a v1.2+ HAL feature. 3199 * Returns true when operation is successful 3200 * On error, or if these features are not supported, false is returned. 3201 */ removeDppUri(@onNull String ifaceName, int bootstrapId)3202 public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId) { 3203 final String methodStr = "removeDppUri"; 3204 3205 if (!isV1_2()) { 3206 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3207 return false; 3208 } 3209 3210 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3211 if (iface == null) { 3212 return false; 3213 } 3214 3215 // Get a v1.2 supplicant STA Interface 3216 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3217 getStaIfaceMockableV1_2(iface); 3218 3219 if (staIfaceV12 == null) { 3220 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3221 return false; 3222 } 3223 3224 try { 3225 // Support for DPP (Easy connect) 3226 // Requires HAL v1.2 or higher 3227 SupplicantStatus status = staIfaceV12.removeDppUri(bootstrapId); 3228 return checkStatusAndLogFailure(status, methodStr); 3229 } catch (RemoteException e) { 3230 handleRemoteException(e, methodStr); 3231 } 3232 3233 return false; 3234 } 3235 3236 /** 3237 * Stops/aborts DPP Initiator request 3238 * 3239 * This is a v1.2+ HAL feature. 3240 * Returns true when operation is successful 3241 * On error, or if these features are not supported, false is returned. 3242 */ stopDppInitiator(@onNull String ifaceName)3243 public boolean stopDppInitiator(@NonNull String ifaceName) { 3244 final String methodStr = "stopDppInitiator"; 3245 3246 if (!isV1_2()) { 3247 return false; 3248 } 3249 3250 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3251 if (iface == null) { 3252 return false; 3253 } 3254 3255 // Get a v1.2 supplicant STA Interface 3256 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3257 getStaIfaceMockableV1_2(iface); 3258 3259 if (staIfaceV12 == null) { 3260 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3261 return false; 3262 } 3263 3264 try { 3265 // Support for DPP (Easy connect) 3266 // Requires HAL v1.2 or higher 3267 SupplicantStatus status = staIfaceV12.stopDppInitiator(); 3268 return checkStatusAndLogFailure(status, methodStr); 3269 } catch (RemoteException e) { 3270 handleRemoteException(e, methodStr); 3271 } 3272 3273 return false; 3274 } 3275 3276 /** 3277 * Starts DPP Configurator-Initiator request 3278 * 3279 * This is a v1.2+ HAL feature. 3280 * Returns true when operation is successful 3281 * On error, or if these features are not supported, false is returned. 3282 */ startDppConfiguratorInitiator(@onNull String ifaceName, int peerBootstrapId, int ownBootstrapId, @NonNull String ssid, String password, String psk, int netRole, int securityAkm)3283 public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId, 3284 int ownBootstrapId, @NonNull String ssid, String password, String psk, 3285 int netRole, int securityAkm) { 3286 final String methodStr = "startDppConfiguratorInitiator"; 3287 3288 if (!isV1_2()) { 3289 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3290 return false; 3291 } 3292 3293 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3294 if (iface == null) { 3295 return false; 3296 } 3297 3298 // Get a v1.2 supplicant STA Interface 3299 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3300 getStaIfaceMockableV1_2(iface); 3301 3302 if (staIfaceV12 == null) { 3303 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3304 return false; 3305 } 3306 3307 try { 3308 // Support for DPP (Easy connect) 3309 // Requires HAL v1.2 or higher 3310 SupplicantStatus status = staIfaceV12.startDppConfiguratorInitiator(peerBootstrapId, 3311 ownBootstrapId, ssid, password != null ? password : "", psk != null ? psk : "", 3312 netRole, securityAkm); 3313 return checkStatusAndLogFailure(status, methodStr); 3314 } catch (RemoteException e) { 3315 handleRemoteException(e, methodStr); 3316 } 3317 3318 return false; 3319 } 3320 3321 /** 3322 * Starts DPP Enrollee-Initiator request 3323 * 3324 * This is a v1.2+ HAL feature. 3325 * Returns true when operation is successful 3326 * On error, or if these features are not supported, false is returned. 3327 */ startDppEnrolleeInitiator(@onNull String ifaceName, int peerBootstrapId, int ownBootstrapId)3328 public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId, 3329 int ownBootstrapId) { 3330 final String methodStr = "startDppEnrolleeInitiator"; 3331 3332 if (!isV1_2()) { 3333 Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); 3334 return false; 3335 } 3336 3337 ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); 3338 if (iface == null) { 3339 return false; 3340 } 3341 3342 // Get a v1.2 supplicant STA Interface 3343 android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface staIfaceV12 = 3344 getStaIfaceMockableV1_2(iface); 3345 3346 if (staIfaceV12 == null) { 3347 Log.e(TAG, methodStr + ": ISupplicantStaIface is null"); 3348 return false; 3349 } 3350 3351 try { 3352 // Support for DPP (Easy connect) 3353 // Requires HAL v1.2 or higher 3354 SupplicantStatus status = staIfaceV12.startDppEnrolleeInitiator(peerBootstrapId, 3355 ownBootstrapId); 3356 return checkStatusAndLogFailure(status, methodStr); 3357 } catch (RemoteException e) { 3358 handleRemoteException(e, methodStr); 3359 } 3360 3361 return false; 3362 } 3363 3364 /** 3365 * Register callbacks for DPP events. 3366 * 3367 * @param dppCallback DPP callback object. 3368 */ registerDppCallback(DppEventCallback dppCallback)3369 public void registerDppCallback(DppEventCallback dppCallback) { 3370 mDppCallback = dppCallback; 3371 } 3372 } 3373