1 /* 2 * Copyright (C) 2008 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 17 package com.android.server.wifi; 18 19 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE; 20 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.net.MacAddress; 24 import android.net.TrafficStats; 25 import android.net.apf.ApfCapabilities; 26 import android.net.wifi.ScanResult; 27 import android.net.wifi.SoftApConfiguration; 28 import android.net.wifi.WifiAnnotations; 29 import android.net.wifi.WifiConfiguration; 30 import android.net.wifi.WifiScanner; 31 import android.net.wifi.WifiSsid; 32 import android.net.wifi.nl80211.DeviceWiphyCapabilities; 33 import android.net.wifi.nl80211.NativeScanResult; 34 import android.net.wifi.nl80211.RadioChainInfo; 35 import android.net.wifi.nl80211.WifiNl80211Manager; 36 import android.os.Handler; 37 import android.os.SystemClock; 38 import android.text.TextUtils; 39 import android.util.ArraySet; 40 import android.util.Log; 41 42 import com.android.internal.annotations.Immutable; 43 import com.android.internal.util.HexDump; 44 import com.android.server.wifi.hotspot2.NetworkDetail; 45 import com.android.server.wifi.util.FrameParser; 46 import com.android.server.wifi.util.InformationElementUtil; 47 import com.android.server.wifi.util.NativeUtil; 48 import com.android.server.wifi.util.NetdWrapper; 49 import com.android.server.wifi.util.NetdWrapper.NetdEventObserver; 50 51 import java.io.PrintWriter; 52 import java.io.StringWriter; 53 import java.lang.annotation.Retention; 54 import java.lang.annotation.RetentionPolicy; 55 import java.nio.ByteBuffer; 56 import java.nio.ByteOrder; 57 import java.text.SimpleDateFormat; 58 import java.util.ArrayList; 59 import java.util.Arrays; 60 import java.util.Date; 61 import java.util.HashMap; 62 import java.util.HashSet; 63 import java.util.Iterator; 64 import java.util.List; 65 import java.util.Map; 66 import java.util.Objects; 67 import java.util.Random; 68 import java.util.Set; 69 import java.util.TimeZone; 70 71 /** 72 * Native calls for bring up/shut down of the supplicant daemon and for 73 * sending requests to the supplicant daemon 74 * 75 * {@hide} 76 */ 77 public class WifiNative { 78 private static final String TAG = "WifiNative"; 79 80 private final SupplicantStaIfaceHal mSupplicantStaIfaceHal; 81 private final HostapdHal mHostapdHal; 82 private final WifiVendorHal mWifiVendorHal; 83 private final WifiNl80211Manager mWifiCondManager; 84 private final WifiMonitor mWifiMonitor; 85 private final PropertyService mPropertyService; 86 private final WifiMetrics mWifiMetrics; 87 private final Handler mHandler; 88 private final Random mRandom; 89 private final WifiInjector mWifiInjector; 90 private NetdWrapper mNetdWrapper; 91 private boolean mVerboseLoggingEnabled = false; 92 WifiNative(WifiVendorHal vendorHal, SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, WifiNl80211Manager condManager, WifiMonitor wifiMonitor, PropertyService propertyService, WifiMetrics wifiMetrics, Handler handler, Random random, WifiInjector wifiInjector)93 public WifiNative(WifiVendorHal vendorHal, 94 SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, 95 WifiNl80211Manager condManager, WifiMonitor wifiMonitor, 96 PropertyService propertyService, WifiMetrics wifiMetrics, 97 Handler handler, Random random, 98 WifiInjector wifiInjector) { 99 mWifiVendorHal = vendorHal; 100 mSupplicantStaIfaceHal = staIfaceHal; 101 mHostapdHal = hostapdHal; 102 mWifiCondManager = condManager; 103 mWifiMonitor = wifiMonitor; 104 mPropertyService = propertyService; 105 mWifiMetrics = wifiMetrics; 106 mHandler = handler; 107 mRandom = random; 108 mWifiInjector = wifiInjector; 109 } 110 111 /** 112 * Enable verbose logging for all sub modules. 113 */ enableVerboseLogging(int verbose)114 public void enableVerboseLogging(int verbose) { 115 mVerboseLoggingEnabled = verbose > 0 ? true : false; 116 mWifiCondManager.enableVerboseLogging(mVerboseLoggingEnabled); 117 mSupplicantStaIfaceHal.enableVerboseLogging(mVerboseLoggingEnabled); 118 mHostapdHal.enableVerboseLogging(mVerboseLoggingEnabled); 119 mWifiVendorHal.enableVerboseLogging(mVerboseLoggingEnabled); 120 } 121 122 /** 123 * Callbacks for SoftAp interface. 124 */ 125 public interface SoftApListener extends WifiNl80211Manager.SoftApCallback { 126 // dummy for now - provide a shell so that clients don't use a 127 // WifiNl80211Manager-specific API. 128 } 129 130 /******************************************************** 131 * Interface management related methods. 132 ********************************************************/ 133 /** 134 * Meta-info about every iface that is active. 135 */ 136 private static class Iface { 137 /** Type of ifaces possible */ 138 public static final int IFACE_TYPE_AP = 0; 139 public static final int IFACE_TYPE_STA_FOR_CONNECTIVITY = 1; 140 public static final int IFACE_TYPE_STA_FOR_SCAN = 2; 141 142 @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA_FOR_CONNECTIVITY, IFACE_TYPE_STA_FOR_SCAN}) 143 @Retention(RetentionPolicy.SOURCE) 144 public @interface IfaceType{} 145 146 /** Identifier allocated for the interface */ 147 public final int id; 148 /** Type of the iface: STA (for Connectivity or Scan) or AP */ 149 public @IfaceType int type; 150 /** Name of the interface */ 151 public String name; 152 /** Is the interface up? This is used to mask up/down notifications to external clients. */ 153 public boolean isUp; 154 /** External iface destroyed listener for the iface */ 155 public InterfaceCallback externalListener; 156 /** Network observer registered for this interface */ 157 public NetworkObserverInternal networkObserver; 158 /** Interface feature set / capabilities */ 159 public long featureSet; 160 public DeviceWiphyCapabilities phyCapabilities; 161 Iface(int id, @Iface.IfaceType int type)162 Iface(int id, @Iface.IfaceType int type) { 163 this.id = id; 164 this.type = type; 165 } 166 167 @Override toString()168 public String toString() { 169 StringBuffer sb = new StringBuffer(); 170 String typeString; 171 switch(type) { 172 case IFACE_TYPE_STA_FOR_CONNECTIVITY: 173 typeString = "STA_CONNECTIVITY"; 174 break; 175 case IFACE_TYPE_STA_FOR_SCAN: 176 typeString = "STA_SCAN"; 177 break; 178 case IFACE_TYPE_AP: 179 typeString = "AP"; 180 break; 181 default: 182 typeString = "<UNKNOWN>"; 183 break; 184 } 185 sb.append("Iface:") 186 .append("{") 187 .append("Name=").append(name) 188 .append(",") 189 .append("Id=").append(id) 190 .append(",") 191 .append("Type=").append(typeString) 192 .append("}"); 193 return sb.toString(); 194 } 195 } 196 197 /** 198 * Iface Management entity. This class maintains list of all the active ifaces. 199 */ 200 private static class IfaceManager { 201 /** Integer to allocate for the next iface being created */ 202 private int mNextId; 203 /** Map of the id to the iface structure */ 204 private HashMap<Integer, Iface> mIfaces = new HashMap<>(); 205 206 /** Allocate a new iface for the given type */ allocateIface(@face.IfaceType int type)207 private Iface allocateIface(@Iface.IfaceType int type) { 208 Iface iface = new Iface(mNextId, type); 209 mIfaces.put(mNextId, iface); 210 mNextId++; 211 return iface; 212 } 213 214 /** Remove the iface using the provided id */ removeIface(int id)215 private Iface removeIface(int id) { 216 return mIfaces.remove(id); 217 } 218 219 /** Lookup the iface using the provided id */ getIface(int id)220 private Iface getIface(int id) { 221 return mIfaces.get(id); 222 } 223 224 /** Lookup the iface using the provided name */ getIface(@onNull String ifaceName)225 private Iface getIface(@NonNull String ifaceName) { 226 for (Iface iface : mIfaces.values()) { 227 if (TextUtils.equals(iface.name, ifaceName)) { 228 return iface; 229 } 230 } 231 return null; 232 } 233 234 /** Iterator to use for deleting all the ifaces while performing teardown on each of them */ getIfaceIdIter()235 private Iterator<Integer> getIfaceIdIter() { 236 return mIfaces.keySet().iterator(); 237 } 238 239 /** Checks if there are any iface active. */ hasAnyIface()240 private boolean hasAnyIface() { 241 return !mIfaces.isEmpty(); 242 } 243 244 /** Checks if there are any iface of the given type active. */ hasAnyIfaceOfType(@face.IfaceType int type)245 private boolean hasAnyIfaceOfType(@Iface.IfaceType int type) { 246 for (Iface iface : mIfaces.values()) { 247 if (iface.type == type) { 248 return true; 249 } 250 } 251 return false; 252 } 253 254 /** Checks if there are any iface of the given type active. */ findAnyIfaceOfType(@face.IfaceType int type)255 private Iface findAnyIfaceOfType(@Iface.IfaceType int type) { 256 for (Iface iface : mIfaces.values()) { 257 if (iface.type == type) { 258 return iface; 259 } 260 } 261 return null; 262 } 263 264 /** Checks if there are any STA (for connectivity) iface active. */ hasAnyStaIfaceForConnectivity()265 private boolean hasAnyStaIfaceForConnectivity() { 266 return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY); 267 } 268 269 /** Checks if there are any STA (for scan) iface active. */ hasAnyStaIfaceForScan()270 private boolean hasAnyStaIfaceForScan() { 271 return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_SCAN); 272 } 273 274 /** Checks if there are any AP iface active. */ hasAnyApIface()275 private boolean hasAnyApIface() { 276 return hasAnyIfaceOfType(Iface.IFACE_TYPE_AP); 277 } 278 279 /** Finds the name of any STA iface active. */ findAnyStaIfaceName()280 private String findAnyStaIfaceName() { 281 Iface iface = findAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY); 282 if (iface == null) { 283 iface = findAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_SCAN); 284 } 285 if (iface == null) { 286 return null; 287 } 288 return iface.name; 289 } 290 291 /** Finds the name of any AP iface active. */ findAnyApIfaceName()292 private String findAnyApIfaceName() { 293 Iface iface = findAnyIfaceOfType(Iface.IFACE_TYPE_AP); 294 if (iface == null) { 295 return null; 296 } 297 return iface.name; 298 } 299 findAllStaIfaceNames()300 private @NonNull Set<String> findAllStaIfaceNames() { 301 Set<String> ifaceNames = new ArraySet<>(); 302 for (Iface iface : mIfaces.values()) { 303 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY 304 || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 305 ifaceNames.add(iface.name); 306 } 307 } 308 return ifaceNames; 309 } 310 311 /** Removes the existing iface that does not match the provided id. */ removeExistingIface(int newIfaceId)312 public Iface removeExistingIface(int newIfaceId) { 313 Iface removedIface = null; 314 // The number of ifaces in the database could be 1 existing & 1 new at the max. 315 if (mIfaces.size() > 2) { 316 Log.wtf(TAG, "More than 1 existing interface found"); 317 } 318 Iterator<Map.Entry<Integer, Iface>> iter = mIfaces.entrySet().iterator(); 319 while (iter.hasNext()) { 320 Map.Entry<Integer, Iface> entry = iter.next(); 321 if (entry.getKey() != newIfaceId) { 322 removedIface = entry.getValue(); 323 iter.remove(); 324 } 325 } 326 return removedIface; 327 } 328 } 329 330 private class NormalScanEventCallback implements WifiNl80211Manager.ScanEventCallback { 331 private String mIfaceName; 332 NormalScanEventCallback(String ifaceName)333 NormalScanEventCallback(String ifaceName) { 334 mIfaceName = ifaceName; 335 } 336 337 @Override onScanResultReady()338 public void onScanResultReady() { 339 Log.d(TAG, "Scan result ready event"); 340 mWifiMonitor.broadcastScanResultEvent(mIfaceName); 341 } 342 343 @Override onScanFailed()344 public void onScanFailed() { 345 Log.d(TAG, "Scan failed event"); 346 mWifiMonitor.broadcastScanFailedEvent(mIfaceName); 347 } 348 } 349 350 private class PnoScanEventCallback implements WifiNl80211Manager.ScanEventCallback { 351 private String mIfaceName; 352 PnoScanEventCallback(String ifaceName)353 PnoScanEventCallback(String ifaceName) { 354 mIfaceName = ifaceName; 355 } 356 357 @Override onScanResultReady()358 public void onScanResultReady() { 359 Log.d(TAG, "Pno scan result event"); 360 mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName); 361 mWifiMetrics.incrementPnoFoundNetworkEventCount(); 362 } 363 364 @Override onScanFailed()365 public void onScanFailed() { 366 Log.d(TAG, "Pno Scan failed event"); 367 mWifiMetrics.incrementPnoScanFailedCount(); 368 } 369 } 370 371 private final Object mLock = new Object(); 372 private final IfaceManager mIfaceMgr = new IfaceManager(); 373 private HashSet<StatusListener> mStatusListeners = new HashSet<>(); 374 375 /** Helper method invoked to start supplicant if there were no ifaces */ startHal()376 private boolean startHal() { 377 synchronized (mLock) { 378 if (!mIfaceMgr.hasAnyIface()) { 379 if (mWifiVendorHal.isVendorHalSupported()) { 380 if (!mWifiVendorHal.startVendorHal()) { 381 Log.e(TAG, "Failed to start vendor HAL"); 382 return false; 383 } 384 } else { 385 Log.i(TAG, "Vendor Hal not supported, ignoring start."); 386 } 387 } 388 return true; 389 } 390 } 391 392 /** Helper method invoked to stop HAL if there are no more ifaces */ stopHalAndWificondIfNecessary()393 private void stopHalAndWificondIfNecessary() { 394 synchronized (mLock) { 395 if (!mIfaceMgr.hasAnyIface()) { 396 if (!mWifiCondManager.tearDownInterfaces()) { 397 Log.e(TAG, "Failed to teardown ifaces from wificond"); 398 } 399 if (mWifiVendorHal.isVendorHalSupported()) { 400 mWifiVendorHal.stopVendorHal(); 401 } else { 402 Log.i(TAG, "Vendor Hal not supported, ignoring stop."); 403 } 404 } 405 } 406 } 407 408 private static final int CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS = 100; 409 private static final int CONNECT_TO_SUPPLICANT_RETRY_TIMES = 50; 410 /** 411 * This method is called to wait for establishing connection to wpa_supplicant. 412 * 413 * @return true if connection is established, false otherwise. 414 */ startAndWaitForSupplicantConnection()415 private boolean startAndWaitForSupplicantConnection() { 416 // Start initialization if not already started. 417 if (!mSupplicantStaIfaceHal.isInitializationStarted() 418 && !mSupplicantStaIfaceHal.initialize()) { 419 return false; 420 } 421 if (!mSupplicantStaIfaceHal.startDaemon()) { 422 Log.e(TAG, "Failed to startup supplicant"); 423 return false; 424 } 425 boolean connected = false; 426 int connectTries = 0; 427 while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) { 428 // Check if the initialization is complete. 429 connected = mSupplicantStaIfaceHal.isInitializationComplete(); 430 if (connected) { 431 break; 432 } 433 try { 434 Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS); 435 } catch (InterruptedException ignore) { 436 } 437 } 438 return connected; 439 } 440 441 /** Helper method invoked to start supplicant if there were no STA ifaces */ startSupplicant()442 private boolean startSupplicant() { 443 synchronized (mLock) { 444 if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) { 445 if (!startAndWaitForSupplicantConnection()) { 446 Log.e(TAG, "Failed to connect to supplicant"); 447 return false; 448 } 449 if (!mSupplicantStaIfaceHal.registerDeathHandler( 450 new SupplicantDeathHandlerInternal())) { 451 Log.e(TAG, "Failed to register supplicant death handler"); 452 return false; 453 } 454 } 455 return true; 456 } 457 } 458 459 /** Helper method invoked to stop supplicant if there are no more STA ifaces */ stopSupplicantIfNecessary()460 private void stopSupplicantIfNecessary() { 461 synchronized (mLock) { 462 if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) { 463 if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) { 464 Log.e(TAG, "Failed to deregister supplicant death handler"); 465 } 466 mSupplicantStaIfaceHal.terminate(); 467 } 468 } 469 } 470 471 /** Helper method invoked to start hostapd if there were no AP ifaces */ startHostapd()472 private boolean startHostapd() { 473 synchronized (mLock) { 474 if (!mIfaceMgr.hasAnyApIface()) { 475 if (!startAndWaitForHostapdConnection()) { 476 Log.e(TAG, "Failed to connect to hostapd"); 477 return false; 478 } 479 if (!mHostapdHal.registerDeathHandler( 480 new HostapdDeathHandlerInternal())) { 481 Log.e(TAG, "Failed to register hostapd death handler"); 482 return false; 483 } 484 } 485 return true; 486 } 487 } 488 489 /** Helper method invoked to stop hostapd if there are no more AP ifaces */ stopHostapdIfNecessary()490 private void stopHostapdIfNecessary() { 491 synchronized (mLock) { 492 if (!mIfaceMgr.hasAnyApIface()) { 493 if (!mHostapdHal.deregisterDeathHandler()) { 494 Log.e(TAG, "Failed to deregister hostapd death handler"); 495 } 496 mHostapdHal.terminate(); 497 } 498 } 499 } 500 501 /** Helper method to register a network observer and return it */ registerNetworkObserver(NetworkObserverInternal observer)502 private boolean registerNetworkObserver(NetworkObserverInternal observer) { 503 if (observer == null) return false; 504 mNetdWrapper.registerObserver(observer); 505 return true; 506 } 507 508 /** Helper method to unregister a network observer */ unregisterNetworkObserver(NetworkObserverInternal observer)509 private boolean unregisterNetworkObserver(NetworkObserverInternal observer) { 510 if (observer == null) return false; 511 mNetdWrapper.unregisterObserver(observer); 512 return true; 513 } 514 515 /** 516 * Helper method invoked to teardown client iface (for connectivity) and perform 517 * necessary cleanup 518 */ onClientInterfaceForConnectivityDestroyed(@onNull Iface iface)519 private void onClientInterfaceForConnectivityDestroyed(@NonNull Iface iface) { 520 synchronized (mLock) { 521 mWifiMonitor.stopMonitoring(iface.name); 522 if (!unregisterNetworkObserver(iface.networkObserver)) { 523 Log.e(TAG, "Failed to unregister network observer on " + iface); 524 } 525 if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) { 526 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface); 527 } 528 if (!mWifiCondManager.tearDownClientInterface(iface.name)) { 529 Log.e(TAG, "Failed to teardown iface in wificond on " + iface); 530 } 531 stopSupplicantIfNecessary(); 532 stopHalAndWificondIfNecessary(); 533 } 534 } 535 536 /** Helper method invoked to teardown client iface (for scan) and perform necessary cleanup */ onClientInterfaceForScanDestroyed(@onNull Iface iface)537 private void onClientInterfaceForScanDestroyed(@NonNull Iface iface) { 538 synchronized (mLock) { 539 mWifiMonitor.stopMonitoring(iface.name); 540 if (!unregisterNetworkObserver(iface.networkObserver)) { 541 Log.e(TAG, "Failed to unregister network observer on " + iface); 542 } 543 if (!mWifiCondManager.tearDownClientInterface(iface.name)) { 544 Log.e(TAG, "Failed to teardown iface in wificond on " + iface); 545 } 546 stopHalAndWificondIfNecessary(); 547 } 548 } 549 550 /** Helper method invoked to teardown softAp iface and perform necessary cleanup */ onSoftApInterfaceDestroyed(@onNull Iface iface)551 private void onSoftApInterfaceDestroyed(@NonNull Iface iface) { 552 synchronized (mLock) { 553 if (!unregisterNetworkObserver(iface.networkObserver)) { 554 Log.e(TAG, "Failed to unregister network observer on " + iface); 555 } 556 if (!mHostapdHal.removeAccessPoint(iface.name)) { 557 Log.e(TAG, "Failed to remove access point on " + iface); 558 } 559 if (!mWifiCondManager.tearDownSoftApInterface(iface.name)) { 560 Log.e(TAG, "Failed to teardown iface in wificond on " + iface); 561 } 562 stopHostapdIfNecessary(); 563 stopHalAndWificondIfNecessary(); 564 } 565 } 566 567 /** Helper method invoked to teardown iface and perform necessary cleanup */ onInterfaceDestroyed(@onNull Iface iface)568 private void onInterfaceDestroyed(@NonNull Iface iface) { 569 synchronized (mLock) { 570 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) { 571 onClientInterfaceForConnectivityDestroyed(iface); 572 } else if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 573 onClientInterfaceForScanDestroyed(iface); 574 } else if (iface.type == Iface.IFACE_TYPE_AP) { 575 onSoftApInterfaceDestroyed(iface); 576 } 577 // Invoke the external callback. 578 iface.externalListener.onDestroyed(iface.name); 579 } 580 } 581 582 /** 583 * Callback to be invoked by HalDeviceManager when an interface is destroyed. 584 */ 585 private class InterfaceDestoyedListenerInternal 586 implements HalDeviceManager.InterfaceDestroyedListener { 587 /** Identifier allocated for the interface */ 588 private final int mInterfaceId; 589 InterfaceDestoyedListenerInternal(int ifaceId)590 InterfaceDestoyedListenerInternal(int ifaceId) { 591 mInterfaceId = ifaceId; 592 } 593 594 @Override onDestroyed(@onNull String ifaceName)595 public void onDestroyed(@NonNull String ifaceName) { 596 synchronized (mLock) { 597 final Iface iface = mIfaceMgr.removeIface(mInterfaceId); 598 if (iface == null) { 599 if (mVerboseLoggingEnabled) { 600 Log.v(TAG, "Received iface destroyed notification on an invalid iface=" 601 + ifaceName); 602 } 603 return; 604 } 605 onInterfaceDestroyed(iface); 606 Log.i(TAG, "Successfully torn down " + iface); 607 } 608 } 609 } 610 611 /** 612 * Helper method invoked to trigger the status changed callback after one of the native 613 * daemon's death. 614 */ onNativeDaemonDeath()615 private void onNativeDaemonDeath() { 616 synchronized (mLock) { 617 for (StatusListener listener : mStatusListeners) { 618 listener.onStatusChanged(false); 619 } 620 for (StatusListener listener : mStatusListeners) { 621 listener.onStatusChanged(true); 622 } 623 } 624 } 625 626 /** 627 * Death handler for the Vendor HAL daemon. 628 */ 629 private class VendorHalDeathHandlerInternal implements VendorHalDeathEventHandler { 630 @Override onDeath()631 public void onDeath() { 632 synchronized (mLock) { 633 Log.i(TAG, "Vendor HAL died. Cleaning up internal state."); 634 onNativeDaemonDeath(); 635 mWifiMetrics.incrementNumHalCrashes(); 636 } 637 } 638 } 639 640 /** 641 * Death handler for the wificond daemon. 642 */ 643 private class WificondDeathHandlerInternal implements Runnable { 644 @Override run()645 public void run() { 646 synchronized (mLock) { 647 Log.i(TAG, "wificond died. Cleaning up internal state."); 648 onNativeDaemonDeath(); 649 mWifiMetrics.incrementNumWificondCrashes(); 650 } 651 } 652 } 653 654 /** 655 * Death handler for the supplicant daemon. 656 */ 657 private class SupplicantDeathHandlerInternal implements SupplicantDeathEventHandler { 658 @Override onDeath()659 public void onDeath() { 660 synchronized (mLock) { 661 Log.i(TAG, "wpa_supplicant died. Cleaning up internal state."); 662 onNativeDaemonDeath(); 663 mWifiMetrics.incrementNumSupplicantCrashes(); 664 } 665 } 666 } 667 668 /** 669 * Death handler for the hostapd daemon. 670 */ 671 private class HostapdDeathHandlerInternal implements HostapdDeathEventHandler { 672 @Override onDeath()673 public void onDeath() { 674 synchronized (mLock) { 675 Log.i(TAG, "hostapd died. Cleaning up internal state."); 676 onNativeDaemonDeath(); 677 mWifiMetrics.incrementNumHostapdCrashes(); 678 } 679 } 680 } 681 682 /** Helper method invoked to handle interface change. */ onInterfaceStateChanged(Iface iface, boolean isUp)683 private void onInterfaceStateChanged(Iface iface, boolean isUp) { 684 synchronized (mLock) { 685 // Mask multiple notifications with the same state. 686 if (isUp == iface.isUp) { 687 if (mVerboseLoggingEnabled) { 688 Log.v(TAG, "Interface status unchanged on " + iface + " from " + isUp 689 + ", Ignoring..."); 690 } 691 return; 692 } 693 Log.i(TAG, "Interface state changed on " + iface + ", isUp=" + isUp); 694 if (isUp) { 695 iface.externalListener.onUp(iface.name); 696 } else { 697 iface.externalListener.onDown(iface.name); 698 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY 699 || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 700 mWifiMetrics.incrementNumClientInterfaceDown(); 701 } else if (iface.type == Iface.IFACE_TYPE_AP) { 702 mWifiMetrics.incrementNumSoftApInterfaceDown(); 703 } 704 } 705 iface.isUp = isUp; 706 } 707 } 708 709 /** 710 * Network observer to use for all interface up/down notifications. 711 */ 712 private class NetworkObserverInternal implements NetdEventObserver { 713 /** Identifier allocated for the interface */ 714 private final int mInterfaceId; 715 NetworkObserverInternal(int id)716 NetworkObserverInternal(int id) { 717 mInterfaceId = id; 718 } 719 720 /** 721 * Note: We should ideally listen to 722 * {@link NetdEventObserver#interfaceStatusChanged(String, boolean)} here. But, that 723 * callback is not working currently (broken in netd). So, instead listen to link state 724 * change callbacks as triggers to query the real interface state. We should get rid of 725 * this workaround if we get the |interfaceStatusChanged| callback to work in netd. 726 * Also, this workaround will not detect an interface up event, if the link state is 727 * still down. 728 */ 729 @Override interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp)730 public void interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp) { 731 // This is invoked from the main system_server thread. Post to our handler. 732 mHandler.post(() -> { 733 synchronized (mLock) { 734 final Iface ifaceWithId = mIfaceMgr.getIface(mInterfaceId); 735 if (ifaceWithId == null) { 736 if (mVerboseLoggingEnabled) { 737 Log.v(TAG, "Received iface link up/down notification on an invalid" 738 + " iface=" + mInterfaceId); 739 } 740 return; 741 } 742 final Iface ifaceWithName = mIfaceMgr.getIface(ifaceName); 743 if (ifaceWithName == null || ifaceWithName != ifaceWithId) { 744 if (mVerboseLoggingEnabled) { 745 Log.v(TAG, "Received iface link up/down notification on an invalid" 746 + " iface=" + ifaceName); 747 } 748 return; 749 } 750 onInterfaceStateChanged(ifaceWithName, isInterfaceUp(ifaceName)); 751 } 752 }); 753 } 754 755 @Override interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp)756 public void interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp) { 757 // unused currently. Look at note above. 758 } 759 } 760 761 /** 762 * Radio mode change handler for the Vendor HAL daemon. 763 */ 764 private class VendorHalRadioModeChangeHandlerInternal 765 implements VendorHalRadioModeChangeEventHandler { 766 @Override onMcc(int band)767 public void onMcc(int band) { 768 synchronized (mLock) { 769 Log.i(TAG, "Device is in MCC mode now"); 770 mWifiMetrics.incrementNumRadioModeChangeToMcc(); 771 } 772 } 773 @Override onScc(int band)774 public void onScc(int band) { 775 synchronized (mLock) { 776 Log.i(TAG, "Device is in SCC mode now"); 777 mWifiMetrics.incrementNumRadioModeChangeToScc(); 778 } 779 } 780 @Override onSbs(int band)781 public void onSbs(int band) { 782 synchronized (mLock) { 783 Log.i(TAG, "Device is in SBS mode now"); 784 mWifiMetrics.incrementNumRadioModeChangeToSbs(); 785 } 786 } 787 @Override onDbs()788 public void onDbs() { 789 synchronized (mLock) { 790 Log.i(TAG, "Device is in DBS mode now"); 791 mWifiMetrics.incrementNumRadioModeChangeToDbs(); 792 } 793 } 794 } 795 796 // For devices that don't support the vendor HAL, we will not support any concurrency. 797 // So simulate the HalDeviceManager behavior by triggering the destroy listener for 798 // any active interface. handleIfaceCreationWhenVendorHalNotSupported(@onNull Iface newIface)799 private String handleIfaceCreationWhenVendorHalNotSupported(@NonNull Iface newIface) { 800 synchronized (mLock) { 801 Iface existingIface = mIfaceMgr.removeExistingIface(newIface.id); 802 if (existingIface != null) { 803 onInterfaceDestroyed(existingIface); 804 Log.i(TAG, "Successfully torn down " + existingIface); 805 } 806 // Return the interface name directly from the system property. 807 return mPropertyService.getString("wifi.interface", "wlan0"); 808 } 809 } 810 811 /** 812 * Helper function to handle creation of STA iface. 813 * For devices which do not the support the HAL, this will bypass HalDeviceManager & 814 * teardown any existing iface. 815 */ createStaIface(@onNull Iface iface)816 private String createStaIface(@NonNull Iface iface) { 817 synchronized (mLock) { 818 if (mWifiVendorHal.isVendorHalSupported()) { 819 return mWifiVendorHal.createStaIface( 820 new InterfaceDestoyedListenerInternal(iface.id)); 821 } else { 822 Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface."); 823 return handleIfaceCreationWhenVendorHalNotSupported(iface); 824 } 825 } 826 } 827 828 /** 829 * Helper function to handle creation of AP iface. 830 * For devices which do not the support the HAL, this will bypass HalDeviceManager & 831 * teardown any existing iface. 832 */ createApIface(@onNull Iface iface)833 private String createApIface(@NonNull Iface iface) { 834 synchronized (mLock) { 835 if (mWifiVendorHal.isVendorHalSupported()) { 836 return mWifiVendorHal.createApIface( 837 new InterfaceDestoyedListenerInternal(iface.id)); 838 } else { 839 Log.i(TAG, "Vendor Hal not supported, ignoring createApIface."); 840 return handleIfaceCreationWhenVendorHalNotSupported(iface); 841 } 842 } 843 } 844 845 // For devices that don't support the vendor HAL, we will not support any concurrency. 846 // So simulate the HalDeviceManager behavior by triggering the destroy listener for 847 // the interface. handleIfaceRemovalWhenVendorHalNotSupported(@onNull Iface iface)848 private boolean handleIfaceRemovalWhenVendorHalNotSupported(@NonNull Iface iface) { 849 synchronized (mLock) { 850 mIfaceMgr.removeIface(iface.id); 851 onInterfaceDestroyed(iface); 852 Log.i(TAG, "Successfully torn down " + iface); 853 return true; 854 } 855 } 856 857 /** 858 * Helper function to handle removal of STA iface. 859 * For devices which do not the support the HAL, this will bypass HalDeviceManager & 860 * teardown any existing iface. 861 */ removeStaIface(@onNull Iface iface)862 private boolean removeStaIface(@NonNull Iface iface) { 863 synchronized (mLock) { 864 if (mWifiVendorHal.isVendorHalSupported()) { 865 return mWifiVendorHal.removeStaIface(iface.name); 866 } else { 867 Log.i(TAG, "Vendor Hal not supported, ignoring removeStaIface."); 868 return handleIfaceRemovalWhenVendorHalNotSupported(iface); 869 } 870 } 871 } 872 873 /** 874 * Helper function to handle removal of STA iface. 875 */ removeApIface(@onNull Iface iface)876 private boolean removeApIface(@NonNull Iface iface) { 877 synchronized (mLock) { 878 if (mWifiVendorHal.isVendorHalSupported()) { 879 return mWifiVendorHal.removeApIface(iface.name); 880 } else { 881 Log.i(TAG, "Vendor Hal not supported, ignoring removeApIface."); 882 return handleIfaceRemovalWhenVendorHalNotSupported(iface); 883 } 884 } 885 } 886 887 /** 888 * Initialize the native modules. 889 * 890 * @return true on success, false otherwise. 891 */ initialize()892 public boolean initialize() { 893 synchronized (mLock) { 894 if (!mWifiVendorHal.initialize(new VendorHalDeathHandlerInternal())) { 895 Log.e(TAG, "Failed to initialize vendor HAL"); 896 return false; 897 } 898 mWifiCondManager.setOnServiceDeadCallback(new WificondDeathHandlerInternal()); 899 mWifiCondManager.tearDownInterfaces(); 900 mWifiVendorHal.registerRadioModeChangeHandler( 901 new VendorHalRadioModeChangeHandlerInternal()); 902 mNetdWrapper = mWifiInjector.makeNetdWrapper(); 903 return true; 904 } 905 } 906 907 /** 908 * Callback to notify when the status of one of the native daemons 909 * (wificond, wpa_supplicant & vendor HAL) changes. 910 */ 911 public interface StatusListener { 912 /** 913 * @param allReady Indicates if all the native daemons are ready for operation or not. 914 */ onStatusChanged(boolean allReady)915 void onStatusChanged(boolean allReady); 916 } 917 918 /** 919 * Register a StatusListener to get notified about any status changes from the native daemons. 920 * 921 * It is safe to re-register the same callback object - duplicates are detected and only a 922 * single copy kept. 923 * 924 * @param listener StatusListener listener object. 925 */ registerStatusListener(@onNull StatusListener listener)926 public void registerStatusListener(@NonNull StatusListener listener) { 927 mStatusListeners.add(listener); 928 } 929 930 /** 931 * Callback to notify when the availability of an interface has changed. 932 */ 933 public interface InterfaceAvailableForRequestListener { 934 /** 935 * @param isAvailable Whether it is possible to create an iface of the specified type or 936 * not. 937 */ onAvailabilityChanged(boolean isAvailable)938 void onAvailabilityChanged(boolean isAvailable); 939 } 940 941 /** 942 * Register a callback to notify when the availability of Client interface has changed. 943 * 944 * It is safe to re-register the same callback object - duplicates are detected and only a 945 * single copy kept. 946 * 947 * @param listener Instance of {@link InterfaceAvailableForRequestListener}. 948 */ registerClientInterfaceAvailabilityListener( @onNull InterfaceAvailableForRequestListener listener)949 public void registerClientInterfaceAvailabilityListener( 950 @NonNull InterfaceAvailableForRequestListener listener) { 951 mWifiVendorHal.registerStaIfaceAvailabilityListener(listener); 952 } 953 954 /** 955 * Register a callback to notify when the availability of SoftAp interface has changed. 956 * 957 * It is safe to re-register the same callback object - duplicates are detected and only a 958 * single copy kept. 959 * 960 * @param listener Instance of {@link InterfaceAvailableForRequestListener}. 961 */ registerSoftApInterfaceAvailabilityListener( @onNull InterfaceAvailableForRequestListener listener)962 public void registerSoftApInterfaceAvailabilityListener( 963 @NonNull InterfaceAvailableForRequestListener listener) { 964 mWifiVendorHal.registerApIfaceAvailabilityListener(listener); 965 } 966 967 /** 968 * Callback to notify when the associated interface is destroyed, up or down. 969 */ 970 public interface InterfaceCallback { 971 /** 972 * Interface destroyed by HalDeviceManager. 973 * 974 * @param ifaceName Name of the iface. 975 */ onDestroyed(String ifaceName)976 void onDestroyed(String ifaceName); 977 978 /** 979 * Interface is up. 980 * 981 * @param ifaceName Name of the iface. 982 */ onUp(String ifaceName)983 void onUp(String ifaceName); 984 985 /** 986 * Interface is down. 987 * 988 * @param ifaceName Name of the iface. 989 */ onDown(String ifaceName)990 void onDown(String ifaceName); 991 } 992 initializeNwParamsForClientInterface(@onNull String ifaceName)993 private void initializeNwParamsForClientInterface(@NonNull String ifaceName) { 994 try { 995 // A runtime crash or shutting down AP mode can leave 996 // IP addresses configured, and this affects 997 // connectivity when supplicant starts up. 998 // Ensure we have no IP addresses before a supplicant start. 999 mNetdWrapper.clearInterfaceAddresses(ifaceName); 1000 1001 // Set privacy extensions 1002 mNetdWrapper.setInterfaceIpv6PrivacyExtensions(ifaceName, true); 1003 1004 // IPv6 is enabled only as long as access point is connected since: 1005 // - IPv6 addresses and routes stick around after disconnection 1006 // - kernel is unaware when connected and fails to start IPv6 negotiation 1007 // - kernel can start autoconfiguration when 802.1x is not complete 1008 mNetdWrapper.disableIpv6(ifaceName); 1009 } catch (IllegalStateException e) { 1010 Log.e(TAG, "Unable to change interface settings", e); 1011 } 1012 } 1013 1014 /** 1015 * Setup an interface for client mode (for connectivity) operations. 1016 * 1017 * This method configures an interface in STA mode in all the native daemons 1018 * (wificond, wpa_supplicant & vendor HAL). 1019 * 1020 * @param interfaceCallback Associated callback for notifying status changes for the iface. 1021 * @return Returns the name of the allocated interface, will be null on failure. 1022 */ setupInterfaceForClientInConnectivityMode( @onNull InterfaceCallback interfaceCallback)1023 public String setupInterfaceForClientInConnectivityMode( 1024 @NonNull InterfaceCallback interfaceCallback) { 1025 synchronized (mLock) { 1026 if (!startHal()) { 1027 Log.e(TAG, "Failed to start Hal"); 1028 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal(); 1029 return null; 1030 } 1031 if (!startSupplicant()) { 1032 Log.e(TAG, "Failed to start supplicant"); 1033 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant(); 1034 return null; 1035 } 1036 Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY); 1037 if (iface == null) { 1038 Log.e(TAG, "Failed to allocate new STA iface"); 1039 return null; 1040 } 1041 iface.externalListener = interfaceCallback; 1042 iface.name = createStaIface(iface); 1043 if (TextUtils.isEmpty(iface.name)) { 1044 Log.e(TAG, "Failed to create STA iface in vendor HAL"); 1045 mIfaceMgr.removeIface(iface.id); 1046 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal(); 1047 return null; 1048 } 1049 if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run, 1050 new NormalScanEventCallback(iface.name), 1051 new PnoScanEventCallback(iface.name))) { 1052 Log.e(TAG, "Failed to setup iface in wificond on " + iface); 1053 teardownInterface(iface.name); 1054 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond(); 1055 return null; 1056 } 1057 if (!mSupplicantStaIfaceHal.setupIface(iface.name)) { 1058 Log.e(TAG, "Failed to setup iface in supplicant on " + iface); 1059 teardownInterface(iface.name); 1060 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant(); 1061 return null; 1062 } 1063 iface.networkObserver = new NetworkObserverInternal(iface.id); 1064 if (!registerNetworkObserver(iface.networkObserver)) { 1065 Log.e(TAG, "Failed to register network observer on " + iface); 1066 teardownInterface(iface.name); 1067 return null; 1068 } 1069 mWifiMonitor.startMonitoring(iface.name); 1070 // Just to avoid any race conditions with interface state change callbacks, 1071 // update the interface state before we exit. 1072 onInterfaceStateChanged(iface, isInterfaceUp(iface.name)); 1073 initializeNwParamsForClientInterface(iface.name); 1074 Log.i(TAG, "Successfully setup " + iface); 1075 1076 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1077 return iface.name; 1078 } 1079 } 1080 1081 /** 1082 * Setup an interface for client mode (for scan) operations. 1083 * 1084 * This method configures an interface in STA mode in the native daemons 1085 * (wificond, vendor HAL). 1086 * 1087 * @param interfaceCallback Associated callback for notifying status changes for the iface. 1088 * @return Returns the name of the allocated interface, will be null on failure. 1089 */ setupInterfaceForClientInScanMode( @onNull InterfaceCallback interfaceCallback)1090 public String setupInterfaceForClientInScanMode( 1091 @NonNull InterfaceCallback interfaceCallback) { 1092 synchronized (mLock) { 1093 if (!startHal()) { 1094 Log.e(TAG, "Failed to start Hal"); 1095 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal(); 1096 return null; 1097 } 1098 Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN); 1099 if (iface == null) { 1100 Log.e(TAG, "Failed to allocate new STA iface"); 1101 return null; 1102 } 1103 iface.externalListener = interfaceCallback; 1104 iface.name = createStaIface(iface); 1105 if (TextUtils.isEmpty(iface.name)) { 1106 Log.e(TAG, "Failed to create iface in vendor HAL"); 1107 mIfaceMgr.removeIface(iface.id); 1108 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal(); 1109 return null; 1110 } 1111 if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run, 1112 new NormalScanEventCallback(iface.name), 1113 new PnoScanEventCallback(iface.name))) { 1114 Log.e(TAG, "Failed to setup iface in wificond=" + iface.name); 1115 teardownInterface(iface.name); 1116 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond(); 1117 return null; 1118 } 1119 iface.networkObserver = new NetworkObserverInternal(iface.id); 1120 if (!registerNetworkObserver(iface.networkObserver)) { 1121 Log.e(TAG, "Failed to register network observer for iface=" + iface.name); 1122 teardownInterface(iface.name); 1123 return null; 1124 } 1125 mWifiMonitor.startMonitoring(iface.name); 1126 // Just to avoid any race conditions with interface state change callbacks, 1127 // update the interface state before we exit. 1128 onInterfaceStateChanged(iface, isInterfaceUp(iface.name)); 1129 Log.i(TAG, "Successfully setup " + iface); 1130 1131 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1132 return iface.name; 1133 } 1134 } 1135 1136 /** 1137 * Setup an interface for Soft AP mode operations. 1138 * 1139 * This method configures an interface in AP mode in all the native daemons 1140 * (wificond, wpa_supplicant & vendor HAL). 1141 * 1142 * @param interfaceCallback Associated callback for notifying status changes for the iface. 1143 * @return Returns the name of the allocated interface, will be null on failure. 1144 */ setupInterfaceForSoftApMode(@onNull InterfaceCallback interfaceCallback)1145 public String setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) { 1146 synchronized (mLock) { 1147 if (!startHal()) { 1148 Log.e(TAG, "Failed to start Hal"); 1149 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal(); 1150 return null; 1151 } 1152 if (!startHostapd()) { 1153 Log.e(TAG, "Failed to start hostapd"); 1154 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd(); 1155 return null; 1156 } 1157 Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP); 1158 if (iface == null) { 1159 Log.e(TAG, "Failed to allocate new AP iface"); 1160 return null; 1161 } 1162 iface.externalListener = interfaceCallback; 1163 iface.name = createApIface(iface); 1164 if (TextUtils.isEmpty(iface.name)) { 1165 Log.e(TAG, "Failed to create AP iface in vendor HAL"); 1166 mIfaceMgr.removeIface(iface.id); 1167 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal(); 1168 return null; 1169 } 1170 if (!mWifiCondManager.setupInterfaceForSoftApMode(iface.name)) { 1171 Log.e(TAG, "Failed to setup iface in wificond on " + iface); 1172 teardownInterface(iface.name); 1173 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond(); 1174 return null; 1175 } 1176 iface.networkObserver = new NetworkObserverInternal(iface.id); 1177 if (!registerNetworkObserver(iface.networkObserver)) { 1178 Log.e(TAG, "Failed to register network observer on " + iface); 1179 teardownInterface(iface.name); 1180 return null; 1181 } 1182 // Just to avoid any race conditions with interface state change callbacks, 1183 // update the interface state before we exit. 1184 onInterfaceStateChanged(iface, isInterfaceUp(iface.name)); 1185 Log.i(TAG, "Successfully setup " + iface); 1186 1187 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1188 return iface.name; 1189 } 1190 } 1191 1192 /** 1193 * Switches an existing Client mode interface from connectivity 1194 * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY} to scan mode 1195 * {@link Iface#IFACE_TYPE_STA_FOR_SCAN}. 1196 * 1197 * @param ifaceName Name of the interface. 1198 * @return true if the operation succeeded, false if there is an error or the iface is already 1199 * in scan mode. 1200 */ switchClientInterfaceToScanMode(@onNull String ifaceName)1201 public boolean switchClientInterfaceToScanMode(@NonNull String ifaceName) { 1202 synchronized (mLock) { 1203 final Iface iface = mIfaceMgr.getIface(ifaceName); 1204 if (iface == null) { 1205 Log.e(TAG, "Trying to switch to scan mode on an invalid iface=" + ifaceName); 1206 return false; 1207 } 1208 if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 1209 Log.e(TAG, "Already in scan mode on iface=" + ifaceName); 1210 return true; 1211 } 1212 if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) { 1213 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface); 1214 teardownInterface(iface.name); 1215 return false; 1216 } 1217 iface.type = Iface.IFACE_TYPE_STA_FOR_SCAN; 1218 stopSupplicantIfNecessary(); 1219 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1220 iface.phyCapabilities = null; 1221 Log.i(TAG, "Successfully switched to scan mode on iface=" + iface); 1222 return true; 1223 } 1224 } 1225 1226 /** 1227 * Switches an existing Client mode interface from scan mode 1228 * {@link Iface#IFACE_TYPE_STA_FOR_SCAN} to connectivity mode 1229 * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY}. 1230 * 1231 * @param ifaceName Name of the interface. 1232 * @return true if the operation succeeded, false if there is an error or the iface is already 1233 * in scan mode. 1234 */ switchClientInterfaceToConnectivityMode(@onNull String ifaceName)1235 public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName) { 1236 synchronized (mLock) { 1237 final Iface iface = mIfaceMgr.getIface(ifaceName); 1238 if (iface == null) { 1239 Log.e(TAG, "Trying to switch to connectivity mode on an invalid iface=" 1240 + ifaceName); 1241 return false; 1242 } 1243 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) { 1244 Log.e(TAG, "Already in connectivity mode on iface=" + ifaceName); 1245 return true; 1246 } 1247 if (!startSupplicant()) { 1248 Log.e(TAG, "Failed to start supplicant"); 1249 teardownInterface(iface.name); 1250 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant(); 1251 return false; 1252 } 1253 if (!mSupplicantStaIfaceHal.setupIface(iface.name)) { 1254 Log.e(TAG, "Failed to setup iface in supplicant on " + iface); 1255 teardownInterface(iface.name); 1256 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant(); 1257 return false; 1258 } 1259 iface.type = Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY; 1260 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1261 Log.i(TAG, "Successfully switched to connectivity mode on iface=" + iface); 1262 return true; 1263 } 1264 } 1265 1266 /** 1267 * 1268 * Check if the interface is up or down. 1269 * 1270 * @param ifaceName Name of the interface. 1271 * @return true if iface is up, false if it's down or on error. 1272 */ isInterfaceUp(@onNull String ifaceName)1273 public boolean isInterfaceUp(@NonNull String ifaceName) { 1274 synchronized (mLock) { 1275 final Iface iface = mIfaceMgr.getIface(ifaceName); 1276 if (iface == null) { 1277 Log.e(TAG, "Trying to get iface state on invalid iface=" + ifaceName); 1278 return false; 1279 } 1280 try { 1281 return mNetdWrapper.isInterfaceUp(ifaceName); 1282 } catch (IllegalStateException e) { 1283 Log.e(TAG, "Unable to get interface config", e); 1284 return false; 1285 } 1286 } 1287 } 1288 1289 /** 1290 * Teardown an interface in Client/AP mode. 1291 * 1292 * This method tears down the associated interface from all the native daemons 1293 * (wificond, wpa_supplicant & vendor HAL). 1294 * Also, brings down the HAL, supplicant or hostapd as necessary. 1295 * 1296 * @param ifaceName Name of the interface. 1297 */ teardownInterface(@onNull String ifaceName)1298 public void teardownInterface(@NonNull String ifaceName) { 1299 synchronized (mLock) { 1300 final Iface iface = mIfaceMgr.getIface(ifaceName); 1301 if (iface == null) { 1302 Log.e(TAG, "Trying to teardown an invalid iface=" + ifaceName); 1303 return; 1304 } 1305 // Trigger the iface removal from HAL. The rest of the cleanup will be triggered 1306 // from the interface destroyed callback. 1307 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY 1308 || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 1309 if (!removeStaIface(iface)) { 1310 Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName); 1311 return; 1312 } 1313 } else if (iface.type == Iface.IFACE_TYPE_AP) { 1314 if (!removeApIface(iface)) { 1315 Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName); 1316 return; 1317 } 1318 } 1319 Log.i(TAG, "Successfully initiated teardown for iface=" + ifaceName); 1320 } 1321 } 1322 1323 /** 1324 * Teardown all the active interfaces. 1325 * 1326 * This method tears down the associated interfaces from all the native daemons 1327 * (wificond, wpa_supplicant & vendor HAL). 1328 * Also, brings down the HAL, supplicant or hostapd as necessary. 1329 */ teardownAllInterfaces()1330 public void teardownAllInterfaces() { 1331 synchronized (mLock) { 1332 Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter(); 1333 while (ifaceIdIter.hasNext()) { 1334 Iface iface = mIfaceMgr.getIface(ifaceIdIter.next()); 1335 ifaceIdIter.remove(); 1336 onInterfaceDestroyed(iface); 1337 Log.i(TAG, "Successfully torn down " + iface); 1338 } 1339 Log.i(TAG, "Successfully torn down all ifaces"); 1340 } 1341 } 1342 1343 /** 1344 * Get name of the client interface. 1345 * 1346 * This is mainly used by external modules that needs to perform some 1347 * client operations on the STA interface. 1348 * 1349 * TODO(b/70932231): This may need to be reworked once we start supporting STA + STA. 1350 * 1351 * @return Interface name of any active client interface, null if no active client interface 1352 * exist. 1353 * Return Values for the different scenarios are listed below: 1354 * a) When there are no client interfaces, returns null. 1355 * b) when there is 1 client interface, returns the name of that interface. 1356 * c) When there are 2 or more client interface, returns the name of any client interface. 1357 */ getClientInterfaceName()1358 public String getClientInterfaceName() { 1359 synchronized (mLock) { 1360 return mIfaceMgr.findAnyStaIfaceName(); 1361 } 1362 } 1363 1364 /** 1365 * Get names of all the client interfaces. 1366 * 1367 * @return List of interface name of all active client interfaces. 1368 */ getClientInterfaceNames()1369 public Set<String> getClientInterfaceNames() { 1370 synchronized (mLock) { 1371 return mIfaceMgr.findAllStaIfaceNames(); 1372 } 1373 } 1374 1375 /** 1376 * Get name of the softap interface. 1377 * 1378 * This is mainly used by external modules that needs to perform some 1379 * operations on the AP interface. 1380 * 1381 * TODO(b/70932231): This may need to be reworked once we start supporting AP + AP. 1382 * 1383 * @return Interface name of any active softap interface, null if no active softap interface 1384 * exist. 1385 * Return Values for the different scenarios are listed below: 1386 * a) When there are no softap interfaces, returns null. 1387 * b) when there is 1 softap interface, returns the name of that interface. 1388 * c) When there are 2 or more softap interface, returns the name of any softap interface. 1389 */ getSoftApInterfaceName()1390 public String getSoftApInterfaceName() { 1391 synchronized (mLock) { 1392 return mIfaceMgr.findAnyApIfaceName(); 1393 } 1394 } 1395 1396 /******************************************************** 1397 * Wificond operations 1398 ********************************************************/ 1399 1400 /** 1401 * Request signal polling to wificond. 1402 * 1403 * @param ifaceName Name of the interface. 1404 * Returns an SignalPollResult object. 1405 * Returns null on failure. 1406 */ signalPoll(@onNull String ifaceName)1407 public WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String ifaceName) { 1408 return mWifiCondManager.signalPoll(ifaceName); 1409 } 1410 1411 /** 1412 * Query the list of valid frequencies for the provided band. 1413 * The result depends on the on the country code that has been set. 1414 * 1415 * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants. 1416 * The following bands are supported {@link WifiAnnotations.WifiBandBasic}: 1417 * WifiScanner.WIFI_BAND_24_GHZ 1418 * WifiScanner.WIFI_BAND_5_GHZ 1419 * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY 1420 * WifiScanner.WIFI_BAND_6_GHZ 1421 * @return frequencies vector of valid frequencies (MHz), or null for error. 1422 * @throws IllegalArgumentException if band is not recognized. 1423 */ getChannelsForBand(@ifiAnnotations.WifiBandBasic int band)1424 public int [] getChannelsForBand(@WifiAnnotations.WifiBandBasic int band) { 1425 return mWifiCondManager.getChannelsMhzForBand(band); 1426 } 1427 1428 /** 1429 * Start a scan using wificond for the given parameters. 1430 * @param ifaceName Name of the interface. 1431 * @param scanType Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}, 1432 * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}. 1433 * @param freqs list of frequencies to scan for, if null scan all supported channels. 1434 * @param hiddenNetworkSSIDs List of hidden networks to be scanned for. 1435 * @return Returns true on success. 1436 */ scan( @onNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs, List<String> hiddenNetworkSSIDs)1437 public boolean scan( 1438 @NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs, 1439 List<String> hiddenNetworkSSIDs) { 1440 List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>(); 1441 for (String hiddenNetworkSsid : hiddenNetworkSSIDs) { 1442 try { 1443 hiddenNetworkSsidsArrays.add( 1444 NativeUtil.byteArrayFromArrayList( 1445 NativeUtil.decodeSsid(hiddenNetworkSsid))); 1446 } catch (IllegalArgumentException e) { 1447 Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e); 1448 continue; 1449 } 1450 } 1451 return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays); 1452 } 1453 1454 /** 1455 * Fetch the latest scan result from kernel via wificond. 1456 * @param ifaceName Name of the interface. 1457 * @return Returns an ArrayList of ScanDetail. 1458 * Returns an empty ArrayList on failure. 1459 */ getScanResults(@onNull String ifaceName)1460 public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) { 1461 return convertNativeScanResults(mWifiCondManager.getScanResults( 1462 ifaceName, WifiNl80211Manager.SCAN_TYPE_SINGLE_SCAN)); 1463 } 1464 1465 /** 1466 * Fetch the latest scan result from kernel via wificond. 1467 * @param ifaceName Name of the interface. 1468 * @return Returns an ArrayList of ScanDetail. 1469 * Returns an empty ArrayList on failure. 1470 */ getPnoScanResults(@onNull String ifaceName)1471 public ArrayList<ScanDetail> getPnoScanResults(@NonNull String ifaceName) { 1472 return convertNativeScanResults(mWifiCondManager.getScanResults(ifaceName, 1473 WifiNl80211Manager.SCAN_TYPE_PNO_SCAN)); 1474 } 1475 convertNativeScanResults(List<NativeScanResult> nativeResults)1476 private ArrayList<ScanDetail> convertNativeScanResults(List<NativeScanResult> nativeResults) { 1477 ArrayList<ScanDetail> results = new ArrayList<>(); 1478 for (NativeScanResult result : nativeResults) { 1479 WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.getSsid()); 1480 MacAddress bssidMac = result.getBssid(); 1481 if (bssidMac == null) { 1482 Log.e(TAG, "Invalid MAC (BSSID) for SSID " + wifiSsid); 1483 continue; 1484 } 1485 String bssid = bssidMac.toString(); 1486 ScanResult.InformationElement[] ies = 1487 InformationElementUtil.parseInformationElements(result.getInformationElements()); 1488 InformationElementUtil.Capabilities capabilities = 1489 new InformationElementUtil.Capabilities(); 1490 capabilities.from(ies, result.getCapabilities(), isEnhancedOpenSupported()); 1491 String flags = capabilities.generateCapabilitiesString(); 1492 NetworkDetail networkDetail; 1493 try { 1494 networkDetail = new NetworkDetail(bssid, ies, null, result.getFrequencyMhz()); 1495 } catch (IllegalArgumentException e) { 1496 Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e); 1497 continue; 1498 } 1499 1500 ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags, 1501 result.getSignalMbm() / 100, result.getFrequencyMhz(), result.getTsf(), ies, 1502 null, result.getInformationElements()); 1503 ScanResult scanResult = scanDetail.getScanResult(); 1504 scanResult.setWifiStandard(wifiModeToWifiStandard(networkDetail.getWifiMode())); 1505 1506 // Fill up the radio chain info. 1507 scanResult.radioChainInfos = 1508 new ScanResult.RadioChainInfo[result.getRadioChainInfos().size()]; 1509 int idx = 0; 1510 for (RadioChainInfo nativeRadioChainInfo : result.getRadioChainInfos()) { 1511 scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo(); 1512 scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.getChainId(); 1513 scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.getLevelDbm(); 1514 idx++; 1515 } 1516 results.add(scanDetail); 1517 } 1518 if (mVerboseLoggingEnabled) { 1519 Log.d(TAG, "get " + results.size() + " scan results from wificond"); 1520 } 1521 1522 return results; 1523 } 1524 1525 @WifiAnnotations.WifiStandard wifiModeToWifiStandard(int wifiMode)1526 private static int wifiModeToWifiStandard(int wifiMode) { 1527 switch (wifiMode) { 1528 case InformationElementUtil.WifiMode.MODE_11A: 1529 case InformationElementUtil.WifiMode.MODE_11B: 1530 case InformationElementUtil.WifiMode.MODE_11G: 1531 return ScanResult.WIFI_STANDARD_LEGACY; 1532 case InformationElementUtil.WifiMode.MODE_11N: 1533 return ScanResult.WIFI_STANDARD_11N; 1534 case InformationElementUtil.WifiMode.MODE_11AC: 1535 return ScanResult.WIFI_STANDARD_11AC; 1536 case InformationElementUtil.WifiMode.MODE_11AX: 1537 return ScanResult.WIFI_STANDARD_11AX; 1538 case InformationElementUtil.WifiMode.MODE_UNDEFINED: 1539 default: 1540 return ScanResult.WIFI_STANDARD_UNKNOWN; 1541 } 1542 } 1543 1544 private boolean mIsEnhancedOpenSupportedInitialized = false; 1545 private boolean mIsEnhancedOpenSupported; 1546 1547 /** 1548 * Check if OWE (Enhanced Open) is supported on the device 1549 * 1550 * @return true if OWE is supported 1551 */ isEnhancedOpenSupported()1552 private boolean isEnhancedOpenSupported() { 1553 if (mIsEnhancedOpenSupportedInitialized) { 1554 return mIsEnhancedOpenSupported; 1555 } 1556 1557 String iface = getClientInterfaceName(); 1558 if (iface == null) { 1559 // Client interface might not be initialized during boot or Wi-Fi off 1560 return false; 1561 } 1562 1563 mIsEnhancedOpenSupportedInitialized = true; 1564 mIsEnhancedOpenSupported = (getSupportedFeatureSet(iface) & WIFI_FEATURE_OWE) != 0; 1565 return mIsEnhancedOpenSupported; 1566 } 1567 1568 /** 1569 * Start PNO scan. 1570 * @param ifaceName Name of the interface. 1571 * @param pnoSettings Pno scan configuration. 1572 * @return true on success. 1573 */ startPnoScan(@onNull String ifaceName, PnoSettings pnoSettings)1574 public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings) { 1575 return mWifiCondManager.startPnoScan(ifaceName, pnoSettings.toNativePnoSettings(), 1576 Runnable::run, 1577 new WifiNl80211Manager.PnoScanRequestCallback() { 1578 @Override 1579 public void onPnoRequestSucceeded() { 1580 mWifiMetrics.incrementPnoScanStartAttemptCount(); 1581 } 1582 1583 @Override 1584 public void onPnoRequestFailed() { 1585 mWifiMetrics.incrementPnoScanStartAttemptCount(); 1586 mWifiMetrics.incrementPnoScanFailedCount(); 1587 } 1588 }); 1589 } 1590 1591 /** 1592 * Stop PNO scan. 1593 * @param ifaceName Name of the interface. 1594 * @return true on success. 1595 */ 1596 public boolean stopPnoScan(@NonNull String ifaceName) { 1597 return mWifiCondManager.stopPnoScan(ifaceName); 1598 } 1599 1600 /** 1601 * Sends an arbitrary 802.11 management frame on the current channel. 1602 * 1603 * @param ifaceName Name of the interface. 1604 * @param frame Bytes of the 802.11 management frame to be sent, including the header, but not 1605 * including the frame check sequence (FCS). 1606 * @param callback A callback triggered when the transmitted frame is ACKed or the transmission 1607 * fails. 1608 * @param mcs The MCS index that the frame will be sent at. If mcs < 0, the driver will select 1609 * the rate automatically. If the device does not support sending the frame at a 1610 * specified MCS rate, the transmission will be aborted and 1611 * {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called 1612 * with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}. 1613 */ 1614 public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame, 1615 @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) { 1616 mWifiCondManager.sendMgmtFrame(ifaceName, frame, mcs, Runnable::run, callback); 1617 } 1618 1619 /** 1620 * Sends a probe request to the AP and waits for a response in order to determine whether 1621 * there is connectivity between the device and AP. 1622 * 1623 * @param ifaceName Name of the interface. 1624 * @param receiverMac the MAC address of the AP that the probe request will be sent to. 1625 * @param callback callback triggered when the probe was ACKed by the AP, or when 1626 * an error occurs after the link probe was started. 1627 * @param mcs The MCS index that this probe will be sent at. If mcs < 0, the driver will select 1628 * the rate automatically. If the device does not support sending the frame at a 1629 * specified MCS rate, the transmission will be aborted and 1630 * {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called 1631 * with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}. 1632 */ 1633 public void probeLink(@NonNull String ifaceName, @NonNull MacAddress receiverMac, 1634 @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) { 1635 if (callback == null) { 1636 Log.e(TAG, "callback cannot be null!"); 1637 return; 1638 } 1639 1640 if (receiverMac == null) { 1641 Log.e(TAG, "Receiver MAC address cannot be null!"); 1642 callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN); 1643 return; 1644 } 1645 1646 String senderMacStr = getMacAddress(ifaceName); 1647 if (senderMacStr == null) { 1648 Log.e(TAG, "Failed to get this device's MAC Address"); 1649 callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN); 1650 return; 1651 } 1652 1653 byte[] frame = buildProbeRequestFrame( 1654 receiverMac.toByteArray(), 1655 NativeUtil.macAddressToByteArray(senderMacStr)); 1656 sendMgmtFrame(ifaceName, frame, callback, mcs); 1657 } 1658 1659 // header = 24 bytes, minimal body = 2 bytes, no FCS (will be added by driver) 1660 private static final int BASIC_PROBE_REQUEST_FRAME_SIZE = 24 + 2; 1661 1662 private byte[] buildProbeRequestFrame(byte[] receiverMac, byte[] transmitterMac) { 1663 ByteBuffer frame = ByteBuffer.allocate(BASIC_PROBE_REQUEST_FRAME_SIZE); 1664 // ByteBuffer is big endian by default, switch to little endian 1665 frame.order(ByteOrder.LITTLE_ENDIAN); 1666 1667 // Protocol version = 0, Type = management, Subtype = Probe Request 1668 frame.put((byte) 0x40); 1669 1670 // no flags set 1671 frame.put((byte) 0x00); 1672 1673 // duration = 60 microseconds. Note: this is little endian 1674 // Note: driver should calculate the duration and replace it before sending, putting a 1675 // reasonable default value here just in case. 1676 frame.putShort((short) 0x3c); 1677 1678 // receiver/destination MAC address byte array 1679 frame.put(receiverMac); 1680 // sender MAC address byte array 1681 frame.put(transmitterMac); 1682 // BSSID (same as receiver address since we are sending to the AP) 1683 frame.put(receiverMac); 1684 1685 // Generate random sequence number, fragment number = 0 1686 // Note: driver should replace the sequence number with the correct number that is 1687 // incremented from the last used sequence number. Putting a random sequence number as a 1688 // default here just in case. 1689 // bit 0 is least significant bit, bit 15 is most significant bit 1690 // bits [0, 7] go in byte 0 1691 // bits [8, 15] go in byte 1 1692 // bits [0, 3] represent the fragment number (which is 0) 1693 // bits [4, 15] represent the sequence number (which is random) 1694 // clear bits [0, 3] to set fragment number = 0 1695 short sequenceAndFragmentNumber = (short) (mRandom.nextInt() & 0xfff0); 1696 frame.putShort(sequenceAndFragmentNumber); 1697 1698 // NL80211 rejects frames with an empty body, so we just need to put a placeholder 1699 // information element. 1700 // Tag for SSID 1701 frame.put((byte) 0x00); 1702 // Represents broadcast SSID. Not accurate, but works as placeholder. 1703 frame.put((byte) 0x00); 1704 1705 return frame.array(); 1706 } 1707 1708 private static final int CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS = 100; 1709 private static final int CONNECT_TO_HOSTAPD_RETRY_TIMES = 50; 1710 /** 1711 * This method is called to wait for establishing connection to hostapd. 1712 * 1713 * @return true if connection is established, false otherwise. 1714 */ 1715 private boolean startAndWaitForHostapdConnection() { 1716 // Start initialization if not already started. 1717 if (!mHostapdHal.isInitializationStarted() 1718 && !mHostapdHal.initialize()) { 1719 return false; 1720 } 1721 if (!mHostapdHal.startDaemon()) { 1722 Log.e(TAG, "Failed to startup hostapd"); 1723 return false; 1724 } 1725 boolean connected = false; 1726 int connectTries = 0; 1727 while (!connected && connectTries++ < CONNECT_TO_HOSTAPD_RETRY_TIMES) { 1728 // Check if the initialization is complete. 1729 connected = mHostapdHal.isInitializationComplete(); 1730 if (connected) { 1731 break; 1732 } 1733 try { 1734 Thread.sleep(CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS); 1735 } catch (InterruptedException ignore) { 1736 } 1737 } 1738 return connected; 1739 } 1740 1741 /** 1742 * Start Soft AP operation using the provided configuration. 1743 * 1744 * @param ifaceName Name of the interface. 1745 * @param config Configuration to use for the soft ap created. 1746 * @param listener Callback for AP events. 1747 * @return true on success, false otherwise. 1748 */ 1749 public boolean startSoftAp( 1750 @NonNull String ifaceName, SoftApConfiguration config, SoftApListener listener) { 1751 if (!mWifiCondManager.registerApCallback(ifaceName, Runnable::run, listener)) { 1752 Log.e(TAG, "Failed to register ap listener"); 1753 return false; 1754 } 1755 if (!mHostapdHal.addAccessPoint(ifaceName, config, listener::onFailure)) { 1756 Log.e(TAG, "Failed to add acccess point"); 1757 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd(); 1758 return false; 1759 } 1760 return true; 1761 } 1762 1763 /** 1764 * Force a softap client disconnect with specific reason code. 1765 * 1766 * @param ifaceName Name of the interface. 1767 * @param client Mac address to force disconnect in clients of the SoftAp. 1768 * @param reasonCode One of disconnect reason code which defined in {@link ApConfigUtil}. 1769 * @return true on success, false otherwise. 1770 */ 1771 public boolean forceClientDisconnect(@NonNull String ifaceName, 1772 @NonNull MacAddress client, int reasonCode) { 1773 return mHostapdHal.forceClientDisconnect(ifaceName, client, reasonCode); 1774 } 1775 1776 /** 1777 * Set MAC address of the given interface 1778 * @param interfaceName Name of the interface 1779 * @param mac Mac address to change into 1780 * @return true on success 1781 */ 1782 public boolean setMacAddress(String interfaceName, MacAddress mac) { 1783 // TODO(b/72459123): Suppress interface down/up events from this call 1784 // Trigger an explicit disconnect to avoid losing the disconnect event reason (if currently 1785 // connected) from supplicant if the interface is brought down for MAC address change. 1786 disconnect(interfaceName); 1787 return mWifiVendorHal.setMacAddress(interfaceName, mac); 1788 } 1789 1790 /** 1791 * Returns true if Hal version supports setMacAddress, otherwise false. 1792 * 1793 * @param interfaceName Name of the interface 1794 */ 1795 public boolean isSetMacAddressSupported(@NonNull String interfaceName) { 1796 return mWifiVendorHal.isSetMacAddressSupported(interfaceName); 1797 } 1798 1799 /** 1800 * Get the factory MAC address of the given interface 1801 * @param interfaceName Name of the interface. 1802 * @return factory MAC address, or null on a failed call or if feature is unavailable. 1803 */ 1804 public MacAddress getFactoryMacAddress(@NonNull String interfaceName) { 1805 return mWifiVendorHal.getFactoryMacAddress(interfaceName); 1806 } 1807 1808 /******************************************************** 1809 * Hostapd operations 1810 ********************************************************/ 1811 1812 /** 1813 * Callback to notify hostapd death. 1814 */ 1815 public interface HostapdDeathEventHandler { 1816 /** 1817 * Invoked when the supplicant dies. 1818 */ 1819 void onDeath(); 1820 } 1821 1822 /******************************************************** 1823 * Supplicant operations 1824 ********************************************************/ 1825 1826 /** 1827 * Callback to notify supplicant death. 1828 */ 1829 public interface SupplicantDeathEventHandler { 1830 /** 1831 * Invoked when the supplicant dies. 1832 */ 1833 void onDeath(); 1834 } 1835 1836 /** 1837 * Set supplicant log level 1838 * 1839 * @param turnOnVerbose Whether to turn on verbose logging or not. 1840 */ 1841 public void setSupplicantLogLevel(boolean turnOnVerbose) { 1842 mSupplicantStaIfaceHal.setLogLevel(turnOnVerbose); 1843 } 1844 1845 /** 1846 * Trigger a reconnection if the iface is disconnected. 1847 * 1848 * @param ifaceName Name of the interface. 1849 * @return true if request is sent successfully, false otherwise. 1850 */ 1851 public boolean reconnect(@NonNull String ifaceName) { 1852 return mSupplicantStaIfaceHal.reconnect(ifaceName); 1853 } 1854 1855 /** 1856 * Trigger a reassociation even if the iface is currently connected. 1857 * 1858 * @param ifaceName Name of the interface. 1859 * @return true if request is sent successfully, false otherwise. 1860 */ 1861 public boolean reassociate(@NonNull String ifaceName) { 1862 return mSupplicantStaIfaceHal.reassociate(ifaceName); 1863 } 1864 1865 /** 1866 * Trigger a disconnection from the currently connected network. 1867 * 1868 * @param ifaceName Name of the interface. 1869 * @return true if request is sent successfully, false otherwise. 1870 */ 1871 public boolean disconnect(@NonNull String ifaceName) { 1872 return mSupplicantStaIfaceHal.disconnect(ifaceName); 1873 } 1874 1875 /** 1876 * Makes a callback to HIDL to getMacAddress from supplicant 1877 * 1878 * @param ifaceName Name of the interface. 1879 * @return string containing the MAC address, or null on a failed call 1880 */ 1881 public String getMacAddress(@NonNull String ifaceName) { 1882 return mSupplicantStaIfaceHal.getMacAddress(ifaceName); 1883 } 1884 1885 public static final int RX_FILTER_TYPE_V4_MULTICAST = 0; 1886 public static final int RX_FILTER_TYPE_V6_MULTICAST = 1; 1887 /** 1888 * Start filtering out Multicast V4 packets 1889 * @param ifaceName Name of the interface. 1890 * @return {@code true} if the operation succeeded, {@code false} otherwise 1891 * 1892 * Multicast filtering rules work as follows: 1893 * 1894 * The driver can filter multicast (v4 and/or v6) and broadcast packets when in 1895 * a power optimized mode (typically when screen goes off). 1896 * 1897 * In order to prevent the driver from filtering the multicast/broadcast packets, we have to 1898 * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective 1899 * 1900 * DRIVER RXFILTER-ADD Num 1901 * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 1902 * 1903 * and DRIVER RXFILTER-START 1904 * In order to stop the usage of these rules, we do 1905 * 1906 * DRIVER RXFILTER-STOP 1907 * DRIVER RXFILTER-REMOVE Num 1908 * where Num is as described for RXFILTER-ADD 1909 * 1910 * The SETSUSPENDOPT driver command overrides the filtering rules 1911 */ 1912 public boolean startFilteringMulticastV4Packets(@NonNull String ifaceName) { 1913 return mSupplicantStaIfaceHal.stopRxFilter(ifaceName) 1914 && mSupplicantStaIfaceHal.removeRxFilter( 1915 ifaceName, RX_FILTER_TYPE_V4_MULTICAST) 1916 && mSupplicantStaIfaceHal.startRxFilter(ifaceName); 1917 } 1918 1919 /** 1920 * Stop filtering out Multicast V4 packets. 1921 * @param ifaceName Name of the interface. 1922 * @return {@code true} if the operation succeeded, {@code false} otherwise 1923 */ 1924 public boolean stopFilteringMulticastV4Packets(@NonNull String ifaceName) { 1925 return mSupplicantStaIfaceHal.stopRxFilter(ifaceName) 1926 && mSupplicantStaIfaceHal.addRxFilter( 1927 ifaceName, RX_FILTER_TYPE_V4_MULTICAST) 1928 && mSupplicantStaIfaceHal.startRxFilter(ifaceName); 1929 } 1930 1931 /** 1932 * Start filtering out Multicast V6 packets 1933 * @param ifaceName Name of the interface. 1934 * @return {@code true} if the operation succeeded, {@code false} otherwise 1935 */ 1936 public boolean startFilteringMulticastV6Packets(@NonNull String ifaceName) { 1937 return mSupplicantStaIfaceHal.stopRxFilter(ifaceName) 1938 && mSupplicantStaIfaceHal.removeRxFilter( 1939 ifaceName, RX_FILTER_TYPE_V6_MULTICAST) 1940 && mSupplicantStaIfaceHal.startRxFilter(ifaceName); 1941 } 1942 1943 /** 1944 * Stop filtering out Multicast V6 packets. 1945 * @param ifaceName Name of the interface. 1946 * @return {@code true} if the operation succeeded, {@code false} otherwise 1947 */ 1948 public boolean stopFilteringMulticastV6Packets(@NonNull String ifaceName) { 1949 return mSupplicantStaIfaceHal.stopRxFilter(ifaceName) 1950 && mSupplicantStaIfaceHal.addRxFilter( 1951 ifaceName, RX_FILTER_TYPE_V6_MULTICAST) 1952 && mSupplicantStaIfaceHal.startRxFilter(ifaceName); 1953 } 1954 1955 public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 1956 public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 1957 public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 1958 /** 1959 * Sets the bluetooth coexistence mode. 1960 * 1961 * @param ifaceName Name of the interface. 1962 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 1963 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 1964 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 1965 * @return Whether the mode was successfully set. 1966 */ 1967 public boolean setBluetoothCoexistenceMode(@NonNull String ifaceName, int mode) { 1968 return mSupplicantStaIfaceHal.setBtCoexistenceMode(ifaceName, mode); 1969 } 1970 1971 /** 1972 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 1973 * some of the low-level scan parameters used by the driver are changed to 1974 * reduce interference with A2DP streaming. 1975 * 1976 * @param ifaceName Name of the interface. 1977 * @param setCoexScanMode whether to enable or disable this mode 1978 * @return {@code true} if the command succeeded, {@code false} otherwise. 1979 */ 1980 public boolean setBluetoothCoexistenceScanMode( 1981 @NonNull String ifaceName, boolean setCoexScanMode) { 1982 return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled( 1983 ifaceName, setCoexScanMode); 1984 } 1985 1986 /** 1987 * Enable or disable suspend mode optimizations. 1988 * 1989 * @param ifaceName Name of the interface. 1990 * @param enabled true to enable, false otherwise. 1991 * @return true if request is sent successfully, false otherwise. 1992 */ 1993 public boolean setSuspendOptimizations(@NonNull String ifaceName, boolean enabled) { 1994 return mSupplicantStaIfaceHal.setSuspendModeEnabled(ifaceName, enabled); 1995 } 1996 1997 /** 1998 * Set country code. 1999 * 2000 * @param ifaceName Name of the interface. 2001 * @param countryCode 2 byte ASCII string. For ex: US, CA. 2002 * @return true if request is sent successfully, false otherwise. 2003 */ 2004 public boolean setCountryCode(@NonNull String ifaceName, String countryCode) { 2005 return mSupplicantStaIfaceHal.setCountryCode(ifaceName, countryCode); 2006 } 2007 2008 /** 2009 * Flush all previously configured HLPs. 2010 * 2011 * @return true if request is sent successfully, false otherwise. 2012 */ 2013 public boolean flushAllHlp(@NonNull String ifaceName) { 2014 return mSupplicantStaIfaceHal.flushAllHlp(ifaceName); 2015 } 2016 2017 /** 2018 * Set FILS HLP packet. 2019 * 2020 * @param dst Destination MAC address. 2021 * @param hlpPacket Hlp Packet data in hex. 2022 * @return true if request is sent successfully, false otherwise. 2023 */ 2024 public boolean addHlpReq(@NonNull String ifaceName, MacAddress dst, byte [] hlpPacket) { 2025 return mSupplicantStaIfaceHal.addHlpReq(ifaceName, dst.toByteArray(), hlpPacket); 2026 } 2027 2028 /** 2029 * Initiate TDLS discover and setup or teardown with the specified peer. 2030 * 2031 * @param ifaceName Name of the interface. 2032 * @param macAddr MAC Address of the peer. 2033 * @param enable true to start discovery and setup, false to teardown. 2034 */ 2035 public void startTdls(@NonNull String ifaceName, String macAddr, boolean enable) { 2036 if (enable) { 2037 mSupplicantStaIfaceHal.initiateTdlsDiscover(ifaceName, macAddr); 2038 mSupplicantStaIfaceHal.initiateTdlsSetup(ifaceName, macAddr); 2039 } else { 2040 mSupplicantStaIfaceHal.initiateTdlsTeardown(ifaceName, macAddr); 2041 } 2042 } 2043 2044 /** 2045 * Start WPS pin display operation with the specified peer. 2046 * 2047 * @param ifaceName Name of the interface. 2048 * @param bssid BSSID of the peer. 2049 * @return true if request is sent successfully, false otherwise. 2050 */ 2051 public boolean startWpsPbc(@NonNull String ifaceName, String bssid) { 2052 return mSupplicantStaIfaceHal.startWpsPbc(ifaceName, bssid); 2053 } 2054 2055 /** 2056 * Start WPS pin keypad operation with the specified pin. 2057 * 2058 * @param ifaceName Name of the interface. 2059 * @param pin Pin to be used. 2060 * @return true if request is sent successfully, false otherwise. 2061 */ 2062 public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) { 2063 return mSupplicantStaIfaceHal.startWpsPinKeypad(ifaceName, pin); 2064 } 2065 2066 /** 2067 * Start WPS pin display operation with the specified peer. 2068 * 2069 * @param ifaceName Name of the interface. 2070 * @param bssid BSSID of the peer. 2071 * @return new pin generated on success, null otherwise. 2072 */ 2073 public String startWpsPinDisplay(@NonNull String ifaceName, String bssid) { 2074 return mSupplicantStaIfaceHal.startWpsPinDisplay(ifaceName, bssid); 2075 } 2076 2077 /** 2078 * Sets whether to use external sim for SIM/USIM processing. 2079 * 2080 * @param ifaceName Name of the interface. 2081 * @param external true to enable, false otherwise. 2082 * @return true if request is sent successfully, false otherwise. 2083 */ 2084 public boolean setExternalSim(@NonNull String ifaceName, boolean external) { 2085 return mSupplicantStaIfaceHal.setExternalSim(ifaceName, external); 2086 } 2087 2088 /** 2089 * Sim auth response types. 2090 */ 2091 public static final String SIM_AUTH_RESP_TYPE_GSM_AUTH = "GSM-AUTH"; 2092 public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTH = "UMTS-AUTH"; 2093 public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTS = "UMTS-AUTS"; 2094 2095 /** 2096 * EAP-SIM Error Codes 2097 */ 2098 public static final int EAP_SIM_NOT_SUBSCRIBED = 1031; 2099 public static final int EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED = 16385; 2100 2101 /** 2102 * Send the sim auth response for the currently configured network. 2103 * 2104 * @param ifaceName Name of the interface. 2105 * @param type |GSM-AUTH|, |UMTS-AUTH| or |UMTS-AUTS|. 2106 * @param response Response params. 2107 * @return true if succeeds, false otherwise. 2108 */ 2109 public boolean simAuthResponse( 2110 @NonNull String ifaceName, String type, String response) { 2111 if (SIM_AUTH_RESP_TYPE_GSM_AUTH.equals(type)) { 2112 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse( 2113 ifaceName, response); 2114 } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTH.equals(type)) { 2115 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse( 2116 ifaceName, response); 2117 } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTS.equals(type)) { 2118 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse( 2119 ifaceName, response); 2120 } else { 2121 return false; 2122 } 2123 } 2124 2125 /** 2126 * Send the eap sim gsm auth failure for the currently configured network. 2127 * 2128 * @param ifaceName Name of the interface. 2129 * @return true if succeeds, false otherwise. 2130 */ 2131 public boolean simAuthFailedResponse(@NonNull String ifaceName) { 2132 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure(ifaceName); 2133 } 2134 2135 /** 2136 * Send the eap sim umts auth failure for the currently configured network. 2137 * 2138 * @param ifaceName Name of the interface. 2139 * @return true if succeeds, false otherwise. 2140 */ 2141 public boolean umtsAuthFailedResponse(@NonNull String ifaceName) { 2142 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure(ifaceName); 2143 } 2144 2145 /** 2146 * Send the eap identity response for the currently configured network. 2147 * 2148 * @param ifaceName Name of the interface. 2149 * @param unencryptedResponse String to send. 2150 * @param encryptedResponse String to send. 2151 * @return true if succeeds, false otherwise. 2152 */ 2153 public boolean simIdentityResponse(@NonNull String ifaceName, String unencryptedResponse, 2154 String encryptedResponse) { 2155 return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(ifaceName, 2156 unencryptedResponse, encryptedResponse); 2157 } 2158 2159 /** 2160 * This get anonymous identity from supplicant and returns it as a string. 2161 * 2162 * @param ifaceName Name of the interface. 2163 * @return anonymous identity string if succeeds, null otherwise. 2164 */ 2165 public String getEapAnonymousIdentity(@NonNull String ifaceName) { 2166 return mSupplicantStaIfaceHal.getCurrentNetworkEapAnonymousIdentity(ifaceName); 2167 } 2168 2169 /** 2170 * Start WPS pin registrar operation with the specified peer and pin. 2171 * 2172 * @param ifaceName Name of the interface. 2173 * @param bssid BSSID of the peer. 2174 * @param pin Pin to be used. 2175 * @return true if request is sent successfully, false otherwise. 2176 */ 2177 public boolean startWpsRegistrar(@NonNull String ifaceName, String bssid, String pin) { 2178 return mSupplicantStaIfaceHal.startWpsRegistrar(ifaceName, bssid, pin); 2179 } 2180 2181 /** 2182 * Cancels any ongoing WPS requests. 2183 * 2184 * @param ifaceName Name of the interface. 2185 * @return true if request is sent successfully, false otherwise. 2186 */ 2187 public boolean cancelWps(@NonNull String ifaceName) { 2188 return mSupplicantStaIfaceHal.cancelWps(ifaceName); 2189 } 2190 2191 /** 2192 * Set WPS device name. 2193 * 2194 * @param ifaceName Name of the interface. 2195 * @param name String to be set. 2196 * @return true if request is sent successfully, false otherwise. 2197 */ 2198 public boolean setDeviceName(@NonNull String ifaceName, String name) { 2199 return mSupplicantStaIfaceHal.setWpsDeviceName(ifaceName, name); 2200 } 2201 2202 /** 2203 * Set WPS device type. 2204 * 2205 * @param ifaceName Name of the interface. 2206 * @param type Type specified as a string. Used format: <categ>-<OUI>-<subcateg> 2207 * @return true if request is sent successfully, false otherwise. 2208 */ 2209 public boolean setDeviceType(@NonNull String ifaceName, String type) { 2210 return mSupplicantStaIfaceHal.setWpsDeviceType(ifaceName, type); 2211 } 2212 2213 /** 2214 * Set WPS config methods 2215 * 2216 * @param cfg List of config methods. 2217 * @return true if request is sent successfully, false otherwise. 2218 */ 2219 public boolean setConfigMethods(@NonNull String ifaceName, String cfg) { 2220 return mSupplicantStaIfaceHal.setWpsConfigMethods(ifaceName, cfg); 2221 } 2222 2223 /** 2224 * Set WPS manufacturer. 2225 * 2226 * @param ifaceName Name of the interface. 2227 * @param value String to be set. 2228 * @return true if request is sent successfully, false otherwise. 2229 */ 2230 public boolean setManufacturer(@NonNull String ifaceName, String value) { 2231 return mSupplicantStaIfaceHal.setWpsManufacturer(ifaceName, value); 2232 } 2233 2234 /** 2235 * Set WPS model name. 2236 * 2237 * @param ifaceName Name of the interface. 2238 * @param value String to be set. 2239 * @return true if request is sent successfully, false otherwise. 2240 */ 2241 public boolean setModelName(@NonNull String ifaceName, String value) { 2242 return mSupplicantStaIfaceHal.setWpsModelName(ifaceName, value); 2243 } 2244 2245 /** 2246 * Set WPS model number. 2247 * 2248 * @param ifaceName Name of the interface. 2249 * @param value String to be set. 2250 * @return true if request is sent successfully, false otherwise. 2251 */ 2252 public boolean setModelNumber(@NonNull String ifaceName, String value) { 2253 return mSupplicantStaIfaceHal.setWpsModelNumber(ifaceName, value); 2254 } 2255 2256 /** 2257 * Set WPS serial number. 2258 * 2259 * @param ifaceName Name of the interface. 2260 * @param value String to be set. 2261 * @return true if request is sent successfully, false otherwise. 2262 */ 2263 public boolean setSerialNumber(@NonNull String ifaceName, String value) { 2264 return mSupplicantStaIfaceHal.setWpsSerialNumber(ifaceName, value); 2265 } 2266 2267 /** 2268 * Enable or disable power save mode. 2269 * 2270 * @param ifaceName Name of the interface. 2271 * @param enabled true to enable, false to disable. 2272 */ 2273 public void setPowerSave(@NonNull String ifaceName, boolean enabled) { 2274 mSupplicantStaIfaceHal.setPowerSave(ifaceName, enabled); 2275 } 2276 2277 /** 2278 * Enable or disable low latency mode. 2279 * 2280 * @param enabled true to enable, false to disable. 2281 * @return true on success, false on failure 2282 */ 2283 public boolean setLowLatencyMode(boolean enabled) { 2284 return mWifiVendorHal.setLowLatencyMode(enabled); 2285 } 2286 2287 /** 2288 * Set concurrency priority between P2P & STA operations. 2289 * 2290 * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations, 2291 * false otherwise. 2292 * @return true if request is sent successfully, false otherwise. 2293 */ 2294 public boolean setConcurrencyPriority(boolean isStaHigherPriority) { 2295 return mSupplicantStaIfaceHal.setConcurrencyPriority(isStaHigherPriority); 2296 } 2297 2298 /** 2299 * Enable/Disable auto reconnect functionality in wpa_supplicant. 2300 * 2301 * @param ifaceName Name of the interface. 2302 * @param enable true to enable auto reconnecting, false to disable. 2303 * @return true if request is sent successfully, false otherwise. 2304 */ 2305 public boolean enableStaAutoReconnect(@NonNull String ifaceName, boolean enable) { 2306 return mSupplicantStaIfaceHal.enableAutoReconnect(ifaceName, enable); 2307 } 2308 2309 /** 2310 * Add the provided network configuration to wpa_supplicant and initiate connection to it. 2311 * This method does the following: 2312 * 1. Abort any ongoing scan to unblock the connection request. 2313 * 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect). 2314 * 3. Add a new network to wpa_supplicant. 2315 * 4. Save the provided configuration to wpa_supplicant. 2316 * 5. Select the new network in wpa_supplicant. 2317 * 6. Triggers reconnect command to wpa_supplicant. 2318 * 2319 * @param ifaceName Name of the interface. 2320 * @param configuration WifiConfiguration parameters for the provided network. 2321 * @return {@code true} if it succeeds, {@code false} otherwise 2322 */ 2323 public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) { 2324 // Abort ongoing scan before connect() to unblock connection request. 2325 mWifiCondManager.abortScan(ifaceName); 2326 return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration); 2327 } 2328 2329 /** 2330 * Initiates roaming to the already configured network in wpa_supplicant. If the network 2331 * configuration provided does not match the already configured network, then this triggers 2332 * a new connection attempt (instead of roam). 2333 * 1. Abort any ongoing scan to unblock the roam request. 2334 * 2. First check if we're attempting to connect to the same network as we currently have 2335 * configured. 2336 * 3. Set the new bssid for the network in wpa_supplicant. 2337 * 4. Triggers reassociate command to wpa_supplicant. 2338 * 2339 * @param ifaceName Name of the interface. 2340 * @param configuration WifiConfiguration parameters for the provided network. 2341 * @return {@code true} if it succeeds, {@code false} otherwise 2342 */ 2343 public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) { 2344 // Abort ongoing scan before connect() to unblock roaming request. 2345 mWifiCondManager.abortScan(ifaceName); 2346 return mSupplicantStaIfaceHal.roamToNetwork(ifaceName, configuration); 2347 } 2348 2349 /** 2350 * Remove all the networks. 2351 * 2352 * @param ifaceName Name of the interface. 2353 * @return {@code true} if it succeeds, {@code false} otherwise 2354 */ 2355 public boolean removeAllNetworks(@NonNull String ifaceName) { 2356 return mSupplicantStaIfaceHal.removeAllNetworks(ifaceName); 2357 } 2358 2359 /** 2360 * Set the BSSID for the currently configured network in wpa_supplicant. 2361 * 2362 * @param ifaceName Name of the interface. 2363 * @return true if successful, false otherwise. 2364 */ 2365 public boolean setConfiguredNetworkBSSID(@NonNull String ifaceName, String bssid) { 2366 return mSupplicantStaIfaceHal.setCurrentNetworkBssid(ifaceName, bssid); 2367 } 2368 2369 /** 2370 * Initiate ANQP query. 2371 * 2372 * @param ifaceName Name of the interface. 2373 * @param bssid BSSID of the AP to be queried 2374 * @param anqpIds Set of anqp IDs. 2375 * @param hs20Subtypes Set of HS20 subtypes. 2376 * @return true on success, false otherwise. 2377 */ 2378 public boolean requestAnqp( 2379 @NonNull String ifaceName, String bssid, Set<Integer> anqpIds, 2380 Set<Integer> hs20Subtypes) { 2381 if (bssid == null || ((anqpIds == null || anqpIds.isEmpty()) 2382 && (hs20Subtypes == null || hs20Subtypes.isEmpty()))) { 2383 Log.e(TAG, "Invalid arguments for ANQP request."); 2384 return false; 2385 } 2386 ArrayList<Short> anqpIdList = new ArrayList<>(); 2387 for (Integer anqpId : anqpIds) { 2388 anqpIdList.add(anqpId.shortValue()); 2389 } 2390 ArrayList<Integer> hs20SubtypeList = new ArrayList<>(); 2391 hs20SubtypeList.addAll(hs20Subtypes); 2392 return mSupplicantStaIfaceHal.initiateAnqpQuery( 2393 ifaceName, bssid, anqpIdList, hs20SubtypeList); 2394 } 2395 2396 /** 2397 * Request a passpoint icon file |filename| from the specified AP |bssid|. 2398 * 2399 * @param ifaceName Name of the interface. 2400 * @param bssid BSSID of the AP 2401 * @param fileName name of the icon file 2402 * @return true if request is sent successfully, false otherwise 2403 */ 2404 public boolean requestIcon(@NonNull String ifaceName, String bssid, String fileName) { 2405 if (bssid == null || fileName == null) { 2406 Log.e(TAG, "Invalid arguments for Icon request."); 2407 return false; 2408 } 2409 return mSupplicantStaIfaceHal.initiateHs20IconQuery(ifaceName, bssid, fileName); 2410 } 2411 2412 /** 2413 * Get the currently configured network's WPS NFC token. 2414 * 2415 * @param ifaceName Name of the interface. 2416 * @return Hex string corresponding to the WPS NFC token. 2417 */ 2418 public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) { 2419 return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken(ifaceName); 2420 } 2421 2422 /** 2423 * Clean HAL cached data for |networkId|. 2424 * 2425 * @param networkId network id of the network to be removed from supplicant. 2426 */ 2427 public void removeNetworkCachedData(int networkId) { 2428 mSupplicantStaIfaceHal.removeNetworkCachedData(networkId); 2429 } 2430 2431 /** Clear HAL cached data for |networkId| if MAC address is changed. 2432 * 2433 * @param networkId network id of the network to be checked. 2434 * @param curMacAddress current MAC address 2435 */ 2436 public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) { 2437 mSupplicantStaIfaceHal.removeNetworkCachedDataIfNeeded(networkId, curMacAddress); 2438 } 2439 2440 /* 2441 * DPP 2442 */ 2443 2444 /** 2445 * Adds a DPP peer URI to the URI list. 2446 * 2447 * @param ifaceName Interface name 2448 * @param uri Bootstrap (URI) string (e.g. DPP:....) 2449 * @return ID, or -1 for failure 2450 */ 2451 public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) { 2452 return mSupplicantStaIfaceHal.addDppPeerUri(ifaceName, uri); 2453 } 2454 2455 /** 2456 * Removes a DPP URI to the URI list given an ID. 2457 * 2458 * @param ifaceName Interface name 2459 * @param bootstrapId Bootstrap (URI) ID 2460 * @return true when operation is successful, or false for failure 2461 */ 2462 public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId) { 2463 return mSupplicantStaIfaceHal.removeDppUri(ifaceName, bootstrapId); 2464 } 2465 2466 /** 2467 * Stops/aborts DPP Initiator request 2468 * 2469 * @param ifaceName Interface name 2470 * @return true when operation is successful, or false for failure 2471 */ 2472 public boolean stopDppInitiator(@NonNull String ifaceName) { 2473 return mSupplicantStaIfaceHal.stopDppInitiator(ifaceName); 2474 } 2475 2476 /** 2477 * Starts DPP Configurator-Initiator request 2478 * 2479 * @param ifaceName Interface name 2480 * @param peerBootstrapId Peer's bootstrap (URI) ID 2481 * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none 2482 * @param ssid SSID of the selected network 2483 * @param password Password of the selected network, or 2484 * @param psk PSK of the selected network in hexadecimal representation 2485 * @param netRole The network role of the enrollee (STA or AP) 2486 * @param securityAkm Security AKM to use: PSK, SAE 2487 * @return true when operation is successful, or false for failure 2488 */ 2489 public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId, 2490 int ownBootstrapId, @NonNull String ssid, String password, String psk, 2491 int netRole, int securityAkm) { 2492 return mSupplicantStaIfaceHal.startDppConfiguratorInitiator(ifaceName, peerBootstrapId, 2493 ownBootstrapId, ssid, password, psk, netRole, securityAkm); 2494 } 2495 2496 /** 2497 * Starts DPP Enrollee-Initiator request 2498 * 2499 * @param ifaceName Interface name 2500 * @param peerBootstrapId Peer's bootstrap (URI) ID 2501 * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none 2502 * @return true when operation is successful, or false for failure 2503 */ 2504 public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId, 2505 int ownBootstrapId) { 2506 return mSupplicantStaIfaceHal.startDppEnrolleeInitiator(ifaceName, peerBootstrapId, 2507 ownBootstrapId); 2508 } 2509 2510 /** 2511 * Callback to notify about DPP success, failure and progress events. 2512 */ 2513 public interface DppEventCallback { 2514 /** 2515 * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the 2516 * peer DPP configurator. 2517 * 2518 * @param newWifiConfiguration New Wi-Fi configuration received from the configurator 2519 */ 2520 void onSuccessConfigReceived(WifiConfiguration newWifiConfiguration); 2521 2522 /** 2523 * DPP Success event. 2524 * 2525 * @param dppStatusCode Status code of the success event. 2526 */ 2527 void onSuccess(int dppStatusCode); 2528 2529 /** 2530 * DPP Progress event. 2531 * 2532 * @param dppStatusCode Status code of the progress event. 2533 */ 2534 void onProgress(int dppStatusCode); 2535 2536 /** 2537 * DPP Failure event. 2538 * 2539 * @param dppStatusCode Status code of the failure event. 2540 * @param ssid SSID of the network the Enrollee tried to connect to. 2541 * @param channelList List of channels the Enrollee scanned for the network. 2542 * @param bandList List of bands the Enrollee supports. 2543 */ 2544 void onFailure(int dppStatusCode, String ssid, String channelList, int[] bandList); 2545 } 2546 2547 /** 2548 * Registers DPP event callbacks. 2549 * 2550 * @param dppEventCallback Callback object. 2551 */ 2552 public void registerDppEventCallback(DppEventCallback dppEventCallback) { 2553 mSupplicantStaIfaceHal.registerDppCallback(dppEventCallback); 2554 } 2555 2556 /******************************************************** 2557 * Vendor HAL operations 2558 ********************************************************/ 2559 /** 2560 * Callback to notify vendor HAL death. 2561 */ 2562 public interface VendorHalDeathEventHandler { 2563 /** 2564 * Invoked when the vendor HAL dies. 2565 */ 2566 void onDeath(); 2567 } 2568 2569 /** 2570 * Callback to notify when vendor HAL detects that a change in radio mode. 2571 */ 2572 public interface VendorHalRadioModeChangeEventHandler { 2573 /** 2574 * Invoked when the vendor HAL detects a change to MCC mode. 2575 * MCC (Multi channel concurrency) = Multiple interfaces are active on the same band, 2576 * different channels, same radios. 2577 * 2578 * @param band Band on which MCC is detected (specified by one of the 2579 * WifiScanner.WIFI_BAND_* constants) 2580 */ 2581 void onMcc(int band); 2582 /** 2583 * Invoked when the vendor HAL detects a change to SCC mode. 2584 * SCC (Single channel concurrency) = Multiple interfaces are active on the same band, same 2585 * channels, same radios. 2586 * 2587 * @param band Band on which SCC is detected (specified by one of the 2588 * WifiScanner.WIFI_BAND_* constants) 2589 */ 2590 void onScc(int band); 2591 /** 2592 * Invoked when the vendor HAL detects a change to SBS mode. 2593 * SBS (Single Band Simultaneous) = Multiple interfaces are active on the same band, 2594 * different channels, different radios. 2595 * 2596 * @param band Band on which SBS is detected (specified by one of the 2597 * WifiScanner.WIFI_BAND_* constants) 2598 */ 2599 void onSbs(int band); 2600 /** 2601 * Invoked when the vendor HAL detects a change to DBS mode. 2602 * DBS (Dual Band Simultaneous) = Multiple interfaces are active on the different bands, 2603 * different channels, different radios. 2604 */ 2605 void onDbs(); 2606 } 2607 2608 /** 2609 * Tests whether the HAL is running or not 2610 */ 2611 public boolean isHalStarted() { 2612 return mWifiVendorHal.isHalStarted(); 2613 } 2614 2615 // TODO: Change variable names to camel style. 2616 public static class ScanCapabilities { 2617 public int max_scan_cache_size; 2618 public int max_scan_buckets; 2619 public int max_ap_cache_per_scan; 2620 public int max_rssi_sample_size; 2621 public int max_scan_reporting_threshold; 2622 } 2623 2624 /** 2625 * Gets the scan capabilities 2626 * 2627 * @param ifaceName Name of the interface. 2628 * @param capabilities object to be filled in 2629 * @return true for success. false for failure 2630 */ 2631 public boolean getBgScanCapabilities( 2632 @NonNull String ifaceName, ScanCapabilities capabilities) { 2633 return mWifiVendorHal.getBgScanCapabilities(ifaceName, capabilities); 2634 } 2635 2636 public static class ChannelSettings { 2637 public int frequency; 2638 public int dwell_time_ms; 2639 public boolean passive; 2640 } 2641 2642 public static class BucketSettings { 2643 public int bucket; 2644 public int band; 2645 public int period_ms; 2646 public int max_period_ms; 2647 public int step_count; 2648 public int report_events; 2649 public int num_channels; 2650 public ChannelSettings[] channels; 2651 } 2652 2653 /** 2654 * Network parameters for hidden networks to be scanned for. 2655 */ 2656 public static class HiddenNetwork { 2657 public String ssid; 2658 2659 @Override 2660 public boolean equals(Object otherObj) { 2661 if (this == otherObj) { 2662 return true; 2663 } else if (otherObj == null || getClass() != otherObj.getClass()) { 2664 return false; 2665 } 2666 HiddenNetwork other = (HiddenNetwork) otherObj; 2667 return Objects.equals(ssid, other.ssid); 2668 } 2669 2670 @Override 2671 public int hashCode() { 2672 return Objects.hash(ssid); 2673 } 2674 } 2675 2676 public static class ScanSettings { 2677 /** 2678 * Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}, 2679 * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}. 2680 */ 2681 @WifiAnnotations.ScanType 2682 public int scanType; 2683 public int base_period_ms; 2684 public int max_ap_per_scan; 2685 public int report_threshold_percent; 2686 public int report_threshold_num_scans; 2687 public int num_buckets; 2688 /* Not used for bg scans. Only works for single scans. */ 2689 public HiddenNetwork[] hiddenNetworks; 2690 public BucketSettings[] buckets; 2691 } 2692 2693 /** 2694 * Network parameters to start PNO scan. 2695 */ 2696 public static class PnoNetwork { 2697 public String ssid; 2698 public byte flags; 2699 public byte auth_bit_field; 2700 public int[] frequencies; 2701 2702 @Override 2703 public boolean equals(Object otherObj) { 2704 if (this == otherObj) { 2705 return true; 2706 } else if (otherObj == null || getClass() != otherObj.getClass()) { 2707 return false; 2708 } 2709 PnoNetwork other = (PnoNetwork) otherObj; 2710 return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags) 2711 && (auth_bit_field == other.auth_bit_field)) 2712 && Arrays.equals(frequencies, other.frequencies); 2713 } 2714 2715 @Override 2716 public int hashCode() { 2717 return Objects.hash(ssid, flags, auth_bit_field, frequencies); 2718 } 2719 2720 android.net.wifi.nl80211.PnoNetwork toNativePnoNetwork() { 2721 android.net.wifi.nl80211.PnoNetwork nativePnoNetwork = 2722 new android.net.wifi.nl80211.PnoNetwork(); 2723 nativePnoNetwork.setHidden( 2724 (flags & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0); 2725 try { 2726 nativePnoNetwork.setSsid( 2727 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid))); 2728 } catch (IllegalArgumentException e) { 2729 Log.e(TAG, "Illegal argument " + ssid, e); 2730 return null; 2731 } 2732 nativePnoNetwork.setFrequenciesMhz(frequencies); 2733 return nativePnoNetwork; 2734 } 2735 } 2736 2737 /** 2738 * Parameters to start PNO scan. This holds the list of networks which are going to used for 2739 * PNO scan. 2740 */ 2741 public static class PnoSettings { 2742 public int min5GHzRssi; 2743 public int min24GHzRssi; 2744 public int min6GHzRssi; 2745 public int periodInMs; 2746 public boolean isConnected; 2747 public PnoNetwork[] networkList; 2748 2749 android.net.wifi.nl80211.PnoSettings toNativePnoSettings() { 2750 android.net.wifi.nl80211.PnoSettings nativePnoSettings = 2751 new android.net.wifi.nl80211.PnoSettings(); 2752 nativePnoSettings.setIntervalMillis(periodInMs); 2753 nativePnoSettings.setMin2gRssiDbm(min24GHzRssi); 2754 nativePnoSettings.setMin5gRssiDbm(min5GHzRssi); 2755 nativePnoSettings.setMin6gRssiDbm(min6GHzRssi); 2756 2757 List<android.net.wifi.nl80211.PnoNetwork> pnoNetworks = new ArrayList<>(); 2758 if (networkList != null) { 2759 for (PnoNetwork network : networkList) { 2760 android.net.wifi.nl80211.PnoNetwork nativeNetwork = 2761 network.toNativePnoNetwork(); 2762 if (nativeNetwork != null) { 2763 pnoNetworks.add(nativeNetwork); 2764 } 2765 } 2766 } 2767 nativePnoSettings.setPnoNetworks(pnoNetworks); 2768 return nativePnoSettings; 2769 } 2770 } 2771 2772 public static interface ScanEventHandler { 2773 /** 2774 * Called for each AP as it is found with the entire contents of the beacon/probe response. 2775 * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified. 2776 */ 2777 void onFullScanResult(ScanResult fullScanResult, int bucketsScanned); 2778 /** 2779 * Callback on an event during a gscan scan. 2780 * See WifiNative.WIFI_SCAN_* for possible values. 2781 */ 2782 void onScanStatus(int event); 2783 /** 2784 * Called with the current cached scan results when gscan is paused. 2785 */ 2786 void onScanPaused(WifiScanner.ScanData[] data); 2787 /** 2788 * Called with the current cached scan results when gscan is resumed. 2789 */ 2790 void onScanRestarted(); 2791 } 2792 2793 /** 2794 * Handler to notify the occurrence of various events during PNO scan. 2795 */ 2796 public interface PnoEventHandler { 2797 /** 2798 * Callback to notify when one of the shortlisted networks is found during PNO scan. 2799 * @param results List of Scan results received. 2800 */ 2801 void onPnoNetworkFound(ScanResult[] results); 2802 2803 /** 2804 * Callback to notify when the PNO scan schedule fails. 2805 */ 2806 void onPnoScanFailed(); 2807 } 2808 2809 public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0; 2810 public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1; 2811 public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2; 2812 public static final int WIFI_SCAN_FAILED = 3; 2813 2814 /** 2815 * Starts a background scan. 2816 * Any ongoing scan will be stopped first 2817 * 2818 * @param ifaceName Name of the interface. 2819 * @param settings to control the scan 2820 * @param eventHandler to call with the results 2821 * @return true for success 2822 */ 2823 public boolean startBgScan( 2824 @NonNull String ifaceName, ScanSettings settings, ScanEventHandler eventHandler) { 2825 return mWifiVendorHal.startBgScan(ifaceName, settings, eventHandler); 2826 } 2827 2828 /** 2829 * Stops any ongoing backgound scan 2830 * @param ifaceName Name of the interface. 2831 */ 2832 public void stopBgScan(@NonNull String ifaceName) { 2833 mWifiVendorHal.stopBgScan(ifaceName); 2834 } 2835 2836 /** 2837 * Pauses an ongoing backgound scan 2838 * @param ifaceName Name of the interface. 2839 */ 2840 public void pauseBgScan(@NonNull String ifaceName) { 2841 mWifiVendorHal.pauseBgScan(ifaceName); 2842 } 2843 2844 /** 2845 * Restarts a paused scan 2846 * @param ifaceName Name of the interface. 2847 */ 2848 public void restartBgScan(@NonNull String ifaceName) { 2849 mWifiVendorHal.restartBgScan(ifaceName); 2850 } 2851 2852 /** 2853 * Gets the latest scan results received. 2854 * @param ifaceName Name of the interface. 2855 */ 2856 public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) { 2857 return mWifiVendorHal.getBgScanResults(ifaceName); 2858 } 2859 2860 /** 2861 * Gets the latest link layer stats 2862 * @param ifaceName Name of the interface. 2863 */ 2864 public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) { 2865 return mWifiVendorHal.getWifiLinkLayerStats(ifaceName); 2866 } 2867 2868 /** 2869 * Returns whether STA/AP concurrency is supported or not. 2870 */ 2871 public boolean isStaApConcurrencySupported() { 2872 synchronized (mLock) { 2873 return mWifiVendorHal.isStaApConcurrencySupported(); 2874 } 2875 } 2876 2877 /** 2878 * Get the supported features 2879 * 2880 * @param ifaceName Name of the interface. 2881 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 2882 */ 2883 public long getSupportedFeatureSet(@NonNull String ifaceName) { 2884 synchronized (mLock) { 2885 Iface iface = mIfaceMgr.getIface(ifaceName); 2886 if (iface == null) { 2887 Log.e(TAG, "Could not get Iface object for interface " + ifaceName); 2888 return 0; 2889 } 2890 2891 return iface.featureSet; 2892 } 2893 } 2894 2895 /** 2896 * Get the supported features 2897 * 2898 * @param ifaceName Name of the interface. 2899 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 2900 */ 2901 private long getSupportedFeatureSetInternal(@NonNull String ifaceName) { 2902 return mSupplicantStaIfaceHal.getAdvancedKeyMgmtCapabilities(ifaceName) 2903 | mWifiVendorHal.getSupportedFeatureSet(ifaceName) 2904 | mSupplicantStaIfaceHal.getWpaDriverFeatureSet(ifaceName); 2905 } 2906 2907 /** 2908 * Class to retrieve connection capability parameters after association 2909 */ 2910 public static class ConnectionCapabilities { 2911 public @WifiAnnotations.WifiStandard int wifiStandard; 2912 public int channelBandwidth; 2913 public int maxNumberTxSpatialStreams; 2914 public int maxNumberRxSpatialStreams; 2915 ConnectionCapabilities() { 2916 wifiStandard = ScanResult.WIFI_STANDARD_UNKNOWN; 2917 channelBandwidth = ScanResult.CHANNEL_WIDTH_20MHZ; 2918 maxNumberTxSpatialStreams = 1; 2919 maxNumberRxSpatialStreams = 1; 2920 } 2921 } 2922 2923 /** 2924 * Returns connection capabilities of the current network 2925 * 2926 * @param ifaceName Name of the interface. 2927 * @return connection capabilities of the current network 2928 */ 2929 public ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) { 2930 return mSupplicantStaIfaceHal.getConnectionCapabilities(ifaceName); 2931 } 2932 2933 /** 2934 * Get the APF (Android Packet Filter) capabilities of the device 2935 * @param ifaceName Name of the interface. 2936 */ 2937 public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) { 2938 return mWifiVendorHal.getApfCapabilities(ifaceName); 2939 } 2940 2941 /** 2942 * Installs an APF program on this iface, replacing any existing program. 2943 * 2944 * @param ifaceName Name of the interface 2945 * @param filter is the android packet filter program 2946 * @return true for success 2947 */ 2948 public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) { 2949 return mWifiVendorHal.installPacketFilter(ifaceName, filter); 2950 } 2951 2952 /** 2953 * Reads the APF program and data buffer for this iface. 2954 * 2955 * @param ifaceName Name of the interface 2956 * @return the buffer returned by the driver, or null in case of an error 2957 */ 2958 public byte[] readPacketFilter(@NonNull String ifaceName) { 2959 return mWifiVendorHal.readPacketFilter(ifaceName); 2960 } 2961 2962 /** 2963 * Set country code for this AP iface. 2964 * @param ifaceName Name of the interface. 2965 * @param countryCode - two-letter country code (as ISO 3166) 2966 * @return true for success 2967 */ 2968 public boolean setCountryCodeHal(@NonNull String ifaceName, String countryCode) { 2969 return mWifiVendorHal.setCountryCodeHal(ifaceName, countryCode); 2970 } 2971 2972 //--------------------------------------------------------------------------------- 2973 /* Wifi Logger commands/events */ 2974 public static interface WifiLoggerEventHandler { 2975 void onRingBufferData(RingBufferStatus status, byte[] buffer); 2976 void onWifiAlert(int errorCode, byte[] buffer); 2977 } 2978 2979 /** 2980 * Registers the logger callback and enables alerts. 2981 * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked. 2982 * 2983 * @param handler Callback to be invoked. 2984 * @return true on success, false otherwise. 2985 */ 2986 public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) { 2987 return mWifiVendorHal.setLoggingEventHandler(handler); 2988 } 2989 2990 /** 2991 * Control debug data collection 2992 * 2993 * @param verboseLevel 0 to 3, inclusive. 0 stops logging. 2994 * @param flags Ignored. 2995 * @param maxInterval Maximum interval between reports; ignore if 0. 2996 * @param minDataSize Minimum data size in buffer for report; ignore if 0. 2997 * @param ringName Name of the ring for which data collection is to start. 2998 * @return true for success, false otherwise. 2999 */ 3000 public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval, 3001 int minDataSize, String ringName){ 3002 return mWifiVendorHal.startLoggingRingBuffer( 3003 verboseLevel, flags, maxInterval, minDataSize, ringName); 3004 } 3005 3006 /** 3007 * Logger features exposed. 3008 * This is a no-op now, will always return -1. 3009 * 3010 * @return true on success, false otherwise. 3011 */ 3012 public int getSupportedLoggerFeatureSet() { 3013 return mWifiVendorHal.getSupportedLoggerFeatureSet(); 3014 } 3015 3016 /** 3017 * Stops all logging and resets the logger callback. 3018 * This stops both the alerts and ring buffer data collection. 3019 * @return true on success, false otherwise. 3020 */ 3021 public boolean resetLogHandler() { 3022 return mWifiVendorHal.resetLogHandler(); 3023 } 3024 3025 /** 3026 * Vendor-provided wifi driver version string 3027 * 3028 * @return String returned from the HAL. 3029 */ 3030 public String getDriverVersion() { 3031 return mWifiVendorHal.getDriverVersion(); 3032 } 3033 3034 /** 3035 * Vendor-provided wifi firmware version string 3036 * 3037 * @return String returned from the HAL. 3038 */ 3039 public String getFirmwareVersion() { 3040 return mWifiVendorHal.getFirmwareVersion(); 3041 } 3042 3043 public static class RingBufferStatus{ 3044 String name; 3045 int flag; 3046 int ringBufferId; 3047 int ringBufferByteSize; 3048 int verboseLevel; 3049 int writtenBytes; 3050 int readBytes; 3051 int writtenRecords; 3052 3053 // Bit masks for interpreting |flag| 3054 public static final int HAS_BINARY_ENTRIES = (1 << 0); 3055 public static final int HAS_ASCII_ENTRIES = (1 << 1); 3056 public static final int HAS_PER_PACKET_ENTRIES = (1 << 2); 3057 3058 @Override 3059 public String toString() { 3060 return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId + 3061 " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel + 3062 " writtenBytes: " + writtenBytes + " readBytes: " + readBytes + 3063 " writtenRecords: " + writtenRecords; 3064 } 3065 } 3066 3067 /** 3068 * API to get the status of all ring buffers supported by driver 3069 */ 3070 public RingBufferStatus[] getRingBufferStatus() { 3071 return mWifiVendorHal.getRingBufferStatus(); 3072 } 3073 3074 /** 3075 * Indicates to driver that all the data has to be uploaded urgently 3076 * 3077 * @param ringName Name of the ring buffer requested. 3078 * @return true on success, false otherwise. 3079 */ 3080 public boolean getRingBufferData(String ringName) { 3081 return mWifiVendorHal.getRingBufferData(ringName); 3082 } 3083 3084 /** 3085 * Request hal to flush ring buffers to files 3086 * 3087 * @return true on success, false otherwise. 3088 */ 3089 public boolean flushRingBufferData() { 3090 return mWifiVendorHal.flushRingBufferData(); 3091 } 3092 3093 /** 3094 * Request vendor debug info from the firmware 3095 * 3096 * @return Raw data obtained from the HAL. 3097 */ 3098 public byte[] getFwMemoryDump() { 3099 return mWifiVendorHal.getFwMemoryDump(); 3100 } 3101 3102 /** 3103 * Request vendor debug info from the driver 3104 * 3105 * @return Raw data obtained from the HAL. 3106 */ 3107 public byte[] getDriverStateDump() { 3108 return mWifiVendorHal.getDriverStateDump(); 3109 } 3110 3111 //--------------------------------------------------------------------------------- 3112 /* Packet fate API */ 3113 3114 @Immutable 3115 abstract static class FateReport { 3116 final static int USEC_PER_MSEC = 1000; 3117 // The driver timestamp is a 32-bit counter, in microseconds. This field holds the 3118 // maximal value of a driver timestamp in milliseconds. 3119 final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000); 3120 final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS"); 3121 3122 final byte mFate; 3123 final long mDriverTimestampUSec; 3124 final byte mFrameType; 3125 final byte[] mFrameBytes; 3126 final long mEstimatedWallclockMSec; 3127 3128 FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 3129 mFate = fate; 3130 mDriverTimestampUSec = driverTimestampUSec; 3131 mEstimatedWallclockMSec = 3132 convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec); 3133 mFrameType = frameType; 3134 mFrameBytes = frameBytes; 3135 } 3136 3137 public String toTableRowString() { 3138 StringWriter sw = new StringWriter(); 3139 PrintWriter pw = new PrintWriter(sw); 3140 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 3141 dateFormatter.setTimeZone(TimeZone.getDefault()); 3142 pw.format("%-15s %12s %-9s %-32s %-12s %-23s %s\n", 3143 mDriverTimestampUSec, 3144 dateFormatter.format(new Date(mEstimatedWallclockMSec)), 3145 directionToString(), fateToString(), parser.mMostSpecificProtocolString, 3146 parser.mTypeString, parser.mResultString); 3147 return sw.toString(); 3148 } 3149 3150 public String toVerboseStringWithPiiAllowed() { 3151 StringWriter sw = new StringWriter(); 3152 PrintWriter pw = new PrintWriter(sw); 3153 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 3154 pw.format("Frame direction: %s\n", directionToString()); 3155 pw.format("Frame timestamp: %d\n", mDriverTimestampUSec); 3156 pw.format("Frame fate: %s\n", fateToString()); 3157 pw.format("Frame type: %s\n", frameTypeToString(mFrameType)); 3158 pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString); 3159 pw.format("Frame protocol type: %s\n", parser.mTypeString); 3160 pw.format("Frame length: %d\n", mFrameBytes.length); 3161 pw.append("Frame bytes"); 3162 pw.append(HexDump.dumpHexString(mFrameBytes)); // potentially contains PII 3163 pw.append("\n"); 3164 return sw.toString(); 3165 } 3166 3167 /* Returns a header to match the output of toTableRowString(). */ 3168 public static String getTableHeader() { 3169 StringWriter sw = new StringWriter(); 3170 PrintWriter pw = new PrintWriter(sw); 3171 pw.format("\n%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 3172 "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result"); 3173 pw.format("%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 3174 "---------", "--------", "---------", "----", "--------", "----", "------"); 3175 return sw.toString(); 3176 } 3177 3178 protected abstract String directionToString(); 3179 3180 protected abstract String fateToString(); 3181 3182 private static String frameTypeToString(byte frameType) { 3183 switch (frameType) { 3184 case WifiLoggerHal.FRAME_TYPE_UNKNOWN: 3185 return "unknown"; 3186 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II: 3187 return "data"; 3188 case WifiLoggerHal.FRAME_TYPE_80211_MGMT: 3189 return "802.11 management"; 3190 default: 3191 return Byte.toString(frameType); 3192 } 3193 } 3194 3195 /** 3196 * Converts a driver timestamp to a wallclock time, based on the current 3197 * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of 3198 * microseconds, with the same base as BOOTTIME. 3199 */ 3200 private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) { 3201 final long wallclockMillisNow = System.currentTimeMillis(); 3202 final long boottimeMillisNow = SystemClock.elapsedRealtime(); 3203 final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC; 3204 3205 long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC; 3206 if (boottimeTimestampMillis < driverTimestampMillis) { 3207 // The 32-bit microsecond count has wrapped between the time that the driver 3208 // recorded the packet, and the call to this function. Adjust the BOOTTIME 3209 // timestamp, to compensate. 3210 // 3211 // Note that overflow is not a concern here, since the result is less than 3212 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above, 3213 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since 3214 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit 3215 // within a long. 3216 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC; 3217 } 3218 3219 final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis; 3220 return wallclockMillisNow - millisSincePacketTimestamp; 3221 } 3222 } 3223 3224 /** 3225 * Represents the fate information for one outbound packet. 3226 */ 3227 @Immutable 3228 public static final class TxFateReport extends FateReport { 3229 TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 3230 super(fate, driverTimestampUSec, frameType, frameBytes); 3231 } 3232 3233 @Override 3234 protected String directionToString() { 3235 return "TX"; 3236 } 3237 3238 @Override 3239 protected String fateToString() { 3240 switch (mFate) { 3241 case WifiLoggerHal.TX_PKT_FATE_ACKED: 3242 return "acked"; 3243 case WifiLoggerHal.TX_PKT_FATE_SENT: 3244 return "sent"; 3245 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED: 3246 return "firmware queued"; 3247 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID: 3248 return "firmware dropped (invalid frame)"; 3249 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS: 3250 return "firmware dropped (no bufs)"; 3251 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER: 3252 return "firmware dropped (other)"; 3253 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED: 3254 return "driver queued"; 3255 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID: 3256 return "driver dropped (invalid frame)"; 3257 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS: 3258 return "driver dropped (no bufs)"; 3259 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER: 3260 return "driver dropped (other)"; 3261 default: 3262 return Byte.toString(mFate); 3263 } 3264 } 3265 } 3266 3267 /** 3268 * Represents the fate information for one inbound packet. 3269 */ 3270 @Immutable 3271 public static final class RxFateReport extends FateReport { 3272 RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 3273 super(fate, driverTimestampUSec, frameType, frameBytes); 3274 } 3275 3276 @Override 3277 protected String directionToString() { 3278 return "RX"; 3279 } 3280 3281 @Override 3282 protected String fateToString() { 3283 switch (mFate) { 3284 case WifiLoggerHal.RX_PKT_FATE_SUCCESS: 3285 return "success"; 3286 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED: 3287 return "firmware queued"; 3288 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER: 3289 return "firmware dropped (filter)"; 3290 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID: 3291 return "firmware dropped (invalid frame)"; 3292 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS: 3293 return "firmware dropped (no bufs)"; 3294 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER: 3295 return "firmware dropped (other)"; 3296 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED: 3297 return "driver queued"; 3298 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER: 3299 return "driver dropped (filter)"; 3300 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID: 3301 return "driver dropped (invalid frame)"; 3302 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS: 3303 return "driver dropped (no bufs)"; 3304 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER: 3305 return "driver dropped (other)"; 3306 default: 3307 return Byte.toString(mFate); 3308 } 3309 } 3310 } 3311 3312 /** 3313 * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started. 3314 * 3315 * @param ifaceName Name of the interface. 3316 * @return true for success, false otherwise. 3317 */ 3318 public boolean startPktFateMonitoring(@NonNull String ifaceName) { 3319 return mWifiVendorHal.startPktFateMonitoring(ifaceName); 3320 } 3321 3322 /** 3323 * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started. 3324 * 3325 * @param ifaceName Name of the interface. 3326 * @return true for success, false otherwise. 3327 */ 3328 public boolean getTxPktFates(@NonNull String ifaceName, TxFateReport[] reportBufs) { 3329 return mWifiVendorHal.getTxPktFates(ifaceName, reportBufs); 3330 } 3331 3332 /** 3333 * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started. 3334 * @param ifaceName Name of the interface. 3335 */ 3336 public boolean getRxPktFates(@NonNull String ifaceName, RxFateReport[] reportBufs) { 3337 return mWifiVendorHal.getRxPktFates(ifaceName, reportBufs); 3338 } 3339 3340 /** 3341 * Get the tx packet counts for the interface. 3342 * 3343 * @param ifaceName Name of the interface. 3344 * @return tx packet counts 3345 */ 3346 public long getTxPackets(@NonNull String ifaceName) { 3347 return TrafficStats.getTxPackets(ifaceName); 3348 } 3349 3350 /** 3351 * Get the rx packet counts for the interface. 3352 * 3353 * @param ifaceName Name of the interface 3354 * @return rx packet counts 3355 */ 3356 public long getRxPackets(@NonNull String ifaceName) { 3357 return TrafficStats.getRxPackets(ifaceName); 3358 } 3359 3360 /** 3361 * Start sending the specified keep alive packets periodically. 3362 * 3363 * @param ifaceName Name of the interface. 3364 * @param slot Integer used to identify each request. 3365 * @param dstMac Destination MAC Address 3366 * @param packet Raw packet contents to send. 3367 * @param protocol The ethernet protocol type 3368 * @param period Period to use for sending these packets. 3369 * @return 0 for success, -1 for error 3370 */ 3371 public int startSendingOffloadedPacket(@NonNull String ifaceName, int slot, 3372 byte[] dstMac, byte[] packet, int protocol, int period) { 3373 byte[] srcMac = NativeUtil.macAddressToByteArray(getMacAddress(ifaceName)); 3374 return mWifiVendorHal.startSendingOffloadedPacket( 3375 ifaceName, slot, srcMac, dstMac, packet, protocol, period); 3376 } 3377 3378 /** 3379 * Stop sending the specified keep alive packets. 3380 * 3381 * @param ifaceName Name of the interface. 3382 * @param slot id - same as startSendingOffloadedPacket call. 3383 * @return 0 for success, -1 for error 3384 */ 3385 public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) { 3386 return mWifiVendorHal.stopSendingOffloadedPacket(ifaceName, slot); 3387 } 3388 3389 public static interface WifiRssiEventHandler { 3390 void onRssiThresholdBreached(byte curRssi); 3391 } 3392 3393 /** 3394 * Start RSSI monitoring on the currently connected access point. 3395 * 3396 * @param ifaceName Name of the interface. 3397 * @param maxRssi Maximum RSSI threshold. 3398 * @param minRssi Minimum RSSI threshold. 3399 * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi 3400 * @return 0 for success, -1 for failure 3401 */ 3402 public int startRssiMonitoring( 3403 @NonNull String ifaceName, byte maxRssi, byte minRssi, 3404 WifiRssiEventHandler rssiEventHandler) { 3405 return mWifiVendorHal.startRssiMonitoring( 3406 ifaceName, maxRssi, minRssi, rssiEventHandler); 3407 } 3408 3409 /** 3410 * Stop RSSI monitoring on the currently connected access point. 3411 * 3412 * @param ifaceName Name of the interface. 3413 * @return 0 for success, -1 for failure 3414 */ 3415 public int stopRssiMonitoring(@NonNull String ifaceName) { 3416 return mWifiVendorHal.stopRssiMonitoring(ifaceName); 3417 } 3418 3419 /** 3420 * Fetch the host wakeup reasons stats from wlan driver. 3421 * 3422 * @return the |WlanWakeReasonAndCounts| object retrieved from the wlan driver. 3423 */ 3424 public WlanWakeReasonAndCounts getWlanWakeReasonCount() { 3425 return mWifiVendorHal.getWlanWakeReasonCount(); 3426 } 3427 3428 /** 3429 * Enable/Disable Neighbour discovery offload functionality in the firmware. 3430 * 3431 * @param ifaceName Name of the interface. 3432 * @param enabled true to enable, false to disable. 3433 * @return true for success, false otherwise. 3434 */ 3435 public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) { 3436 return mWifiVendorHal.configureNeighborDiscoveryOffload(ifaceName, enabled); 3437 } 3438 3439 // Firmware roaming control. 3440 3441 /** 3442 * Class to retrieve firmware roaming capability parameters. 3443 */ 3444 public static class RoamingCapabilities { 3445 public int maxBlacklistSize; 3446 public int maxWhitelistSize; 3447 } 3448 3449 /** 3450 * Query the firmware roaming capabilities. 3451 * @param ifaceName Name of the interface. 3452 * @return true for success, false otherwise. 3453 */ 3454 public boolean getRoamingCapabilities( 3455 @NonNull String ifaceName, RoamingCapabilities capabilities) { 3456 return mWifiVendorHal.getRoamingCapabilities(ifaceName, capabilities); 3457 } 3458 3459 /** 3460 * Macros for controlling firmware roaming. 3461 */ 3462 public static final int DISABLE_FIRMWARE_ROAMING = 0; 3463 public static final int ENABLE_FIRMWARE_ROAMING = 1; 3464 3465 /** 3466 * Indicates success for enableFirmwareRoaming 3467 */ 3468 public static final int SET_FIRMWARE_ROAMING_SUCCESS = 0; 3469 3470 /** 3471 * Indicates failure for enableFirmwareRoaming 3472 */ 3473 public static final int SET_FIRMWARE_ROAMING_FAILURE = 1; 3474 3475 /** 3476 * Indicates temporary failure for enableFirmwareRoaming - try again later 3477 */ 3478 public static final int SET_FIRMWARE_ROAMING_BUSY = 2; 3479 3480 /** 3481 * Enable/disable firmware roaming. 3482 * 3483 * @param ifaceName Name of the interface. 3484 * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE, 3485 * or SET_FIRMWARE_ROAMING_BUSY 3486 */ 3487 public int enableFirmwareRoaming(@NonNull String ifaceName, int state) { 3488 return mWifiVendorHal.enableFirmwareRoaming(ifaceName, state); 3489 } 3490 3491 /** 3492 * Class for specifying the roaming configurations. 3493 */ 3494 public static class RoamingConfig { 3495 public ArrayList<String> blacklistBssids; 3496 public ArrayList<String> whitelistSsids; 3497 } 3498 3499 /** 3500 * Set firmware roaming configurations. 3501 * @param ifaceName Name of the interface. 3502 */ 3503 public boolean configureRoaming(@NonNull String ifaceName, RoamingConfig config) { 3504 return mWifiVendorHal.configureRoaming(ifaceName, config); 3505 } 3506 3507 /** 3508 * Reset firmware roaming configuration. 3509 * @param ifaceName Name of the interface. 3510 */ 3511 public boolean resetRoamingConfiguration(@NonNull String ifaceName) { 3512 // Pass in an empty RoamingConfig object which translates to zero size 3513 // blacklist and whitelist to reset the firmware roaming configuration. 3514 return mWifiVendorHal.configureRoaming(ifaceName, new RoamingConfig()); 3515 } 3516 3517 /** 3518 * Select one of the pre-configured transmit power level scenarios or reset it back to normal. 3519 * Primarily used for meeting SAR requirements. 3520 * 3521 * @param sarInfo The collection of inputs used to select the SAR scenario. 3522 * @return true for success; false for failure or if the HAL version does not support this API. 3523 */ 3524 public boolean selectTxPowerScenario(SarInfo sarInfo) { 3525 return mWifiVendorHal.selectTxPowerScenario(sarInfo); 3526 } 3527 3528 /** 3529 * Set MBO cellular data status 3530 * 3531 * @param ifaceName Name of the interface. 3532 * @param available cellular data status, 3533 * true means cellular data available, false otherwise. 3534 */ 3535 public void setMboCellularDataStatus(@NonNull String ifaceName, boolean available) { 3536 mSupplicantStaIfaceHal.setMboCellularDataStatus(ifaceName, available); 3537 return; 3538 } 3539 3540 /** 3541 * Query of support of Wi-Fi standard 3542 * 3543 * @param ifaceName name of the interface to check support on 3544 * @param standard the wifi standard to check on 3545 * @return true if the wifi standard is supported on this interface, false otherwise. 3546 */ 3547 public boolean isWifiStandardSupported(@NonNull String ifaceName, 3548 @WifiAnnotations.WifiStandard int standard) { 3549 synchronized (mLock) { 3550 Iface iface = mIfaceMgr.getIface(ifaceName); 3551 if (iface == null || iface.phyCapabilities == null) { 3552 return false; 3553 } 3554 return iface.phyCapabilities.isWifiStandardSupported(standard); 3555 } 3556 } 3557 3558 /** 3559 * Get the Wiphy capabilities of a device for a given interface 3560 * If the interface is not associated with one, 3561 * it will be read from the device through wificond 3562 * 3563 * @param ifaceName name of the interface 3564 * @return the device capabilities for this interface 3565 */ 3566 public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) { 3567 synchronized (mLock) { 3568 Iface iface = mIfaceMgr.getIface(ifaceName); 3569 if (iface == null) { 3570 Log.e(TAG, "Failed to get device capabilities, interface not found: " + ifaceName); 3571 return null; 3572 } 3573 if (iface.phyCapabilities == null) { 3574 iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities(ifaceName); 3575 } 3576 return iface.phyCapabilities; 3577 } 3578 } 3579 3580 /** 3581 * Set the Wiphy capabilities of a device for a given interface 3582 * 3583 * @param ifaceName name of the interface 3584 * @param capabilities the wiphy capabilities to set for this interface 3585 */ 3586 public void setDeviceWiphyCapabilities(@NonNull String ifaceName, 3587 DeviceWiphyCapabilities capabilities) { 3588 synchronized (mLock) { 3589 Iface iface = mIfaceMgr.getIface(ifaceName); 3590 if (iface == null) { 3591 Log.e(TAG, "Failed to set device capabilities, interface not found: " + ifaceName); 3592 return; 3593 } 3594 iface.phyCapabilities = capabilities; 3595 } 3596 } 3597 } 3598