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 static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP; 22 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP_BRIDGE; 23 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_NAN; 24 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_P2P; 25 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_STA; 26 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_NATIVE_EXTENDED_SUPPORTED_FEATURES; 27 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_NATIVE_SUPPORTED_FEATURES; 28 import static com.android.server.wifi.p2p.WifiP2pNative.P2P_IFACE_NAME; 29 import static com.android.server.wifi.p2p.WifiP2pNative.P2P_INTERFACE_PROPERTY; 30 import static com.android.server.wifi.util.GeneralUtil.longToBitset; 31 import static com.android.wifi.flags.Flags.rsnOverriding; 32 33 import android.annotation.IntDef; 34 import android.annotation.NonNull; 35 import android.annotation.Nullable; 36 import android.annotation.SuppressLint; 37 import android.hardware.wifi.WifiStatusCode; 38 import android.net.MacAddress; 39 import android.net.TrafficStats; 40 import android.net.apf.ApfCapabilities; 41 import android.net.wifi.CoexUnsafeChannel; 42 import android.net.wifi.DeauthenticationReasonCode; 43 import android.net.wifi.MscsParams; 44 import android.net.wifi.OuiKeyedData; 45 import android.net.wifi.QosPolicyParams; 46 import android.net.wifi.ScanResult; 47 import android.net.wifi.SecurityParams; 48 import android.net.wifi.SoftApConfiguration; 49 import android.net.wifi.WifiAnnotations; 50 import android.net.wifi.WifiAvailableChannel; 51 import android.net.wifi.WifiConfiguration; 52 import android.net.wifi.WifiContext; 53 import android.net.wifi.WifiManager; 54 import android.net.wifi.WifiManager.RoamingMode; 55 import android.net.wifi.WifiScanner; 56 import android.net.wifi.WifiScanner.ScanData; 57 import android.net.wifi.WifiSsid; 58 import android.net.wifi.nl80211.DeviceWiphyCapabilities; 59 import android.net.wifi.nl80211.NativeScanResult; 60 import android.net.wifi.nl80211.NativeWifiClient; 61 import android.net.wifi.nl80211.RadioChainInfo; 62 import android.net.wifi.nl80211.WifiNl80211Manager; 63 import android.net.wifi.twt.TwtRequest; 64 import android.net.wifi.twt.TwtSessionCallback; 65 import android.net.wifi.usd.PublishConfig; 66 import android.net.wifi.usd.SubscribeConfig; 67 import android.os.Bundle; 68 import android.os.Handler; 69 import android.os.IBinder; 70 import android.os.SystemClock; 71 import android.os.WorkSource; 72 import android.text.TextUtils; 73 import android.util.ArrayMap; 74 import android.util.ArraySet; 75 import android.util.Log; 76 import android.util.SparseArray; 77 import android.util.SparseIntArray; 78 79 import androidx.annotation.Keep; 80 81 import com.android.internal.annotations.Immutable; 82 import com.android.internal.annotations.VisibleForTesting; 83 import com.android.internal.util.HexDump; 84 import com.android.modules.utils.build.SdkLevel; 85 import com.android.server.wifi.SupplicantStaIfaceHal.QosPolicyStatus; 86 import com.android.server.wifi.WifiLinkLayerStats.ScanResultWithSameFreq; 87 import com.android.server.wifi.hal.WifiChip; 88 import com.android.server.wifi.hal.WifiHal; 89 import com.android.server.wifi.hal.WifiNanIface; 90 import com.android.server.wifi.hotspot2.NetworkDetail; 91 import com.android.server.wifi.mainline_supplicant.MainlineSupplicant; 92 import com.android.server.wifi.mockwifi.MockWifiServiceUtil; 93 import com.android.server.wifi.proto.WifiStatsLog; 94 import com.android.server.wifi.usd.UsdRequestManager; 95 import com.android.server.wifi.util.FrameParser; 96 import com.android.server.wifi.util.InformationElementUtil; 97 import com.android.server.wifi.util.NativeUtil; 98 import com.android.server.wifi.util.NetdWrapper; 99 import com.android.server.wifi.util.NetdWrapper.NetdEventObserver; 100 import com.android.wifi.flags.Flags; 101 import com.android.wifi.resources.R; 102 103 import java.io.PrintWriter; 104 import java.io.StringWriter; 105 import java.lang.annotation.Retention; 106 import java.lang.annotation.RetentionPolicy; 107 import java.nio.ByteBuffer; 108 import java.nio.ByteOrder; 109 import java.text.SimpleDateFormat; 110 import java.util.ArrayList; 111 import java.util.Arrays; 112 import java.util.BitSet; 113 import java.util.Collections; 114 import java.util.Date; 115 import java.util.HashMap; 116 import java.util.HashSet; 117 import java.util.Iterator; 118 import java.util.List; 119 import java.util.Map; 120 import java.util.Objects; 121 import java.util.Random; 122 import java.util.Set; 123 import java.util.TimeZone; 124 125 /** 126 * Native calls for bring up/shut down of the supplicant daemon and for 127 * sending requests to the supplicant daemon 128 * 129 * {@hide} 130 */ 131 public class WifiNative { 132 private static final String TAG = "WifiNative"; 133 134 private final SupplicantStaIfaceHal mSupplicantStaIfaceHal; 135 private final HostapdHal mHostapdHal; 136 private final WifiVendorHal mWifiVendorHal; 137 private final WifiNl80211Manager mWifiCondManager; 138 private final WifiMonitor mWifiMonitor; 139 private final PropertyService mPropertyService; 140 private final WifiMetrics mWifiMetrics; 141 private final Handler mHandler; 142 private final Random mRandom; 143 private final BuildProperties mBuildProperties; 144 private final WifiInjector mWifiInjector; 145 private final WifiContext mContext; 146 private NetdWrapper mNetdWrapper; 147 private boolean mVerboseLoggingEnabled = false; 148 private boolean mIsEnhancedOpenSupported = false; 149 @VisibleForTesting boolean mIsRsnOverridingSupported = false; 150 private final List<CoexUnsafeChannel> mCachedCoexUnsafeChannels = new ArrayList<>(); 151 private int mCachedCoexRestrictions; 152 private CountryCodeChangeListenerInternal mCountryCodeChangeListener; 153 private boolean mUseFakeScanDetails; 154 private final ArrayList<ScanDetail> mFakeScanDetails = new ArrayList<>(); 155 private BitSet mCachedFeatureSet = null; 156 private boolean mQosPolicyFeatureEnabled = false; 157 private final Map<String, String> mWifiCondIfacesForBridgedAp = new ArrayMap<>(); 158 private MockWifiServiceUtil mMockWifiModem = null; 159 private InterfaceObserverInternal mInterfaceObserver; 160 private InterfaceEventCallback mInterfaceListener; 161 private @WifiManager.MloMode int mCachedMloMode = WifiManager.MLO_MODE_DEFAULT; 162 private boolean mIsLocationModeEnabled = false; 163 private long mLastLocationModeEnabledTimeMs = 0; 164 private Map<String, Bundle> mCachedTwtCapabilities = new ArrayMap<>(); 165 private final MainlineSupplicant mMainlineSupplicant; 166 167 /** 168 * Mapping of unknown AKMs configured in overlay config item 169 * config_wifiUnknownAkmToKnownAkmMapping to ScanResult security key management scheme 170 * (ScanResult.KEY_MGMT_XX) 171 */ 172 @VisibleForTesting @Nullable SparseIntArray mUnknownAkmMap; 173 private SupplicantStaIfaceHal.UsdCapabilitiesInternal mCachedUsdCapabilities = null; 174 WifiNative(WifiVendorHal vendorHal, SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, WifiNl80211Manager condManager, WifiMonitor wifiMonitor, PropertyService propertyService, WifiMetrics wifiMetrics, Handler handler, Random random, BuildProperties buildProperties, WifiInjector wifiInjector, MainlineSupplicant mainlineSupplicant)175 public WifiNative(WifiVendorHal vendorHal, 176 SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, 177 WifiNl80211Manager condManager, WifiMonitor wifiMonitor, 178 PropertyService propertyService, WifiMetrics wifiMetrics, 179 Handler handler, Random random, BuildProperties buildProperties, 180 WifiInjector wifiInjector, MainlineSupplicant mainlineSupplicant) { 181 mWifiVendorHal = vendorHal; 182 mSupplicantStaIfaceHal = staIfaceHal; 183 mHostapdHal = hostapdHal; 184 mWifiCondManager = condManager; 185 mWifiMonitor = wifiMonitor; 186 mPropertyService = propertyService; 187 mWifiMetrics = wifiMetrics; 188 mHandler = handler; 189 mRandom = random; 190 mBuildProperties = buildProperties; 191 mWifiInjector = wifiInjector; 192 mContext = wifiInjector.getContext(); 193 mMainlineSupplicant = mainlineSupplicant; 194 initializeUnknownAkmMapping(); 195 } 196 initializeUnknownAkmMapping()197 private void initializeUnknownAkmMapping() { 198 String[] unknownAkmMapping = 199 mContext.getResources() 200 .getStringArray(R.array.config_wifiUnknownAkmToKnownAkmMapping); 201 if (unknownAkmMapping == null) { 202 return; 203 } 204 for (String line : unknownAkmMapping) { 205 if (line == null) { 206 continue; 207 } 208 String[] items = line.split(","); 209 if (items.length != 2) { 210 Log.e( 211 TAG, 212 "Failed to parse config_wifiUnknownAkmToKnownAkmMapping line=" 213 + line 214 + ". Should contain only two values separated by comma"); 215 continue; 216 } 217 try { 218 int unknownAkm = Integer.parseInt(items[0].trim()); 219 int knownAkm = Integer.parseInt(items[1].trim()); 220 // Convert the OEM configured known AKM suite selector to 221 // ScanResult security key management scheme(ScanResult.KEY_MGMT_XX)*/ 222 int keyMgmtScheme = 223 InformationElementUtil.Capabilities.akmToScanResultKeyManagementScheme( 224 knownAkm); 225 if (keyMgmtScheme != ScanResult.KEY_MGMT_UNKNOWN) { 226 if (mUnknownAkmMap == null) { 227 mUnknownAkmMap = new SparseIntArray(); 228 } 229 mUnknownAkmMap.put(unknownAkm, keyMgmtScheme); 230 Log.d( 231 TAG, 232 "unknown AKM = " 233 + unknownAkm 234 + " - converted keyMgmtScheme: " 235 + keyMgmtScheme); 236 } else { 237 Log.e( 238 TAG, 239 "Known AKM: " 240 + knownAkm 241 + " is not defined in the framework." 242 + " Hence Failed to add AKM: " 243 + unknownAkm 244 + " in UnknownAkmMap." 245 + " Parsed config from overlay: " 246 + line); 247 } 248 } catch (Exception e) { 249 // failure to parse. Something is wrong with the configuration. 250 Log.e( 251 TAG, 252 "Parsing config_wifiUnknownAkmToKnownAkmMapping line=" 253 + line 254 + ". Exception occurred:" 255 + e); 256 } 257 } 258 } 259 260 /** 261 * Enable verbose logging for all sub modules. 262 */ enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)263 public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) { 264 Log.d(TAG, "enableVerboseLogging " + verboseEnabled + " hal " + halVerboseEnabled); 265 mVerboseLoggingEnabled = verboseEnabled; 266 mWifiCondManager.enableVerboseLogging(verboseEnabled); 267 mSupplicantStaIfaceHal.enableVerboseLogging(verboseEnabled, halVerboseEnabled); 268 mHostapdHal.enableVerboseLogging(verboseEnabled, halVerboseEnabled); 269 mWifiVendorHal.enableVerboseLogging(verboseEnabled, halVerboseEnabled); 270 mIfaceMgr.enableVerboseLogging(verboseEnabled); 271 } 272 273 /** 274 * Get TWT capabilities for the interface 275 */ getTwtCapabilities(String interfaceName)276 public Bundle getTwtCapabilities(String interfaceName) { 277 return mCachedTwtCapabilities.get(interfaceName); 278 } 279 280 /** 281 * Whether USD subscriber is supported in USD capability or not. 282 */ isUsdSubscriberSupported()283 public boolean isUsdSubscriberSupported() { 284 return mCachedUsdCapabilities != null && mCachedUsdCapabilities.isUsdSubscriberSupported; 285 } 286 287 /** 288 * Whether USD publisher is supported in USD capability or not. 289 */ isUsdPublisherSupported()290 public boolean isUsdPublisherSupported() { 291 return mCachedUsdCapabilities != null && mCachedUsdCapabilities.isUsdPublisherSupported; 292 } 293 294 /** 295 * Gets USD capabilities. 296 */ getUsdCapabilities()297 public SupplicantStaIfaceHal.UsdCapabilitiesInternal getUsdCapabilities() { 298 return mCachedUsdCapabilities; 299 } 300 301 /** 302 * Start USD publish. 303 */ startUsdPublish(String interfaceName, int cmdId, PublishConfig publishConfig)304 public boolean startUsdPublish(String interfaceName, int cmdId, PublishConfig publishConfig) { 305 return mSupplicantStaIfaceHal.startUsdPublish(interfaceName, cmdId, publishConfig); 306 } 307 308 /** 309 * Register a framework callback to receive USD events from HAL. 310 */ registerUsdEventsCallback( UsdRequestManager.UsdNativeEventsCallback usdNativeEventsCallback)311 public void registerUsdEventsCallback( 312 UsdRequestManager.UsdNativeEventsCallback usdNativeEventsCallback) { 313 mSupplicantStaIfaceHal.registerUsdEventsCallback(usdNativeEventsCallback); 314 } 315 316 /** 317 * Start USD subscribe. 318 */ startUsdSubscribe(String interfaceName, int cmdId, SubscribeConfig subscribeConfig)319 public boolean startUsdSubscribe(String interfaceName, int cmdId, 320 SubscribeConfig subscribeConfig) { 321 return mSupplicantStaIfaceHal.startUsdSubscribe(interfaceName, cmdId, subscribeConfig); 322 } 323 324 /** 325 * Update USD publish. 326 */ updateUsdPublish(String interfaceName, int publishId, byte[] ssi)327 public void updateUsdPublish(String interfaceName, int publishId, byte[] ssi) { 328 mSupplicantStaIfaceHal.updateUsdPublish(interfaceName, publishId, ssi); 329 } 330 331 /** 332 * Cancel USD publish. 333 */ cancelUsdPublish(String interfaceName, int publishId)334 public void cancelUsdPublish(String interfaceName, int publishId) { 335 mSupplicantStaIfaceHal.cancelUsdPublish(interfaceName, publishId); 336 } 337 338 /** 339 * Cancel USD subscribe. 340 */ cancelUsdSubscribe(String interfaceName, int subscribeId)341 public void cancelUsdSubscribe(String interfaceName, int subscribeId) { 342 mSupplicantStaIfaceHal.cancelUsdSubscribe(interfaceName, subscribeId); 343 } 344 345 /** 346 * Send USD message to the peer identified by the peerId and the peerMacAddress. 347 */ sendUsdMessage(String interfaceName, int ownId, int peerId, MacAddress peerMacAddress, byte[] message)348 public boolean sendUsdMessage(String interfaceName, int ownId, int peerId, 349 MacAddress peerMacAddress, byte[] message) { 350 return mSupplicantStaIfaceHal.sendUsdMessage(interfaceName, ownId, peerId, peerMacAddress, 351 message); 352 } 353 354 /** 355 * Callbacks for SoftAp interface. 356 */ 357 public class SoftApHalCallbackFromWificond implements WifiNl80211Manager.SoftApCallback { 358 // placeholder for now - provide a shell so that clients don't use a 359 // WifiNl80211Manager-specific API. 360 private String mIfaceName; 361 private SoftApHalCallback mSoftApHalCallback; 362 SoftApHalCallbackFromWificond(String ifaceName, SoftApHalCallback softApHalCallback)363 SoftApHalCallbackFromWificond(String ifaceName, 364 SoftApHalCallback softApHalCallback) { 365 mIfaceName = ifaceName; 366 mSoftApHalCallback = softApHalCallback; 367 } 368 369 @Override onFailure()370 public void onFailure() { 371 mSoftApHalCallback.onFailure(); 372 } 373 374 @Override onSoftApChannelSwitched(int frequency, int bandwidth)375 public void onSoftApChannelSwitched(int frequency, int bandwidth) { 376 mSoftApHalCallback.onInfoChanged(mIfaceName, frequency, bandwidth, 377 ScanResult.WIFI_STANDARD_UNKNOWN, null, null, Collections.emptyList()); 378 } 379 380 @Override onConnectedClientsChanged(NativeWifiClient client, boolean isConnected)381 public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected) { 382 mSoftApHalCallback.onConnectedClientsChanged(mIfaceName, 383 client.getMacAddress(), isConnected, 384 DeauthenticationReasonCode.REASON_UNKNOWN); 385 } 386 } 387 388 @SuppressLint("NewApi") 389 private static class CountryCodeChangeListenerInternal implements 390 WifiNl80211Manager.CountryCodeChangedListener { 391 private WifiCountryCode.ChangeListener mListener; 392 setChangeListener(@onNull WifiCountryCode.ChangeListener listener)393 public void setChangeListener(@NonNull WifiCountryCode.ChangeListener listener) { 394 mListener = listener; 395 } 396 onSetCountryCodeSucceeded(String country)397 public void onSetCountryCodeSucceeded(String country) { 398 Log.d(TAG, "onSetCountryCodeSucceeded: " + country); 399 if (mListener != null) { 400 mListener.onSetCountryCodeSucceeded(country); 401 } 402 } 403 404 @Override onCountryCodeChanged(String country)405 public void onCountryCodeChanged(String country) { 406 Log.d(TAG, "onCountryCodeChanged: " + country); 407 if (mListener != null) { 408 mListener.onDriverCountryCodeChanged(country); 409 } 410 } 411 } 412 413 /** 414 * Callbacks for SoftAp instance. 415 */ 416 public interface SoftApHalCallback { 417 /** 418 * Invoked when there is a fatal failure and the SoftAp is shutdown. 419 */ onFailure()420 void onFailure(); 421 422 /** 423 * Invoked when there is a fatal happen in specific instance only. 424 */ onInstanceFailure(String instanceName)425 default void onInstanceFailure(String instanceName) {} 426 427 /** 428 * Invoked when a channel switch event happens - i.e. the SoftAp is moved to a different 429 * channel. Also called on initial registration. 430 * 431 * @param apIfaceInstance The identity of the ap instance. 432 * @param frequency The new frequency of the SoftAp. A value of 0 is invalid and is an 433 * indication that the SoftAp is not enabled. 434 * @param bandwidth The new bandwidth of the SoftAp. 435 * @param generation The new generation of the SoftAp. 436 * @param apIfaceInstanceMacAddress MAC Address of the apIfaceInstance. 437 * @param mldMacAddress MAC Address of the multiple link device (MLD) which apIfaceInstance 438 * is associated with. 439 * @param vendorData List of {@link OuiKeyedData} containing vendor-specific configuration 440 * data, or empty list if not provided. 441 */ onInfoChanged(String apIfaceInstance, int frequency, int bandwidth, int generation, @Nullable MacAddress apIfaceInstanceMacAddress, @Nullable MacAddress mldMacAddress, @NonNull List<OuiKeyedData> vendorData)442 void onInfoChanged(String apIfaceInstance, int frequency, int bandwidth, 443 int generation, @Nullable MacAddress apIfaceInstanceMacAddress, 444 @Nullable MacAddress mldMacAddress, 445 @NonNull List<OuiKeyedData> vendorData); 446 /** 447 * Invoked when there is a change in the associated station (STA). 448 * 449 * @param apIfaceInstance The identity of the ap instance. 450 * @param clientAddress Macaddress of the client. 451 * @param isConnected Indication as to whether the client is connected (true), or 452 * disconnected (false). 453 * @param disconnectReason The reason for disconnection, if applicable. This 454 * parameter is only meaningful when {@code isConnected} is false. 455 */ onConnectedClientsChanged(String apIfaceInstance, MacAddress clientAddress, boolean isConnected, @WifiAnnotations.SoftApDisconnectReason int disconnectReason)456 void onConnectedClientsChanged(String apIfaceInstance, MacAddress clientAddress, 457 boolean isConnected, @WifiAnnotations.SoftApDisconnectReason int disconnectReason); 458 } 459 460 /******************************************************** 461 * Interface management related methods. 462 ********************************************************/ 463 /** 464 * Meta-info about every iface that is active. 465 */ 466 public static class Iface { 467 /** Type of ifaces possible */ 468 public static final int IFACE_TYPE_AP = 0; 469 public static final int IFACE_TYPE_STA_FOR_CONNECTIVITY = 1; 470 public static final int IFACE_TYPE_STA_FOR_SCAN = 2; 471 public static final int IFACE_TYPE_P2P = 3; 472 public static final int IFACE_TYPE_NAN = 4; 473 474 @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA_FOR_CONNECTIVITY, IFACE_TYPE_STA_FOR_SCAN, 475 IFACE_TYPE_P2P, IFACE_TYPE_NAN}) 476 @Retention(RetentionPolicy.SOURCE) 477 public @interface IfaceType{} 478 479 /** Identifier allocated for the interface */ 480 public final int id; 481 /** Type of the iface: STA (for Connectivity or Scan) or AP */ 482 public @IfaceType int type; 483 /** Name of the interface */ 484 public String name; 485 /** Is the interface up? This is used to mask up/down notifications to external clients. */ 486 public boolean isUp; 487 /** External iface destroyed listener for the iface */ 488 public InterfaceCallback externalListener; 489 /** Network observer registered for this interface */ 490 public NetworkObserverInternal networkObserver; 491 /** Interface feature set / capabilities */ 492 public BitSet featureSet = new BitSet(); 493 public int bandsSupported; 494 public DeviceWiphyCapabilities phyCapabilities; 495 public WifiHal.WifiInterface iface; 496 Iface(int id, @Iface.IfaceType int type)497 Iface(int id, @Iface.IfaceType int type) { 498 this.id = id; 499 this.type = type; 500 } 501 502 @Override toString()503 public String toString() { 504 StringBuffer sb = new StringBuffer(); 505 String typeString; 506 switch(type) { 507 case IFACE_TYPE_STA_FOR_CONNECTIVITY: 508 typeString = "STA_CONNECTIVITY"; 509 break; 510 case IFACE_TYPE_STA_FOR_SCAN: 511 typeString = "STA_SCAN"; 512 break; 513 case IFACE_TYPE_AP: 514 typeString = "AP"; 515 break; 516 case IFACE_TYPE_P2P: 517 typeString = "P2P"; 518 break; 519 case IFACE_TYPE_NAN: 520 typeString = "NAN"; 521 break; 522 default: 523 typeString = "<UNKNOWN>"; 524 break; 525 } 526 sb.append("Iface:") 527 .append("{") 528 .append("Name=").append(name) 529 .append(",") 530 .append("Id=").append(id) 531 .append(",") 532 .append("Type=").append(typeString) 533 .append("}"); 534 return sb.toString(); 535 } 536 } 537 538 /** 539 * Iface Management entity. This class maintains list of all the active ifaces. 540 */ 541 private static class IfaceManager { 542 /** Integer to allocate for the next iface being created */ 543 private int mNextId; 544 /** Map of the id to the iface structure */ 545 private HashMap<Integer, Iface> mIfaces = new HashMap<>(); 546 private boolean mVerboseLoggingEnabled = false; 547 enableVerboseLogging(boolean enable)548 public void enableVerboseLogging(boolean enable) { 549 mVerboseLoggingEnabled = enable; 550 } 551 552 /** Allocate a new iface for the given type */ allocateIface(@face.IfaceType int type)553 private Iface allocateIface(@Iface.IfaceType int type) { 554 if (mVerboseLoggingEnabled) { 555 Log.d(TAG, "IfaceManager#allocateIface: type=" + type + ", pre-map=" + mIfaces); 556 } 557 Iface iface = new Iface(mNextId, type); 558 mIfaces.put(mNextId, iface); 559 mNextId++; 560 return iface; 561 } 562 563 /** Remove the iface using the provided id */ removeIface(int id)564 private Iface removeIface(int id) { 565 if (mVerboseLoggingEnabled) { 566 Log.d(TAG, "IfaceManager#removeIface: id=" + id + ", pre-map=" + mIfaces); 567 } 568 return mIfaces.remove(id); 569 } 570 571 /** Lookup the iface using the provided id */ getIface(int id)572 private Iface getIface(int id) { 573 return mIfaces.get(id); 574 } 575 576 /** Lookup the iface using the provided name */ getIface(@onNull String ifaceName)577 private Iface getIface(@NonNull String ifaceName) { 578 for (Iface iface : mIfaces.values()) { 579 if (TextUtils.equals(iface.name, ifaceName)) { 580 return iface; 581 } 582 } 583 return null; 584 } 585 586 /** Iterator to use for deleting all the ifaces while performing teardown on each of them */ getIfaceIdIter()587 private Iterator<Integer> getIfaceIdIter() { 588 return mIfaces.keySet().iterator(); 589 } 590 591 /** Checks if there are any iface active. */ hasAnyIface()592 private boolean hasAnyIface() { 593 return !mIfaces.isEmpty(); 594 } 595 596 /** Checks if there are any iface of the given type active. */ hasAnyIfaceOfType(@face.IfaceType int type)597 private boolean hasAnyIfaceOfType(@Iface.IfaceType int type) { 598 for (Iface iface : mIfaces.values()) { 599 if (iface.type == type) { 600 return true; 601 } 602 } 603 return false; 604 } 605 606 /** Checks if there are any P2P iface active. */ hasAnyP2pIface()607 private boolean hasAnyP2pIface() { 608 return hasAnyIfaceOfType(Iface.IFACE_TYPE_P2P); 609 } 610 611 /** Checks if there are any STA (for connectivity) iface active. */ hasAnyStaIfaceForConnectivity()612 private boolean hasAnyStaIfaceForConnectivity() { 613 return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY); 614 } 615 616 /** Checks if there are any STA (for scan) iface active. */ hasAnyStaIfaceForScan()617 private boolean hasAnyStaIfaceForScan() { 618 return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_SCAN); 619 } 620 621 /** Checks if there are any AP iface active. */ hasAnyApIface()622 private boolean hasAnyApIface() { 623 return hasAnyIfaceOfType(Iface.IFACE_TYPE_AP); 624 } 625 findAllStaIfaceNames()626 private @NonNull Set<String> findAllStaIfaceNames() { 627 Set<String> ifaceNames = new ArraySet<>(); 628 for (Iface iface : mIfaces.values()) { 629 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY 630 || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 631 ifaceNames.add(iface.name); 632 } 633 } 634 return ifaceNames; 635 } 636 findAllApIfaceNames()637 private @NonNull Set<String> findAllApIfaceNames() { 638 Set<String> ifaceNames = new ArraySet<>(); 639 for (Iface iface : mIfaces.values()) { 640 if (iface.type == Iface.IFACE_TYPE_AP) { 641 ifaceNames.add(iface.name); 642 } 643 } 644 return ifaceNames; 645 } 646 647 /** Removes the existing iface that does not match the provided id. */ removeExistingIface(int newIfaceId)648 public Iface removeExistingIface(int newIfaceId) { 649 if (mVerboseLoggingEnabled) { 650 Log.d(TAG, "IfaceManager#removeExistingIface: newIfaceId=" + newIfaceId 651 + ", pre-map=" + mIfaces); 652 } 653 Iface removedIface = null; 654 // The number of ifaces in the database could be 1 existing & 1 new at the max. 655 if (mIfaces.size() > 2) { 656 Log.wtf(TAG, "More than 1 existing interface found"); 657 } 658 Iterator<Map.Entry<Integer, Iface>> iter = mIfaces.entrySet().iterator(); 659 while (iter.hasNext()) { 660 Map.Entry<Integer, Iface> entry = iter.next(); 661 if (entry.getKey() != newIfaceId) { 662 removedIface = entry.getValue(); 663 iter.remove(); 664 } 665 } 666 return removedIface; 667 } 668 669 @Override toString()670 public String toString() { 671 return mIfaces.toString(); 672 } 673 } 674 675 private class NormalScanEventCallback implements WifiNl80211Manager.ScanEventCallback { 676 private String mIfaceName; 677 NormalScanEventCallback(String ifaceName)678 NormalScanEventCallback(String ifaceName) { 679 mIfaceName = ifaceName; 680 } 681 682 @Override onScanResultReady()683 public void onScanResultReady() { 684 Log.d(TAG, "Scan result ready event"); 685 mWifiMonitor.broadcastScanResultEvent(mIfaceName); 686 } 687 688 @Override onScanFailed()689 public void onScanFailed() { 690 Log.d(TAG, "Scan failed event"); 691 mWifiMonitor.broadcastScanFailedEvent(mIfaceName, WifiScanner.REASON_UNSPECIFIED); 692 } 693 694 @Override onScanFailed(int errorCode)695 public void onScanFailed(int errorCode) { 696 Log.d(TAG, "Scan failed event: errorCode: " + errorCode); 697 mWifiMonitor.broadcastScanFailedEvent(mIfaceName, errorCode); 698 } 699 } 700 701 private class PnoScanEventCallback implements WifiNl80211Manager.ScanEventCallback { 702 private String mIfaceName; 703 PnoScanEventCallback(String ifaceName)704 PnoScanEventCallback(String ifaceName) { 705 mIfaceName = ifaceName; 706 } 707 708 @Override onScanResultReady()709 public void onScanResultReady() { 710 Log.d(TAG, "Pno scan result event"); 711 mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName); 712 mWifiMetrics.incrementPnoFoundNetworkEventCount(); 713 } 714 715 @Override onScanFailed()716 public void onScanFailed() { 717 Log.d(TAG, "Pno Scan failed event"); 718 WifiStatsLog.write(WifiStatsLog.PNO_SCAN_STOPPED, 719 WifiStatsLog.PNO_SCAN_STOPPED__STOP_REASON__SCAN_FAILED, 720 0, false, false, false, false, // default values 721 WifiStatsLog.PNO_SCAN_STOPPED__FAILURE_CODE__WIFICOND_SCAN_FAILURE); 722 } 723 } 724 725 private final Object mLock = new Object(); 726 private final IfaceManager mIfaceMgr = new IfaceManager(); 727 private HashSet<StatusListener> mStatusListeners = new HashSet<>(); 728 729 /** Helper method invoked to start supplicant if there were no ifaces */ startHal()730 private boolean startHal() { 731 synchronized (mLock) { 732 if (!mIfaceMgr.hasAnyIface()) { 733 if (mWifiVendorHal.isVendorHalSupported()) { 734 if (!mWifiVendorHal.startVendorHal()) { 735 Log.e(TAG, "Failed to start vendor HAL"); 736 return false; 737 } 738 if (SdkLevel.isAtLeastS()) { 739 mWifiVendorHal.setCoexUnsafeChannels( 740 mCachedCoexUnsafeChannels, mCachedCoexRestrictions); 741 } 742 } else { 743 Log.i(TAG, "Vendor Hal not supported, ignoring start."); 744 } 745 } 746 registerWificondListenerIfNecessary(); 747 return true; 748 } 749 } 750 751 /** Helper method invoked to stop HAL if there are no more ifaces */ stopHalAndWificondIfNecessary()752 private void stopHalAndWificondIfNecessary() { 753 synchronized (mLock) { 754 if (!mIfaceMgr.hasAnyIface()) { 755 if (!mWifiCondManager.tearDownInterfaces()) { 756 Log.e(TAG, "Failed to teardown ifaces from wificond"); 757 } 758 if (mWifiVendorHal.isVendorHalSupported()) { 759 mWifiVendorHal.stopVendorHal(); 760 } else { 761 Log.i(TAG, "Vendor Hal not supported, ignoring stop."); 762 } 763 } 764 } 765 } 766 767 /** 768 * Helper method invoked to setup wificond related callback/listener. 769 */ registerWificondListenerIfNecessary()770 private void registerWificondListenerIfNecessary() { 771 if (mCountryCodeChangeListener == null && SdkLevel.isAtLeastS()) { 772 // The country code listener is a new API in S. 773 mCountryCodeChangeListener = new CountryCodeChangeListenerInternal(); 774 mWifiCondManager.registerCountryCodeChangedListener(Runnable::run, 775 mCountryCodeChangeListener); 776 } 777 } 778 779 private static final int CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS = 100; 780 private static final int CONNECT_TO_SUPPLICANT_RETRY_TIMES = 50; 781 /** 782 * This method is called to wait for establishing connection to wpa_supplicant. 783 * 784 * @return true if connection is established, false otherwise. 785 */ startAndWaitForSupplicantConnection()786 private boolean startAndWaitForSupplicantConnection() { 787 // Start initialization if not already started. 788 if (!mSupplicantStaIfaceHal.isInitializationStarted() 789 && !mSupplicantStaIfaceHal.initialize()) { 790 return false; 791 } 792 if (!mSupplicantStaIfaceHal.startDaemon()) { 793 Log.e(TAG, "Failed to startup supplicant"); 794 return false; 795 } 796 boolean connected = false; 797 int connectTries = 0; 798 while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) { 799 // Check if the initialization is complete. 800 connected = mSupplicantStaIfaceHal.isInitializationComplete(); 801 if (connected) { 802 break; 803 } 804 try { 805 Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS); 806 } catch (InterruptedException ignore) { 807 } 808 } 809 return connected; 810 } 811 812 /** Helper method invoked to start supplicant if there were no STA ifaces */ startSupplicant()813 private boolean startSupplicant() { 814 synchronized (mLock) { 815 if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) { 816 if (!startAndWaitForSupplicantConnection()) { 817 Log.e(TAG, "Failed to connect to supplicant"); 818 return false; 819 } 820 if (!mSupplicantStaIfaceHal.registerDeathHandler( 821 new SupplicantDeathHandlerInternal())) { 822 Log.e(TAG, "Failed to register supplicant death handler"); 823 return false; 824 } 825 if (mMainlineSupplicant.isAvailable()) { 826 if (mMainlineSupplicant.startService()) { 827 mMainlineSupplicant.registerFrameworkDeathHandler( 828 new MainlineSupplicantDeathHandlerInternal()); 829 } else { 830 // Fail quietly if the mainline supplicant does not start 831 Log.e(TAG, "Unable to start the mainline supplicant"); 832 } 833 } 834 } 835 return true; 836 } 837 } 838 839 /** Helper method invoked to stop supplicant if there are no more STA ifaces */ stopSupplicantIfNecessary()840 private void stopSupplicantIfNecessary() { 841 synchronized (mLock) { 842 if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) { 843 if (mSupplicantStaIfaceHal.isInitializationStarted()) { 844 if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) { 845 Log.e(TAG, "Failed to deregister supplicant death handler"); 846 } 847 848 } 849 if (!mIfaceMgr.hasAnyP2pIface()) { 850 if (mSupplicantStaIfaceHal.isInitializationStarted()) { 851 mSupplicantStaIfaceHal.terminate(); 852 } else { 853 mWifiInjector.getWifiP2pNative().stopP2pSupplicantIfNecessary(); 854 } 855 } 856 857 // Mainline supplicant should be disabled if no STA ifaces are in use 858 if (mMainlineSupplicant.isActive()) { 859 mMainlineSupplicant.unregisterFrameworkDeathHandler(); 860 mMainlineSupplicant.stopService(); 861 } 862 } 863 } 864 } 865 866 /** Helper method invoked to start hostapd if there were no AP ifaces */ startHostapd()867 private boolean startHostapd() { 868 synchronized (mLock) { 869 if (!mIfaceMgr.hasAnyApIface()) { 870 if (!startAndWaitForHostapdConnection()) { 871 Log.e(TAG, "Failed to connect to hostapd"); 872 return false; 873 } 874 if (!mHostapdHal.registerDeathHandler( 875 new HostapdDeathHandlerInternal())) { 876 Log.e(TAG, "Failed to register hostapd death handler"); 877 return false; 878 } 879 } 880 return true; 881 } 882 } 883 884 /** Helper method invoked to stop hostapd if there are no more AP ifaces */ stopHostapdIfNecessary()885 private void stopHostapdIfNecessary() { 886 synchronized (mLock) { 887 if (!mIfaceMgr.hasAnyApIface()) { 888 if (!mHostapdHal.deregisterDeathHandler()) { 889 Log.e(TAG, "Failed to deregister hostapd death handler"); 890 } 891 mHostapdHal.terminate(); 892 } 893 } 894 } 895 896 /** 897 * Helper method to register a new {@link InterfaceObserverInternal}, if there is no previous 898 * observer in place and {@link WifiGlobals#isWifiInterfaceAddedSelfRecoveryEnabled()} is 899 * enabled. 900 */ registerInterfaceObserver()901 private void registerInterfaceObserver() { 902 if (!mWifiInjector.getWifiGlobals().isWifiInterfaceAddedSelfRecoveryEnabled()) { 903 return; 904 } 905 if (mInterfaceObserver != null) { 906 Log.d(TAG, "Interface observer has previously been registered."); 907 return; 908 } 909 mInterfaceObserver = new InterfaceObserverInternal(); 910 mNetdWrapper.registerObserver(mInterfaceObserver); 911 Log.d(TAG, "Registered new interface observer."); 912 } 913 914 /** Helper method to register a network observer and return it */ registerNetworkObserver(NetworkObserverInternal observer)915 private boolean registerNetworkObserver(NetworkObserverInternal observer) { 916 if (observer == null) return false; 917 mNetdWrapper.registerObserver(observer); 918 return true; 919 } 920 921 /** Helper method to unregister a network observer */ unregisterNetworkObserver(NetworkObserverInternal observer)922 private boolean unregisterNetworkObserver(NetworkObserverInternal observer) { 923 if (observer == null) return false; 924 mNetdWrapper.unregisterObserver(observer); 925 return true; 926 } 927 928 /** 929 * Helper method invoked to teardown client iface (for connectivity) and perform 930 * necessary cleanup 931 */ onClientInterfaceForConnectivityDestroyed(@onNull Iface iface)932 private void onClientInterfaceForConnectivityDestroyed(@NonNull Iface iface) { 933 synchronized (mLock) { 934 mWifiMonitor.stopMonitoring(iface.name); 935 if (!unregisterNetworkObserver(iface.networkObserver)) { 936 Log.e(TAG, "Failed to unregister network observer on " + iface); 937 } 938 if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) { 939 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface); 940 } 941 if (mMainlineSupplicant.isActive() 942 && !mMainlineSupplicant.removeStaInterface(iface.name)) { 943 Log.e(TAG, "Unable to tear down " + iface.name + " in the mainline supplicant" 944 + " after client interface destroyed"); 945 } 946 if (!mWifiCondManager.tearDownClientInterface(iface.name)) { 947 Log.e(TAG, "Failed to teardown iface in wificond on " + iface); 948 } 949 stopSupplicantIfNecessary(); 950 stopHalAndWificondIfNecessary(); 951 } 952 } 953 954 /** Helper method invoked to teardown client iface (for scan) and perform necessary cleanup */ onClientInterfaceForScanDestroyed(@onNull Iface iface)955 private void onClientInterfaceForScanDestroyed(@NonNull Iface iface) { 956 synchronized (mLock) { 957 mWifiMonitor.stopMonitoring(iface.name); 958 if (!unregisterNetworkObserver(iface.networkObserver)) { 959 Log.e(TAG, "Failed to unregister network observer on " + iface); 960 } 961 if (!mWifiCondManager.tearDownClientInterface(iface.name)) { 962 Log.e(TAG, "Failed to teardown iface in wificond on " + iface); 963 } 964 stopHalAndWificondIfNecessary(); 965 } 966 } 967 968 /** Helper method invoked to teardown softAp iface and perform necessary cleanup */ onSoftApInterfaceDestroyed(@onNull Iface iface)969 private void onSoftApInterfaceDestroyed(@NonNull Iface iface) { 970 synchronized (mLock) { 971 if (!unregisterNetworkObserver(iface.networkObserver)) { 972 Log.e(TAG, "Failed to unregister network observer on " + iface); 973 } 974 if (!mHostapdHal.removeAccessPoint(iface.name)) { 975 Log.e(TAG, "Failed to remove access point on " + iface); 976 } 977 String wificondIface = iface.name; 978 String bridgedApInstance = mWifiCondIfacesForBridgedAp.remove(iface.name); 979 if (bridgedApInstance != null) { 980 wificondIface = bridgedApInstance; 981 } 982 if (!mWifiCondManager.tearDownSoftApInterface(wificondIface)) { 983 Log.e(TAG, "Failed to teardown iface in wificond on " + iface); 984 } 985 stopHostapdIfNecessary(); 986 stopHalAndWificondIfNecessary(); 987 } 988 } 989 990 /** Helper method invoked to teardown iface and perform necessary cleanup */ onInterfaceDestroyed(@onNull Iface iface)991 private void onInterfaceDestroyed(@NonNull Iface iface) { 992 synchronized (mLock) { 993 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) { 994 onClientInterfaceForConnectivityDestroyed(iface); 995 } else if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 996 onClientInterfaceForScanDestroyed(iface); 997 } else if (iface.type == Iface.IFACE_TYPE_AP) { 998 onSoftApInterfaceDestroyed(iface); 999 } 1000 // Invoke the external callback only if the iface was not destroyed because of vendor 1001 // HAL crash. In case of vendor HAL crash, let the crash recovery destroy the mode 1002 // managers. 1003 if (mWifiVendorHal.isVendorHalReady()) { 1004 iface.externalListener.onDestroyed(iface.name); 1005 } 1006 } 1007 } 1008 1009 /** 1010 * Callback to be invoked by HalDeviceManager when an interface is destroyed. 1011 */ 1012 private class InterfaceDestoyedListenerInternal 1013 implements HalDeviceManager.InterfaceDestroyedListener { 1014 /** Identifier allocated for the interface */ 1015 private final int mInterfaceId; 1016 InterfaceDestoyedListenerInternal(int ifaceId)1017 InterfaceDestoyedListenerInternal(int ifaceId) { 1018 mInterfaceId = ifaceId; 1019 } 1020 1021 @Override onDestroyed(@onNull String ifaceName)1022 public void onDestroyed(@NonNull String ifaceName) { 1023 synchronized (mLock) { 1024 final Iface iface = mIfaceMgr.removeIface(mInterfaceId); 1025 if (iface == null) { 1026 if (mVerboseLoggingEnabled) { 1027 Log.v(TAG, "Received iface destroyed notification on an invalid iface=" 1028 + ifaceName); 1029 } 1030 return; 1031 } 1032 onInterfaceDestroyed(iface); 1033 Log.i(TAG, "Successfully torn down " + iface); 1034 } 1035 } 1036 } 1037 1038 /** 1039 * Helper method invoked to trigger the status changed callback after one of the native 1040 * daemon's death. 1041 */ onNativeDaemonDeath()1042 private void onNativeDaemonDeath() { 1043 synchronized (mLock) { 1044 for (StatusListener listener : mStatusListeners) { 1045 listener.onStatusChanged(false); 1046 } 1047 for (StatusListener listener : mStatusListeners) { 1048 listener.onStatusChanged(true); 1049 } 1050 } 1051 } 1052 1053 /** 1054 * Death handler for the Vendor HAL daemon. 1055 */ 1056 private class VendorHalDeathHandlerInternal implements VendorHalDeathEventHandler { 1057 @Override onDeath()1058 public void onDeath() { 1059 mHandler.post(() -> { 1060 Log.i(TAG, "Vendor HAL died. Cleaning up internal state."); 1061 onNativeDaemonDeath(); 1062 mWifiMetrics.incrementNumHalCrashes(); 1063 }); 1064 } 1065 } 1066 1067 /** 1068 * Death handler for the wificond daemon. 1069 */ 1070 private class WificondDeathHandlerInternal implements Runnable { 1071 @Override run()1072 public void run() { 1073 mHandler.post(() -> { 1074 Log.i(TAG, "wificond died. Cleaning up internal state."); 1075 onNativeDaemonDeath(); 1076 mWifiMetrics.incrementNumWificondCrashes(); 1077 }); 1078 } 1079 } 1080 1081 /** 1082 * Death handler for the supplicant daemon. 1083 */ 1084 private class SupplicantDeathHandlerInternal implements SupplicantDeathEventHandler { 1085 @Override onDeath()1086 public void onDeath() { 1087 mHandler.post(() -> { 1088 Log.i(TAG, "wpa_supplicant died. Cleaning up internal state."); 1089 onNativeDaemonDeath(); 1090 mWifiMetrics.incrementNumSupplicantCrashes(); 1091 }); 1092 } 1093 } 1094 1095 /** 1096 * Death handler for the hostapd daemon. 1097 */ 1098 private class HostapdDeathHandlerInternal implements HostapdDeathEventHandler { 1099 @Override onDeath()1100 public void onDeath() { 1101 mHandler.post(() -> { 1102 Log.i(TAG, "hostapd died. Cleaning up internal state."); 1103 onNativeDaemonDeath(); 1104 mWifiMetrics.incrementNumHostapdCrashes(); 1105 }); 1106 } 1107 } 1108 1109 /** 1110 * Death handler for the mainline supplicant. 1111 */ 1112 private class MainlineSupplicantDeathHandlerInternal implements SupplicantDeathEventHandler { onDeath()1113 public void onDeath() { 1114 mHandler.post(() -> { 1115 // TODO: Add metrics for mainline supplicant crashes 1116 Log.i(TAG, "Mainline supplicant died. Cleaning up internal state."); 1117 onNativeDaemonDeath(); 1118 }); 1119 } 1120 } 1121 1122 /** Helper method invoked to handle interface change. */ onInterfaceStateChanged(Iface iface, boolean isUp)1123 private void onInterfaceStateChanged(Iface iface, boolean isUp) { 1124 synchronized (mLock) { 1125 // Mask multiple notifications with the same state. 1126 if (isUp == iface.isUp) { 1127 if (mVerboseLoggingEnabled) { 1128 Log.v(TAG, "Interface status unchanged on " + iface + " from " + isUp 1129 + ", Ignoring..."); 1130 } 1131 return; 1132 } 1133 Log.i(TAG, "Interface state changed on " + iface + ", isUp=" + isUp); 1134 if (isUp) { 1135 iface.externalListener.onUp(iface.name); 1136 } else { 1137 iface.externalListener.onDown(iface.name); 1138 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY 1139 || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 1140 mWifiMetrics.incrementNumClientInterfaceDown(); 1141 } else if (iface.type == Iface.IFACE_TYPE_AP) { 1142 mWifiMetrics.incrementNumSoftApInterfaceDown(); 1143 } 1144 } 1145 iface.isUp = isUp; 1146 } 1147 } 1148 1149 /** 1150 * Listener for wifi interface events. 1151 */ 1152 public interface InterfaceEventCallback { 1153 1154 /** 1155 * Interface physical-layer link state has changed. 1156 * 1157 * @param ifaceName The interface. 1158 * @param isLinkUp True if the physical link-layer connection signal is valid. 1159 */ onInterfaceLinkStateChanged(String ifaceName, boolean isLinkUp)1160 void onInterfaceLinkStateChanged(String ifaceName, boolean isLinkUp); 1161 1162 /** 1163 * Interface has been added. 1164 * 1165 * @param ifaceName Name of the interface. 1166 */ onInterfaceAdded(String ifaceName)1167 void onInterfaceAdded(String ifaceName); 1168 } 1169 1170 /** 1171 * Register a listener for wifi interface events. 1172 * 1173 * @param ifaceEventCallback Listener object. 1174 */ setWifiNativeInterfaceEventCallback(InterfaceEventCallback ifaceEventCallback)1175 public void setWifiNativeInterfaceEventCallback(InterfaceEventCallback ifaceEventCallback) { 1176 mInterfaceListener = ifaceEventCallback; 1177 Log.d(TAG, "setWifiNativeInterfaceEventCallback"); 1178 } 1179 1180 private class InterfaceObserverInternal implements NetdEventObserver { 1181 private static final String TAG = "InterfaceObserverInternal"; 1182 private final String mSelfRecoveryInterfaceName = mContext.getResources().getString( 1183 R.string.config_wifiSelfRecoveryInterfaceName); 1184 1185 @Override interfaceLinkStateChanged(String ifaceName, boolean isLinkUp)1186 public void interfaceLinkStateChanged(String ifaceName, boolean isLinkUp) { 1187 if (!ifaceName.equals(mSelfRecoveryInterfaceName)) { 1188 return; 1189 } 1190 Log.d(TAG, "Received interfaceLinkStateChanged, iface=" + ifaceName + " up=" 1191 + isLinkUp); 1192 if (mInterfaceListener != null) { 1193 mInterfaceListener.onInterfaceLinkStateChanged(ifaceName, isLinkUp); 1194 } else { 1195 Log.e(TAG, "Received interfaceLinkStateChanged, interfaceListener=null"); 1196 } 1197 } 1198 1199 @Override interfaceStatusChanged(String iface, boolean up)1200 public void interfaceStatusChanged(String iface, boolean up) { 1201 // unused. 1202 } 1203 1204 @Override interfaceAdded(String ifaceName)1205 public void interfaceAdded(String ifaceName) { 1206 if (!ifaceName.equals(mSelfRecoveryInterfaceName)) { 1207 return; 1208 } 1209 Log.d(TAG, "Received interfaceAdded, iface=" + ifaceName); 1210 if (mInterfaceListener != null) { 1211 mInterfaceListener.onInterfaceAdded(ifaceName); 1212 } else { 1213 Log.e(TAG, "Received interfaceAdded, interfaceListener=null"); 1214 } 1215 } 1216 1217 } 1218 1219 /** 1220 * Network observer to use for all interface up/down notifications. 1221 */ 1222 private class NetworkObserverInternal implements NetdEventObserver { 1223 /** Identifier allocated for the interface */ 1224 private final int mInterfaceId; 1225 NetworkObserverInternal(int id)1226 NetworkObserverInternal(int id) { 1227 mInterfaceId = id; 1228 } 1229 1230 /** 1231 * Note: We should ideally listen to 1232 * {@link NetdEventObserver#interfaceStatusChanged(String, boolean)} here. But, that 1233 * callback is not working currently (broken in netd). So, instead listen to link state 1234 * change callbacks as triggers to query the real interface state. We should get rid of 1235 * this workaround if we get the |interfaceStatusChanged| callback to work in netd. 1236 * Also, this workaround will not detect an interface up event, if the link state is 1237 * still down. 1238 */ 1239 @Override interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp)1240 public void interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp) { 1241 // This is invoked from the main system_server thread. Post to our handler. 1242 mHandler.post(() -> { 1243 synchronized (mLock) { 1244 if (mVerboseLoggingEnabled) { 1245 Log.d(TAG, "interfaceLinkStateChanged: ifaceName=" + ifaceName 1246 + ", mInterfaceId = " + mInterfaceId 1247 + ", mIfaceMgr=" + mIfaceMgr.toString()); 1248 } 1249 final Iface ifaceWithId = mIfaceMgr.getIface(mInterfaceId); 1250 if (ifaceWithId == null) { 1251 if (mVerboseLoggingEnabled) { 1252 Log.v(TAG, "Received iface link up/down notification on an invalid" 1253 + " iface=" + mInterfaceId); 1254 } 1255 return; 1256 } 1257 final Iface ifaceWithName = mIfaceMgr.getIface(ifaceName); 1258 if (ifaceWithName == null || ifaceWithName != ifaceWithId) { 1259 if (mVerboseLoggingEnabled) { 1260 Log.v(TAG, "Received iface link up/down notification on an invalid" 1261 + " iface=" + ifaceName); 1262 } 1263 return; 1264 } 1265 onInterfaceStateChanged(ifaceWithName, isInterfaceUp(ifaceName)); 1266 } 1267 }); 1268 } 1269 1270 @Override interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp)1271 public void interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp) { 1272 // unused currently. Look at note above. 1273 } 1274 1275 @Override interfaceAdded(String iface)1276 public void interfaceAdded(String iface){ 1277 // unused currently. 1278 } 1279 } 1280 1281 /** 1282 * Radio mode change handler for the Vendor HAL daemon. 1283 */ 1284 private class VendorHalRadioModeChangeHandlerInternal 1285 implements VendorHalRadioModeChangeEventHandler { 1286 @Override onMcc(int band)1287 public void onMcc(int band) { 1288 synchronized (mLock) { 1289 Log.i(TAG, "Device is in MCC mode now"); 1290 mWifiMetrics.incrementNumRadioModeChangeToMcc(); 1291 } 1292 } 1293 @Override onScc(int band)1294 public void onScc(int band) { 1295 synchronized (mLock) { 1296 Log.i(TAG, "Device is in SCC mode now"); 1297 mWifiMetrics.incrementNumRadioModeChangeToScc(); 1298 } 1299 } 1300 @Override onSbs(int band)1301 public void onSbs(int band) { 1302 synchronized (mLock) { 1303 Log.i(TAG, "Device is in SBS mode now"); 1304 mWifiMetrics.incrementNumRadioModeChangeToSbs(); 1305 } 1306 } 1307 @Override onDbs()1308 public void onDbs() { 1309 synchronized (mLock) { 1310 Log.i(TAG, "Device is in DBS mode now"); 1311 mWifiMetrics.incrementNumRadioModeChangeToDbs(); 1312 } 1313 } 1314 } 1315 1316 // For devices that don't support the vendor HAL, we will not support any concurrency. 1317 // So simulate the HalDeviceManager behavior by triggering the destroy listener for 1318 // any active interface. handleIfaceCreationWhenVendorHalNotSupported(@onNull Iface newIface)1319 private String handleIfaceCreationWhenVendorHalNotSupported(@NonNull Iface newIface) { 1320 synchronized (mLock) { 1321 Iface existingIface = mIfaceMgr.removeExistingIface(newIface.id); 1322 if (existingIface != null) { 1323 onInterfaceDestroyed(existingIface); 1324 Log.i(TAG, "Successfully torn down " + existingIface); 1325 } 1326 // Return the interface name directly from the system property. 1327 return mPropertyService.getString("wifi.interface", "wlan0"); 1328 } 1329 } 1330 1331 /** 1332 * Helper function to handle creation of STA iface. 1333 * For devices which do not the support the HAL, this will bypass HalDeviceManager & 1334 * teardown any existing iface. 1335 */ createStaIface(@onNull Iface iface, @NonNull WorkSource requestorWs, @NonNull ConcreteClientModeManager concreteClientModeManager)1336 private String createStaIface(@NonNull Iface iface, @NonNull WorkSource requestorWs, 1337 @NonNull ConcreteClientModeManager concreteClientModeManager) { 1338 synchronized (mLock) { 1339 if (mWifiVendorHal.isVendorHalSupported()) { 1340 return mWifiVendorHal.createStaIface( 1341 new InterfaceDestoyedListenerInternal(iface.id), requestorWs, 1342 concreteClientModeManager); 1343 } else { 1344 Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface."); 1345 return handleIfaceCreationWhenVendorHalNotSupported(iface); 1346 } 1347 } 1348 } 1349 1350 /** 1351 * Helper function to handle creation of AP iface. 1352 * For devices which do not the support the HAL, this will bypass HalDeviceManager & 1353 * teardown any existing iface. 1354 */ createApIface(@onNull Iface iface, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged, @NonNull SoftApManager softApManager, @NonNull List<OuiKeyedData> vendorData)1355 private String createApIface(@NonNull Iface iface, @NonNull WorkSource requestorWs, 1356 @SoftApConfiguration.BandType int band, boolean isBridged, 1357 @NonNull SoftApManager softApManager, @NonNull List<OuiKeyedData> vendorData) { 1358 synchronized (mLock) { 1359 if (mWifiVendorHal.isVendorHalSupported()) { 1360 return mWifiVendorHal.createApIface( 1361 new InterfaceDestoyedListenerInternal(iface.id), requestorWs, 1362 band, isBridged, softApManager, vendorData); 1363 } else { 1364 Log.i(TAG, "Vendor Hal not supported, ignoring createApIface."); 1365 return handleIfaceCreationWhenVendorHalNotSupported(iface); 1366 } 1367 } 1368 } 1369 createP2pIfaceFromHalOrGetNameFromProperty( HalDeviceManager.InterfaceDestroyedListener p2pInterfaceDestroyedListener, Handler handler, WorkSource requestorWs)1370 private String createP2pIfaceFromHalOrGetNameFromProperty( 1371 HalDeviceManager.InterfaceDestroyedListener p2pInterfaceDestroyedListener, 1372 Handler handler, WorkSource requestorWs) { 1373 synchronized (mLock) { 1374 if (mWifiVendorHal.isVendorHalSupported()) { 1375 return mWifiInjector.getHalDeviceManager().createP2pIface( 1376 p2pInterfaceDestroyedListener, handler, requestorWs); 1377 } else { 1378 Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface."); 1379 return mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME); 1380 } 1381 } 1382 } 1383 1384 /** 1385 * Helper function to handle creation of P2P iface. 1386 * For devices which do not the support the HAL, this will bypass HalDeviceManager & 1387 * teardown any existing iface. 1388 */ createP2pIface( HalDeviceManager.InterfaceDestroyedListener p2pInterfaceDestroyedListener, Handler handler, WorkSource requestorWs)1389 public Iface createP2pIface( 1390 HalDeviceManager.InterfaceDestroyedListener p2pInterfaceDestroyedListener, 1391 Handler handler, WorkSource requestorWs) { 1392 synchronized (mLock) { 1393 // Make sure HAL is started for p2p 1394 if (!startHal()) { 1395 Log.e(TAG, "Failed to start Hal"); 1396 mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToHal(); 1397 return null; 1398 } 1399 // maintain iface status in WifiNative 1400 Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_P2P); 1401 if (iface == null) { 1402 Log.e(TAG, "Failed to allocate new P2P iface"); 1403 stopHalAndWificondIfNecessary(); 1404 return null; 1405 } 1406 iface.name = createP2pIfaceFromHalOrGetNameFromProperty( 1407 p2pInterfaceDestroyedListener, handler, requestorWs); 1408 if (TextUtils.isEmpty(iface.name)) { 1409 Log.e(TAG, "Failed to create P2p iface in HalDeviceManager"); 1410 mIfaceMgr.removeIface(iface.id); 1411 mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToHal(); 1412 stopHalAndWificondIfNecessary(); 1413 return null; 1414 } 1415 return iface; 1416 } 1417 } 1418 1419 /** 1420 * Teardown P2p iface with input interface Id which was returned by createP2pIface. 1421 * 1422 * @param interfaceId the interface identify which was gerenated when creating P2p iface. 1423 */ teardownP2pIface(int interfaceId)1424 public void teardownP2pIface(int interfaceId) { 1425 synchronized (mLock) { 1426 mIfaceMgr.removeIface(interfaceId); 1427 stopHalAndWificondIfNecessary(); 1428 stopSupplicantIfNecessary(); 1429 } 1430 } 1431 1432 /** 1433 * Helper function to handle creation of Nan iface. 1434 */ createNanIface( HalDeviceManager.InterfaceDestroyedListener nanInterfaceDestroyedListener, Handler handler, WorkSource requestorWs)1435 public Iface createNanIface( 1436 HalDeviceManager.InterfaceDestroyedListener nanInterfaceDestroyedListener, 1437 Handler handler, WorkSource requestorWs) { 1438 synchronized (mLock) { 1439 // Make sure HAL is started for Nan 1440 if (!startHal()) { 1441 Log.e(TAG, "Failed to start Hal"); 1442 return null; 1443 } 1444 // maintain iface status in WifiNative 1445 Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_NAN); 1446 if (iface != null) { 1447 WifiNanIface nanIface = mWifiInjector.getHalDeviceManager().createNanIface( 1448 nanInterfaceDestroyedListener, handler, requestorWs); 1449 if (nanIface != null) { 1450 iface.iface = nanIface; 1451 iface.name = nanIface.getName(); 1452 if (!TextUtils.isEmpty(iface.name)) { 1453 return iface; 1454 } 1455 } 1456 mIfaceMgr.removeIface(iface.id); 1457 } 1458 Log.e(TAG, "Failed to allocate new Nan iface"); 1459 stopHalAndWificondIfNecessary(); 1460 return null; 1461 } 1462 } 1463 1464 /** 1465 * Teardown Nan iface with input interface Id which was returned by createP2pIface. 1466 * 1467 * @param interfaceId the interface identify which was gerenated when creating P2p iface. 1468 */ teardownNanIface(int interfaceId)1469 public void teardownNanIface(int interfaceId) { 1470 synchronized (mLock) { 1471 mIfaceMgr.removeIface(interfaceId); 1472 stopHalAndWificondIfNecessary(); 1473 } 1474 } 1475 1476 /** 1477 * Get list of instance name from this bridged AP iface. 1478 * 1479 * @param ifaceName Name of the bridged interface. 1480 * @return list of instance name when succeed, otherwise null. 1481 */ 1482 @Nullable getBridgedApInstances(@onNull String ifaceName)1483 public List<String> getBridgedApInstances(@NonNull String ifaceName) { 1484 synchronized (mLock) { 1485 if (mWifiVendorHal.isVendorHalSupported()) { 1486 return mWifiVendorHal.getBridgedApInstances(ifaceName); 1487 } else { 1488 Log.i(TAG, "Vendor Hal not supported, ignoring getBridgedApInstances."); 1489 return null; 1490 } 1491 } 1492 } 1493 1494 // For devices that don't support the vendor HAL, we will not support any concurrency. 1495 // So simulate the HalDeviceManager behavior by triggering the destroy listener for 1496 // the interface. handleIfaceRemovalWhenVendorHalNotSupported(@onNull Iface iface)1497 private boolean handleIfaceRemovalWhenVendorHalNotSupported(@NonNull Iface iface) { 1498 synchronized (mLock) { 1499 mIfaceMgr.removeIface(iface.id); 1500 onInterfaceDestroyed(iface); 1501 Log.i(TAG, "Successfully torn down " + iface); 1502 return true; 1503 } 1504 } 1505 1506 /** 1507 * Helper function to handle removal of STA iface. 1508 * For devices which do not the support the HAL, this will bypass HalDeviceManager & 1509 * teardown any existing iface. 1510 */ removeStaIface(@onNull Iface iface)1511 private boolean removeStaIface(@NonNull Iface iface) { 1512 synchronized (mLock) { 1513 if (mWifiVendorHal.isVendorHalSupported()) { 1514 return mWifiVendorHal.removeStaIface(iface.name); 1515 } else { 1516 Log.i(TAG, "Vendor Hal not supported, ignoring removeStaIface."); 1517 return handleIfaceRemovalWhenVendorHalNotSupported(iface); 1518 } 1519 } 1520 } 1521 1522 /** 1523 * Helper function to handle removal of STA iface. 1524 */ removeApIface(@onNull Iface iface)1525 private boolean removeApIface(@NonNull Iface iface) { 1526 synchronized (mLock) { 1527 if (mWifiVendorHal.isVendorHalSupported()) { 1528 return mWifiVendorHal.removeApIface(iface.name); 1529 } else { 1530 Log.i(TAG, "Vendor Hal not supported, ignoring removeApIface."); 1531 return handleIfaceRemovalWhenVendorHalNotSupported(iface); 1532 } 1533 } 1534 } 1535 1536 /** 1537 * Helper function to remove specific instance in bridged AP iface. 1538 * 1539 * @param ifaceName Name of the iface. 1540 * @param apIfaceInstance The identity of the ap instance. 1541 * @param isMloAp true when current access point is using multiple link operation. 1542 * @return true if the operation succeeded, false if there is an error in Hal. 1543 */ removeIfaceInstanceFromBridgedApIface(@onNull String ifaceName, @NonNull String apIfaceInstance, boolean isMloAp)1544 public boolean removeIfaceInstanceFromBridgedApIface(@NonNull String ifaceName, 1545 @NonNull String apIfaceInstance, boolean isMloAp) { 1546 synchronized (mLock) { 1547 if (isMloAp && mHostapdHal != null && Flags.mloSap()) { 1548 mHostapdHal.removeLinkFromMultipleLinkBridgedApIface(ifaceName, 1549 apIfaceInstance); 1550 } 1551 if (mWifiVendorHal.isVendorHalSupported()) { 1552 return mWifiVendorHal.removeIfaceInstanceFromBridgedApIface(ifaceName, 1553 apIfaceInstance); 1554 } else { 1555 return false; 1556 } 1557 } 1558 } 1559 1560 /** 1561 * Register listener for subsystem restart event 1562 * 1563 * @param listener SubsystemRestartListener listener object. 1564 */ registerSubsystemRestartListener( HalDeviceManager.SubsystemRestartListener listener)1565 public void registerSubsystemRestartListener( 1566 HalDeviceManager.SubsystemRestartListener listener) { 1567 if (listener != null) { 1568 mWifiVendorHal.registerSubsystemRestartListener(listener); 1569 } 1570 } 1571 1572 /** 1573 * Initialize the native modules. 1574 * 1575 * @return true on success, false otherwise. 1576 */ initialize()1577 public boolean initialize() { 1578 synchronized (mLock) { 1579 if (!mWifiVendorHal.initialize(new VendorHalDeathHandlerInternal())) { 1580 Log.e(TAG, "Failed to initialize vendor HAL"); 1581 return false; 1582 } 1583 mWifiCondManager.setOnServiceDeadCallback(new WificondDeathHandlerInternal()); 1584 mWifiCondManager.tearDownInterfaces(); 1585 mWifiVendorHal.registerRadioModeChangeHandler( 1586 new VendorHalRadioModeChangeHandlerInternal()); 1587 mNetdWrapper = mWifiInjector.makeNetdWrapper(); 1588 return true; 1589 } 1590 } 1591 1592 /** 1593 * Callback to notify when the status of one of the native daemons 1594 * (wificond, wpa_supplicant & vendor HAL) changes. 1595 */ 1596 public interface StatusListener { 1597 /** 1598 * @param allReady Indicates if all the native daemons are ready for operation or not. 1599 */ onStatusChanged(boolean allReady)1600 void onStatusChanged(boolean allReady); 1601 } 1602 1603 /** 1604 * Register a StatusListener to get notified about any status changes from the native daemons. 1605 * 1606 * It is safe to re-register the same callback object - duplicates are detected and only a 1607 * single copy kept. 1608 * 1609 * @param listener StatusListener listener object. 1610 */ registerStatusListener(@onNull StatusListener listener)1611 public void registerStatusListener(@NonNull StatusListener listener) { 1612 synchronized (mLock) { 1613 mStatusListeners.add(listener); 1614 } 1615 } 1616 1617 /** 1618 * Callback to notify when the associated interface is destroyed, up or down. 1619 */ 1620 public interface InterfaceCallback { 1621 /** 1622 * Interface destroyed by HalDeviceManager. 1623 * 1624 * @param ifaceName Name of the iface. 1625 */ onDestroyed(String ifaceName)1626 void onDestroyed(String ifaceName); 1627 1628 /** 1629 * Interface is up. 1630 * 1631 * @param ifaceName Name of the iface. 1632 */ onUp(String ifaceName)1633 void onUp(String ifaceName); 1634 1635 /** 1636 * Interface is down. 1637 * 1638 * @param ifaceName Name of the iface. 1639 */ onDown(String ifaceName)1640 void onDown(String ifaceName); 1641 } 1642 takeBugReportInterfaceFailureIfNeeded(String bugTitle, String bugDetail)1643 private void takeBugReportInterfaceFailureIfNeeded(String bugTitle, String bugDetail) { 1644 if (mWifiInjector.getDeviceConfigFacade().isInterfaceFailureBugreportEnabled()) { 1645 mWifiInjector.getWifiDiagnostics().takeBugReport(bugTitle, bugDetail); 1646 } 1647 } 1648 1649 /** 1650 * Setup an interface for client mode (for scan) operations. 1651 * 1652 * This method configures an interface in STA mode in the native daemons 1653 * (wificond, vendor HAL). 1654 * 1655 * @param interfaceCallback Associated callback for notifying status changes for the iface. 1656 * @param requestorWs Requestor worksource. 1657 * @param concreteClientModeManager ConcreteClientModeManager requesting the interface. 1658 * @return Returns the name of the allocated interface, will be null on failure. 1659 */ setupInterfaceForClientInScanMode( @onNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs, @NonNull ConcreteClientModeManager concreteClientModeManager)1660 public String setupInterfaceForClientInScanMode( 1661 @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs, 1662 @NonNull ConcreteClientModeManager concreteClientModeManager) { 1663 synchronized (mLock) { 1664 if (!startHal()) { 1665 Log.e(TAG, "Failed to start Hal"); 1666 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal(); 1667 return null; 1668 } 1669 Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN); 1670 if (iface == null) { 1671 Log.e(TAG, "Failed to allocate new STA iface"); 1672 return null; 1673 } 1674 iface.externalListener = interfaceCallback; 1675 iface.name = createStaIface(iface, requestorWs, concreteClientModeManager); 1676 if (TextUtils.isEmpty(iface.name)) { 1677 Log.e(TAG, "Failed to create iface in vendor HAL"); 1678 mIfaceMgr.removeIface(iface.id); 1679 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal(); 1680 return null; 1681 } 1682 if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run, 1683 new NormalScanEventCallback(iface.name), 1684 new PnoScanEventCallback(iface.name))) { 1685 Log.e(TAG, "Failed to setup iface in wificond=" + iface.name); 1686 teardownInterface(iface.name); 1687 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond(); 1688 return null; 1689 } 1690 registerInterfaceObserver(); 1691 iface.networkObserver = new NetworkObserverInternal(iface.id); 1692 if (!registerNetworkObserver(iface.networkObserver)) { 1693 Log.e(TAG, "Failed to register network observer for iface=" + iface.name); 1694 teardownInterface(iface.name); 1695 return null; 1696 } 1697 mWifiMonitor.startMonitoring(iface.name); 1698 // Just to avoid any race conditions with interface state change callbacks, 1699 // update the interface state before we exit. 1700 onInterfaceStateChanged(iface, isInterfaceUp(iface.name)); 1701 mWifiVendorHal.enableLinkLayerStats(iface.name); 1702 Log.i(TAG, "Successfully setup " + iface); 1703 1704 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1705 updateSupportedBandForStaInternal(iface); 1706 1707 mWifiVendorHal.enableStaChannelForPeerNetwork(mContext.getResources().getBoolean( 1708 R.bool.config_wifiEnableStaIndoorChannelForPeerNetwork), 1709 mContext.getResources().getBoolean( 1710 R.bool.config_wifiEnableStaDfsChannelForPeerNetwork)); 1711 return iface.name; 1712 } 1713 } 1714 1715 /** 1716 * Return true when the device supports Wi-Fi 7 MLD AP and multiple links operation (MLO). 1717 */ isMLDApSupportMLO()1718 public boolean isMLDApSupportMLO() { 1719 if (!Flags.mloSap()) { 1720 return false; 1721 } 1722 BitSet cachedFeatureSet = getCompleteFeatureSetFromConfigStore(); 1723 return mWifiInjector.getWifiGlobals().isMLDApSupported() 1724 && cachedFeatureSet.get(WifiManager.WIFI_FEATURE_SOFTAP_MLO); 1725 } 1726 1727 /** 1728 * Return true when the device supports multiple Wi-Fi 7 multi-link devices (MLD) on SoftAp. 1729 */ isMultipleMLDSupportedOnSap()1730 public boolean isMultipleMLDSupportedOnSap() { 1731 if (!Flags.multipleMldOnSapSupported()) { 1732 return false; 1733 } 1734 BitSet cachedFeatureSet = getCompleteFeatureSetFromConfigStore(); 1735 return cachedFeatureSet.get(WifiManager.WIFI_FEATURE_MULTIPLE_MLD_ON_SAP); 1736 } 1737 1738 /** 1739 * Setup an interface for Soft AP mode operations. 1740 * 1741 * This method configures an interface in AP mode in all the native daemons 1742 * (wificond, wpa_supplicant & vendor HAL). 1743 * 1744 * @param interfaceCallback Associated callback for notifying status changes for the iface. 1745 * @param requestorWs Requestor worksource. 1746 * @param isBridged Whether or not AP interface is a bridge interface. 1747 * @param softApManager SoftApManager of the request. 1748 * @param vendorData List of {@link OuiKeyedData} containing vendor-provided 1749 * configuration data. Empty list indicates no vendor data. 1750 * @return Returns the name of the allocated interface, will be null on failure. 1751 */ setupInterfaceForSoftApMode( @onNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged, @NonNull SoftApManager softApManager, @NonNull List<OuiKeyedData> vendorData, boolean isUsingMlo)1752 public String setupInterfaceForSoftApMode( 1753 @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs, 1754 @SoftApConfiguration.BandType int band, boolean isBridged, 1755 @NonNull SoftApManager softApManager, @NonNull List<OuiKeyedData> vendorData, 1756 boolean isUsingMlo) { 1757 synchronized (mLock) { 1758 String bugTitle = "Wi-Fi BugReport (softAp interface failure)"; 1759 String errorMsg = ""; 1760 if (!startHal()) { 1761 errorMsg = "Failed to start softAp Hal"; 1762 Log.e(TAG, errorMsg); 1763 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal(); 1764 takeBugReportInterfaceFailureIfNeeded(bugTitle, errorMsg); 1765 softApManager.writeSoftApStartedEvent(SoftApManager.START_RESULT_FAILURE_START_HAL); 1766 return null; 1767 } 1768 if (!startHostapd()) { 1769 errorMsg = "Failed to start softAp hostapd"; 1770 Log.e(TAG, errorMsg); 1771 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd(); 1772 takeBugReportInterfaceFailureIfNeeded(bugTitle, errorMsg); 1773 softApManager.writeSoftApStartedEvent( 1774 SoftApManager.START_RESULT_FAILURE_START_HOSTAPD); 1775 return null; 1776 } 1777 Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP); 1778 if (iface == null) { 1779 Log.e(TAG, "Failed to allocate new AP iface"); 1780 return null; 1781 } 1782 iface.externalListener = interfaceCallback; 1783 iface.name = createApIface(iface, requestorWs, band, isBridged, softApManager, 1784 vendorData); 1785 if (TextUtils.isEmpty(iface.name)) { 1786 errorMsg = "Failed to create softAp iface in vendor HAL"; 1787 Log.e(TAG, errorMsg); 1788 mIfaceMgr.removeIface(iface.id); 1789 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal(); 1790 takeBugReportInterfaceFailureIfNeeded(bugTitle, errorMsg); 1791 return null; 1792 } 1793 String ifaceInstanceName = iface.name; 1794 if (isBridged && !isUsingMlo) { 1795 List<String> instances = getBridgedApInstances(iface.name); 1796 if (instances == null || instances.size() == 0) { 1797 errorMsg = "Failed to get bridged AP instances" + iface.name; 1798 Log.e(TAG, errorMsg); 1799 teardownInterface(iface.name); 1800 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal(); 1801 takeBugReportInterfaceFailureIfNeeded(bugTitle, errorMsg); 1802 return null; 1803 } 1804 // Always select first instance as wificond interface. 1805 ifaceInstanceName = instances.get(0); 1806 mWifiCondIfacesForBridgedAp.put(iface.name, ifaceInstanceName); 1807 } 1808 if (!mWifiCondManager.setupInterfaceForSoftApMode(ifaceInstanceName)) { 1809 errorMsg = "Failed to setup softAp iface in wifiCond manager on " + iface; 1810 Log.e(TAG, errorMsg); 1811 teardownInterface(iface.name); 1812 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond(); 1813 takeBugReportInterfaceFailureIfNeeded(bugTitle, errorMsg); 1814 return null; 1815 } 1816 iface.networkObserver = new NetworkObserverInternal(iface.id); 1817 if (!registerNetworkObserver(iface.networkObserver)) { 1818 Log.e(TAG, "Failed to register network observer on " + iface); 1819 teardownInterface(iface.name); 1820 return null; 1821 } 1822 // Just to avoid any race conditions with interface state change callbacks, 1823 // update the interface state before we exit. 1824 onInterfaceStateChanged(iface, isInterfaceUp(iface.name)); 1825 Log.i(TAG, "Successfully setup " + iface); 1826 1827 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1828 updateSupportedBandForStaInternal(iface); 1829 return iface.name; 1830 } 1831 } 1832 1833 /** 1834 * Switches an existing Client mode interface from connectivity 1835 * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY} to scan mode 1836 * {@link Iface#IFACE_TYPE_STA_FOR_SCAN}. 1837 * 1838 * @param ifaceName Name of the interface. 1839 * @param requestorWs Requestor worksource. 1840 * @return true if the operation succeeded, false if there is an error or the iface is already 1841 * in scan mode. 1842 */ switchClientInterfaceToScanMode(@onNull String ifaceName, @NonNull WorkSource requestorWs)1843 public boolean switchClientInterfaceToScanMode(@NonNull String ifaceName, 1844 @NonNull WorkSource requestorWs) { 1845 synchronized (mLock) { 1846 Iface iface = null; 1847 Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter(); 1848 while (ifaceIdIter.hasNext()) { 1849 Iface nextIface = mIfaceMgr.getIface(ifaceIdIter.next()); 1850 if (nextIface.name.equals(ifaceName)) { 1851 if (nextIface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) { 1852 iface = nextIface; 1853 break; 1854 } else if (nextIface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 1855 Log.e(TAG, "Already in scan mode on iface=" + ifaceName); 1856 return true; 1857 } 1858 } 1859 } 1860 1861 if (iface == null) { 1862 Log.e(TAG, "Trying to switch to scan mode on an invalid iface=" + ifaceName); 1863 return false; 1864 } 1865 1866 if (mWifiVendorHal.isVendorHalSupported() 1867 && !mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, requestorWs)) { 1868 Log.e(TAG, "Failed to replace requestor ws on " + iface); 1869 teardownInterface(iface.name); 1870 return false; 1871 } 1872 if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) { 1873 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface); 1874 teardownInterface(iface.name); 1875 return false; 1876 } 1877 if (mMainlineSupplicant.isActive() 1878 && !mMainlineSupplicant.removeStaInterface(iface.name)) { 1879 Log.e(TAG, "Unable to tear down " + iface.name + " in the mainline supplicant" 1880 + " for switch to scan mode"); 1881 } 1882 iface.type = Iface.IFACE_TYPE_STA_FOR_SCAN; 1883 stopSupplicantIfNecessary(); 1884 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1885 updateSupportedBandForStaInternal(iface); 1886 iface.phyCapabilities = null; 1887 Log.i(TAG, "Successfully switched to scan mode on iface=" + iface); 1888 return true; 1889 } 1890 } 1891 1892 /** 1893 * Switches an existing Client mode interface from scan mode 1894 * {@link Iface#IFACE_TYPE_STA_FOR_SCAN} to connectivity mode 1895 * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY}. 1896 * 1897 * @param ifaceName Name of the interface. 1898 * @param requestorWs Requestor worksource. 1899 * @return true if the operation succeeded, false if there is an error or the iface is already 1900 * in scan mode. 1901 */ switchClientInterfaceToConnectivityMode(@onNull String ifaceName, @NonNull WorkSource requestorWs)1902 public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName, 1903 @NonNull WorkSource requestorWs) { 1904 synchronized (mLock) { 1905 Iface iface = null; 1906 Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter(); 1907 while (ifaceIdIter.hasNext()) { 1908 Iface nextIface = mIfaceMgr.getIface(ifaceIdIter.next()); 1909 if (nextIface.name.equals(ifaceName)) { 1910 if (nextIface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 1911 iface = nextIface; 1912 break; 1913 } else if (nextIface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) { 1914 Log.e(TAG, "Already in connectivity mode on iface=" + ifaceName); 1915 return true; 1916 } 1917 } 1918 } 1919 1920 if (iface == null) { 1921 Log.e(TAG, "Trying to switch to connectivity mode on an invalid iface=" 1922 + ifaceName); 1923 return false; 1924 } 1925 1926 if (mWifiVendorHal.isVendorHalSupported() 1927 && !mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, requestorWs)) { 1928 Log.e(TAG, "Failed to replace requestor ws on " + iface); 1929 teardownInterface(iface.name); 1930 return false; 1931 } 1932 if (!startSupplicant()) { 1933 Log.e(TAG, "Failed to start supplicant"); 1934 teardownInterface(iface.name); 1935 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant(); 1936 return false; 1937 } 1938 if (!mSupplicantStaIfaceHal.setupIface(iface.name)) { 1939 Log.e(TAG, "Failed to setup iface in supplicant on " + iface); 1940 teardownInterface(iface.name); 1941 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant(); 1942 return false; 1943 } 1944 if (mContext.getResources().getBoolean( 1945 R.bool.config_wifiNetworkCentricQosPolicyFeatureEnabled) 1946 && isSupplicantUsingAidlService()) { 1947 mQosPolicyFeatureEnabled = mSupplicantStaIfaceHal 1948 .setNetworkCentricQosPolicyFeatureEnabled(iface.name, true); 1949 if (!mQosPolicyFeatureEnabled) { 1950 Log.e(TAG, "Failed to enable QoS policy feature for iface " + iface.name); 1951 } 1952 } 1953 if (mMainlineSupplicant.isActive() 1954 && !mMainlineSupplicant.addStaInterface(iface.name)) { 1955 Log.e(TAG, "Unable to add interface " + iface.name + " to mainline supplicant"); 1956 } 1957 iface.type = Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY; 1958 iface.featureSet = getSupportedFeatureSetInternal(iface.name); 1959 saveCompleteFeatureSetInConfigStoreIfNecessary(iface.featureSet); 1960 updateSupportedBandForStaInternal(iface); 1961 mIsEnhancedOpenSupported = iface.featureSet.get(WIFI_FEATURE_OWE); 1962 if (rsnOverriding()) { 1963 mIsRsnOverridingSupported = isSupplicantAidlServiceVersionAtLeast(4) 1964 ? mSupplicantStaIfaceHal.isRsnOverridingSupported(iface.name) 1965 : mContext.getResources().getBoolean( 1966 R.bool.config_wifiRsnOverridingEnabled); 1967 } 1968 Log.i(TAG, "Successfully switched to connectivity mode on iface=" + iface); 1969 return true; 1970 } 1971 } 1972 1973 /** 1974 * Change the requestor WorkSource for a given STA iface. 1975 * @return true if the operation succeeded, false otherwise. 1976 */ replaceStaIfaceRequestorWs(@onNull String ifaceName, WorkSource newWorkSource)1977 public boolean replaceStaIfaceRequestorWs(@NonNull String ifaceName, WorkSource newWorkSource) { 1978 final Iface iface = mIfaceMgr.getIface(ifaceName); 1979 if (iface == null) { 1980 Log.e(TAG, "Called replaceStaIfaceRequestorWs() on an invalid iface=" + ifaceName); 1981 return false; 1982 } 1983 if (!mWifiVendorHal.isVendorHalSupported()) { 1984 // if vendor HAL isn't supported, return true since there's nothing to do. 1985 return true; 1986 } 1987 if (!mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, newWorkSource)) { 1988 Log.e(TAG, "Failed to replace requestor ws on " + iface); 1989 teardownInterface(iface.name); 1990 return false; 1991 } 1992 return true; 1993 } 1994 1995 /** 1996 * 1997 * Check if the interface is up or down. 1998 * 1999 * @param ifaceName Name of the interface. 2000 * @return true if iface is up, false if it's down or on error. 2001 */ isInterfaceUp(@onNull String ifaceName)2002 public boolean isInterfaceUp(@NonNull String ifaceName) { 2003 synchronized (mLock) { 2004 final Iface iface = mIfaceMgr.getIface(ifaceName); 2005 if (iface == null) { 2006 Log.e(TAG, "Trying to get iface state on invalid iface=" + ifaceName); 2007 return false; 2008 } 2009 try { 2010 return mNetdWrapper.isInterfaceUp(ifaceName); 2011 } catch (IllegalStateException e) { 2012 Log.e(TAG, "Unable to get interface config", e); 2013 return false; 2014 } 2015 } 2016 } 2017 2018 /** 2019 * Teardown an interface in Client/AP mode. 2020 * 2021 * This method tears down the associated interface from all the native daemons 2022 * (wificond, wpa_supplicant & vendor HAL). 2023 * Also, brings down the HAL, supplicant or hostapd as necessary. 2024 * 2025 * @param ifaceName Name of the interface. 2026 */ teardownInterface(@onNull String ifaceName)2027 public void teardownInterface(@NonNull String ifaceName) { 2028 synchronized (mLock) { 2029 final Iface iface = mIfaceMgr.getIface(ifaceName); 2030 if (iface == null) { 2031 Log.e(TAG, "Trying to teardown an invalid iface=" + ifaceName); 2032 return; 2033 } 2034 // Trigger the iface removal from HAL. The rest of the cleanup will be triggered 2035 // from the interface destroyed callback. 2036 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY 2037 || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) { 2038 if (!removeStaIface(iface)) { 2039 Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName); 2040 return; 2041 } 2042 } else if (iface.type == Iface.IFACE_TYPE_AP) { 2043 if (!removeApIface(iface)) { 2044 Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName); 2045 return; 2046 } 2047 } 2048 Log.i(TAG, "Successfully initiated teardown for iface=" + ifaceName); 2049 } 2050 } 2051 2052 /** 2053 * Teardown all the active interfaces. 2054 * 2055 * This method tears down the associated interfaces from all the native daemons 2056 * (wificond, wpa_supplicant & vendor HAL). 2057 * Also, brings down the HAL, supplicant or hostapd as necessary. 2058 */ teardownAllInterfaces()2059 public void teardownAllInterfaces() { 2060 synchronized (mLock) { 2061 Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter(); 2062 while (ifaceIdIter.hasNext()) { 2063 Iface iface = mIfaceMgr.getIface(ifaceIdIter.next()); 2064 ifaceIdIter.remove(); 2065 onInterfaceDestroyed(iface); 2066 Log.i(TAG, "Successfully torn down " + iface); 2067 } 2068 Log.i(TAG, "Successfully torn down all ifaces"); 2069 } 2070 } 2071 2072 /** 2073 * Get names of all the client interfaces. 2074 * 2075 * @return List of interface name of all active client interfaces. 2076 */ getClientInterfaceNames()2077 public Set<String> getClientInterfaceNames() { 2078 synchronized (mLock) { 2079 return mIfaceMgr.findAllStaIfaceNames(); 2080 } 2081 } 2082 2083 /** 2084 * Get names of all the client interfaces. 2085 * 2086 * @return List of interface name of all active client interfaces. 2087 */ getSoftApInterfaceNames()2088 public Set<String> getSoftApInterfaceNames() { 2089 synchronized (mLock) { 2090 return mIfaceMgr.findAllApIfaceNames(); 2091 } 2092 } 2093 2094 /******************************************************** 2095 * Wificond operations 2096 ********************************************************/ 2097 2098 /** 2099 * Query the list of valid frequencies for the provided band. 2100 * The result depends on the on the country code that has been set. 2101 * 2102 * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants. 2103 * The following bands are supported {@link WifiAnnotations.WifiBandBasic}: 2104 * WifiScanner.WIFI_BAND_24_GHZ 2105 * WifiScanner.WIFI_BAND_5_GHZ 2106 * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY 2107 * WifiScanner.WIFI_BAND_6_GHZ 2108 * WifiScanner.WIFI_BAND_60_GHZ 2109 * @return frequencies vector of valid frequencies (MHz), or null for error. 2110 * @throws IllegalArgumentException if band is not recognized. 2111 */ 2112 @Keep getChannelsForBand(@ifiAnnotations.WifiBandBasic int band)2113 public int [] getChannelsForBand(@WifiAnnotations.WifiBandBasic int band) { 2114 if (!SdkLevel.isAtLeastS() && band == WifiScanner.WIFI_BAND_60_GHZ) { 2115 // 60 GHz band is new in Android S, return empty array on older SDK versions 2116 return new int[0]; 2117 } 2118 return mWifiCondManager.getChannelsMhzForBand(band); 2119 } 2120 2121 /** 2122 * Start a scan using wificond for the given parameters. 2123 * @param ifaceName Name of the interface. 2124 * @param scanType Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}, 2125 * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}. 2126 * @param freqs list of frequencies to scan for, if null scan all supported channels. 2127 * @param hiddenNetworkSSIDs List of hidden networks to be scanned for. 2128 * @param enable6GhzRnr whether Reduced Neighbor Report should be enabled for 6Ghz scanning. 2129 * @param vendorIes Byte array of vendor IEs 2130 * @return Returns true on success. 2131 */ scan( @onNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs, List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr, byte[] vendorIes)2132 public int scan( 2133 @NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs, 2134 List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr, byte[] vendorIes) { 2135 int scanRequestStatus = WifiScanner.REASON_SUCCEEDED; 2136 boolean scanStatus = true; 2137 List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>(); 2138 for (String hiddenNetworkSsid : hiddenNetworkSSIDs) { 2139 try { 2140 hiddenNetworkSsidsArrays.add( 2141 NativeUtil.byteArrayFromArrayList( 2142 NativeUtil.decodeSsid(hiddenNetworkSsid))); 2143 } catch (IllegalArgumentException e) { 2144 Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e); 2145 continue; 2146 } 2147 } 2148 if (SdkLevel.isAtLeastS()) { 2149 // enable6GhzRnr is a new parameter first introduced in Android S. 2150 Bundle extraScanningParams = new Bundle(); 2151 extraScanningParams.putBoolean(WifiNl80211Manager.SCANNING_PARAM_ENABLE_6GHZ_RNR, 2152 enable6GhzRnr); 2153 if (SdkLevel.isAtLeastU()) { 2154 extraScanningParams.putByteArray(WifiNl80211Manager.EXTRA_SCANNING_PARAM_VENDOR_IES, 2155 vendorIes); 2156 scanRequestStatus = mWifiCondManager.startScan2(ifaceName, scanType, freqs, 2157 hiddenNetworkSsidsArrays, extraScanningParams); 2158 } else { 2159 scanStatus = mWifiCondManager.startScan(ifaceName, scanType, freqs, 2160 hiddenNetworkSsidsArrays, 2161 extraScanningParams); 2162 scanRequestStatus = scanStatus 2163 ? WifiScanner.REASON_SUCCEEDED : WifiScanner.REASON_UNSPECIFIED; 2164 2165 } 2166 } else { 2167 scanStatus = mWifiCondManager.startScan(ifaceName, scanType, freqs, 2168 hiddenNetworkSsidsArrays); 2169 scanRequestStatus = scanStatus 2170 ? WifiScanner.REASON_SUCCEEDED : WifiScanner.REASON_UNSPECIFIED; 2171 } 2172 2173 return scanRequestStatus; 2174 } 2175 2176 /** 2177 * Fetch the latest scan result from kernel via wificond. 2178 * @param ifaceName Name of the interface. 2179 * @return Returns an ArrayList of ScanDetail. 2180 * Returns an empty ArrayList on failure. 2181 */ getScanResults(@onNull String ifaceName)2182 public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) { 2183 if (mUseFakeScanDetails) { 2184 synchronized (mFakeScanDetails) { 2185 ArrayList<ScanDetail> copyList = new ArrayList<>(); 2186 for (ScanDetail sd: mFakeScanDetails) { 2187 ScanDetail copy = new ScanDetail(sd); 2188 copy.getScanResult().ifaceName = ifaceName; 2189 // otherwise the fake will be too old 2190 copy.getScanResult().timestamp = SystemClock.elapsedRealtime() * 1000; 2191 copyList.add(copy); 2192 } 2193 return copyList; 2194 } 2195 } 2196 if (mMockWifiModem != null 2197 && mMockWifiModem.isMethodConfigured( 2198 MockWifiServiceUtil.MOCK_NL80211_SERVICE, "getScanResults")) { 2199 Log.i(TAG, "getScanResults was called from mock wificond"); 2200 return convertNativeScanResults(ifaceName, mMockWifiModem.getWifiNl80211Manager() 2201 .getScanResults(ifaceName, WifiNl80211Manager.SCAN_TYPE_SINGLE_SCAN)); 2202 } 2203 return convertNativeScanResults(ifaceName, mWifiCondManager.getScanResults( 2204 ifaceName, WifiNl80211Manager.SCAN_TYPE_SINGLE_SCAN)); 2205 } 2206 2207 /** 2208 * Start faking scan results - using information provided via 2209 * {@link #addFakeScanDetail(ScanDetail)}. Stop with {@link #stopFakingScanDetails()}. 2210 */ startFakingScanDetails()2211 public void startFakingScanDetails() { 2212 if (mBuildProperties.isUserBuild()) { 2213 Log.wtf(TAG, "Can't fake scan results in a user build!"); 2214 return; 2215 } 2216 Log.d(TAG, "Starting faking scan results - " + mFakeScanDetails); 2217 mUseFakeScanDetails = true; 2218 } 2219 2220 /** 2221 * Add fake scan result. Fakes are not used until activated via 2222 * {@link #startFakingScanDetails()}. 2223 * @param fakeScanDetail 2224 */ addFakeScanDetail(@onNull ScanDetail fakeScanDetail)2225 public void addFakeScanDetail(@NonNull ScanDetail fakeScanDetail) { 2226 synchronized (mFakeScanDetails) { 2227 mFakeScanDetails.add(fakeScanDetail); 2228 } 2229 } 2230 2231 /** 2232 * Reset the fake scan result list updated via {@link #addFakeScanDetail(ScanDetail)} .} 2233 */ resetFakeScanDetails()2234 public void resetFakeScanDetails() { 2235 synchronized (mFakeScanDetails) { 2236 mFakeScanDetails.clear(); 2237 } 2238 } 2239 2240 /** 2241 * Stop faking scan results. Started with {@link #startFakingScanDetails()}. 2242 */ stopFakingScanDetails()2243 public void stopFakingScanDetails() { 2244 mUseFakeScanDetails = false; 2245 } 2246 2247 /** 2248 * Fetch the latest scan result from kernel via wificond. 2249 * @param ifaceName Name of the interface. 2250 * @return Returns an ArrayList of ScanDetail. 2251 * Returns an empty ArrayList on failure. 2252 */ getPnoScanResults(@onNull String ifaceName)2253 public ArrayList<ScanDetail> getPnoScanResults(@NonNull String ifaceName) { 2254 if (mMockWifiModem != null 2255 && mMockWifiModem.isMethodConfigured( 2256 MockWifiServiceUtil.MOCK_NL80211_SERVICE, "getPnoScanResults")) { 2257 Log.i(TAG, "getPnoScanResults was called from mock wificond"); 2258 return convertNativeScanResults(ifaceName, mMockWifiModem.getWifiNl80211Manager() 2259 .getScanResults(ifaceName, WifiNl80211Manager.SCAN_TYPE_PNO_SCAN)); 2260 } 2261 return convertNativeScanResults(ifaceName, mWifiCondManager.getScanResults(ifaceName, 2262 WifiNl80211Manager.SCAN_TYPE_PNO_SCAN)); 2263 } 2264 2265 /** 2266 * Get the max number of SSIDs that the driver supports per scan. 2267 * @param ifaceName Name of the interface. 2268 */ getMaxSsidsPerScan(@onNull String ifaceName)2269 public int getMaxSsidsPerScan(@NonNull String ifaceName) { 2270 if (SdkLevel.isAtLeastT()) { 2271 return mWifiCondManager.getMaxSsidsPerScan(ifaceName); 2272 } else { 2273 return -1; 2274 } 2275 } 2276 convertNativeScanResults(@onNull String ifaceName, List<NativeScanResult> nativeResults)2277 private ArrayList<ScanDetail> convertNativeScanResults(@NonNull String ifaceName, 2278 List<NativeScanResult> nativeResults) { 2279 ArrayList<ScanDetail> results = new ArrayList<>(); 2280 for (NativeScanResult result : nativeResults) { 2281 if (result.getSsid().length > 32) { 2282 Log.e(TAG, "Invalid SSID length (> 32 bytes): " 2283 + Arrays.toString(result.getSsid())); 2284 continue; 2285 } 2286 WifiSsid originalSsid = WifiSsid.fromBytes(result.getSsid()); 2287 MacAddress bssidMac = result.getBssid(); 2288 if (bssidMac == null) { 2289 Log.e(TAG, "Invalid MAC (BSSID) for SSID " + originalSsid); 2290 continue; 2291 } 2292 String bssid = bssidMac.toString(); 2293 ScanResult.InformationElement[] ies = 2294 InformationElementUtil.parseInformationElements(result.getInformationElements()); 2295 InformationElementUtil.Capabilities capabilities = 2296 new InformationElementUtil.Capabilities(); 2297 capabilities.from( 2298 ies, 2299 result.getCapabilities(), 2300 mIsEnhancedOpenSupported, 2301 mIsRsnOverridingSupported, 2302 result.getFrequencyMhz(), 2303 mUnknownAkmMap); 2304 String flags = capabilities.generateCapabilitiesString(); 2305 NetworkDetail networkDetail; 2306 try { 2307 networkDetail = new NetworkDetail(bssid, ies, null, result.getFrequencyMhz()); 2308 } catch (IllegalArgumentException e) { 2309 Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e); 2310 continue; 2311 } 2312 2313 WifiSsid translatedSsid = mWifiInjector.getSsidTranslator() 2314 .getTranslatedSsidAndRecordBssidCharset(originalSsid, bssidMac); 2315 ScanDetail scanDetail = new ScanDetail(networkDetail, translatedSsid, bssid, flags, 2316 result.getSignalMbm() / 100, result.getFrequencyMhz(), result.getTsf(), ies, 2317 null, result.getInformationElements()); 2318 ScanResult scanResult = scanDetail.getScanResult(); 2319 scanResult.setWifiStandard(wifiModeToWifiStandard(networkDetail.getWifiMode())); 2320 scanResult.ifaceName = ifaceName; 2321 2322 // Fill up the radio chain info. 2323 scanResult.radioChainInfos = 2324 new ScanResult.RadioChainInfo[result.getRadioChainInfos().size()]; 2325 int idx = 0; 2326 for (RadioChainInfo nativeRadioChainInfo : result.getRadioChainInfos()) { 2327 scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo(); 2328 scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.getChainId(); 2329 scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.getLevelDbm(); 2330 idx++; 2331 } 2332 2333 // Fill MLO Attributes 2334 scanResult.setApMldMacAddress(networkDetail.getMldMacAddress()); 2335 scanResult.setApMloLinkId(networkDetail.getMloLinkId()); 2336 scanResult.setAffiliatedMloLinks(networkDetail.getAffiliatedMloLinks()); 2337 2338 results.add(scanDetail); 2339 } 2340 if (mVerboseLoggingEnabled) { 2341 Log.d(TAG, "get " + results.size() + " scan results from wificond"); 2342 } 2343 2344 return results; 2345 } 2346 2347 @WifiAnnotations.WifiStandard wifiModeToWifiStandard(int wifiMode)2348 private static int wifiModeToWifiStandard(int wifiMode) { 2349 switch (wifiMode) { 2350 case InformationElementUtil.WifiMode.MODE_11A: 2351 case InformationElementUtil.WifiMode.MODE_11B: 2352 case InformationElementUtil.WifiMode.MODE_11G: 2353 return ScanResult.WIFI_STANDARD_LEGACY; 2354 case InformationElementUtil.WifiMode.MODE_11N: 2355 return ScanResult.WIFI_STANDARD_11N; 2356 case InformationElementUtil.WifiMode.MODE_11AC: 2357 return ScanResult.WIFI_STANDARD_11AC; 2358 case InformationElementUtil.WifiMode.MODE_11AX: 2359 return ScanResult.WIFI_STANDARD_11AX; 2360 case InformationElementUtil.WifiMode.MODE_11BE: 2361 return ScanResult.WIFI_STANDARD_11BE; 2362 case InformationElementUtil.WifiMode.MODE_UNDEFINED: 2363 default: 2364 return ScanResult.WIFI_STANDARD_UNKNOWN; 2365 } 2366 } 2367 2368 /** 2369 * Start PNO scan. 2370 * @param ifaceName Name of the interface. 2371 * @param pnoSettings Pno scan configuration. 2372 * @return true on success. 2373 */ startPnoScan(@onNull String ifaceName, PnoSettings pnoSettings)2374 public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings) { 2375 if (mMockWifiModem != null 2376 && mMockWifiModem.isMethodConfigured( 2377 MockWifiServiceUtil.MOCK_NL80211_SERVICE, "startPnoScan")) { 2378 Log.i(TAG, "startPnoScan was called from mock wificond"); 2379 return mMockWifiModem.getWifiNl80211Manager() 2380 .startPnoScan(ifaceName, pnoSettings.toNativePnoSettings(), 2381 Runnable::run, 2382 new WifiNl80211Manager.PnoScanRequestCallback() { 2383 @Override 2384 public void onPnoRequestSucceeded() { 2385 } 2386 2387 @Override 2388 public void onPnoRequestFailed() { 2389 } 2390 }); 2391 } 2392 return mWifiCondManager.startPnoScan(ifaceName, pnoSettings.toNativePnoSettings(), 2393 Runnable::run, 2394 new WifiNl80211Manager.PnoScanRequestCallback() { 2395 @Override 2396 public void onPnoRequestSucceeded() { 2397 mWifiMetrics.incrementPnoScanStartAttemptCount(); 2398 } 2399 2400 @Override 2401 public void onPnoRequestFailed() { 2402 WifiStatsLog.write(WifiStatsLog.PNO_SCAN_STOPPED, 2403 WifiStatsLog.PNO_SCAN_STOPPED__STOP_REASON__SCAN_FAILED, 2404 0, false, false, false, false, // default values 2405 WifiStatsLog 2406 .PNO_SCAN_STOPPED__FAILURE_CODE__WIFICOND_REQUEST_FAILURE); 2407 } 2408 }); 2409 } 2410 2411 /** 2412 * Stop PNO scan. 2413 * @param ifaceName Name of the interface. 2414 * @return true on success. 2415 */ 2416 public boolean stopPnoScan(@NonNull String ifaceName) { 2417 return mWifiCondManager.stopPnoScan(ifaceName); 2418 } 2419 2420 /** 2421 * Sends an arbitrary 802.11 management frame on the current channel. 2422 * 2423 * @param ifaceName Name of the interface. 2424 * @param frame Bytes of the 802.11 management frame to be sent, including the header, but not 2425 * including the frame check sequence (FCS). 2426 * @param callback A callback triggered when the transmitted frame is ACKed or the transmission 2427 * fails. 2428 * @param mcs The MCS index that the frame will be sent at. If mcs < 0, the driver will select 2429 * the rate automatically. If the device does not support sending the frame at a 2430 * specified MCS rate, the transmission will be aborted and 2431 * {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called 2432 * with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}. 2433 */ 2434 public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame, 2435 @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) { 2436 mWifiCondManager.sendMgmtFrame(ifaceName, frame, mcs, Runnable::run, callback); 2437 } 2438 2439 /** 2440 * Sends a probe request to the AP and waits for a response in order to determine whether 2441 * there is connectivity between the device and AP. 2442 * 2443 * @param ifaceName Name of the interface. 2444 * @param receiverMac the MAC address of the AP that the probe request will be sent to. 2445 * @param callback callback triggered when the probe was ACKed by the AP, or when 2446 * an error occurs after the link probe was started. 2447 * @param mcs The MCS index that this probe will be sent at. If mcs < 0, the driver will select 2448 * the rate automatically. If the device does not support sending the frame at a 2449 * specified MCS rate, the transmission will be aborted and 2450 * {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called 2451 * with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}. 2452 */ 2453 public void probeLink(@NonNull String ifaceName, @NonNull MacAddress receiverMac, 2454 @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) { 2455 if (callback == null) { 2456 Log.e(TAG, "callback cannot be null!"); 2457 return; 2458 } 2459 2460 if (receiverMac == null) { 2461 Log.e(TAG, "Receiver MAC address cannot be null!"); 2462 callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN); 2463 return; 2464 } 2465 2466 String senderMacStr = getMacAddress(ifaceName); 2467 if (senderMacStr == null) { 2468 Log.e(TAG, "Failed to get this device's MAC Address"); 2469 callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN); 2470 return; 2471 } 2472 2473 byte[] frame = buildProbeRequestFrame( 2474 receiverMac.toByteArray(), 2475 NativeUtil.macAddressToByteArray(senderMacStr)); 2476 sendMgmtFrame(ifaceName, frame, callback, mcs); 2477 } 2478 2479 // header = 24 bytes, minimal body = 2 bytes, no FCS (will be added by driver) 2480 private static final int BASIC_PROBE_REQUEST_FRAME_SIZE = 24 + 2; 2481 2482 private byte[] buildProbeRequestFrame(byte[] receiverMac, byte[] transmitterMac) { 2483 ByteBuffer frame = ByteBuffer.allocate(BASIC_PROBE_REQUEST_FRAME_SIZE); 2484 // ByteBuffer is big endian by default, switch to little endian 2485 frame.order(ByteOrder.LITTLE_ENDIAN); 2486 2487 // Protocol version = 0, Type = management, Subtype = Probe Request 2488 frame.put((byte) 0x40); 2489 2490 // no flags set 2491 frame.put((byte) 0x00); 2492 2493 // duration = 60 microseconds. Note: this is little endian 2494 // Note: driver should calculate the duration and replace it before sending, putting a 2495 // reasonable default value here just in case. 2496 frame.putShort((short) 0x3c); 2497 2498 // receiver/destination MAC address byte array 2499 frame.put(receiverMac); 2500 // sender MAC address byte array 2501 frame.put(transmitterMac); 2502 // BSSID (same as receiver address since we are sending to the AP) 2503 frame.put(receiverMac); 2504 2505 // Generate random sequence number, fragment number = 0 2506 // Note: driver should replace the sequence number with the correct number that is 2507 // incremented from the last used sequence number. Putting a random sequence number as a 2508 // default here just in case. 2509 // bit 0 is least significant bit, bit 15 is most significant bit 2510 // bits [0, 7] go in byte 0 2511 // bits [8, 15] go in byte 1 2512 // bits [0, 3] represent the fragment number (which is 0) 2513 // bits [4, 15] represent the sequence number (which is random) 2514 // clear bits [0, 3] to set fragment number = 0 2515 short sequenceAndFragmentNumber = (short) (mRandom.nextInt() & 0xfff0); 2516 frame.putShort(sequenceAndFragmentNumber); 2517 2518 // NL80211 rejects frames with an empty body, so we just need to put a placeholder 2519 // information element. 2520 // Tag for SSID 2521 frame.put((byte) 0x00); 2522 // Represents broadcast SSID. Not accurate, but works as placeholder. 2523 frame.put((byte) 0x00); 2524 2525 return frame.array(); 2526 } 2527 2528 private static final int CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS = 100; 2529 private static final int CONNECT_TO_HOSTAPD_RETRY_TIMES = 50; 2530 /** 2531 * This method is called to wait for establishing connection to hostapd. 2532 * 2533 * @return true if connection is established, false otherwise. 2534 */ 2535 private boolean startAndWaitForHostapdConnection() { 2536 // Start initialization if not already started. 2537 if (!mHostapdHal.isInitializationStarted() 2538 && !mHostapdHal.initialize()) { 2539 return false; 2540 } 2541 if (!mHostapdHal.startDaemon()) { 2542 Log.e(TAG, "Failed to startup hostapd"); 2543 return false; 2544 } 2545 boolean connected = false; 2546 int connectTries = 0; 2547 while (!connected && connectTries++ < CONNECT_TO_HOSTAPD_RETRY_TIMES) { 2548 // Check if the initialization is complete. 2549 connected = mHostapdHal.isInitializationComplete(); 2550 if (connected) { 2551 break; 2552 } 2553 try { 2554 Thread.sleep(CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS); 2555 } catch (InterruptedException ignore) { 2556 } 2557 } 2558 return connected; 2559 } 2560 2561 /** 2562 * Start Soft AP operation using the provided configuration. 2563 * 2564 * @param ifaceName Name of the interface. 2565 * @param config Configuration to use for the soft ap created. 2566 * @param isMetered Indicates the network is metered or not. 2567 * @param callback Callback for AP events. 2568 * @return one of {@link SoftApManager.StartResult} 2569 */ 2570 public @SoftApManager.StartResult int startSoftAp( 2571 @NonNull String ifaceName, SoftApConfiguration config, boolean isMetered, 2572 SoftApHalCallback callback, boolean isUsingMlo) { 2573 if (mHostapdHal.isApInfoCallbackSupported()) { 2574 if (!mHostapdHal.registerApCallback(ifaceName, callback)) { 2575 Log.e(TAG, "Failed to register ap hal event callback"); 2576 return SoftApManager.START_RESULT_FAILURE_REGISTER_AP_CALLBACK_HOSTAPD; 2577 } 2578 } else { 2579 SoftApHalCallbackFromWificond softApHalCallbackFromWificond = 2580 new SoftApHalCallbackFromWificond(ifaceName, callback); 2581 if (!mWifiCondManager.registerApCallback(ifaceName, 2582 Runnable::run, softApHalCallbackFromWificond)) { 2583 Log.e(TAG, "Failed to register ap hal event callback from wificond"); 2584 return SoftApManager.START_RESULT_FAILURE_REGISTER_AP_CALLBACK_WIFICOND; 2585 } 2586 } 2587 if (!mHostapdHal.addAccessPoint(ifaceName, config, isMetered, 2588 isUsingMlo, 2589 getBridgedApInstances(ifaceName), 2590 callback::onFailure)) { 2591 String errorMsg = "Failed to add softAp"; 2592 Log.e(TAG, errorMsg); 2593 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd(); 2594 takeBugReportInterfaceFailureIfNeeded("Wi-Fi BugReport (softap interface failure)", 2595 errorMsg); 2596 return SoftApManager.START_RESULT_FAILURE_ADD_AP_HOSTAPD; 2597 } 2598 2599 return SoftApManager.START_RESULT_SUCCESS; 2600 } 2601 2602 /** 2603 * Force a softap client disconnect with specific reason code. 2604 * 2605 * @param ifaceName Name of the interface. 2606 * @param client Mac address to force disconnect in clients of the SoftAp. 2607 * @param reasonCode One of disconnect reason code which defined in {@link ApConfigUtil}. 2608 * @return true on success, false otherwise. 2609 */ 2610 @Keep 2611 public boolean forceClientDisconnect(@NonNull String ifaceName, 2612 @NonNull MacAddress client, int reasonCode) { 2613 return mHostapdHal.forceClientDisconnect(ifaceName, client, reasonCode); 2614 } 2615 2616 /** 2617 * Set MAC address of the given interface 2618 * @param interfaceName Name of the interface 2619 * @param mac Mac address to change into 2620 * @return true on success 2621 */ 2622 public boolean setStaMacAddress(String interfaceName, MacAddress mac) { 2623 // TODO(b/72459123): Suppress interface down/up events from this call 2624 // Trigger an explicit disconnect to avoid losing the disconnect event reason (if currently 2625 // connected) from supplicant if the interface is brought down for MAC address change. 2626 disconnect(interfaceName); 2627 return mWifiVendorHal.setStaMacAddress(interfaceName, mac); 2628 } 2629 2630 /** 2631 * Set MAC address of the given interface 2632 * @param interfaceName Name of the interface 2633 * @param mac Mac address to change into 2634 * @return true on success 2635 */ 2636 public boolean setApMacAddress(String interfaceName, MacAddress mac) { 2637 return mWifiVendorHal.setApMacAddress(interfaceName, mac); 2638 } 2639 2640 /** 2641 * Returns true if Hal version supports setMacAddress, otherwise false. 2642 * 2643 * @param interfaceName Name of the interface 2644 */ 2645 public boolean isApSetMacAddressSupported(@NonNull String interfaceName) { 2646 return mWifiVendorHal.isApSetMacAddressSupported(interfaceName); 2647 } 2648 2649 /** 2650 * Get the factory MAC address of the given interface 2651 * @param interfaceName Name of the interface. 2652 * @return factory MAC address, or null on a failed call or if feature is unavailable. 2653 */ 2654 public MacAddress getStaFactoryMacAddress(@NonNull String interfaceName) { 2655 return mWifiVendorHal.getStaFactoryMacAddress(interfaceName); 2656 } 2657 2658 /** 2659 * Get the factory MAC address of the given interface 2660 * @param interfaceName Name of the interface. 2661 * @return factory MAC address, or null on a failed call or if feature is unavailable. 2662 */ 2663 public MacAddress getApFactoryMacAddress(@NonNull String interfaceName) { 2664 return mWifiVendorHal.getApFactoryMacAddress(interfaceName); 2665 } 2666 2667 /** 2668 * Reset MAC address to factory MAC address on the given interface 2669 * 2670 * @param interfaceName Name of the interface 2671 * @return true for success 2672 */ 2673 public boolean resetApMacToFactoryMacAddress(@NonNull String interfaceName) { 2674 return mWifiVendorHal.resetApMacToFactoryMacAddress(interfaceName); 2675 } 2676 2677 /** 2678 * Set the unsafe channels and restrictions to avoid for coex. 2679 * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid 2680 * @param restrictions Bitmask of WifiManager.COEX_RESTRICTION_ flags 2681 */ 2682 public void setCoexUnsafeChannels( 2683 @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) { 2684 mCachedCoexUnsafeChannels.clear(); 2685 mCachedCoexUnsafeChannels.addAll(unsafeChannels); 2686 mCachedCoexRestrictions = restrictions; 2687 mWifiVendorHal.setCoexUnsafeChannels(mCachedCoexUnsafeChannels, mCachedCoexRestrictions); 2688 } 2689 2690 /******************************************************** 2691 * Hostapd operations 2692 ********************************************************/ 2693 2694 /** 2695 * Callback to notify hostapd death. 2696 */ 2697 public interface HostapdDeathEventHandler { 2698 /** 2699 * Invoked when the supplicant dies. 2700 */ 2701 void onDeath(); 2702 } 2703 2704 /******************************************************** 2705 * Supplicant operations 2706 ********************************************************/ 2707 2708 /** 2709 * Callback to notify supplicant death. 2710 */ 2711 public interface SupplicantDeathEventHandler { 2712 /** 2713 * Invoked when the supplicant dies. 2714 */ 2715 void onDeath(); 2716 } 2717 2718 /** 2719 * Set supplicant log level 2720 * 2721 * @param turnOnVerbose Whether to turn on verbose logging or not. 2722 */ 2723 public void setSupplicantLogLevel(boolean turnOnVerbose) { 2724 mSupplicantStaIfaceHal.setLogLevel(turnOnVerbose); 2725 } 2726 2727 /** 2728 * Trigger a reconnection if the iface is disconnected. 2729 * 2730 * @param ifaceName Name of the interface. 2731 * @return true if request is sent successfully, false otherwise. 2732 */ 2733 public boolean reconnect(@NonNull String ifaceName) { 2734 return mSupplicantStaIfaceHal.reconnect(ifaceName); 2735 } 2736 2737 /** 2738 * Trigger a reassociation even if the iface is currently connected. 2739 * 2740 * @param ifaceName Name of the interface. 2741 * @return true if request is sent successfully, false otherwise. 2742 */ 2743 public boolean reassociate(@NonNull String ifaceName) { 2744 return mSupplicantStaIfaceHal.reassociate(ifaceName); 2745 } 2746 2747 /** 2748 * Trigger a disconnection from the currently connected network. 2749 * 2750 * @param ifaceName Name of the interface. 2751 * @return true if request is sent successfully, false otherwise. 2752 */ 2753 public boolean disconnect(@NonNull String ifaceName) { 2754 return mSupplicantStaIfaceHal.disconnect(ifaceName); 2755 } 2756 2757 /** 2758 * Makes a callback to HIDL to getMacAddress from supplicant 2759 * 2760 * @param ifaceName Name of the interface. 2761 * @return string containing the MAC address, or null on a failed call 2762 */ 2763 public String getMacAddress(@NonNull String ifaceName) { 2764 return mSupplicantStaIfaceHal.getMacAddress(ifaceName); 2765 } 2766 2767 public static final int RX_FILTER_TYPE_V4_MULTICAST = 0; 2768 public static final int RX_FILTER_TYPE_V6_MULTICAST = 1; 2769 /** 2770 * Start filtering out Multicast V4 packets 2771 * @param ifaceName Name of the interface. 2772 * @return {@code true} if the operation succeeded, {@code false} otherwise 2773 * 2774 * Multicast filtering rules work as follows: 2775 * 2776 * The driver can filter multicast (v4 and/or v6) and broadcast packets when in 2777 * a power optimized mode (typically when screen goes off). 2778 * 2779 * In order to prevent the driver from filtering the multicast/broadcast packets, we have to 2780 * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective 2781 * 2782 * DRIVER RXFILTER-ADD Num 2783 * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 2784 * 2785 * and DRIVER RXFILTER-START 2786 * In order to stop the usage of these rules, we do 2787 * 2788 * DRIVER RXFILTER-STOP 2789 * DRIVER RXFILTER-REMOVE Num 2790 * where Num is as described for RXFILTER-ADD 2791 * 2792 * The SETSUSPENDOPT driver command overrides the filtering rules 2793 */ 2794 public boolean startFilteringMulticastV4Packets(@NonNull String ifaceName) { 2795 return mSupplicantStaIfaceHal.stopRxFilter(ifaceName) 2796 && mSupplicantStaIfaceHal.removeRxFilter( 2797 ifaceName, RX_FILTER_TYPE_V4_MULTICAST) 2798 && mSupplicantStaIfaceHal.startRxFilter(ifaceName); 2799 } 2800 2801 /** 2802 * Stop filtering out Multicast V4 packets. 2803 * @param ifaceName Name of the interface. 2804 * @return {@code true} if the operation succeeded, {@code false} otherwise 2805 */ 2806 public boolean stopFilteringMulticastV4Packets(@NonNull String ifaceName) { 2807 return mSupplicantStaIfaceHal.stopRxFilter(ifaceName) 2808 && mSupplicantStaIfaceHal.addRxFilter( 2809 ifaceName, RX_FILTER_TYPE_V4_MULTICAST) 2810 && mSupplicantStaIfaceHal.startRxFilter(ifaceName); 2811 } 2812 2813 /** 2814 * Start filtering out Multicast V6 packets 2815 * @param ifaceName Name of the interface. 2816 * @return {@code true} if the operation succeeded, {@code false} otherwise 2817 */ 2818 public boolean startFilteringMulticastV6Packets(@NonNull String ifaceName) { 2819 return mSupplicantStaIfaceHal.stopRxFilter(ifaceName) 2820 && mSupplicantStaIfaceHal.removeRxFilter( 2821 ifaceName, RX_FILTER_TYPE_V6_MULTICAST) 2822 && mSupplicantStaIfaceHal.startRxFilter(ifaceName); 2823 } 2824 2825 /** 2826 * Stop filtering out Multicast V6 packets. 2827 * @param ifaceName Name of the interface. 2828 * @return {@code true} if the operation succeeded, {@code false} otherwise 2829 */ 2830 public boolean stopFilteringMulticastV6Packets(@NonNull String ifaceName) { 2831 return mSupplicantStaIfaceHal.stopRxFilter(ifaceName) 2832 && mSupplicantStaIfaceHal.addRxFilter( 2833 ifaceName, RX_FILTER_TYPE_V6_MULTICAST) 2834 && mSupplicantStaIfaceHal.startRxFilter(ifaceName); 2835 } 2836 2837 public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 2838 public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 2839 public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 2840 /** 2841 * Sets the bluetooth coexistence mode. 2842 * 2843 * @param ifaceName Name of the interface. 2844 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 2845 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 2846 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 2847 * @return Whether the mode was successfully set. 2848 */ 2849 public boolean setBluetoothCoexistenceMode(@NonNull String ifaceName, int mode) { 2850 return mSupplicantStaIfaceHal.setBtCoexistenceMode(ifaceName, mode); 2851 } 2852 2853 /** 2854 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 2855 * some of the low-level scan parameters used by the driver are changed to 2856 * reduce interference with A2DP streaming. 2857 * 2858 * @param ifaceName Name of the interface. 2859 * @param setCoexScanMode whether to enable or disable this mode 2860 * @return {@code true} if the command succeeded, {@code false} otherwise. 2861 */ 2862 public boolean setBluetoothCoexistenceScanMode( 2863 @NonNull String ifaceName, boolean setCoexScanMode) { 2864 return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled( 2865 ifaceName, setCoexScanMode); 2866 } 2867 2868 /** 2869 * Enable or disable suspend mode optimizations. 2870 * 2871 * @param ifaceName Name of the interface. 2872 * @param enabled true to enable, false otherwise. 2873 * @return true if request is sent successfully, false otherwise. 2874 */ 2875 public boolean setSuspendOptimizations(@NonNull String ifaceName, boolean enabled) { 2876 return mSupplicantStaIfaceHal.setSuspendModeEnabled(ifaceName, enabled); 2877 } 2878 2879 /** 2880 * Set country code for STA interface 2881 * 2882 * @param ifaceName Name of the STA interface. 2883 * @param countryCode 2 byte ASCII string. For ex: US, CA. 2884 * @return true if request is sent successfully, false otherwise. 2885 */ 2886 public boolean setStaCountryCode(@NonNull String ifaceName, String countryCode) { 2887 if (mSupplicantStaIfaceHal.setCountryCode(ifaceName, countryCode)) { 2888 if (mCountryCodeChangeListener != null) { 2889 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode); 2890 } 2891 return true; 2892 } 2893 return false; 2894 } 2895 2896 /** 2897 * Flush all previously configured HLPs. 2898 * 2899 * @return true if request is sent successfully, false otherwise. 2900 */ 2901 public boolean flushAllHlp(@NonNull String ifaceName) { 2902 return mSupplicantStaIfaceHal.flushAllHlp(ifaceName); 2903 } 2904 2905 /** 2906 * Set FILS HLP packet. 2907 * 2908 * @param dst Destination MAC address. 2909 * @param hlpPacket Hlp Packet data in hex. 2910 * @return true if request is sent successfully, false otherwise. 2911 */ 2912 public boolean addHlpReq(@NonNull String ifaceName, MacAddress dst, byte [] hlpPacket) { 2913 return mSupplicantStaIfaceHal.addHlpReq(ifaceName, dst.toByteArray(), hlpPacket); 2914 } 2915 2916 /** 2917 * Initiate TDLS discover and setup or teardown with the specified peer. 2918 * 2919 * @param ifaceName Name of the interface. 2920 * @param macAddr MAC Address of the peer. 2921 * @param enable true to start discovery and setup, false to teardown. 2922 * @return true if request is sent successfully, false otherwise. 2923 */ 2924 public boolean startTdls(@NonNull String ifaceName, String macAddr, boolean enable) { 2925 boolean ret = true; 2926 if (enable) { 2927 mSupplicantStaIfaceHal.initiateTdlsDiscover(ifaceName, macAddr); 2928 ret = mSupplicantStaIfaceHal.initiateTdlsSetup(ifaceName, macAddr); 2929 } else { 2930 ret = mSupplicantStaIfaceHal.initiateTdlsTeardown(ifaceName, macAddr); 2931 } 2932 return ret; 2933 } 2934 2935 /** 2936 * Start WPS pin display operation with the specified peer. 2937 * 2938 * @param ifaceName Name of the interface. 2939 * @param bssid BSSID of the peer. 2940 * @return true if request is sent successfully, false otherwise. 2941 */ 2942 public boolean startWpsPbc(@NonNull String ifaceName, String bssid) { 2943 return mSupplicantStaIfaceHal.startWpsPbc(ifaceName, bssid); 2944 } 2945 2946 /** 2947 * Start WPS pin keypad operation with the specified pin. 2948 * 2949 * @param ifaceName Name of the interface. 2950 * @param pin Pin to be used. 2951 * @return true if request is sent successfully, false otherwise. 2952 */ 2953 public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) { 2954 return mSupplicantStaIfaceHal.startWpsPinKeypad(ifaceName, pin); 2955 } 2956 2957 /** 2958 * Start WPS pin display operation with the specified peer. 2959 * 2960 * @param ifaceName Name of the interface. 2961 * @param bssid BSSID of the peer. 2962 * @return new pin generated on success, null otherwise. 2963 */ 2964 public String startWpsPinDisplay(@NonNull String ifaceName, String bssid) { 2965 return mSupplicantStaIfaceHal.startWpsPinDisplay(ifaceName, bssid); 2966 } 2967 2968 /** 2969 * Sets whether to use external sim for SIM/USIM processing. 2970 * 2971 * @param ifaceName Name of the interface. 2972 * @param external true to enable, false otherwise. 2973 * @return true if request is sent successfully, false otherwise. 2974 */ 2975 public boolean setExternalSim(@NonNull String ifaceName, boolean external) { 2976 return mSupplicantStaIfaceHal.setExternalSim(ifaceName, external); 2977 } 2978 2979 /** 2980 * Sim auth response types. 2981 */ 2982 public static final String SIM_AUTH_RESP_TYPE_GSM_AUTH = "GSM-AUTH"; 2983 public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTH = "UMTS-AUTH"; 2984 public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTS = "UMTS-AUTS"; 2985 2986 /** 2987 * EAP-SIM Error Codes 2988 */ 2989 public static final int EAP_SIM_NOT_SUBSCRIBED = 1031; 2990 public static final int EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED = 16385; 2991 2992 /** 2993 * Send the sim auth response for the currently configured network. 2994 * 2995 * @param ifaceName Name of the interface. 2996 * @param type |GSM-AUTH|, |UMTS-AUTH| or |UMTS-AUTS|. 2997 * @param response Response params. 2998 * @return true if succeeds, false otherwise. 2999 */ 3000 public boolean simAuthResponse( 3001 @NonNull String ifaceName, String type, String response) { 3002 if (SIM_AUTH_RESP_TYPE_GSM_AUTH.equals(type)) { 3003 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse( 3004 ifaceName, response); 3005 } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTH.equals(type)) { 3006 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse( 3007 ifaceName, response); 3008 } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTS.equals(type)) { 3009 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse( 3010 ifaceName, response); 3011 } else { 3012 return false; 3013 } 3014 } 3015 3016 /** 3017 * Send the eap sim gsm auth failure for the currently configured network. 3018 * 3019 * @param ifaceName Name of the interface. 3020 * @return true if succeeds, false otherwise. 3021 */ 3022 public boolean simAuthFailedResponse(@NonNull String ifaceName) { 3023 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure(ifaceName); 3024 } 3025 3026 /** 3027 * Send the eap sim umts auth failure for the currently configured network. 3028 * 3029 * @param ifaceName Name of the interface. 3030 * @return true if succeeds, false otherwise. 3031 */ 3032 public boolean umtsAuthFailedResponse(@NonNull String ifaceName) { 3033 return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure(ifaceName); 3034 } 3035 3036 /** 3037 * Send the eap identity response for the currently configured network. 3038 * 3039 * @param ifaceName Name of the interface. 3040 * @param unencryptedResponse String to send. 3041 * @param encryptedResponse String to send. 3042 * @return true if succeeds, false otherwise. 3043 */ 3044 public boolean simIdentityResponse(@NonNull String ifaceName, String unencryptedResponse, 3045 String encryptedResponse) { 3046 return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(ifaceName, 3047 unencryptedResponse, encryptedResponse); 3048 } 3049 3050 /** 3051 * This get anonymous identity from supplicant and returns it as a string. 3052 * 3053 * @param ifaceName Name of the interface. 3054 * @return anonymous identity string if succeeds, null otherwise. 3055 */ 3056 public String getEapAnonymousIdentity(@NonNull String ifaceName) { 3057 String anonymousIdentity = mSupplicantStaIfaceHal 3058 .getCurrentNetworkEapAnonymousIdentity(ifaceName); 3059 3060 if (TextUtils.isEmpty(anonymousIdentity)) { 3061 return anonymousIdentity; 3062 } 3063 3064 int indexOfDecoration = anonymousIdentity.lastIndexOf('!'); 3065 if (indexOfDecoration >= 0) { 3066 if (anonymousIdentity.substring(indexOfDecoration).length() < 2) { 3067 // Invalid identity, shouldn't happen 3068 Log.e(TAG, "Unexpected anonymous identity: " + anonymousIdentity); 3069 return null; 3070 } 3071 // Truncate RFC 7542 decorated prefix, if exists. Keep only the anonymous identity or 3072 // pseudonym. 3073 anonymousIdentity = anonymousIdentity.substring(indexOfDecoration + 1); 3074 } 3075 3076 return anonymousIdentity; 3077 } 3078 3079 /** 3080 * Start WPS pin registrar operation with the specified peer and pin. 3081 * 3082 * @param ifaceName Name of the interface. 3083 * @param bssid BSSID of the peer. 3084 * @param pin Pin to be used. 3085 * @return true if request is sent successfully, false otherwise. 3086 */ 3087 public boolean startWpsRegistrar(@NonNull String ifaceName, String bssid, String pin) { 3088 return mSupplicantStaIfaceHal.startWpsRegistrar(ifaceName, bssid, pin); 3089 } 3090 3091 /** 3092 * Cancels any ongoing WPS requests. 3093 * 3094 * @param ifaceName Name of the interface. 3095 * @return true if request is sent successfully, false otherwise. 3096 */ 3097 public boolean cancelWps(@NonNull String ifaceName) { 3098 return mSupplicantStaIfaceHal.cancelWps(ifaceName); 3099 } 3100 3101 /** 3102 * Set WPS device name. 3103 * 3104 * @param ifaceName Name of the interface. 3105 * @param name String to be set. 3106 * @return true if request is sent successfully, false otherwise. 3107 */ 3108 public boolean setDeviceName(@NonNull String ifaceName, String name) { 3109 return mSupplicantStaIfaceHal.setWpsDeviceName(ifaceName, name); 3110 } 3111 3112 /** 3113 * Set WPS device type. 3114 * 3115 * @param ifaceName Name of the interface. 3116 * @param type Type specified as a string. Used format: <categ>-<OUI>-<subcateg> 3117 * @return true if request is sent successfully, false otherwise. 3118 */ 3119 public boolean setDeviceType(@NonNull String ifaceName, String type) { 3120 return mSupplicantStaIfaceHal.setWpsDeviceType(ifaceName, type); 3121 } 3122 3123 /** 3124 * Set WPS config methods 3125 * 3126 * @param cfg List of config methods. 3127 * @return true if request is sent successfully, false otherwise. 3128 */ 3129 public boolean setConfigMethods(@NonNull String ifaceName, String cfg) { 3130 return mSupplicantStaIfaceHal.setWpsConfigMethods(ifaceName, cfg); 3131 } 3132 3133 /** 3134 * Set WPS manufacturer. 3135 * 3136 * @param ifaceName Name of the interface. 3137 * @param value String to be set. 3138 * @return true if request is sent successfully, false otherwise. 3139 */ 3140 public boolean setManufacturer(@NonNull String ifaceName, String value) { 3141 return mSupplicantStaIfaceHal.setWpsManufacturer(ifaceName, value); 3142 } 3143 3144 /** 3145 * Set WPS model name. 3146 * 3147 * @param ifaceName Name of the interface. 3148 * @param value String to be set. 3149 * @return true if request is sent successfully, false otherwise. 3150 */ 3151 public boolean setModelName(@NonNull String ifaceName, String value) { 3152 return mSupplicantStaIfaceHal.setWpsModelName(ifaceName, value); 3153 } 3154 3155 /** 3156 * Set WPS model number. 3157 * 3158 * @param ifaceName Name of the interface. 3159 * @param value String to be set. 3160 * @return true if request is sent successfully, false otherwise. 3161 */ 3162 public boolean setModelNumber(@NonNull String ifaceName, String value) { 3163 return mSupplicantStaIfaceHal.setWpsModelNumber(ifaceName, value); 3164 } 3165 3166 /** 3167 * Set WPS serial number. 3168 * 3169 * @param ifaceName Name of the interface. 3170 * @param value String to be set. 3171 * @return true if request is sent successfully, false otherwise. 3172 */ 3173 public boolean setSerialNumber(@NonNull String ifaceName, String value) { 3174 return mSupplicantStaIfaceHal.setWpsSerialNumber(ifaceName, value); 3175 } 3176 3177 /** 3178 * Enable or disable power save mode. 3179 * 3180 * @param ifaceName Name of the interface. 3181 * @param enabled true to enable, false to disable. 3182 */ 3183 public void setPowerSave(@NonNull String ifaceName, boolean enabled) { 3184 mSupplicantStaIfaceHal.setPowerSave(ifaceName, enabled); 3185 } 3186 3187 /** 3188 * Enable or disable low latency mode. 3189 * 3190 * @param enabled true to enable, false to disable. 3191 * @return true on success, false on failure 3192 */ 3193 public boolean setLowLatencyMode(boolean enabled) { 3194 return mWifiVendorHal.setLowLatencyMode(enabled); 3195 } 3196 3197 /** 3198 * Set concurrency priority between P2P & STA operations. 3199 * 3200 * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations, 3201 * false otherwise. 3202 * @return true if request is sent successfully, false otherwise. 3203 */ 3204 public boolean setConcurrencyPriority(boolean isStaHigherPriority) { 3205 return mSupplicantStaIfaceHal.setConcurrencyPriority(isStaHigherPriority); 3206 } 3207 3208 /** 3209 * Enable/Disable auto reconnect functionality in wpa_supplicant. 3210 * 3211 * @param ifaceName Name of the interface. 3212 * @param enable true to enable auto reconnecting, false to disable. 3213 * @return true if request is sent successfully, false otherwise. 3214 */ 3215 public boolean enableStaAutoReconnect(@NonNull String ifaceName, boolean enable) { 3216 return mSupplicantStaIfaceHal.enableAutoReconnect(ifaceName, enable); 3217 } 3218 3219 /** 3220 * Add the provided network configuration to wpa_supplicant and initiate connection to it. 3221 * This method does the following: 3222 * 1. Abort any ongoing scan to unblock the connection request. 3223 * 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect). 3224 * 3. Add a new network to wpa_supplicant. 3225 * 4. Save the provided configuration to wpa_supplicant. 3226 * 5. Select the new network in wpa_supplicant. 3227 * 6. Triggers reconnect command to wpa_supplicant. 3228 * 3229 * @param ifaceName Name of the interface. 3230 * @param configuration WifiConfiguration parameters for the provided network. 3231 * @return {@code true} if it succeeds, {@code false} otherwise 3232 */ 3233 public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) { 3234 // Abort ongoing scan before connect() to unblock connection request. 3235 mWifiCondManager.abortScan(ifaceName); 3236 return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration); 3237 } 3238 3239 /** 3240 * Initiates roaming to the already configured network in wpa_supplicant. If the network 3241 * configuration provided does not match the already configured network, then this triggers 3242 * a new connection attempt (instead of roam). 3243 * 1. Abort any ongoing scan to unblock the roam request. 3244 * 2. First check if we're attempting to connect to the same network as we currently have 3245 * configured. 3246 * 3. Set the new bssid for the network in wpa_supplicant. 3247 * 4. Triggers reassociate command to wpa_supplicant. 3248 * 3249 * @param ifaceName Name of the interface. 3250 * @param configuration WifiConfiguration parameters for the provided network. 3251 * @return {@code true} if it succeeds, {@code false} otherwise 3252 */ 3253 public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) { 3254 // Abort ongoing scan before connect() to unblock roaming request. 3255 mWifiCondManager.abortScan(ifaceName); 3256 return mSupplicantStaIfaceHal.roamToNetwork(ifaceName, configuration); 3257 } 3258 3259 /** 3260 * Remove all the networks. 3261 * 3262 * @param ifaceName Name of the interface. 3263 * @return {@code true} if it succeeds, {@code false} otherwise 3264 */ 3265 public boolean removeAllNetworks(@NonNull String ifaceName) { 3266 return mSupplicantStaIfaceHal.removeAllNetworks(ifaceName); 3267 } 3268 3269 /** 3270 * Disable the currently configured network in supplicant 3271 * 3272 * @param ifaceName Name of the interface. 3273 */ 3274 public boolean disableNetwork(@NonNull String ifaceName) { 3275 return mSupplicantStaIfaceHal.disableCurrentNetwork(ifaceName); 3276 } 3277 3278 /** 3279 * Set the BSSID for the currently configured network in wpa_supplicant. 3280 * 3281 * @param ifaceName Name of the interface. 3282 * @return true if successful, false otherwise. 3283 */ 3284 public boolean setNetworkBSSID(@NonNull String ifaceName, String bssid) { 3285 return mSupplicantStaIfaceHal.setCurrentNetworkBssid(ifaceName, bssid); 3286 } 3287 3288 /** 3289 * Initiate ANQP query. 3290 * 3291 * @param ifaceName Name of the interface. 3292 * @param bssid BSSID of the AP to be queried 3293 * @param anqpIds Set of anqp IDs. 3294 * @param hs20Subtypes Set of HS20 subtypes. 3295 * @return true on success, false otherwise. 3296 */ 3297 public boolean requestAnqp( 3298 @NonNull String ifaceName, String bssid, Set<Integer> anqpIds, 3299 Set<Integer> hs20Subtypes) { 3300 if (bssid == null || ((anqpIds == null || anqpIds.isEmpty()) 3301 && (hs20Subtypes == null || hs20Subtypes.isEmpty()))) { 3302 Log.e(TAG, "Invalid arguments for ANQP request."); 3303 return false; 3304 } 3305 ArrayList<Short> anqpIdList = new ArrayList<>(); 3306 for (Integer anqpId : anqpIds) { 3307 anqpIdList.add(anqpId.shortValue()); 3308 } 3309 ArrayList<Integer> hs20SubtypeList = new ArrayList<>(); 3310 hs20SubtypeList.addAll(hs20Subtypes); 3311 return mSupplicantStaIfaceHal.initiateAnqpQuery( 3312 ifaceName, bssid, anqpIdList, hs20SubtypeList); 3313 } 3314 3315 /** 3316 * Request a passpoint icon file |filename| from the specified AP |bssid|. 3317 * 3318 * @param ifaceName Name of the interface. 3319 * @param bssid BSSID of the AP 3320 * @param fileName name of the icon file 3321 * @return true if request is sent successfully, false otherwise 3322 */ 3323 public boolean requestIcon(@NonNull String ifaceName, String bssid, String fileName) { 3324 if (bssid == null || fileName == null) { 3325 Log.e(TAG, "Invalid arguments for Icon request."); 3326 return false; 3327 } 3328 return mSupplicantStaIfaceHal.initiateHs20IconQuery(ifaceName, bssid, fileName); 3329 } 3330 3331 /** 3332 * Initiate Venue URL ANQP query. 3333 * 3334 * @param ifaceName Name of the interface. 3335 * @param bssid BSSID of the AP to be queried 3336 * @return true on success, false otherwise. 3337 */ 3338 public boolean requestVenueUrlAnqp( 3339 @NonNull String ifaceName, String bssid) { 3340 if (bssid == null) { 3341 Log.e(TAG, "Invalid arguments for Venue URL ANQP request."); 3342 return false; 3343 } 3344 return mSupplicantStaIfaceHal.initiateVenueUrlAnqpQuery(ifaceName, bssid); 3345 } 3346 3347 /** 3348 * Get the currently configured network's WPS NFC token. 3349 * 3350 * @param ifaceName Name of the interface. 3351 * @return Hex string corresponding to the WPS NFC token. 3352 */ 3353 public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) { 3354 return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken(ifaceName); 3355 } 3356 3357 /** 3358 * Clean HAL cached data for |networkId|. 3359 * 3360 * @param networkId network id of the network to be removed from supplicant. 3361 */ 3362 public void removeNetworkCachedData(int networkId) { 3363 mSupplicantStaIfaceHal.removeNetworkCachedData(networkId); 3364 } 3365 3366 /** Clear HAL cached data for |networkId| if MAC address is changed. 3367 * 3368 * @param networkId network id of the network to be checked. 3369 * @param curMacAddress current MAC address 3370 */ 3371 public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) { 3372 mSupplicantStaIfaceHal.removeNetworkCachedDataIfNeeded(networkId, curMacAddress); 3373 } 3374 3375 /* 3376 * DPP 3377 */ 3378 3379 /** 3380 * Adds a DPP peer URI to the URI list. 3381 * 3382 * @param ifaceName Interface name 3383 * @param uri Bootstrap (URI) string (e.g. DPP:....) 3384 * @return ID, or -1 for failure 3385 */ 3386 public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) { 3387 return mSupplicantStaIfaceHal.addDppPeerUri(ifaceName, uri); 3388 } 3389 3390 /** 3391 * Removes a DPP URI to the URI list given an ID. 3392 * 3393 * @param ifaceName Interface name 3394 * @param bootstrapId Bootstrap (URI) ID 3395 * @return true when operation is successful, or false for failure 3396 */ 3397 public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId) { 3398 return mSupplicantStaIfaceHal.removeDppUri(ifaceName, bootstrapId); 3399 } 3400 3401 /** 3402 * Stops/aborts DPP Initiator request 3403 * 3404 * @param ifaceName Interface name 3405 * @return true when operation is successful, or false for failure 3406 */ 3407 public boolean stopDppInitiator(@NonNull String ifaceName) { 3408 return mSupplicantStaIfaceHal.stopDppInitiator(ifaceName); 3409 } 3410 3411 /** 3412 * Starts DPP Configurator-Initiator request 3413 * 3414 * @param ifaceName Interface name 3415 * @param peerBootstrapId Peer's bootstrap (URI) ID 3416 * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none 3417 * @param ssid SSID of the selected network 3418 * @param password Password of the selected network, or 3419 * @param psk PSK of the selected network in hexadecimal representation 3420 * @param netRole The network role of the enrollee (STA or AP) 3421 * @param securityAkm Security AKM to use: PSK, SAE 3422 * @return true when operation is successful, or false for failure 3423 */ 3424 public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId, 3425 int ownBootstrapId, @NonNull String ssid, String password, String psk, 3426 int netRole, int securityAkm, byte[] privEcKey) { 3427 return mSupplicantStaIfaceHal.startDppConfiguratorInitiator(ifaceName, peerBootstrapId, 3428 ownBootstrapId, ssid, password, psk, netRole, securityAkm, privEcKey); 3429 } 3430 3431 /** 3432 * Starts DPP Enrollee-Initiator request 3433 * 3434 * @param ifaceName Interface name 3435 * @param peerBootstrapId Peer's bootstrap (URI) ID 3436 * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none 3437 * @return true when operation is successful, or false for failure 3438 */ 3439 public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId, 3440 int ownBootstrapId) { 3441 return mSupplicantStaIfaceHal.startDppEnrolleeInitiator(ifaceName, peerBootstrapId, 3442 ownBootstrapId); 3443 } 3444 3445 /** 3446 * Callback to notify about DPP success, failure and progress events. 3447 */ 3448 public interface DppEventCallback { 3449 /** 3450 * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the 3451 * peer DPP configurator. 3452 * 3453 * @param newWifiConfiguration New Wi-Fi configuration received from the configurator 3454 * @param connStatusRequested Flag to indicate that the configurator requested 3455 * connection status 3456 */ 3457 void onSuccessConfigReceived(WifiConfiguration newWifiConfiguration, 3458 boolean connStatusRequested); 3459 3460 /** 3461 * DPP Success event. 3462 * 3463 * @param dppStatusCode Status code of the success event. 3464 */ 3465 void onSuccess(int dppStatusCode); 3466 3467 /** 3468 * DPP Progress event. 3469 * 3470 * @param dppStatusCode Status code of the progress event. 3471 */ 3472 void onProgress(int dppStatusCode); 3473 3474 /** 3475 * DPP Failure event. 3476 * 3477 * @param dppStatusCode Status code of the failure event. 3478 * @param ssid SSID of the network the Enrollee tried to connect to. 3479 * @param channelList List of channels the Enrollee scanned for the network. 3480 * @param bandList List of bands the Enrollee supports. 3481 */ 3482 void onFailure(int dppStatusCode, String ssid, String channelList, int[] bandList); 3483 3484 /** 3485 * DPP Configurator Private keys update. 3486 * 3487 * @param key Configurator's private EC key. 3488 */ 3489 void onDppConfiguratorKeyUpdate(byte[] key); 3490 3491 /** 3492 * Indicates that DPP connection status result frame is sent 3493 * 3494 * @param result DPP Status value indicating the result of a connection attempt. 3495 */ 3496 void onConnectionStatusResultSent(int result); 3497 } 3498 3499 /** 3500 * Class to get generated bootstrap info for DPP responder operation. 3501 */ 3502 public static class DppBootstrapQrCodeInfo { 3503 public int bootstrapId; 3504 public int listenChannel; 3505 public String uri = new String(); 3506 DppBootstrapQrCodeInfo() { 3507 bootstrapId = -1; 3508 listenChannel = -1; 3509 } 3510 } 3511 3512 /** 3513 * Generate DPP bootstrap Information:Bootstrap ID, DPP URI and the listen channel. 3514 * 3515 * @param ifaceName Interface name 3516 * @param deviceInfo Device specific info to attach in DPP URI. 3517 * @param dppCurve Elliptic curve cryptography type used to generate DPP 3518 * public/private key pair. 3519 * @return ID, or -1 for failure 3520 */ 3521 public DppBootstrapQrCodeInfo generateDppBootstrapInfoForResponder(@NonNull String ifaceName, 3522 String deviceInfo, int dppCurve) { 3523 return mSupplicantStaIfaceHal.generateDppBootstrapInfoForResponder(ifaceName, 3524 getMacAddress(ifaceName), deviceInfo, dppCurve); 3525 } 3526 3527 /** 3528 * start DPP Enrollee responder mode. 3529 * 3530 * @param ifaceName Interface name 3531 * @param listenChannel Listen channel to wait for DPP authentication request. 3532 * @return ID, or -1 for failure 3533 */ 3534 public boolean startDppEnrolleeResponder(@NonNull String ifaceName, int listenChannel) { 3535 return mSupplicantStaIfaceHal.startDppEnrolleeResponder(ifaceName, listenChannel); 3536 } 3537 3538 /** 3539 * Stops/aborts DPP Responder request 3540 * 3541 * @param ifaceName Interface name 3542 * @param ownBootstrapId Bootstrap (URI) ID 3543 * @return true when operation is successful, or false for failure 3544 */ 3545 public boolean stopDppResponder(@NonNull String ifaceName, int ownBootstrapId) { 3546 return mSupplicantStaIfaceHal.stopDppResponder(ifaceName, ownBootstrapId); 3547 } 3548 3549 3550 /** 3551 * Registers DPP event callbacks. 3552 * 3553 * @param dppEventCallback Callback object. 3554 */ 3555 public void registerDppEventCallback(DppEventCallback dppEventCallback) { 3556 mSupplicantStaIfaceHal.registerDppCallback(dppEventCallback); 3557 } 3558 3559 /** 3560 * Check whether Supplicant is using the AIDL HAL service. 3561 * 3562 * @return true if the Supplicant is using the AIDL service, false otherwise. 3563 */ 3564 public boolean isSupplicantUsingAidlService() { 3565 return mSupplicantStaIfaceHal.isAidlService(); 3566 } 3567 3568 /** 3569 * Check whether the Supplicant AIDL service is running at least the expected version. 3570 * 3571 * @param expectedVersion Version number to check. 3572 * @return true if the AIDL service is available and >= the expected version, false otherwise. 3573 */ 3574 public boolean isSupplicantAidlServiceVersionAtLeast(int expectedVersion) { 3575 return mSupplicantStaIfaceHal.isAidlServiceVersionAtLeast(expectedVersion); 3576 } 3577 3578 /******************************************************** 3579 * Vendor HAL operations 3580 ********************************************************/ 3581 /** 3582 * Callback to notify vendor HAL death. 3583 */ 3584 public interface VendorHalDeathEventHandler { 3585 /** 3586 * Invoked when the vendor HAL dies. 3587 */ 3588 void onDeath(); 3589 } 3590 3591 /** 3592 * Callback to notify when vendor HAL detects that a change in radio mode. 3593 */ 3594 public interface VendorHalRadioModeChangeEventHandler { 3595 /** 3596 * Invoked when the vendor HAL detects a change to MCC mode. 3597 * MCC (Multi channel concurrency) = Multiple interfaces are active on the same band, 3598 * different channels, same radios. 3599 * 3600 * @param band Band on which MCC is detected (specified by one of the 3601 * WifiScanner.WIFI_BAND_* constants) 3602 */ 3603 void onMcc(int band); 3604 /** 3605 * Invoked when the vendor HAL detects a change to SCC mode. 3606 * SCC (Single channel concurrency) = Multiple interfaces are active on the same band, same 3607 * channels, same radios. 3608 * 3609 * @param band Band on which SCC is detected (specified by one of the 3610 * WifiScanner.WIFI_BAND_* constants) 3611 */ 3612 void onScc(int band); 3613 /** 3614 * Invoked when the vendor HAL detects a change to SBS mode. 3615 * SBS (Single Band Simultaneous) = Multiple interfaces are active on the same band, 3616 * different channels, different radios. 3617 * 3618 * @param band Band on which SBS is detected (specified by one of the 3619 * WifiScanner.WIFI_BAND_* constants) 3620 */ 3621 void onSbs(int band); 3622 /** 3623 * Invoked when the vendor HAL detects a change to DBS mode. 3624 * DBS (Dual Band Simultaneous) = Multiple interfaces are active on the different bands, 3625 * different channels, different radios. 3626 */ 3627 void onDbs(); 3628 } 3629 3630 /** 3631 * Tests whether the HAL is running or not 3632 */ 3633 public boolean isHalStarted() { 3634 return mWifiVendorHal.isHalStarted(); 3635 } 3636 3637 /** 3638 * Tests whether the HAL is supported or not 3639 */ 3640 public boolean isHalSupported() { 3641 return mWifiVendorHal.isVendorHalSupported(); 3642 } 3643 3644 // TODO: Change variable names to camel style. 3645 public static class ScanCapabilities { 3646 public int max_scan_cache_size; 3647 public int max_scan_buckets; 3648 public int max_ap_cache_per_scan; 3649 public int max_rssi_sample_size; 3650 public int max_scan_reporting_threshold; 3651 } 3652 3653 /** 3654 * Gets the scan capabilities 3655 * 3656 * @param ifaceName Name of the interface. 3657 * @param capabilities object to be filled in 3658 * @return true for success. false for failure 3659 */ 3660 public boolean getBgScanCapabilities( 3661 @NonNull String ifaceName, ScanCapabilities capabilities) { 3662 return mWifiVendorHal.getBgScanCapabilities(ifaceName, capabilities); 3663 } 3664 3665 public static class ChannelSettings { 3666 public int frequency; 3667 public int dwell_time_ms; 3668 public boolean passive; 3669 } 3670 3671 public static class BucketSettings { 3672 public int bucket; 3673 public int band; 3674 public int period_ms; 3675 public int max_period_ms; 3676 public int step_count; 3677 public int report_events; 3678 public int num_channels; 3679 public ChannelSettings[] channels; 3680 } 3681 3682 /** 3683 * Network parameters for hidden networks to be scanned for. 3684 */ 3685 public static class HiddenNetwork { 3686 public String ssid; 3687 3688 @Override 3689 public boolean equals(Object otherObj) { 3690 if (this == otherObj) { 3691 return true; 3692 } else if (otherObj == null || getClass() != otherObj.getClass()) { 3693 return false; 3694 } 3695 HiddenNetwork other = (HiddenNetwork) otherObj; 3696 return Objects.equals(ssid, other.ssid); 3697 } 3698 3699 @Override 3700 public int hashCode() { 3701 return Objects.hash(ssid); 3702 } 3703 } 3704 3705 public static class ScanSettings { 3706 /** 3707 * Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}, 3708 * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}. 3709 */ 3710 @WifiAnnotations.ScanType 3711 public int scanType; 3712 public int base_period_ms; 3713 public int max_ap_per_scan; 3714 public int report_threshold_percent; 3715 public int report_threshold_num_scans; 3716 public int num_buckets; 3717 public boolean enable6GhzRnr; 3718 /* Not used for bg scans. Only works for single scans. */ 3719 public HiddenNetwork[] hiddenNetworks; 3720 public BucketSettings[] buckets; 3721 public byte[] vendorIes; 3722 } 3723 3724 /** 3725 * Network parameters to start PNO scan. 3726 */ 3727 public static class PnoNetwork { 3728 public String ssid; 3729 public byte flags; 3730 public byte auth_bit_field; 3731 public int[] frequencies; 3732 3733 @Override 3734 public boolean equals(Object otherObj) { 3735 if (this == otherObj) { 3736 return true; 3737 } else if (otherObj == null || getClass() != otherObj.getClass()) { 3738 return false; 3739 } 3740 PnoNetwork other = (PnoNetwork) otherObj; 3741 return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags) 3742 && (auth_bit_field == other.auth_bit_field)) 3743 && Arrays.equals(frequencies, other.frequencies); 3744 } 3745 3746 @Override 3747 public int hashCode() { 3748 return Objects.hash(ssid, flags, auth_bit_field, Arrays.hashCode(frequencies)); 3749 } 3750 3751 android.net.wifi.nl80211.PnoNetwork toNativePnoNetwork() { 3752 android.net.wifi.nl80211.PnoNetwork nativePnoNetwork = 3753 new android.net.wifi.nl80211.PnoNetwork(); 3754 nativePnoNetwork.setHidden( 3755 (flags & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0); 3756 try { 3757 nativePnoNetwork.setSsid( 3758 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid))); 3759 } catch (IllegalArgumentException e) { 3760 Log.e(TAG, "Illegal argument " + ssid, e); 3761 return null; 3762 } 3763 nativePnoNetwork.setFrequenciesMhz(frequencies); 3764 return nativePnoNetwork; 3765 } 3766 } 3767 3768 /** 3769 * Parameters to start PNO scan. This holds the list of networks which are going to used for 3770 * PNO scan. 3771 */ 3772 public static class PnoSettings { 3773 public int min5GHzRssi; 3774 public int min24GHzRssi; 3775 public int min6GHzRssi; 3776 public int periodInMs; 3777 public int scanIterations; 3778 public int scanIntervalMultiplier; 3779 public boolean isConnected; 3780 public PnoNetwork[] networkList; 3781 3782 android.net.wifi.nl80211.PnoSettings toNativePnoSettings() { 3783 android.net.wifi.nl80211.PnoSettings nativePnoSettings = 3784 new android.net.wifi.nl80211.PnoSettings(); 3785 nativePnoSettings.setIntervalMillis(periodInMs); 3786 nativePnoSettings.setMin2gRssiDbm(min24GHzRssi); 3787 nativePnoSettings.setMin5gRssiDbm(min5GHzRssi); 3788 nativePnoSettings.setMin6gRssiDbm(min6GHzRssi); 3789 if (SdkLevel.isAtLeastU()) { 3790 nativePnoSettings.setScanIterations(scanIterations); 3791 nativePnoSettings.setScanIntervalMultiplier(scanIntervalMultiplier); 3792 } 3793 3794 List<android.net.wifi.nl80211.PnoNetwork> pnoNetworks = new ArrayList<>(); 3795 if (networkList != null) { 3796 for (PnoNetwork network : networkList) { 3797 android.net.wifi.nl80211.PnoNetwork nativeNetwork = 3798 network.toNativePnoNetwork(); 3799 if (nativeNetwork != null) { 3800 pnoNetworks.add(nativeNetwork); 3801 } 3802 } 3803 } 3804 nativePnoSettings.setPnoNetworks(pnoNetworks); 3805 return nativePnoSettings; 3806 } 3807 } 3808 3809 public static interface ScanEventHandler { 3810 /** 3811 * Called for each AP as it is found with the entire contents of the beacon/probe response. 3812 * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified. 3813 */ 3814 void onFullScanResult(ScanResult fullScanResult, int bucketsScanned); 3815 /** 3816 * Callback on an event during a gscan scan. 3817 * See WifiNative.WIFI_SCAN_* for possible values. 3818 */ 3819 void onScanStatus(int event); 3820 /** 3821 * Called with the current cached scan results when gscan is paused. 3822 */ 3823 void onScanPaused(WifiScanner.ScanData[] data); 3824 /** 3825 * Called with the current cached scan results when gscan is resumed. 3826 */ 3827 void onScanRestarted(); 3828 /** 3829 * Callback to notify when the scan request fails. 3830 * See WifiScanner.REASON_* for possible values. 3831 */ 3832 void onScanRequestFailed(int errorCode); 3833 3834 /** 3835 * Callback for all APs ScanResult 3836 */ 3837 void onFullScanResults(List<ScanResult> fullScanResult, int bucketsScanned); 3838 } 3839 3840 /** 3841 * Handler to notify the occurrence of various events during PNO scan. 3842 */ 3843 public interface PnoEventHandler { 3844 /** 3845 * Callback to notify when one of the shortlisted networks is found during PNO scan. 3846 * @param results List of Scan results received. 3847 */ 3848 void onPnoNetworkFound(ScanResult[] results); 3849 3850 /** 3851 * Callback to notify when the PNO scan schedule fails. 3852 */ 3853 void onPnoScanFailed(); 3854 } 3855 3856 public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0; 3857 public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1; 3858 public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2; 3859 public static final int WIFI_SCAN_FAILED = 3; 3860 3861 /** 3862 * Starts a background scan. 3863 * Any ongoing scan will be stopped first 3864 * 3865 * @param ifaceName Name of the interface. 3866 * @param settings to control the scan 3867 * @param eventHandler to call with the results 3868 * @return true for success 3869 */ 3870 public boolean startBgScan( 3871 @NonNull String ifaceName, ScanSettings settings, ScanEventHandler eventHandler) { 3872 return mWifiVendorHal.startBgScan(ifaceName, settings, eventHandler); 3873 } 3874 3875 /** 3876 * Stops any ongoing backgound scan 3877 * @param ifaceName Name of the interface. 3878 */ 3879 public void stopBgScan(@NonNull String ifaceName) { 3880 mWifiVendorHal.stopBgScan(ifaceName); 3881 } 3882 3883 /** 3884 * Pauses an ongoing backgound scan 3885 * @param ifaceName Name of the interface. 3886 */ 3887 public void pauseBgScan(@NonNull String ifaceName) { 3888 mWifiVendorHal.pauseBgScan(ifaceName); 3889 } 3890 3891 /** 3892 * Restarts a paused scan 3893 * @param ifaceName Name of the interface. 3894 */ 3895 public void restartBgScan(@NonNull String ifaceName) { 3896 mWifiVendorHal.restartBgScan(ifaceName); 3897 } 3898 3899 /** 3900 * Gets the latest scan results received. 3901 * @param ifaceName Name of the interface. 3902 */ 3903 public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) { 3904 return mWifiVendorHal.getBgScanResults(ifaceName); 3905 } 3906 3907 /** 3908 * Sets whether global location mode is enabled. 3909 */ 3910 public void setLocationModeEnabled(boolean enabled) { 3911 if (!mIsLocationModeEnabled && enabled) { 3912 mLastLocationModeEnabledTimeMs = SystemClock.elapsedRealtime(); 3913 } 3914 Log.d(TAG, "mIsLocationModeEnabled " + enabled 3915 + " mLastLocationModeEnabledTimeMs " + mLastLocationModeEnabledTimeMs); 3916 mIsLocationModeEnabled = enabled; 3917 } 3918 3919 @NonNull 3920 private ScanResult[] getCachedScanResultsFilteredByLocationModeEnabled( 3921 @NonNull ScanResult[] scanResults) { 3922 List<ScanResult> resultList = new ArrayList<ScanResult>(); 3923 for (ScanResult scanResult : scanResults) { 3924 if (mIsLocationModeEnabled 3925 && scanResult.timestamp >= mLastLocationModeEnabledTimeMs * 1000) { 3926 resultList.add(scanResult); 3927 } 3928 } 3929 return resultList.toArray(new ScanResult[0]); 3930 } 3931 3932 /** 3933 * Gets the cached scan data from the given client interface 3934 */ 3935 @Nullable 3936 ScanData getCachedScanResults(String ifaceName) { 3937 ScanData scanData = mWifiVendorHal.getCachedScanData(ifaceName); 3938 ScanResult[] scanResults = scanData != null ? scanData.getResults() : null; 3939 if (scanResults == null) { 3940 return null; 3941 } 3942 ScanResult[] filteredResults = getCachedScanResultsFilteredByLocationModeEnabled( 3943 scanResults); 3944 return new ScanData(0, 0, 0, scanData.getScannedBands(), filteredResults); 3945 } 3946 3947 /** 3948 * Gets the cached scan data from all client interfaces 3949 */ 3950 @NonNull 3951 public ScanData getCachedScanResultsFromAllClientIfaces() { 3952 ScanData consolidatedScanData = new ScanData(); 3953 Set<String> ifaceNames = getClientInterfaceNames(); 3954 for (String ifaceName : ifaceNames) { 3955 ScanData scanData = getCachedScanResults(ifaceName); 3956 if (scanData == null) { 3957 continue; 3958 } 3959 consolidatedScanData.addResults(scanData.getResults()); 3960 } 3961 return consolidatedScanData; 3962 } 3963 3964 /** 3965 * Gets the latest link layer stats 3966 * @param ifaceName Name of the interface. 3967 */ 3968 @Keep 3969 public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) { 3970 WifiLinkLayerStats stats = mWifiVendorHal.getWifiLinkLayerStats(ifaceName); 3971 if (stats != null) { 3972 stats.aggregateLinkLayerStats(); 3973 stats.wifiMloMode = getMloMode(); 3974 ScanData scanData = getCachedScanResults(ifaceName); 3975 ScanResult[] scanResults = scanData != null ? scanData.getResults() : null; 3976 if (scanResults != null && scanResults.length > 0) { 3977 for (int linkIndex = 0; linkIndex < stats.links.length; ++linkIndex) { 3978 List<ScanResultWithSameFreq> ScanResultsSameFreq = new ArrayList<>(); 3979 for (int scanResultsIndex = 0; scanResultsIndex < scanResults.length; 3980 ++scanResultsIndex) { 3981 if (scanResults[scanResultsIndex].frequency 3982 != stats.links[linkIndex].frequencyMhz) { 3983 continue; 3984 } 3985 ScanResultWithSameFreq ScanResultSameFreq = new ScanResultWithSameFreq(); 3986 ScanResultSameFreq.scan_result_timestamp_micros = 3987 scanResults[scanResultsIndex].timestamp; 3988 ScanResultSameFreq.rssi = scanResults[scanResultsIndex].level; 3989 ScanResultSameFreq.frequencyMhz = 3990 scanResults[scanResultsIndex].frequency; 3991 ScanResultSameFreq.bssid = scanResults[scanResultsIndex].BSSID; 3992 ScanResultsSameFreq.add(ScanResultSameFreq); 3993 } 3994 stats.links[linkIndex].scan_results_same_freq = ScanResultsSameFreq; 3995 } 3996 } 3997 } 3998 return stats; 3999 } 4000 4001 /** 4002 * Gets the usable channels 4003 * @param band one of the {@code WifiScanner#WIFI_BAND_*} constants. 4004 * @param mode bitmask of {@code WifiAvailablechannel#OP_MODE_*} constants. 4005 * @param filter bitmask of filters (regulatory, coex, concurrency). 4006 * 4007 * @return list of channels 4008 */ 4009 public List<WifiAvailableChannel> getUsableChannels( 4010 @WifiScanner.WifiBand int band, 4011 @WifiAvailableChannel.OpMode int mode, 4012 @WifiAvailableChannel.Filter int filter) { 4013 return mWifiVendorHal.getUsableChannels(band, mode, filter); 4014 } 4015 /** 4016 * Returns whether the device supports the requested 4017 * {@link HalDeviceManager.HdmIfaceTypeForCreation} combo. 4018 */ 4019 public boolean canDeviceSupportCreateTypeCombo(SparseArray<Integer> combo) { 4020 synchronized (mLock) { 4021 return mWifiVendorHal.canDeviceSupportCreateTypeCombo(combo); 4022 } 4023 } 4024 4025 /** 4026 * Returns whether STA + AP concurrency is supported or not. 4027 */ 4028 public boolean isStaApConcurrencySupported() { 4029 synchronized (mLock) { 4030 return mWifiVendorHal.canDeviceSupportCreateTypeCombo( 4031 new SparseArray<Integer>() {{ 4032 put(HDM_CREATE_IFACE_STA, 1); 4033 put(HDM_CREATE_IFACE_AP, 1); 4034 }}); 4035 } 4036 } 4037 4038 /** 4039 * Returns whether STA + STA concurrency is supported or not. 4040 */ 4041 public boolean isStaStaConcurrencySupported() { 4042 synchronized (mLock) { 4043 return mWifiVendorHal.canDeviceSupportCreateTypeCombo( 4044 new SparseArray<Integer>() {{ 4045 put(HDM_CREATE_IFACE_STA, 2); 4046 }}); 4047 } 4048 } 4049 4050 /** 4051 * Returns whether P2p + STA concurrency is supported or not. 4052 */ 4053 public boolean isP2pStaConcurrencySupported() { 4054 synchronized (mLock) { 4055 return mWifiVendorHal.canDeviceSupportCreateTypeCombo( 4056 new SparseArray<Integer>() {{ 4057 put(HDM_CREATE_IFACE_STA, 1); 4058 put(HDM_CREATE_IFACE_P2P, 1); 4059 }}); 4060 } 4061 } 4062 4063 /** 4064 * Returns whether Nan + STA concurrency is supported or not. 4065 */ 4066 public boolean isNanStaConcurrencySupported() { 4067 synchronized (mLock) { 4068 return mWifiVendorHal.canDeviceSupportCreateTypeCombo( 4069 new SparseArray<Integer>() {{ 4070 put(HDM_CREATE_IFACE_STA, 1); 4071 put(HDM_CREATE_IFACE_NAN, 1); 4072 }}); 4073 } 4074 } 4075 4076 /** 4077 * Returns whether a new AP iface can be created or not. 4078 */ 4079 public boolean isItPossibleToCreateApIface(@NonNull WorkSource requestorWs) { 4080 synchronized (mLock) { 4081 if (!isHalStarted()) { 4082 return canDeviceSupportCreateTypeCombo( 4083 new SparseArray<Integer>() {{ 4084 put(HDM_CREATE_IFACE_AP, 1); 4085 }}); 4086 } 4087 return mWifiVendorHal.isItPossibleToCreateApIface(requestorWs); 4088 } 4089 } 4090 4091 /** 4092 * Returns whether a new AP iface can be created or not. 4093 */ 4094 public boolean isItPossibleToCreateBridgedApIface(@NonNull WorkSource requestorWs) { 4095 synchronized (mLock) { 4096 if (!isHalStarted()) { 4097 return canDeviceSupportCreateTypeCombo( 4098 new SparseArray<Integer>() {{ 4099 put(HDM_CREATE_IFACE_AP_BRIDGE, 1); 4100 }}); 4101 } 4102 return mWifiVendorHal.isItPossibleToCreateBridgedApIface(requestorWs); 4103 } 4104 } 4105 4106 /** 4107 * Returns whether creating a single AP does not require destroying an existing iface, but 4108 * creating a bridged AP does. 4109 */ 4110 public boolean shouldDowngradeToSingleApForConcurrency(@NonNull WorkSource requestorWs) { 4111 synchronized (mLock) { 4112 if (!mWifiVendorHal.isHalStarted()) { 4113 return false; 4114 } 4115 return !mWifiVendorHal.canDeviceSupportAdditionalIface(HDM_CREATE_IFACE_AP_BRIDGE, 4116 requestorWs) 4117 && mWifiVendorHal.canDeviceSupportAdditionalIface(HDM_CREATE_IFACE_AP, 4118 requestorWs); 4119 } 4120 } 4121 4122 /** 4123 * Returns whether a new STA iface can be created or not. 4124 */ 4125 public boolean isItPossibleToCreateStaIface(@NonNull WorkSource requestorWs) { 4126 synchronized (mLock) { 4127 if (!isHalStarted()) { 4128 return canDeviceSupportCreateTypeCombo( 4129 new SparseArray<Integer>() {{ 4130 put(HDM_CREATE_IFACE_STA, 1); 4131 }}); 4132 } 4133 return mWifiVendorHal.isItPossibleToCreateStaIface(requestorWs); 4134 } 4135 } 4136 4137 /** 4138 * Set primary connection when multiple STA ifaces are active. 4139 * 4140 * @param ifaceName Name of the interface. 4141 * @return true for success 4142 */ 4143 public boolean setMultiStaPrimaryConnection(@NonNull String ifaceName) { 4144 synchronized (mLock) { 4145 return mWifiVendorHal.setMultiStaPrimaryConnection(ifaceName); 4146 } 4147 } 4148 4149 /** 4150 * Multi STA use case flags. 4151 */ 4152 public static final int DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0; 4153 public static final int DUAL_STA_NON_TRANSIENT_UNBIASED = 1; 4154 4155 @IntDef({DUAL_STA_TRANSIENT_PREFER_PRIMARY, DUAL_STA_NON_TRANSIENT_UNBIASED}) 4156 @Retention(RetentionPolicy.SOURCE) 4157 public @interface MultiStaUseCase{} 4158 4159 /** 4160 * Set use-case when multiple STA ifaces are active. 4161 * 4162 * @param useCase one of the use cases. 4163 * @return true for success 4164 */ 4165 public boolean setMultiStaUseCase(@MultiStaUseCase int useCase) { 4166 synchronized (mLock) { 4167 return mWifiVendorHal.setMultiStaUseCase(useCase); 4168 } 4169 } 4170 4171 /** 4172 * Get the supported features 4173 * 4174 * @param ifaceName Name of the interface. 4175 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 4176 */ 4177 public @NonNull BitSet getSupportedFeatureSet(String ifaceName) { 4178 synchronized (mLock) { 4179 // First get the complete feature set stored in config store when supplicant was 4180 // started 4181 BitSet featureSet = getCompleteFeatureSetFromConfigStore(); 4182 // Include the feature set saved in interface class. This is to make sure that 4183 // framework is returning the feature set for SoftAp only products and multi-chip 4184 // products. 4185 if (ifaceName != null) { 4186 Iface iface = mIfaceMgr.getIface(ifaceName); 4187 if (iface != null) { 4188 featureSet.or(iface.featureSet); 4189 } 4190 } 4191 return featureSet; 4192 } 4193 } 4194 4195 /** 4196 * Get the supported bands for STA mode. 4197 * @return supported bands 4198 */ 4199 public @WifiScanner.WifiBand int getSupportedBandsForSta(String ifaceName) { 4200 synchronized (mLock) { 4201 if (ifaceName != null) { 4202 Iface iface = mIfaceMgr.getIface(ifaceName); 4203 if (iface != null) { 4204 return iface.bandsSupported; 4205 } 4206 } 4207 return WifiScanner.WIFI_BAND_UNSPECIFIED; 4208 } 4209 } 4210 4211 /** 4212 * Get the supported features 4213 * 4214 * @param ifaceName Name of the interface. 4215 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 4216 */ 4217 private BitSet getSupportedFeatureSetInternal(@NonNull String ifaceName) { 4218 BitSet featureSet = mSupplicantStaIfaceHal.getAdvancedCapabilities(ifaceName); 4219 featureSet.or(mSupplicantStaIfaceHal.getWpaDriverFeatureSet(ifaceName)); 4220 featureSet.or(mWifiVendorHal.getSupportedFeatureSet(ifaceName)); 4221 if (SdkLevel.isAtLeastT()) { 4222 if (featureSet.get(WifiManager.WIFI_FEATURE_DPP) 4223 && mContext.getResources().getBoolean(R.bool.config_wifiDppAkmSupported)) { 4224 // Set if DPP is filled by supplicant and DPP AKM is enabled by overlay. 4225 featureSet.set(WifiManager.WIFI_FEATURE_DPP_AKM); 4226 Log.v(TAG, ": DPP AKM supported"); 4227 } 4228 } 4229 Bundle twtCapabilities = mWifiVendorHal.getTwtCapabilities(ifaceName); 4230 if (twtCapabilities != null) mCachedTwtCapabilities.put(ifaceName, twtCapabilities); 4231 mCachedUsdCapabilities = mSupplicantStaIfaceHal.getUsdCapabilities(ifaceName); 4232 // Override device capability with overlay setting for publisher support 4233 if (mCachedUsdCapabilities != null && !mContext.getResources().getBoolean( 4234 R.bool.config_wifiUsdPublisherSupported)) { 4235 mCachedUsdCapabilities.isUsdPublisherSupported = false; 4236 } 4237 return featureSet; 4238 } 4239 4240 private void updateSupportedBandForStaInternal(Iface iface) { 4241 List<WifiAvailableChannel> usableChannelList = 4242 mWifiVendorHal.getUsableChannels(WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ, 4243 WifiAvailableChannel.OP_MODE_STA, 4244 WifiAvailableChannel.FILTER_REGULATORY); 4245 int bands = 0; 4246 if (usableChannelList == null) { 4247 // If HAL doesn't support getUsableChannels then check wificond 4248 if (getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ).length > 0) { 4249 bands |= WifiScanner.WIFI_BAND_24_GHZ; 4250 } 4251 if ((getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ).length > 0) 4252 || (getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY).length > 0)) { 4253 bands |= WifiScanner.WIFI_BAND_5_GHZ; 4254 } 4255 if (getChannelsForBand(WifiScanner.WIFI_BAND_6_GHZ).length > 0) { 4256 bands |= WifiScanner.WIFI_BAND_6_GHZ; 4257 } 4258 if (getChannelsForBand(WifiScanner.WIFI_BAND_60_GHZ).length > 0) { 4259 bands |= WifiScanner.WIFI_BAND_60_GHZ; 4260 } 4261 } else { 4262 for (int i = 0; i < usableChannelList.size(); i++) { 4263 int frequency = usableChannelList.get(i).getFrequencyMhz(); 4264 if (ScanResult.is24GHz(frequency)) { 4265 bands |= WifiScanner.WIFI_BAND_24_GHZ; 4266 } else if (ScanResult.is5GHz(frequency)) { 4267 bands |= WifiScanner.WIFI_BAND_5_GHZ; 4268 } else if (ScanResult.is6GHz(frequency)) { 4269 bands |= WifiScanner.WIFI_BAND_6_GHZ; 4270 } else if (ScanResult.is60GHz(frequency)) { 4271 bands |= WifiScanner.WIFI_BAND_60_GHZ; 4272 } 4273 } 4274 } 4275 if (mVerboseLoggingEnabled) { 4276 Log.i(TAG, "updateSupportedBandForStaInternal " + iface.name + " : 0x" 4277 + Integer.toHexString(bands)); 4278 } 4279 iface.bandsSupported = bands; 4280 } 4281 4282 /** 4283 * Class to retrieve connection capability parameters after association 4284 */ 4285 public static class ConnectionCapabilities { 4286 public @WifiAnnotations.WifiStandard int wifiStandard; 4287 public int channelBandwidth; 4288 public int maxNumberTxSpatialStreams; 4289 public int maxNumberRxSpatialStreams; 4290 public boolean is11bMode; 4291 /** Indicates the AP support for TID-to-link mapping negotiation. */ 4292 public boolean apTidToLinkMapNegotiationSupported; 4293 public @NonNull List<OuiKeyedData> vendorData; 4294 ConnectionCapabilities() { 4295 wifiStandard = ScanResult.WIFI_STANDARD_UNKNOWN; 4296 channelBandwidth = ScanResult.CHANNEL_WIDTH_20MHZ; 4297 maxNumberTxSpatialStreams = 1; 4298 maxNumberRxSpatialStreams = 1; 4299 is11bMode = false; 4300 vendorData = Collections.emptyList(); 4301 } 4302 } 4303 4304 /** 4305 * Returns connection capabilities of the current network 4306 * 4307 * @param ifaceName Name of the interface. 4308 * @return connection capabilities of the current network 4309 */ 4310 public ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) { 4311 return mSupplicantStaIfaceHal.getConnectionCapabilities(ifaceName); 4312 } 4313 4314 /** 4315 * Request signal polling to supplicant. 4316 * 4317 * @param ifaceName Name of the interface. 4318 * Returns an array of SignalPollResult objects. 4319 * Returns null on failure. 4320 */ 4321 @Keep 4322 @Nullable 4323 public WifiSignalPollResults signalPoll(@NonNull String ifaceName) { 4324 if (mMockWifiModem != null 4325 && mMockWifiModem.isMethodConfigured( 4326 MockWifiServiceUtil.MOCK_NL80211_SERVICE, "signalPoll")) { 4327 Log.i(TAG, "signalPoll was called from mock wificond"); 4328 WifiNl80211Manager.SignalPollResult result = 4329 mMockWifiModem.getWifiNl80211Manager().signalPoll(ifaceName); 4330 if (result != null) { 4331 // Convert WifiNl80211Manager#SignalPollResult to WifiSignalPollResults. 4332 // Assume single link and linkId = 0. 4333 WifiSignalPollResults results = new WifiSignalPollResults(); 4334 results.addEntry(0, result.currentRssiDbm, result.txBitrateMbps, 4335 result.rxBitrateMbps, result.associationFrequencyMHz); 4336 return results; 4337 } 4338 } 4339 // Query supplicant. 4340 WifiSignalPollResults results = mSupplicantStaIfaceHal.getSignalPollResults( 4341 ifaceName); 4342 if (results == null) { 4343 // Fallback to WifiCond. 4344 WifiNl80211Manager.SignalPollResult result = mWifiCondManager.signalPoll(ifaceName); 4345 if (result != null) { 4346 // Convert WifiNl80211Manager#SignalPollResult to WifiSignalPollResults. 4347 // Assume single link and linkId = 0. 4348 results = new WifiSignalPollResults(); 4349 results.addEntry(0, result.currentRssiDbm, result.txBitrateMbps, 4350 result.rxBitrateMbps, result.associationFrequencyMHz); 4351 } 4352 } 4353 return results; 4354 } 4355 4356 /** 4357 * Class to represent a connection MLO Link 4358 */ 4359 public static class ConnectionMloLink { 4360 private final int mLinkId; 4361 private final MacAddress mStaMacAddress; 4362 private final BitSet mTidsUplinkMap; 4363 private final BitSet mTidsDownlinkMap; 4364 private final MacAddress mApMacAddress; 4365 private final int mFrequencyMHz; 4366 4367 ConnectionMloLink(int id, MacAddress staMacAddress, MacAddress apMacAddress, 4368 byte tidsUplink, byte tidsDownlink, int frequencyMHz) { 4369 mLinkId = id; 4370 mStaMacAddress = staMacAddress; 4371 mApMacAddress = apMacAddress; 4372 mTidsDownlinkMap = BitSet.valueOf(new byte[] { tidsDownlink }); 4373 mTidsUplinkMap = BitSet.valueOf(new byte[] { tidsUplink }); 4374 mFrequencyMHz = frequencyMHz; 4375 }; 4376 4377 /** 4378 * Check if there is any TID mapped to this link in uplink of downlink direction. 4379 * 4380 * @return true if there is any TID mapped to this link, otherwise false. 4381 */ 4382 public boolean isAnyTidMapped() { 4383 if (mTidsDownlinkMap.isEmpty() && mTidsUplinkMap.isEmpty()) { 4384 return false; 4385 } 4386 return true; 4387 } 4388 4389 /** 4390 * Check if a TID is mapped to this link in uplink direction. 4391 * 4392 * @param tid TID value. 4393 * @return true if the TID is mapped in uplink direction. Otherwise, false. 4394 */ 4395 public boolean isTidMappedToUplink(byte tid) { 4396 if (tid < mTidsUplinkMap.length()) { 4397 return mTidsUplinkMap.get(tid); 4398 } 4399 return false; 4400 } 4401 4402 /** 4403 * Check if a TID is mapped to this link in downlink direction. Otherwise, false. 4404 * 4405 * @param tid TID value 4406 * @return true if the TID is mapped in downlink direction. Otherwise, false. 4407 */ 4408 public boolean isTidMappedtoDownlink(byte tid) { 4409 if (tid < mTidsDownlinkMap.length()) { 4410 return mTidsDownlinkMap.get(tid); 4411 } 4412 return false; 4413 } 4414 4415 /** 4416 * Get link id for the link. 4417 * 4418 * @return link id. 4419 */ 4420 public int getLinkId() { 4421 return mLinkId; 4422 } 4423 4424 /** 4425 * Get link STA MAC address. 4426 * 4427 * @return link mac address. 4428 */ 4429 public MacAddress getStaMacAddress() { 4430 return mStaMacAddress; 4431 } 4432 4433 /** 4434 * Get link AP MAC address. 4435 * 4436 * @return MAC address. 4437 */ 4438 public MacAddress getApMacAddress() { 4439 return mApMacAddress; 4440 } 4441 4442 /** 4443 * Get link frequency in MHz. 4444 * 4445 * @return frequency in Mhz. 4446 */ 4447 public int getFrequencyMHz() { 4448 return mFrequencyMHz; 4449 } 4450 } 4451 4452 /** 4453 * Class to represent the MLO links info for a connection that is collected after association 4454 */ 4455 public static class ConnectionMloLinksInfo { 4456 public ConnectionMloLink[] links; 4457 public MacAddress apMldMacAddress; 4458 public int apMloLinkId; 4459 ConnectionMloLinksInfo() { 4460 // Nothing for now 4461 } 4462 } 4463 4464 /** 4465 * Returns connection MLO Links Info. 4466 * 4467 * @param ifaceName Name of the interface. 4468 * @return connection MLO Links Info 4469 */ 4470 public ConnectionMloLinksInfo getConnectionMloLinksInfo(@NonNull String ifaceName) { 4471 return mSupplicantStaIfaceHal.getConnectionMloLinksInfo(ifaceName); 4472 } 4473 4474 /** 4475 * Get the APF (Android Packet Filter) capabilities of the device 4476 * @param ifaceName Name of the interface. 4477 */ 4478 public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) { 4479 return mWifiVendorHal.getApfCapabilities(ifaceName); 4480 } 4481 4482 /** 4483 * Installs an APF program on this iface, replacing any existing program. 4484 * 4485 * @param ifaceName Name of the interface 4486 * @param filter is the android packet filter program 4487 * @return true for success 4488 */ 4489 public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) { 4490 return mWifiVendorHal.installPacketFilter(ifaceName, filter); 4491 } 4492 4493 /** 4494 * Reads the APF program and data buffer for this iface. 4495 * 4496 * @param ifaceName Name of the interface 4497 * @return the buffer returned by the driver, or null in case of an error 4498 */ 4499 public byte[] readPacketFilter(@NonNull String ifaceName) { 4500 return mWifiVendorHal.readPacketFilter(ifaceName); 4501 } 4502 4503 /** 4504 * Set country code for this AP iface. 4505 * @param ifaceName Name of the AP interface. 4506 * @param countryCode - two-letter country code (as ISO 3166) 4507 * @return true for success 4508 */ 4509 public boolean setApCountryCode(@NonNull String ifaceName, String countryCode) { 4510 if (mWifiVendorHal.setApCountryCode(ifaceName, countryCode)) { 4511 if (mCountryCodeChangeListener != null) { 4512 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode); 4513 } 4514 return true; 4515 } 4516 return false; 4517 } 4518 4519 /** 4520 * Set country code for this chip 4521 * @param countryCode - two-letter country code (as ISO 3166) 4522 * @return true for success 4523 */ 4524 public boolean setChipCountryCode(String countryCode) { 4525 if (mWifiVendorHal.setChipCountryCode(countryCode)) { 4526 if (mCountryCodeChangeListener != null) { 4527 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode); 4528 } 4529 return true; 4530 } 4531 return false; 4532 } 4533 4534 //--------------------------------------------------------------------------------- 4535 /* Wifi Logger commands/events */ 4536 public static interface WifiLoggerEventHandler { 4537 void onRingBufferData(RingBufferStatus status, byte[] buffer); 4538 void onWifiAlert(int errorCode, byte[] buffer); 4539 } 4540 4541 /** 4542 * Registers the logger callback and enables alerts. 4543 * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked. 4544 * 4545 * @param handler Callback to be invoked. 4546 * @return true on success, false otherwise. 4547 */ 4548 public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) { 4549 return mWifiVendorHal.setLoggingEventHandler(handler); 4550 } 4551 4552 /** 4553 * Control debug data collection 4554 * 4555 * @param verboseLevel 0 to 3, inclusive. 0 stops logging. 4556 * @param flags Ignored. 4557 * @param maxInterval Maximum interval between reports; ignore if 0. 4558 * @param minDataSize Minimum data size in buffer for report; ignore if 0. 4559 * @param ringName Name of the ring for which data collection is to start. 4560 * @return true for success, false otherwise. 4561 */ 4562 public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval, 4563 int minDataSize, String ringName){ 4564 return mWifiVendorHal.startLoggingRingBuffer( 4565 verboseLevel, flags, maxInterval, minDataSize, ringName); 4566 } 4567 4568 /** 4569 * Logger features exposed. 4570 * This is a no-op now, will always return -1. 4571 * 4572 * @return true on success, false otherwise. 4573 */ 4574 public int getSupportedLoggerFeatureSet() { 4575 return mWifiVendorHal.getSupportedLoggerFeatureSet(); 4576 } 4577 4578 /** 4579 * Stops all logging and resets the logger callback. 4580 * This stops both the alerts and ring buffer data collection. 4581 * @return true on success, false otherwise. 4582 */ 4583 public boolean resetLogHandler() { 4584 return mWifiVendorHal.resetLogHandler(); 4585 } 4586 4587 /** 4588 * Vendor-provided wifi driver version string 4589 * 4590 * @return String returned from the HAL. 4591 */ 4592 public String getDriverVersion() { 4593 return mWifiVendorHal.getDriverVersion(); 4594 } 4595 4596 /** 4597 * Vendor-provided wifi firmware version string 4598 * 4599 * @return String returned from the HAL. 4600 */ 4601 public String getFirmwareVersion() { 4602 return mWifiVendorHal.getFirmwareVersion(); 4603 } 4604 4605 public static class RingBufferStatus{ 4606 public String name; 4607 public int flag; 4608 public int ringBufferId; 4609 public int ringBufferByteSize; 4610 public int verboseLevel; 4611 int writtenBytes; 4612 int readBytes; 4613 int writtenRecords; 4614 4615 // Bit masks for interpreting |flag| 4616 public static final int HAS_BINARY_ENTRIES = (1 << 0); 4617 public static final int HAS_ASCII_ENTRIES = (1 << 1); 4618 public static final int HAS_PER_PACKET_ENTRIES = (1 << 2); 4619 4620 @Override 4621 public String toString() { 4622 return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId + 4623 " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel + 4624 " writtenBytes: " + writtenBytes + " readBytes: " + readBytes + 4625 " writtenRecords: " + writtenRecords; 4626 } 4627 } 4628 4629 /** 4630 * API to get the status of all ring buffers supported by driver 4631 */ 4632 public RingBufferStatus[] getRingBufferStatus() { 4633 return mWifiVendorHal.getRingBufferStatus(); 4634 } 4635 4636 /** 4637 * Indicates to driver that all the data has to be uploaded urgently 4638 * 4639 * @param ringName Name of the ring buffer requested. 4640 * @return true on success, false otherwise. 4641 */ 4642 public boolean getRingBufferData(String ringName) { 4643 return mWifiVendorHal.getRingBufferData(ringName); 4644 } 4645 4646 /** 4647 * Request hal to flush ring buffers to files 4648 * 4649 * @return true on success, false otherwise. 4650 */ 4651 public boolean flushRingBufferData() { 4652 return mWifiVendorHal.flushRingBufferData(); 4653 } 4654 4655 /** 4656 * Request vendor debug info from the firmware 4657 * 4658 * @return Raw data obtained from the HAL. 4659 */ 4660 public byte[] getFwMemoryDump() { 4661 return mWifiVendorHal.getFwMemoryDump(); 4662 } 4663 4664 /** 4665 * Request vendor debug info from the driver 4666 * 4667 * @return Raw data obtained from the HAL. 4668 */ 4669 public byte[] getDriverStateDump() { 4670 return mWifiVendorHal.getDriverStateDump(); 4671 } 4672 4673 /** 4674 * Dump information about the internal state 4675 * 4676 * @param pw PrintWriter to write dump to 4677 */ 4678 protected void dump(PrintWriter pw) { 4679 pw.println("Dump of " + TAG); 4680 pw.println("mIsLocationModeEnabled: " + mIsLocationModeEnabled); 4681 pw.println("mLastLocationModeEnabledTimeMs: " + mLastLocationModeEnabledTimeMs); 4682 mHostapdHal.dump(pw); 4683 } 4684 4685 //--------------------------------------------------------------------------------- 4686 /* Packet fate API */ 4687 4688 @Immutable 4689 public abstract static class FateReport { 4690 final static int USEC_PER_MSEC = 1000; 4691 // The driver timestamp is a 32-bit counter, in microseconds. This field holds the 4692 // maximal value of a driver timestamp in milliseconds. 4693 final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000); 4694 final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS"); 4695 4696 public final byte mFate; 4697 public final long mDriverTimestampUSec; 4698 public final byte mFrameType; 4699 public final byte[] mFrameBytes; 4700 public final long mEstimatedWallclockMSec; 4701 4702 FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 4703 mFate = fate; 4704 mDriverTimestampUSec = driverTimestampUSec; 4705 mEstimatedWallclockMSec = 4706 convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec); 4707 mFrameType = frameType; 4708 mFrameBytes = frameBytes; 4709 } 4710 4711 public String toTableRowString() { 4712 StringWriter sw = new StringWriter(); 4713 PrintWriter pw = new PrintWriter(sw); 4714 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 4715 dateFormatter.setTimeZone(TimeZone.getDefault()); 4716 pw.format("%-15s %12s %-9s %-32s %-12s %-23s %s\n", 4717 mDriverTimestampUSec, 4718 dateFormatter.format(new Date(mEstimatedWallclockMSec)), 4719 directionToString(), fateToString(), parser.mMostSpecificProtocolString, 4720 parser.mTypeString, parser.mResultString); 4721 return sw.toString(); 4722 } 4723 4724 public String toVerboseStringWithPiiAllowed() { 4725 StringWriter sw = new StringWriter(); 4726 PrintWriter pw = new PrintWriter(sw); 4727 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 4728 pw.format("Frame direction: %s\n", directionToString()); 4729 pw.format("Frame timestamp: %d\n", mDriverTimestampUSec); 4730 pw.format("Frame fate: %s\n", fateToString()); 4731 pw.format("Frame type: %s\n", frameTypeToString(mFrameType)); 4732 pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString); 4733 pw.format("Frame protocol type: %s\n", parser.mTypeString); 4734 pw.format("Frame length: %d\n", mFrameBytes.length); 4735 pw.append("Frame bytes"); 4736 pw.append(HexDump.dumpHexString(mFrameBytes)); // potentially contains PII 4737 pw.append("\n"); 4738 return sw.toString(); 4739 } 4740 4741 /* Returns a header to match the output of toTableRowString(). */ 4742 public static String getTableHeader() { 4743 StringWriter sw = new StringWriter(); 4744 PrintWriter pw = new PrintWriter(sw); 4745 pw.format("\n%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 4746 "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result"); 4747 pw.format("%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 4748 "---------", "--------", "---------", "----", "--------", "----", "------"); 4749 return sw.toString(); 4750 } 4751 4752 protected abstract String directionToString(); 4753 4754 protected abstract String fateToString(); 4755 4756 private static String frameTypeToString(byte frameType) { 4757 switch (frameType) { 4758 case WifiLoggerHal.FRAME_TYPE_UNKNOWN: 4759 return "unknown"; 4760 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II: 4761 return "data"; 4762 case WifiLoggerHal.FRAME_TYPE_80211_MGMT: 4763 return "802.11 management"; 4764 default: 4765 return Byte.toString(frameType); 4766 } 4767 } 4768 4769 /** 4770 * Converts a driver timestamp to a wallclock time, based on the current 4771 * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of 4772 * microseconds, with the same base as BOOTTIME. 4773 */ 4774 private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) { 4775 final long wallclockMillisNow = System.currentTimeMillis(); 4776 final long boottimeMillisNow = SystemClock.elapsedRealtime(); 4777 final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC; 4778 4779 long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC; 4780 if (boottimeTimestampMillis < driverTimestampMillis) { 4781 // The 32-bit microsecond count has wrapped between the time that the driver 4782 // recorded the packet, and the call to this function. Adjust the BOOTTIME 4783 // timestamp, to compensate. 4784 // 4785 // Note that overflow is not a concern here, since the result is less than 4786 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above, 4787 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since 4788 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit 4789 // within a long. 4790 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC; 4791 } 4792 4793 final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis; 4794 return wallclockMillisNow - millisSincePacketTimestamp; 4795 } 4796 } 4797 4798 /** 4799 * Represents the fate information for one outbound packet. 4800 */ 4801 @Immutable 4802 public static final class TxFateReport extends FateReport { 4803 public TxFateReport(byte fate, long driverTimestampUSec, byte frameType, 4804 byte[] frameBytes) { 4805 super(fate, driverTimestampUSec, frameType, frameBytes); 4806 } 4807 4808 @Override 4809 protected String directionToString() { 4810 return "TX"; 4811 } 4812 4813 @Override 4814 protected String fateToString() { 4815 switch (mFate) { 4816 case WifiLoggerHal.TX_PKT_FATE_ACKED: 4817 return "acked"; 4818 case WifiLoggerHal.TX_PKT_FATE_SENT: 4819 return "sent"; 4820 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED: 4821 return "firmware queued"; 4822 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID: 4823 return "firmware dropped (invalid frame)"; 4824 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS: 4825 return "firmware dropped (no bufs)"; 4826 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER: 4827 return "firmware dropped (other)"; 4828 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED: 4829 return "driver queued"; 4830 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID: 4831 return "driver dropped (invalid frame)"; 4832 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS: 4833 return "driver dropped (no bufs)"; 4834 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER: 4835 return "driver dropped (other)"; 4836 default: 4837 return Byte.toString(mFate); 4838 } 4839 } 4840 } 4841 4842 /** 4843 * Represents the fate information for one inbound packet. 4844 */ 4845 @Immutable 4846 public static final class RxFateReport extends FateReport { 4847 public RxFateReport(byte fate, long driverTimestampUSec, byte frameType, 4848 byte[] frameBytes) { 4849 super(fate, driverTimestampUSec, frameType, frameBytes); 4850 } 4851 4852 @Override 4853 protected String directionToString() { 4854 return "RX"; 4855 } 4856 4857 @Override 4858 protected String fateToString() { 4859 switch (mFate) { 4860 case WifiLoggerHal.RX_PKT_FATE_SUCCESS: 4861 return "success"; 4862 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED: 4863 return "firmware queued"; 4864 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER: 4865 return "firmware dropped (filter)"; 4866 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID: 4867 return "firmware dropped (invalid frame)"; 4868 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS: 4869 return "firmware dropped (no bufs)"; 4870 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER: 4871 return "firmware dropped (other)"; 4872 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED: 4873 return "driver queued"; 4874 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER: 4875 return "driver dropped (filter)"; 4876 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID: 4877 return "driver dropped (invalid frame)"; 4878 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS: 4879 return "driver dropped (no bufs)"; 4880 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER: 4881 return "driver dropped (other)"; 4882 default: 4883 return Byte.toString(mFate); 4884 } 4885 } 4886 } 4887 4888 /** 4889 * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started. 4890 * 4891 * @param ifaceName Name of the interface. 4892 * @return true for success, false otherwise. 4893 */ 4894 public boolean startPktFateMonitoring(@NonNull String ifaceName) { 4895 return mWifiVendorHal.startPktFateMonitoring(ifaceName); 4896 } 4897 4898 /** 4899 * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started. 4900 * 4901 * @param ifaceName Name of the interface. 4902 * @return TxFateReport list on success, empty list on failure. Never returns null. 4903 */ 4904 @NonNull 4905 public List<TxFateReport> getTxPktFates(@NonNull String ifaceName) { 4906 return mWifiVendorHal.getTxPktFates(ifaceName); 4907 } 4908 4909 /** 4910 * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started. 4911 * @param ifaceName Name of the interface. 4912 * @return RxFateReport list on success, empty list on failure. Never returns null. 4913 */ 4914 @NonNull 4915 public List<RxFateReport> getRxPktFates(@NonNull String ifaceName) { 4916 return mWifiVendorHal.getRxPktFates(ifaceName); 4917 } 4918 4919 /** 4920 * Get the tx packet counts for the interface. 4921 * 4922 * @param ifaceName Name of the interface. 4923 * @return tx packet counts 4924 */ 4925 public long getTxPackets(@NonNull String ifaceName) { 4926 return TrafficStats.getTxPackets(ifaceName); 4927 } 4928 4929 /** 4930 * Get the rx packet counts for the interface. 4931 * 4932 * @param ifaceName Name of the interface 4933 * @return rx packet counts 4934 */ 4935 public long getRxPackets(@NonNull String ifaceName) { 4936 return TrafficStats.getRxPackets(ifaceName); 4937 } 4938 4939 /** 4940 * Start sending the specified keep alive packets periodically. 4941 * 4942 * @param ifaceName Name of the interface. 4943 * @param slot Integer used to identify each request. 4944 * @param dstMac Destination MAC Address 4945 * @param packet Raw packet contents to send. 4946 * @param protocol The ethernet protocol type 4947 * @param period Period to use for sending these packets. 4948 * @return 0 for success, -1 for error 4949 */ 4950 public int startSendingOffloadedPacket(@NonNull String ifaceName, int slot, 4951 byte[] dstMac, byte[] packet, int protocol, int period) { 4952 byte[] srcMac = NativeUtil.macAddressToByteArray(getMacAddress(ifaceName)); 4953 return mWifiVendorHal.startSendingOffloadedPacket( 4954 ifaceName, slot, srcMac, dstMac, packet, protocol, period); 4955 } 4956 4957 /** 4958 * Stop sending the specified keep alive packets. 4959 * 4960 * @param ifaceName Name of the interface. 4961 * @param slot id - same as startSendingOffloadedPacket call. 4962 * @return 0 for success, -1 for error 4963 */ 4964 public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) { 4965 return mWifiVendorHal.stopSendingOffloadedPacket(ifaceName, slot); 4966 } 4967 4968 public static interface WifiRssiEventHandler { 4969 void onRssiThresholdBreached(byte curRssi); 4970 } 4971 4972 /** 4973 * Start RSSI monitoring on the currently connected access point. 4974 * 4975 * @param ifaceName Name of the interface. 4976 * @param maxRssi Maximum RSSI threshold. 4977 * @param minRssi Minimum RSSI threshold. 4978 * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi 4979 * @return 0 for success, -1 for failure 4980 */ 4981 public int startRssiMonitoring( 4982 @NonNull String ifaceName, byte maxRssi, byte minRssi, 4983 WifiRssiEventHandler rssiEventHandler) { 4984 return mWifiVendorHal.startRssiMonitoring( 4985 ifaceName, maxRssi, minRssi, rssiEventHandler); 4986 } 4987 4988 /** 4989 * Stop RSSI monitoring on the currently connected access point. 4990 * 4991 * @param ifaceName Name of the interface. 4992 * @return 0 for success, -1 for failure 4993 */ 4994 public int stopRssiMonitoring(@NonNull String ifaceName) { 4995 return mWifiVendorHal.stopRssiMonitoring(ifaceName); 4996 } 4997 4998 /** 4999 * Fetch the host wakeup reasons stats from wlan driver. 5000 * 5001 * @return the |WlanWakeReasonAndCounts| object retrieved from the wlan driver. 5002 */ 5003 public WlanWakeReasonAndCounts getWlanWakeReasonCount() { 5004 return mWifiVendorHal.getWlanWakeReasonCount(); 5005 } 5006 5007 /** 5008 * Enable/Disable Neighbour discovery offload functionality in the firmware. 5009 * 5010 * @param ifaceName Name of the interface. 5011 * @param enabled true to enable, false to disable. 5012 * @return true for success, false otherwise. 5013 */ 5014 public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) { 5015 return mWifiVendorHal.configureNeighborDiscoveryOffload(ifaceName, enabled); 5016 } 5017 5018 // Firmware roaming control. 5019 5020 /** 5021 * Class to retrieve firmware roaming capability parameters. 5022 */ 5023 public static class RoamingCapabilities { 5024 public int maxBlocklistSize; 5025 public int maxAllowlistSize; 5026 } 5027 5028 /** 5029 * Query the firmware roaming capabilities. 5030 * @param ifaceName Name of the interface. 5031 * @return capabilities object on success, null otherwise. 5032 */ 5033 @Nullable 5034 public RoamingCapabilities getRoamingCapabilities(@NonNull String ifaceName) { 5035 return mWifiVendorHal.getRoamingCapabilities(ifaceName); 5036 } 5037 5038 /** 5039 * Macros for controlling firmware roaming. 5040 */ 5041 public static final int DISABLE_FIRMWARE_ROAMING = 0; 5042 public static final int ENABLE_FIRMWARE_ROAMING = 1; 5043 5044 @IntDef({ENABLE_FIRMWARE_ROAMING, DISABLE_FIRMWARE_ROAMING}) 5045 @Retention(RetentionPolicy.SOURCE) 5046 public @interface RoamingEnableState {} 5047 5048 /** 5049 * Indicates success for enableFirmwareRoaming 5050 */ 5051 public static final int SET_FIRMWARE_ROAMING_SUCCESS = 0; 5052 5053 /** 5054 * Indicates failure for enableFirmwareRoaming 5055 */ 5056 public static final int SET_FIRMWARE_ROAMING_FAILURE = 1; 5057 5058 /** 5059 * Indicates temporary failure for enableFirmwareRoaming - try again later 5060 */ 5061 public static final int SET_FIRMWARE_ROAMING_BUSY = 2; 5062 5063 @IntDef({SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE, SET_FIRMWARE_ROAMING_BUSY}) 5064 @Retention(RetentionPolicy.SOURCE) 5065 public @interface RoamingEnableStatus {} 5066 5067 /** 5068 * Enable/disable firmware roaming. 5069 * 5070 * @param ifaceName Name of the interface. 5071 * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE, 5072 * or SET_FIRMWARE_ROAMING_BUSY 5073 */ 5074 public @RoamingEnableStatus int enableFirmwareRoaming(@NonNull String ifaceName, 5075 @RoamingEnableState int state) { 5076 return mWifiVendorHal.enableFirmwareRoaming(ifaceName, state); 5077 } 5078 5079 /** 5080 * Class for specifying the roaming configurations. 5081 */ 5082 public static class RoamingConfig { 5083 public ArrayList<String> blocklistBssids; 5084 public ArrayList<String> allowlistSsids; 5085 } 5086 5087 /** 5088 * Set firmware roaming configurations. 5089 * @param ifaceName Name of the interface. 5090 */ 5091 public boolean configureRoaming(@NonNull String ifaceName, RoamingConfig config) { 5092 return mWifiVendorHal.configureRoaming(ifaceName, config); 5093 } 5094 5095 /** 5096 * Reset firmware roaming configuration. 5097 * @param ifaceName Name of the interface. 5098 */ 5099 public boolean resetRoamingConfiguration(@NonNull String ifaceName) { 5100 // Pass in an empty RoamingConfig object which translates to zero size 5101 // blacklist and whitelist to reset the firmware roaming configuration. 5102 return mWifiVendorHal.configureRoaming(ifaceName, new RoamingConfig()); 5103 } 5104 5105 /** 5106 * Select one of the pre-configured transmit power level scenarios or reset it back to normal. 5107 * Primarily used for meeting SAR requirements. 5108 * 5109 * @param sarInfo The collection of inputs used to select the SAR scenario. 5110 * @return true for success; false for failure or if the HAL version does not support this API. 5111 */ 5112 public boolean selectTxPowerScenario(SarInfo sarInfo) { 5113 return mWifiVendorHal.selectTxPowerScenario(sarInfo); 5114 } 5115 5116 /** 5117 * Set MBO cellular data status 5118 * 5119 * @param ifaceName Name of the interface. 5120 * @param available cellular data status, 5121 * true means cellular data available, false otherwise. 5122 */ 5123 public void setMboCellularDataStatus(@NonNull String ifaceName, boolean available) { 5124 mSupplicantStaIfaceHal.setMboCellularDataStatus(ifaceName, available); 5125 } 5126 5127 /** 5128 * Query of support of Wi-Fi standard 5129 * 5130 * @param ifaceName name of the interface to check support on 5131 * @param standard the wifi standard to check on 5132 * @return true if the wifi standard is supported on this interface, false otherwise. 5133 */ 5134 public boolean isWifiStandardSupported(@NonNull String ifaceName, 5135 @WifiAnnotations.WifiStandard int standard) { 5136 synchronized (mLock) { 5137 Iface iface = mIfaceMgr.getIface(ifaceName); 5138 if (iface == null || iface.phyCapabilities == null) { 5139 return false; 5140 } 5141 return iface.phyCapabilities.isWifiStandardSupported(standard); 5142 } 5143 } 5144 5145 /** 5146 * Get the Wiphy capabilities of a device for a given interface 5147 * If the interface is not associated with one, 5148 * it will be read from the device through wificond 5149 * 5150 * @param ifaceName name of the interface 5151 * @return the device capabilities for this interface 5152 */ 5153 @Keep 5154 public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) { 5155 return getDeviceWiphyCapabilities(ifaceName, false); 5156 } 5157 5158 /** 5159 * Get the Wiphy capabilities of a device for a given interface 5160 * If the interface is not associated with one, 5161 * it will be read from the device through wificond 5162 * 5163 * @param ifaceName name of the interface 5164 * @param isBridgedAp If the iface is bridge AP iface or not. 5165 * @return the device capabilities for this interface 5166 */ 5167 public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName, 5168 boolean isBridgedAp) { 5169 synchronized (mLock) { 5170 Iface iface = mIfaceMgr.getIface(ifaceName); 5171 if (iface == null) { 5172 Log.e(TAG, "Failed to get device capabilities, interface not found: " + ifaceName); 5173 return null; 5174 } 5175 if (iface.phyCapabilities == null) { 5176 if (isBridgedAp) { 5177 List<String> instances = getBridgedApInstances(ifaceName); 5178 if (instances != null && instances.size() != 0) { 5179 iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities( 5180 instances.get(0)); 5181 } 5182 } else { 5183 iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities(ifaceName); 5184 } 5185 } 5186 if (iface.phyCapabilities != null 5187 && iface.phyCapabilities.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE) 5188 != mWifiInjector.getSettingsConfigStore() 5189 .get(WifiSettingsConfigStore.WIFI_WIPHY_11BE_SUPPORTED)) { 5190 mWifiInjector.getSettingsConfigStore().put( 5191 WifiSettingsConfigStore.WIFI_WIPHY_11BE_SUPPORTED, 5192 iface.phyCapabilities.isWifiStandardSupported( 5193 ScanResult.WIFI_STANDARD_11BE)); 5194 } 5195 return iface.phyCapabilities; 5196 } 5197 } 5198 5199 /** 5200 * Set the Wiphy capabilities of a device for a given interface 5201 * 5202 * @param ifaceName name of the interface 5203 * @param capabilities the wiphy capabilities to set for this interface 5204 */ 5205 @Keep 5206 public void setDeviceWiphyCapabilities(@NonNull String ifaceName, 5207 DeviceWiphyCapabilities capabilities) { 5208 synchronized (mLock) { 5209 Iface iface = mIfaceMgr.getIface(ifaceName); 5210 if (iface == null) { 5211 Log.e(TAG, "Failed to set device capabilities, interface not found: " + ifaceName); 5212 return; 5213 } 5214 iface.phyCapabilities = capabilities; 5215 } 5216 } 5217 5218 /** 5219 * Notify scan mode state to driver to save power in scan-only mode. 5220 * 5221 * @param ifaceName Name of the interface. 5222 * @param enable whether is in scan-only mode 5223 * @return true for success 5224 */ 5225 public boolean setScanMode(String ifaceName, boolean enable) { 5226 return mWifiVendorHal.setScanMode(ifaceName, enable); 5227 } 5228 5229 /** updates linked networks of the |networkId| in supplicant if it's the current network, 5230 * if the current configured network matches |networkId|. 5231 * 5232 * @param ifaceName Name of the interface. 5233 * @param networkId network id of the network to be updated from supplicant. 5234 * @param linkedNetworks Map of config profile key and config for linking. 5235 */ 5236 public boolean updateLinkedNetworks(@NonNull String ifaceName, int networkId, 5237 Map<String, WifiConfiguration> linkedNetworks) { 5238 return mSupplicantStaIfaceHal.updateLinkedNetworks(ifaceName, networkId, linkedNetworks); 5239 } 5240 5241 /** 5242 * Start Subsystem Restart 5243 * @return true on success 5244 */ 5245 public boolean startSubsystemRestart() { 5246 return mWifiVendorHal.startSubsystemRestart(); 5247 } 5248 5249 /** 5250 * Register the provided listener for country code event. 5251 * 5252 * @param listener listener for country code changed events. 5253 */ 5254 public void registerCountryCodeEventListener(WifiCountryCode.ChangeListener listener) { 5255 registerWificondListenerIfNecessary(); 5256 if (mCountryCodeChangeListener != null) { 5257 mCountryCodeChangeListener.setChangeListener(listener); 5258 } 5259 } 5260 5261 /** 5262 * Gets the security params of the current network associated with this interface 5263 * 5264 * @param ifaceName Name of the interface 5265 * @return Security params of the current network associated with the interface 5266 */ 5267 public SecurityParams getCurrentNetworkSecurityParams(@NonNull String ifaceName) { 5268 return mSupplicantStaIfaceHal.getCurrentNetworkSecurityParams(ifaceName); 5269 } 5270 5271 /** 5272 * Check if the network-centric QoS policy feature was successfully enabled. 5273 */ 5274 public boolean isQosPolicyFeatureEnabled() { 5275 return mQosPolicyFeatureEnabled; 5276 } 5277 5278 /** 5279 * Sends a QoS policy response. 5280 * 5281 * @param ifaceName Name of the interface. 5282 * @param qosPolicyRequestId Dialog token to identify the request. 5283 * @param morePolicies Flag to indicate more QoS policies can be accommodated. 5284 * @param qosPolicyStatusList List of framework QosPolicyStatus objects. 5285 * @return true if response is sent successfully, false otherwise. 5286 */ 5287 public boolean sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId, 5288 boolean morePolicies, @NonNull List<QosPolicyStatus> qosPolicyStatusList) { 5289 if (!mQosPolicyFeatureEnabled) { 5290 Log.e(TAG, "Unable to send QoS policy response, feature is not enabled"); 5291 return false; 5292 } 5293 return mSupplicantStaIfaceHal.sendQosPolicyResponse(ifaceName, qosPolicyRequestId, 5294 morePolicies, qosPolicyStatusList); 5295 } 5296 5297 /** 5298 * Indicates the removal of all active QoS policies configured by the AP. 5299 * 5300 * @param ifaceName Name of the interface. 5301 */ 5302 public boolean removeAllQosPolicies(String ifaceName) { 5303 if (!mQosPolicyFeatureEnabled) { 5304 Log.e(TAG, "Unable to remove all QoS policies, feature is not enabled"); 5305 return false; 5306 } 5307 return mSupplicantStaIfaceHal.removeAllQosPolicies(ifaceName); 5308 } 5309 5310 /** 5311 * Send a set of QoS SCS policy add requests to the AP. 5312 * 5313 * Immediate response will indicate which policies were sent to the AP, and which were 5314 * rejected immediately by the supplicant. If any requests were sent to the AP, the AP's 5315 * response will arrive later in the onQosPolicyResponseForScs callback. 5316 * 5317 * @param ifaceName Name of the interface. 5318 * @param policies List of policies that the caller is requesting to add. 5319 * @return List of responses for each policy in the request, or null if an error occurred. 5320 * Status code will be one of 5321 * {@link SupplicantStaIfaceHal.QosPolicyScsRequestStatusCode}. 5322 */ 5323 List<SupplicantStaIfaceHal.QosPolicyStatus> addQosPolicyRequestForScs( 5324 @NonNull String ifaceName, @NonNull List<QosPolicyParams> policies) { 5325 return mSupplicantStaIfaceHal.addQosPolicyRequestForScs(ifaceName, policies); 5326 } 5327 5328 /** 5329 * Request the removal of specific QoS policies for SCS. 5330 * 5331 * Immediate response will indicate which policies were sent to the AP, and which were 5332 * rejected immediately by the supplicant. If any requests were sent to the AP, the AP's 5333 * response will arrive later in the onQosPolicyResponseForScs callback. 5334 * 5335 * @param ifaceName Name of the interface. 5336 * @param policyIds List of policy IDs for policies that should be removed. 5337 * @return List of responses for each policy in the request, or null if an error occurred. 5338 * Status code will be one of 5339 * {@link SupplicantStaIfaceHal.QosPolicyScsRequestStatusCode}. 5340 */ 5341 List<SupplicantStaIfaceHal.QosPolicyStatus> removeQosPolicyForScs( 5342 @NonNull String ifaceName, @NonNull List<Byte> policyIds) { 5343 return mSupplicantStaIfaceHal.removeQosPolicyForScs(ifaceName, policyIds); 5344 } 5345 5346 /** 5347 * Register a callback to receive notifications for QoS SCS transactions. 5348 * Callback should only be registered once. 5349 * 5350 * @param callback {@link SupplicantStaIfaceHal.QosScsResponseCallback} to register. 5351 */ 5352 public void registerQosScsResponseCallback( 5353 @NonNull SupplicantStaIfaceHal.QosScsResponseCallback callback) { 5354 mSupplicantStaIfaceHal.registerQosScsResponseCallback(callback); 5355 } 5356 5357 /** 5358 * Generate DPP credential for network access 5359 * 5360 * @param ifaceName Name of the interface. 5361 * @param ssid ssid of the network 5362 * @param privEcKey Private EC Key for DPP Configurator 5363 * Returns true when operation is successful. On error, false is returned. 5364 */ 5365 public boolean generateSelfDppConfiguration(@NonNull String ifaceName, @NonNull String ssid, 5366 byte[] privEcKey) { 5367 return mSupplicantStaIfaceHal.generateSelfDppConfiguration(ifaceName, ssid, privEcKey); 5368 } 5369 5370 /** 5371 * This set anonymous identity to supplicant. 5372 * 5373 * @param ifaceName Name of the interface. 5374 * @param anonymousIdentity the anonymouns identity. 5375 * @param updateToNativeService write the data to the native service. 5376 * @return true if succeeds, false otherwise. 5377 */ 5378 public boolean setEapAnonymousIdentity(@NonNull String ifaceName, String anonymousIdentity, 5379 boolean updateToNativeService) { 5380 if (null == anonymousIdentity) { 5381 Log.e(TAG, "Cannot set null anonymous identity."); 5382 return false; 5383 } 5384 return mSupplicantStaIfaceHal.setEapAnonymousIdentity(ifaceName, anonymousIdentity, 5385 updateToNativeService); 5386 } 5387 5388 /** 5389 * Notify wificond daemon of country code have changed. 5390 */ 5391 public void countryCodeChanged(String countryCode) { 5392 if (SdkLevel.isAtLeastT()) { 5393 try { 5394 mWifiCondManager.notifyCountryCodeChanged(countryCode); 5395 } catch (RuntimeException re) { 5396 Log.e(TAG, "Fail to notify wificond country code changed to " + countryCode 5397 + "because exception happened:" + re); 5398 } 5399 } 5400 } 5401 5402 /** 5403 * Return the maximum number of concurrent TDLS sessions supported by the device. 5404 * @return -1 if the information is not available on the device 5405 */ 5406 public int getMaxSupportedConcurrentTdlsSessions(@NonNull String ifaceName) { 5407 return mWifiVendorHal.getMaxSupportedConcurrentTdlsSessions(ifaceName); 5408 } 5409 5410 /** 5411 * Save the complete list of features retrieved from WiFi HAL and Supplicant HAL in 5412 * config store. 5413 */ 5414 private void saveCompleteFeatureSetInConfigStoreIfNecessary(BitSet featureSet) { 5415 BitSet cachedFeatureSet = getCompleteFeatureSetFromConfigStore(); 5416 if (!cachedFeatureSet.equals(featureSet)) { 5417 mCachedFeatureSet = featureSet; 5418 mWifiInjector.getSettingsConfigStore() 5419 .put(WIFI_NATIVE_EXTENDED_SUPPORTED_FEATURES, mCachedFeatureSet.toLongArray()); 5420 Log.i(TAG, "Supported features is updated in config store: " + mCachedFeatureSet); 5421 } 5422 } 5423 5424 /** 5425 * Get the feature set from cache/config store 5426 */ 5427 private BitSet getCompleteFeatureSetFromConfigStore() { 5428 if (mCachedFeatureSet == null) { 5429 long[] extendedFeatures = mWifiInjector.getSettingsConfigStore() 5430 .get(WIFI_NATIVE_EXTENDED_SUPPORTED_FEATURES); 5431 if (extendedFeatures == null || extendedFeatures.length == 0) { 5432 // Retrieve the legacy feature set if the extended features are not available 5433 long legacyFeatures = mWifiInjector.getSettingsConfigStore() 5434 .get(WIFI_NATIVE_SUPPORTED_FEATURES); 5435 mCachedFeatureSet = longToBitset(legacyFeatures); 5436 } else { 5437 mCachedFeatureSet = BitSet.valueOf(extendedFeatures); 5438 } 5439 } 5440 return mCachedFeatureSet; 5441 } 5442 5443 /** 5444 * Returns whether or not the hostapd HAL supports reporting single instance died event. 5445 */ 5446 public boolean isSoftApInstanceDiedHandlerSupported() { 5447 return mHostapdHal.isSoftApInstanceDiedHandlerSupported(); 5448 } 5449 5450 /** Checks if there are any STA (for connectivity) iface active. */ 5451 @VisibleForTesting 5452 boolean hasAnyStaIfaceForConnectivity() { 5453 return mIfaceMgr.hasAnyStaIfaceForConnectivity(); 5454 } 5455 5456 /** Checks if there are any STA (for scan) iface active. */ 5457 @VisibleForTesting 5458 boolean hasAnyStaIfaceForScan() { 5459 return mIfaceMgr.hasAnyStaIfaceForScan(); 5460 } 5461 5462 /** Checks if there are any AP iface active. */ 5463 @VisibleForTesting 5464 boolean hasAnyApIface() { 5465 return mIfaceMgr.hasAnyApIface(); 5466 } 5467 5468 /** Checks if there are any iface active. */ 5469 @VisibleForTesting 5470 boolean hasAnyIface() { 5471 return mIfaceMgr.hasAnyIface(); 5472 } 5473 5474 /** Checks if there are any P2P iface active. */ 5475 @VisibleForTesting 5476 boolean hasAnyP2pIface() { 5477 return mIfaceMgr.hasAnyP2pIface(); 5478 } 5479 5480 /** 5481 * Sets or clean mock wifi service 5482 * 5483 * @param serviceName the service name of mock wifi service. When service name is empty, the 5484 * framework will clean mock wifi service. 5485 */ 5486 public void setMockWifiService(String serviceName) { 5487 Log.d(TAG, "set MockWifiModemService to " + serviceName); 5488 if (TextUtils.isEmpty(serviceName)) { 5489 mMockWifiModem.unbindMockModemService(); 5490 mMockWifiModem = null; 5491 mWifiInjector.setMockWifiServiceUtil(null); 5492 return; 5493 } 5494 mMockWifiModem = new MockWifiServiceUtil(mContext, serviceName, mWifiMonitor); 5495 mWifiInjector.setMockWifiServiceUtil(mMockWifiModem); 5496 if (mMockWifiModem == null) { 5497 Log.e(TAG, "MockWifiServiceUtil creation failed."); 5498 return; 5499 } 5500 5501 // mock wifi modem service is set, try to bind all supported mock HAL services 5502 mMockWifiModem.bindAllMockModemService(); 5503 for (int service = MockWifiServiceUtil.MIN_SERVICE_IDX; 5504 service < MockWifiServiceUtil.NUM_SERVICES; service++) { 5505 int retryCount = 0; 5506 IBinder binder; 5507 do { 5508 binder = mMockWifiModem.getServiceBinder(service); 5509 retryCount++; 5510 if (binder == null) { 5511 Log.d(TAG, "Retry(" + retryCount + ") for " 5512 + mMockWifiModem.getModuleName(service)); 5513 try { 5514 Thread.sleep(MockWifiServiceUtil.BINDER_RETRY_MILLIS); 5515 } catch (InterruptedException e) { 5516 } 5517 } 5518 } while ((binder == null) && (retryCount < MockWifiServiceUtil.BINDER_MAX_RETRY)); 5519 5520 if (binder == null) { 5521 Log.e(TAG, "Mock " + mMockWifiModem.getModuleName(service) + " bind fail"); 5522 } 5523 } 5524 } 5525 5526 /** 5527 * Returns mock wifi service name. 5528 */ 5529 public String getMockWifiServiceName() { 5530 String serviceName = mMockWifiModem != null ? mMockWifiModem.getServiceName() : null; 5531 Log.d(TAG, "getMockWifiServiceName - service name is " + serviceName); 5532 return serviceName; 5533 } 5534 5535 /** 5536 * Sets mocked methods which like to be called. 5537 * 5538 * @param methods the methods string with formats HAL name - method name, ... 5539 */ 5540 public boolean setMockWifiMethods(String methods) { 5541 if (mMockWifiModem == null || methods == null) { 5542 return false; 5543 } 5544 return mMockWifiModem.setMockedMethods(methods); 5545 } 5546 5547 /** 5548 * Set maximum acceptable DTIM multiplier to hardware driver. Any multiplier larger than the 5549 * maximum value must not be accepted, it will cause packet loss higher than what the system 5550 * can accept, which will cause unexpected behavior for apps, and may interrupt the network 5551 * connection. 5552 * 5553 * @param ifaceName Name of the interface. 5554 * @param multiplier integer maximum DTIM multiplier value to set. 5555 * @return true for success 5556 */ 5557 public boolean setDtimMultiplier(String ifaceName, int multiplier) { 5558 return mWifiVendorHal.setDtimMultiplier(ifaceName, multiplier); 5559 } 5560 5561 /** 5562 * Set Multi-Link Operation mode. 5563 * 5564 * @param mode Multi-Link Operation mode {@link android.net.wifi.WifiManager.MloMode}. 5565 * @return {@link WifiStatusCode#SUCCESS} if success, otherwise error code. 5566 */ 5567 public @WifiStatusCode int setMloMode(@WifiManager.MloMode int mode) { 5568 @WifiStatusCode int errorCode = mWifiVendorHal.setMloMode(mode); 5569 // If set is success, cache it. 5570 if (errorCode == WifiStatusCode.SUCCESS) mCachedMloMode = mode; 5571 return errorCode; 5572 } 5573 5574 /** 5575 * Get Multi-Link Operation mode. 5576 * 5577 * @return Current Multi-Link Operation mode {@link android.net.wifi.WifiManager.MloMode}. 5578 */ 5579 public @WifiManager.MloMode int getMloMode() { 5580 return mCachedMloMode; 5581 } 5582 5583 /** 5584 * Get the maximum number of links supported by the chip for MLO association. 5585 * 5586 * e.g. if the chip supports eMLSR (Enhanced Multi-Link Single Radio) and STR (Simultaneous 5587 * Transmit and Receive) with following capabilities, 5588 * - Maximum MLO association link count = 3 5589 * - Maximum MLO STR link count = 2 See {@link WifiNative#getMaxMloStrLinkCount(String)} 5590 * One of the possible configuration is - STR (2.4 , eMLSR(5, 6)), provided the radio 5591 * combination of the chip supports it. 5592 * 5593 * Note: This is an input to MLO aware network scoring logic to predict maximum multi-link 5594 * throughput. 5595 * 5596 * @param ifaceName Name of the interface. 5597 * @return maximum number of association links or -1 if error or not available. 5598 */ 5599 public int getMaxMloAssociationLinkCount(@NonNull String ifaceName) { 5600 return mWifiVendorHal.getMaxMloAssociationLinkCount(ifaceName); 5601 } 5602 5603 /** 5604 * Get the maximum number of STR links used in Multi-Link Operation. The maximum number of STR 5605 * links used for MLO can be different from the number of radios supported by the chip. 5606 * 5607 * e.g. if the chip supports eMLSR (Enhanced Multi-Link Single Radio) and STR (Simultaneous 5608 * Transmit and Receive) with following capabilities, 5609 * - Maximum MLO association link count = 3 5610 * See {@link WifiNative#getMaxMloAssociationLinkCount(String)} 5611 * - Maximum MLO STR link count = 2 5612 * One of the possible configuration is - STR (2.4, eMLSR(5, 6)), provided the radio 5613 * combination of the chip supports it. 5614 * 5615 * Note: This is an input to MLO aware network scoring logic to predict maximum multi-link 5616 * throughput. 5617 * 5618 * @param ifaceName Name of the interface. 5619 * @return maximum number of MLO STR links or -1 if error or not available. 5620 */ 5621 public int getMaxMloStrLinkCount(@NonNull String ifaceName) { 5622 return mWifiVendorHal.getMaxMloStrLinkCount(ifaceName); 5623 } 5624 5625 /** 5626 * Check the given band combination is supported simultaneously by the Wi-Fi chip. 5627 * 5628 * Note: This method is for checking simultaneous band operations and not for multichannel 5629 * concurrent operation (MCC). 5630 * 5631 * @param ifaceName Name of the interface. 5632 * @param bands A list of bands in the combination. See {@link WifiScanner.WifiBand} 5633 * for the band enums. List of bands can be in any order. 5634 * @return true if the provided band combination is supported by the chip, otherwise false. 5635 */ 5636 public boolean isBandCombinationSupported(@NonNull String ifaceName, List<Integer> bands) { 5637 return mWifiVendorHal.isBandCombinationSupported(ifaceName, bands); 5638 } 5639 5640 /** 5641 * Get the set of band combinations supported simultaneously by the Wi-Fi Chip. 5642 * 5643 * Note: This method returns simultaneous band operation combination and not multichannel 5644 * concurrent operation (MCC) combination. 5645 * 5646 * @param ifaceName Name of the interface. 5647 * @return An unmodifiable set of supported band combinations. 5648 */ 5649 public Set<List<Integer>> getSupportedBandCombinations(@NonNull String ifaceName) { 5650 return mWifiVendorHal.getSupportedBandCombinations(ifaceName); 5651 } 5652 5653 /** 5654 * Sends the AFC allowed channels and frequencies to the driver. 5655 * 5656 * @param afcChannelAllowance the allowed frequencies and channels received from 5657 * querying the AFC server. 5658 * @return whether the channel allowance was set successfully. 5659 */ 5660 public boolean setAfcChannelAllowance(WifiChip.AfcChannelAllowance afcChannelAllowance) { 5661 return mWifiVendorHal.setAfcChannelAllowance(afcChannelAllowance); 5662 } 5663 5664 /** 5665 * Enable Mirrored Stream Classification Service (MSCS) and configure using 5666 * the provided configuration values. 5667 * 5668 * @param mscsParams {@link MscsParams} object containing the configuration parameters. 5669 * @param ifaceName Name of the interface. 5670 */ 5671 public void enableMscs(@NonNull MscsParams mscsParams, String ifaceName) { 5672 mSupplicantStaIfaceHal.enableMscs(mscsParams, ifaceName); 5673 } 5674 5675 /** 5676 * Resend the previously configured MSCS parameters on this interface, if any exist. 5677 * 5678 * @param ifaceName Name of the interface. 5679 */ 5680 public void resendMscs(String ifaceName) { 5681 mSupplicantStaIfaceHal.resendMscs(ifaceName); 5682 } 5683 5684 /** 5685 * Disable Mirrored Stream Classification Service (MSCS). 5686 * 5687 * @param ifaceName Name of the interface. 5688 */ 5689 public void disableMscs(String ifaceName) { 5690 mSupplicantStaIfaceHal.disableMscs(ifaceName); 5691 } 5692 5693 /** 5694 * Set the roaming mode value. 5695 * 5696 * @param ifaceName Name of the interface. 5697 * @param roamingMode {@link android.net.wifi.WifiManager.RoamingMode}. 5698 * @return {@link WifiStatusCode#SUCCESS} if success, otherwise error code. 5699 */ 5700 public @WifiStatusCode int setRoamingMode(@NonNull String ifaceName, 5701 @RoamingMode int roamingMode) { 5702 return mWifiVendorHal.setRoamingMode(ifaceName, roamingMode); 5703 } 5704 5705 /* 5706 * TWT callback events 5707 */ 5708 public interface WifiTwtEvents { 5709 /** 5710 * Called when a TWT operation fails 5711 * 5712 * @param cmdId Unique command id. 5713 * @param twtErrorCode Error code 5714 */ 5715 void onTwtFailure(int cmdId, @TwtSessionCallback.TwtErrorCode int twtErrorCode); 5716 5717 /** 5718 * Called when {@link #setupTwtSession(int, String, TwtRequest)} succeeds. 5719 * 5720 * @param cmdId Unique command id used in {@link #setupTwtSession(int, String, TwtRequest)} 5721 * @param wakeDurationUs TWT wake duration for the session in microseconds 5722 * @param wakeIntervalUs TWT wake interval for the session in microseconds 5723 * @param linkId Multi link operation link id 5724 * @param sessionId TWT session id 5725 */ 5726 void onTwtSessionCreate(int cmdId, int wakeDurationUs, long wakeIntervalUs, int linkId, 5727 int sessionId); 5728 /** 5729 * Called when TWT session is torn down by {@link #tearDownTwtSession(int, String, int)}. 5730 * Can also be called unsolicitedly by the vendor software with proper reason code. 5731 * 5732 * @param cmdId Unique command id used in {@link #tearDownTwtSession(int, String, int)} 5733 * @param twtSessionId TWT session Id 5734 * @param twtReasonCode Reason code for teardown 5735 */ 5736 void onTwtSessionTeardown(int cmdId, int twtSessionId, 5737 @TwtSessionCallback.TwtReasonCode int twtReasonCode); 5738 5739 /** 5740 * Called as a response to {@link #getStatsTwtSession(int, String, int)} 5741 * 5742 * @param cmdId Unique command id used in {@link #getStatsTwtSession(int, String, int)} 5743 * @param twtSessionId TWT session Id 5744 * @param twtStats TWT stats object 5745 */ 5746 void onTwtSessionStats(int cmdId, int twtSessionId, Bundle twtStats); 5747 } 5748 5749 5750 /** 5751 * Sets up a TWT session for the interface 5752 * 5753 * @param commandId A unique command id to identify this command 5754 * @param interfaceName Interface name 5755 * @param twtRequest TWT request parameters 5756 * @return true if successful, otherwise false 5757 */ 5758 public boolean setupTwtSession(int commandId, String interfaceName, TwtRequest twtRequest) { 5759 return mWifiVendorHal.setupTwtSession(commandId, interfaceName, twtRequest); 5760 } 5761 5762 /** 5763 * Registers TWT callbacks 5764 * 5765 * @param wifiTwtCallback TWT callbacks 5766 */ 5767 public void registerTwtCallbacks(WifiTwtEvents wifiTwtCallback) { 5768 mWifiVendorHal.registerTwtCallbacks(wifiTwtCallback); 5769 } 5770 5771 /** 5772 * Teardown the TWT session 5773 * 5774 * @param commandId A unique command id to identify this command 5775 * @param interfaceName Interface name 5776 * @param sessionId TWT session id 5777 * @return true if successful, otherwise false 5778 */ 5779 public boolean tearDownTwtSession(int commandId, String interfaceName, int sessionId) { 5780 return mWifiVendorHal.tearDownTwtSession(commandId, interfaceName, sessionId); 5781 } 5782 5783 /** 5784 * Gets stats of the TWT session 5785 * 5786 * @param commandId A unique command id to identify this command 5787 * @param interfaceName Interface name 5788 * @param sessionId TWT session id 5789 * @return true if successful, otherwise false 5790 */ 5791 public boolean getStatsTwtSession(int commandId, String interfaceName, int sessionId) { 5792 return mWifiVendorHal.getStatsTwtSession(commandId, interfaceName, sessionId); 5793 } 5794 5795 /** 5796 * Sets the wifi VoIP mode. 5797 * 5798 * @param mode Voip mode as defined by the enum |WifiVoipMode| 5799 * @return true if successful, false otherwise. 5800 */ 5801 public boolean setVoipMode(@WifiChip.WifiVoipMode int mode) { 5802 return mWifiVendorHal.setVoipMode(mode); 5803 } 5804 } 5805