1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE; 20 21 import android.annotation.NonNull; 22 import android.app.AlarmManager; 23 import android.net.wifi.IApInterface; 24 import android.net.wifi.IApInterfaceEventCallback; 25 import android.net.wifi.IClientInterface; 26 import android.net.wifi.IPnoScanEvent; 27 import android.net.wifi.IScanEvent; 28 import android.net.wifi.ISendMgmtFrameEvent; 29 import android.net.wifi.IWifiScannerImpl; 30 import android.net.wifi.IWificond; 31 import android.net.wifi.ScanResult; 32 import android.net.wifi.WifiScanner; 33 import android.net.wifi.WifiSsid; 34 import android.os.Binder; 35 import android.os.Handler; 36 import android.os.IBinder; 37 import android.os.Looper; 38 import android.os.RemoteException; 39 import android.util.Log; 40 41 import com.android.server.wifi.WifiNative.SendMgmtFrameCallback; 42 import com.android.server.wifi.WifiNative.SoftApListener; 43 import com.android.server.wifi.hotspot2.NetworkDetail; 44 import com.android.server.wifi.util.InformationElementUtil; 45 import com.android.server.wifi.util.NativeUtil; 46 import com.android.server.wifi.util.ScanResultUtil; 47 import com.android.server.wifi.wificond.ChannelSettings; 48 import com.android.server.wifi.wificond.HiddenNetwork; 49 import com.android.server.wifi.wificond.NativeScanResult; 50 import com.android.server.wifi.wificond.PnoNetwork; 51 import com.android.server.wifi.wificond.PnoSettings; 52 import com.android.server.wifi.wificond.RadioChainInfo; 53 import com.android.server.wifi.wificond.SingleScanSettings; 54 55 import java.util.ArrayList; 56 import java.util.HashMap; 57 import java.util.List; 58 import java.util.Map; 59 import java.util.Set; 60 import java.util.concurrent.atomic.AtomicBoolean; 61 62 /** 63 * This class provides methods for WifiNative to send control commands to wificond. 64 * NOTE: This class should only be used from WifiNative. 65 */ 66 public class WificondControl implements IBinder.DeathRecipient { 67 private boolean mVerboseLoggingEnabled = false; 68 69 /** 70 * The {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()} 71 * timeout, in milliseconds, after which 72 * {@link SendMgmtFrameCallback#onFailure(int)} will be called with reason 73 * {@link WifiNative#SEND_MGMT_FRAME_ERROR_TIMEOUT}. 74 */ 75 public static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000; 76 77 private static final String TAG = "WificondControl"; 78 79 private static final String TIMEOUT_ALARM_TAG = TAG + " Send Management Frame Timeout"; 80 81 /* Get scan results for a single scan */ 82 public static final int SCAN_TYPE_SINGLE_SCAN = 0; 83 84 /* Get scan results for Pno Scan */ 85 public static final int SCAN_TYPE_PNO_SCAN = 1; 86 87 private WifiInjector mWifiInjector; 88 private WifiMonitor mWifiMonitor; 89 private final CarrierNetworkConfig mCarrierNetworkConfig; 90 private AlarmManager mAlarmManager; 91 private Handler mEventHandler; 92 private Clock mClock; 93 private WifiNative mWifiNative = null; 94 95 // Cached wificond binder handlers. 96 private IWificond mWificond; 97 private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>(); 98 private HashMap<String, IApInterface> mApInterfaces = new HashMap<>(); 99 private HashMap<String, IWifiScannerImpl> mWificondScanners = new HashMap<>(); 100 private HashMap<String, IScanEvent> mScanEventHandlers = new HashMap<>(); 101 private HashMap<String, IPnoScanEvent> mPnoScanEventHandlers = new HashMap<>(); 102 private HashMap<String, IApInterfaceEventCallback> mApInterfaceListeners = new HashMap<>(); 103 private WifiNative.WificondDeathEventHandler mDeathEventHandler; 104 /** 105 * Ensures that no more than one sendMgmtFrame operation runs concurrently. 106 */ 107 private AtomicBoolean mSendMgmtFrameInProgress = new AtomicBoolean(false); 108 private boolean mIsEnhancedOpenSupportedInitialized = false; 109 private boolean mIsEnhancedOpenSupported; 110 111 private class ScanEventHandler extends IScanEvent.Stub { 112 private String mIfaceName; 113 ScanEventHandler(@onNull String ifaceName)114 ScanEventHandler(@NonNull String ifaceName) { 115 mIfaceName = ifaceName; 116 } 117 118 @Override OnScanResultReady()119 public void OnScanResultReady() { 120 Log.d(TAG, "Scan result ready event"); 121 mWifiMonitor.broadcastScanResultEvent(mIfaceName); 122 } 123 124 @Override OnScanFailed()125 public void OnScanFailed() { 126 Log.d(TAG, "Scan failed event"); 127 mWifiMonitor.broadcastScanFailedEvent(mIfaceName); 128 } 129 } 130 WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor, CarrierNetworkConfig carrierNetworkConfig, AlarmManager alarmManager, Looper looper, Clock clock)131 WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor, 132 CarrierNetworkConfig carrierNetworkConfig, AlarmManager alarmManager, Looper looper, 133 Clock clock) { 134 mWifiInjector = wifiInjector; 135 mWifiMonitor = wifiMonitor; 136 mCarrierNetworkConfig = carrierNetworkConfig; 137 mAlarmManager = alarmManager; 138 mEventHandler = new Handler(looper); 139 mClock = clock; 140 } 141 142 private class PnoScanEventHandler extends IPnoScanEvent.Stub { 143 private String mIfaceName; 144 PnoScanEventHandler(@onNull String ifaceName)145 PnoScanEventHandler(@NonNull String ifaceName) { 146 mIfaceName = ifaceName; 147 } 148 149 @Override OnPnoNetworkFound()150 public void OnPnoNetworkFound() { 151 Log.d(TAG, "Pno scan result event"); 152 mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName); 153 mWifiInjector.getWifiMetrics().incrementPnoFoundNetworkEventCount(); 154 } 155 156 @Override OnPnoScanFailed()157 public void OnPnoScanFailed() { 158 Log.d(TAG, "Pno Scan failed event"); 159 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount(); 160 } 161 162 @Override OnPnoScanOverOffloadStarted()163 public void OnPnoScanOverOffloadStarted() { 164 Log.d(TAG, "Pno scan over offload started"); 165 mWifiInjector.getWifiMetrics().incrementPnoScanStartedOverOffloadCount(); 166 } 167 168 @Override OnPnoScanOverOffloadFailed(int reason)169 public void OnPnoScanOverOffloadFailed(int reason) { 170 Log.d(TAG, "Pno scan over offload failed"); 171 mWifiInjector.getWifiMetrics().incrementPnoScanFailedOverOffloadCount(); 172 } 173 } 174 175 /** 176 * Listener for AP Interface events. 177 */ 178 private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub { 179 private SoftApListener mSoftApListener; 180 ApInterfaceEventCallback(SoftApListener listener)181 ApInterfaceEventCallback(SoftApListener listener) { 182 mSoftApListener = listener; 183 } 184 185 @Override onNumAssociatedStationsChanged(int numStations)186 public void onNumAssociatedStationsChanged(int numStations) { 187 mSoftApListener.onNumAssociatedStationsChanged(numStations); 188 } 189 190 @Override onSoftApChannelSwitched(int frequency, int bandwidth)191 public void onSoftApChannelSwitched(int frequency, int bandwidth) { 192 mSoftApListener.onSoftApChannelSwitched(frequency, bandwidth); 193 } 194 } 195 196 /** 197 * Callback triggered by wificond. 198 */ 199 private class SendMgmtFrameEvent extends ISendMgmtFrameEvent.Stub { 200 private SendMgmtFrameCallback mCallback; 201 private AlarmManager.OnAlarmListener mTimeoutCallback; 202 /** 203 * ensures that mCallback is only called once 204 */ 205 private boolean mWasCalled; 206 runIfFirstCall(Runnable r)207 private void runIfFirstCall(Runnable r) { 208 if (mWasCalled) return; 209 mWasCalled = true; 210 211 mSendMgmtFrameInProgress.set(false); 212 r.run(); 213 } 214 SendMgmtFrameEvent(@onNull SendMgmtFrameCallback callback)215 SendMgmtFrameEvent(@NonNull SendMgmtFrameCallback callback) { 216 mCallback = callback; 217 // called in main thread 218 mTimeoutCallback = () -> runIfFirstCall(() -> { 219 if (mVerboseLoggingEnabled) { 220 Log.e(TAG, "Timed out waiting for ACK"); 221 } 222 mCallback.onFailure(WifiNative.SEND_MGMT_FRAME_ERROR_TIMEOUT); 223 }); 224 mWasCalled = false; 225 226 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 227 mClock.getElapsedSinceBootMillis() + SEND_MGMT_FRAME_TIMEOUT_MS, 228 TIMEOUT_ALARM_TAG, mTimeoutCallback, mEventHandler); 229 } 230 231 // called in binder thread 232 @Override OnAck(int elapsedTimeMs)233 public void OnAck(int elapsedTimeMs) { 234 // post to main thread 235 mEventHandler.post(() -> runIfFirstCall(() -> { 236 mAlarmManager.cancel(mTimeoutCallback); 237 mCallback.onAck(elapsedTimeMs); 238 })); 239 } 240 241 // called in binder thread 242 @Override OnFailure(int reason)243 public void OnFailure(int reason) { 244 // post to main thread 245 mEventHandler.post(() -> runIfFirstCall(() -> { 246 mAlarmManager.cancel(mTimeoutCallback); 247 mCallback.onFailure(reason); 248 })); 249 } 250 } 251 252 /** 253 * Called by the binder subsystem upon remote object death. 254 * Invoke all the register death handlers and clear state. 255 */ 256 @Override binderDied()257 public void binderDied() { 258 mEventHandler.post(() -> { 259 Log.e(TAG, "Wificond died!"); 260 clearState(); 261 // Invalidate the global wificond handle on death. Will be refreshed 262 // on the next setup call. 263 mWificond = null; 264 if (mDeathEventHandler != null) { 265 mDeathEventHandler.onDeath(); 266 } 267 }); 268 } 269 270 /** Enable or disable verbose logging of WificondControl. 271 * @param enable True to enable verbose logging. False to disable verbose logging. 272 */ enableVerboseLogging(boolean enable)273 public void enableVerboseLogging(boolean enable) { 274 mVerboseLoggingEnabled = enable; 275 } 276 277 /** 278 * Initializes wificond & registers a death notification for wificond. 279 * This method clears any existing state in wificond daemon. 280 * 281 * @return Returns true on success. 282 */ initialize(@onNull WifiNative.WificondDeathEventHandler handler)283 public boolean initialize(@NonNull WifiNative.WificondDeathEventHandler handler) { 284 if (mDeathEventHandler != null) { 285 Log.e(TAG, "Death handler already present"); 286 } 287 mDeathEventHandler = handler; 288 tearDownInterfaces(); 289 return true; 290 } 291 292 /** 293 * Helper method to retrieve the global wificond handle and register for 294 * death notifications. 295 */ retrieveWificondAndRegisterForDeath()296 private boolean retrieveWificondAndRegisterForDeath() { 297 if (mWificond != null) { 298 if (mVerboseLoggingEnabled) { 299 Log.d(TAG, "Wificond handle already retrieved"); 300 } 301 // We already have a wificond handle. 302 return true; 303 } 304 mWificond = mWifiInjector.makeWificond(); 305 if (mWificond == null) { 306 Log.e(TAG, "Failed to get reference to wificond"); 307 return false; 308 } 309 try { 310 mWificond.asBinder().linkToDeath(this, 0); 311 } catch (RemoteException e) { 312 Log.e(TAG, "Failed to register death notification for wificond"); 313 // The remote has already died. 314 return false; 315 } 316 return true; 317 } 318 319 /** 320 * Setup interface for client mode via wificond. 321 * @return An IClientInterface as wificond client interface binder handler. 322 * Returns null on failure. 323 */ setupInterfaceForClientMode(@onNull String ifaceName)324 public IClientInterface setupInterfaceForClientMode(@NonNull String ifaceName) { 325 Log.d(TAG, "Setting up interface for client mode"); 326 if (!retrieveWificondAndRegisterForDeath()) { 327 return null; 328 } 329 330 IClientInterface clientInterface = null; 331 try { 332 clientInterface = mWificond.createClientInterface(ifaceName); 333 } catch (RemoteException e1) { 334 Log.e(TAG, "Failed to get IClientInterface due to remote exception"); 335 return null; 336 } 337 338 if (clientInterface == null) { 339 Log.e(TAG, "Could not get IClientInterface instance from wificond"); 340 return null; 341 } 342 Binder.allowBlocking(clientInterface.asBinder()); 343 344 // Refresh Handlers 345 mClientInterfaces.put(ifaceName, clientInterface); 346 try { 347 IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl(); 348 if (wificondScanner == null) { 349 Log.e(TAG, "Failed to get WificondScannerImpl"); 350 return null; 351 } 352 mWificondScanners.put(ifaceName, wificondScanner); 353 Binder.allowBlocking(wificondScanner.asBinder()); 354 ScanEventHandler scanEventHandler = new ScanEventHandler(ifaceName); 355 mScanEventHandlers.put(ifaceName, scanEventHandler); 356 wificondScanner.subscribeScanEvents(scanEventHandler); 357 PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(ifaceName); 358 mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler); 359 wificondScanner.subscribePnoScanEvents(pnoScanEventHandler); 360 } catch (RemoteException e) { 361 Log.e(TAG, "Failed to refresh wificond scanner due to remote exception"); 362 } 363 364 return clientInterface; 365 } 366 367 /** 368 * Teardown a specific STA interface configured in wificond. 369 * 370 * @return Returns true on success. 371 */ tearDownClientInterface(@onNull String ifaceName)372 public boolean tearDownClientInterface(@NonNull String ifaceName) { 373 if (getClientInterface(ifaceName) == null) { 374 Log.e(TAG, "No valid wificond client interface handler"); 375 return false; 376 } 377 try { 378 IWifiScannerImpl scannerImpl = mWificondScanners.get(ifaceName); 379 if (scannerImpl != null) { 380 scannerImpl.unsubscribeScanEvents(); 381 scannerImpl.unsubscribePnoScanEvents(); 382 } 383 } catch (RemoteException e) { 384 Log.e(TAG, "Failed to unsubscribe wificond scanner due to remote exception"); 385 return false; 386 } 387 388 boolean success; 389 try { 390 success = mWificond.tearDownClientInterface(ifaceName); 391 } catch (RemoteException e1) { 392 Log.e(TAG, "Failed to teardown client interface due to remote exception"); 393 return false; 394 } 395 if (!success) { 396 Log.e(TAG, "Failed to teardown client interface"); 397 return false; 398 } 399 400 mClientInterfaces.remove(ifaceName); 401 mWificondScanners.remove(ifaceName); 402 mScanEventHandlers.remove(ifaceName); 403 mPnoScanEventHandlers.remove(ifaceName); 404 return true; 405 } 406 407 /** 408 * Setup interface for softAp mode via wificond. 409 * @return An IApInterface as wificond Ap interface binder handler. 410 * Returns null on failure. 411 */ setupInterfaceForSoftApMode(@onNull String ifaceName)412 public IApInterface setupInterfaceForSoftApMode(@NonNull String ifaceName) { 413 Log.d(TAG, "Setting up interface for soft ap mode"); 414 if (!retrieveWificondAndRegisterForDeath()) { 415 return null; 416 } 417 418 IApInterface apInterface = null; 419 try { 420 apInterface = mWificond.createApInterface(ifaceName); 421 } catch (RemoteException e1) { 422 Log.e(TAG, "Failed to get IApInterface due to remote exception"); 423 return null; 424 } 425 426 if (apInterface == null) { 427 Log.e(TAG, "Could not get IApInterface instance from wificond"); 428 return null; 429 } 430 Binder.allowBlocking(apInterface.asBinder()); 431 432 // Refresh Handlers 433 mApInterfaces.put(ifaceName, apInterface); 434 return apInterface; 435 } 436 437 /** 438 * Teardown a specific AP interface configured in wificond. 439 * 440 * @return Returns true on success. 441 */ tearDownSoftApInterface(@onNull String ifaceName)442 public boolean tearDownSoftApInterface(@NonNull String ifaceName) { 443 if (getApInterface(ifaceName) == null) { 444 Log.e(TAG, "No valid wificond ap interface handler"); 445 return false; 446 } 447 boolean success; 448 try { 449 success = mWificond.tearDownApInterface(ifaceName); 450 } catch (RemoteException e1) { 451 Log.e(TAG, "Failed to teardown AP interface due to remote exception"); 452 return false; 453 } 454 if (!success) { 455 Log.e(TAG, "Failed to teardown AP interface"); 456 return false; 457 } 458 mApInterfaces.remove(ifaceName); 459 mApInterfaceListeners.remove(ifaceName); 460 return true; 461 } 462 463 /** 464 * Teardown all interfaces configured in wificond. 465 * @return Returns true on success. 466 */ tearDownInterfaces()467 public boolean tearDownInterfaces() { 468 Log.d(TAG, "tearing down interfaces in wificond"); 469 // Explicitly refresh the wificodn handler because |tearDownInterfaces()| 470 // could be used to cleanup before we setup any interfaces. 471 if (!retrieveWificondAndRegisterForDeath()) { 472 return false; 473 } 474 475 try { 476 for (Map.Entry<String, IWifiScannerImpl> entry : mWificondScanners.entrySet()) { 477 entry.getValue().unsubscribeScanEvents(); 478 entry.getValue().unsubscribePnoScanEvents(); 479 } 480 mWificond.tearDownInterfaces(); 481 clearState(); 482 return true; 483 } catch (RemoteException e) { 484 Log.e(TAG, "Failed to tear down interfaces due to remote exception"); 485 } 486 487 return false; 488 } 489 490 /** Helper function to look up the interface handle using name */ getClientInterface(@onNull String ifaceName)491 private IClientInterface getClientInterface(@NonNull String ifaceName) { 492 return mClientInterfaces.get(ifaceName); 493 } 494 495 /** 496 * Request signal polling to wificond. 497 * @param ifaceName Name of the interface. 498 * Returns an SignalPollResult object. 499 * Returns null on failure. 500 */ signalPoll(@onNull String ifaceName)501 public WifiNative.SignalPollResult signalPoll(@NonNull String ifaceName) { 502 IClientInterface iface = getClientInterface(ifaceName); 503 if (iface == null) { 504 Log.e(TAG, "No valid wificond client interface handler"); 505 return null; 506 } 507 508 int[] resultArray; 509 try { 510 resultArray = iface.signalPoll(); 511 if (resultArray == null || resultArray.length != 4) { 512 Log.e(TAG, "Invalid signal poll result from wificond"); 513 return null; 514 } 515 } catch (RemoteException e) { 516 Log.e(TAG, "Failed to do signal polling due to remote exception"); 517 return null; 518 } 519 WifiNative.SignalPollResult pollResult = new WifiNative.SignalPollResult(); 520 pollResult.currentRssi = resultArray[0]; 521 pollResult.txBitrate = resultArray[1]; 522 pollResult.associationFrequency = resultArray[2]; 523 pollResult.rxBitrate = resultArray[3]; 524 return pollResult; 525 } 526 527 /** 528 * Fetch TX packet counters on current connection from wificond. 529 * @param ifaceName Name of the interface. 530 * Returns an TxPacketCounters object. 531 * Returns null on failure. 532 */ getTxPacketCounters(@onNull String ifaceName)533 public WifiNative.TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) { 534 IClientInterface iface = getClientInterface(ifaceName); 535 if (iface == null) { 536 Log.e(TAG, "No valid wificond client interface handler"); 537 return null; 538 } 539 540 int[] resultArray; 541 try { 542 resultArray = iface.getPacketCounters(); 543 if (resultArray == null || resultArray.length != 2) { 544 Log.e(TAG, "Invalid signal poll result from wificond"); 545 return null; 546 } 547 } catch (RemoteException e) { 548 Log.e(TAG, "Failed to do signal polling due to remote exception"); 549 return null; 550 } 551 WifiNative.TxPacketCounters counters = new WifiNative.TxPacketCounters(); 552 counters.txSucceeded = resultArray[0]; 553 counters.txFailed = resultArray[1]; 554 return counters; 555 } 556 557 /** Helper function to look up the scanner impl handle using name */ getScannerImpl(@onNull String ifaceName)558 private IWifiScannerImpl getScannerImpl(@NonNull String ifaceName) { 559 return mWificondScanners.get(ifaceName); 560 } 561 562 /** 563 * Fetch the latest scan result from kernel via wificond. 564 * @param ifaceName Name of the interface. 565 * @return Returns an ArrayList of ScanDetail. 566 * Returns an empty ArrayList on failure. 567 */ getScanResults(@onNull String ifaceName, int scanType)568 public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) { 569 ArrayList<ScanDetail> results = new ArrayList<>(); 570 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 571 if (scannerImpl == null) { 572 Log.e(TAG, "No valid wificond scanner interface handler"); 573 return results; 574 } 575 try { 576 NativeScanResult[] nativeResults; 577 if (scanType == SCAN_TYPE_SINGLE_SCAN) { 578 nativeResults = scannerImpl.getScanResults(); 579 } else { 580 nativeResults = scannerImpl.getPnoScanResults(); 581 } 582 for (NativeScanResult result : nativeResults) { 583 WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid); 584 String bssid; 585 try { 586 bssid = NativeUtil.macAddressFromByteArray(result.bssid); 587 } catch (IllegalArgumentException e) { 588 Log.e(TAG, "Illegal argument " + result.bssid, e); 589 continue; 590 } 591 if (bssid == null) { 592 Log.e(TAG, "Illegal null bssid"); 593 continue; 594 } 595 ScanResult.InformationElement[] ies = 596 InformationElementUtil.parseInformationElements(result.infoElement); 597 InformationElementUtil.Capabilities capabilities = 598 new InformationElementUtil.Capabilities(); 599 capabilities.from(ies, result.capability, isEnhancedOpenSupported()); 600 String flags = capabilities.generateCapabilitiesString(); 601 NetworkDetail networkDetail; 602 try { 603 networkDetail = new NetworkDetail(bssid, ies, null, result.frequency); 604 } catch (IllegalArgumentException e) { 605 Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e); 606 continue; 607 } 608 609 ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags, 610 result.signalMbm / 100, result.frequency, result.tsf, ies, null); 611 ScanResult scanResult = scanDetail.getScanResult(); 612 // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi 613 // network and it uses EAP. 614 if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult()) 615 && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) { 616 scanResult.isCarrierAp = true; 617 scanResult.carrierApEapType = 618 mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString()); 619 scanResult.carrierName = 620 mCarrierNetworkConfig.getCarrierName(wifiSsid.toString()); 621 } 622 // Fill up the radio chain info. 623 if (result.radioChainInfos != null) { 624 scanResult.radioChainInfos = 625 new ScanResult.RadioChainInfo[result.radioChainInfos.size()]; 626 int idx = 0; 627 for (RadioChainInfo nativeRadioChainInfo : result.radioChainInfos) { 628 scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo(); 629 scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.chainId; 630 scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.level; 631 idx++; 632 } 633 } 634 results.add(scanDetail); 635 } 636 } catch (RemoteException e1) { 637 Log.e(TAG, "Failed to create ScanDetail ArrayList"); 638 } 639 if (mVerboseLoggingEnabled) { 640 Log.d(TAG, "get " + results.size() + " scan results from wificond"); 641 } 642 643 return results; 644 } 645 646 /** 647 * Return scan type for the parcelable {@link SingleScanSettings} 648 */ getScanType(int scanType)649 private static int getScanType(int scanType) { 650 switch (scanType) { 651 case WifiNative.SCAN_TYPE_LOW_LATENCY: 652 return IWifiScannerImpl.SCAN_TYPE_LOW_SPAN; 653 case WifiNative.SCAN_TYPE_LOW_POWER: 654 return IWifiScannerImpl.SCAN_TYPE_LOW_POWER; 655 case WifiNative.SCAN_TYPE_HIGH_ACCURACY: 656 return IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY; 657 default: 658 throw new IllegalArgumentException("Invalid scan type " + scanType); 659 } 660 } 661 662 /** 663 * Start a scan using wificond for the given parameters. 664 * @param ifaceName Name of the interface. 665 * @param scanType Type of scan to perform. 666 * @param freqs list of frequencies to scan for, if null scan all supported channels. 667 * @param hiddenNetworkSSIDs List of hidden networks to be scanned for. 668 * @return Returns true on success. 669 */ scan(@onNull String ifaceName, int scanType, Set<Integer> freqs, List<String> hiddenNetworkSSIDs)670 public boolean scan(@NonNull String ifaceName, 671 int scanType, 672 Set<Integer> freqs, 673 List<String> hiddenNetworkSSIDs) { 674 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 675 if (scannerImpl == null) { 676 Log.e(TAG, "No valid wificond scanner interface handler"); 677 return false; 678 } 679 SingleScanSettings settings = new SingleScanSettings(); 680 try { 681 settings.scanType = getScanType(scanType); 682 } catch (IllegalArgumentException e) { 683 Log.e(TAG, "Invalid scan type ", e); 684 return false; 685 } 686 settings.channelSettings = new ArrayList<>(); 687 settings.hiddenNetworks = new ArrayList<>(); 688 689 if (freqs != null) { 690 for (Integer freq : freqs) { 691 ChannelSettings channel = new ChannelSettings(); 692 channel.frequency = freq; 693 settings.channelSettings.add(channel); 694 } 695 } 696 if (hiddenNetworkSSIDs != null) { 697 for (String ssid : hiddenNetworkSSIDs) { 698 HiddenNetwork network = new HiddenNetwork(); 699 try { 700 network.ssid = NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid)); 701 } catch (IllegalArgumentException e) { 702 Log.e(TAG, "Illegal argument " + ssid, e); 703 continue; 704 } 705 // settings.hiddenNetworks is expected to be very small, so this shouldn't cause 706 // any performance issues. 707 if (!settings.hiddenNetworks.contains(network)) { 708 settings.hiddenNetworks.add(network); 709 } 710 } 711 } 712 713 try { 714 return scannerImpl.scan(settings); 715 } catch (RemoteException e1) { 716 Log.e(TAG, "Failed to request scan due to remote exception"); 717 } 718 return false; 719 } 720 721 /** 722 * Start PNO scan. 723 * @param ifaceName Name of the interface. 724 * @param pnoSettings Pno scan configuration. 725 * @return true on success. 726 */ startPnoScan(@onNull String ifaceName, WifiNative.PnoSettings pnoSettings)727 public boolean startPnoScan(@NonNull String ifaceName, WifiNative.PnoSettings pnoSettings) { 728 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 729 if (scannerImpl == null) { 730 Log.e(TAG, "No valid wificond scanner interface handler"); 731 return false; 732 } 733 PnoSettings settings = new PnoSettings(); 734 settings.pnoNetworks = new ArrayList<>(); 735 settings.intervalMs = pnoSettings.periodInMs; 736 settings.min2gRssi = pnoSettings.min24GHzRssi; 737 settings.min5gRssi = pnoSettings.min5GHzRssi; 738 if (pnoSettings.networkList != null) { 739 for (WifiNative.PnoNetwork network : pnoSettings.networkList) { 740 PnoNetwork condNetwork = new PnoNetwork(); 741 condNetwork.isHidden = (network.flags 742 & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0; 743 try { 744 condNetwork.ssid = 745 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(network.ssid)); 746 } catch (IllegalArgumentException e) { 747 Log.e(TAG, "Illegal argument " + network.ssid, e); 748 continue; 749 } 750 condNetwork.frequencies = network.frequencies; 751 settings.pnoNetworks.add(condNetwork); 752 } 753 } 754 755 try { 756 boolean success = scannerImpl.startPnoScan(settings); 757 mWifiInjector.getWifiMetrics().incrementPnoScanStartAttempCount(); 758 if (!success) { 759 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount(); 760 } 761 return success; 762 } catch (RemoteException e1) { 763 Log.e(TAG, "Failed to start pno scan due to remote exception"); 764 } 765 return false; 766 } 767 768 /** 769 * Stop PNO scan. 770 * @param ifaceName Name of the interface. 771 * @return true on success. 772 */ stopPnoScan(@onNull String ifaceName)773 public boolean stopPnoScan(@NonNull String ifaceName) { 774 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 775 if (scannerImpl == null) { 776 Log.e(TAG, "No valid wificond scanner interface handler"); 777 return false; 778 } 779 try { 780 return scannerImpl.stopPnoScan(); 781 } catch (RemoteException e1) { 782 Log.e(TAG, "Failed to stop pno scan due to remote exception"); 783 } 784 return false; 785 } 786 787 /** 788 * Abort ongoing single scan. 789 * @param ifaceName Name of the interface. 790 */ abortScan(@onNull String ifaceName)791 public void abortScan(@NonNull String ifaceName) { 792 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 793 if (scannerImpl == null) { 794 Log.e(TAG, "No valid wificond scanner interface handler"); 795 return; 796 } 797 try { 798 scannerImpl.abortScan(); 799 } catch (RemoteException e1) { 800 Log.e(TAG, "Failed to request abortScan due to remote exception"); 801 } 802 } 803 804 /** 805 * Query the list of valid frequencies for the provided band. 806 * The result depends on the on the country code that has been set. 807 * 808 * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants. 809 * The following bands are supported: 810 * WifiScanner.WIFI_BAND_24_GHZ 811 * WifiScanner.WIFI_BAND_5_GHZ 812 * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY 813 * @return frequencies vector of valid frequencies (MHz), or null for error. 814 * @throws IllegalArgumentException if band is not recognized. 815 */ getChannelsForBand(int band)816 public int [] getChannelsForBand(int band) { 817 if (mWificond == null) { 818 Log.e(TAG, "No valid wificond scanner interface handler"); 819 return null; 820 } 821 try { 822 switch (band) { 823 case WifiScanner.WIFI_BAND_24_GHZ: 824 return mWificond.getAvailable2gChannels(); 825 case WifiScanner.WIFI_BAND_5_GHZ: 826 return mWificond.getAvailable5gNonDFSChannels(); 827 case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY: 828 return mWificond.getAvailableDFSChannels(); 829 default: 830 throw new IllegalArgumentException("unsupported band " + band); 831 } 832 } catch (RemoteException e1) { 833 Log.e(TAG, "Failed to request getChannelsForBand due to remote exception"); 834 } 835 return null; 836 } 837 838 /** Helper function to look up the interface handle using name */ getApInterface(@onNull String ifaceName)839 private IApInterface getApInterface(@NonNull String ifaceName) { 840 return mApInterfaces.get(ifaceName); 841 } 842 843 /** 844 * Register the provided listener for SoftAp events. 845 * 846 * @param ifaceName Name of the interface. 847 * @param listener Callback for AP events. 848 * @return true on success, false otherwise. 849 */ registerApListener(@onNull String ifaceName, SoftApListener listener)850 public boolean registerApListener(@NonNull String ifaceName, SoftApListener listener) { 851 IApInterface iface = getApInterface(ifaceName); 852 if (iface == null) { 853 Log.e(TAG, "No valid ap interface handler"); 854 return false; 855 } 856 try { 857 IApInterfaceEventCallback callback = new ApInterfaceEventCallback(listener); 858 mApInterfaceListeners.put(ifaceName, callback); 859 boolean success = iface.registerCallback(callback); 860 if (!success) { 861 Log.e(TAG, "Failed to register ap callback."); 862 return false; 863 } 864 } catch (RemoteException e) { 865 Log.e(TAG, "Exception in registering AP callback: " + e); 866 return false; 867 } 868 return true; 869 } 870 871 /** 872 * See {@link WifiNative#sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int)} 873 */ sendMgmtFrame(@onNull String ifaceName, @NonNull byte[] frame, @NonNull SendMgmtFrameCallback callback, int mcs)874 public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame, 875 @NonNull SendMgmtFrameCallback callback, int mcs) { 876 877 if (callback == null) { 878 Log.e(TAG, "callback cannot be null!"); 879 return; 880 } 881 882 if (frame == null) { 883 Log.e(TAG, "frame cannot be null!"); 884 callback.onFailure(WifiNative.SEND_MGMT_FRAME_ERROR_UNKNOWN); 885 return; 886 } 887 888 // TODO (b/112029045) validate mcs 889 IClientInterface clientInterface = getClientInterface(ifaceName); 890 if (clientInterface == null) { 891 Log.e(TAG, "No valid wificond client interface handler"); 892 callback.onFailure(WifiNative.SEND_MGMT_FRAME_ERROR_UNKNOWN); 893 return; 894 } 895 896 if (!mSendMgmtFrameInProgress.compareAndSet(false, true)) { 897 Log.e(TAG, "An existing management frame transmission is in progress!"); 898 callback.onFailure(WifiNative.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED); 899 return; 900 } 901 902 SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(callback); 903 try { 904 clientInterface.SendMgmtFrame(frame, sendMgmtFrameEvent, mcs); 905 } catch (RemoteException e) { 906 Log.e(TAG, "Exception while starting link probe: " + e); 907 // Call sendMgmtFrameEvent.OnFailure() instead of callback.onFailure() so that 908 // sendMgmtFrameEvent can clean up internal state, such as cancelling the timer. 909 sendMgmtFrameEvent.OnFailure(WifiNative.SEND_MGMT_FRAME_ERROR_UNKNOWN); 910 } 911 } 912 913 /** 914 * Clear all internal handles. 915 */ clearState()916 private void clearState() { 917 // Refresh handlers 918 mClientInterfaces.clear(); 919 mWificondScanners.clear(); 920 mPnoScanEventHandlers.clear(); 921 mScanEventHandlers.clear(); 922 mApInterfaces.clear(); 923 mApInterfaceListeners.clear(); 924 mSendMgmtFrameInProgress.set(false); 925 } 926 927 /** 928 * Check if OWE (Enhanced Open) is supported on the device 929 * 930 * @return true if OWE is supported 931 */ isEnhancedOpenSupported()932 private boolean isEnhancedOpenSupported() { 933 if (mIsEnhancedOpenSupportedInitialized) { 934 return mIsEnhancedOpenSupported; 935 } 936 937 // WifiNative handle might be null, check this here 938 if (mWifiNative == null) { 939 mWifiNative = mWifiInjector.getWifiNative(); 940 if (mWifiNative == null) { 941 return false; 942 } 943 } 944 945 String iface = mWifiNative.getClientInterfaceName(); 946 if (iface == null) { 947 // Client interface might not be initialized during boot or Wi-Fi off 948 return false; 949 } 950 951 mIsEnhancedOpenSupportedInitialized = true; 952 mIsEnhancedOpenSupported = (mWifiNative.getSupportedFeatureSet(iface) 953 & WIFI_FEATURE_OWE) != 0; 954 return mIsEnhancedOpenSupported; 955 } 956 } 957