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