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