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 android.net.wifi.IApInterface; 20 import android.net.wifi.IClientInterface; 21 import android.net.wifi.IPnoScanEvent; 22 import android.net.wifi.IScanEvent; 23 import android.net.wifi.IWifiScannerImpl; 24 import android.net.wifi.IWificond; 25 import android.net.wifi.ScanResult; 26 import android.net.wifi.WifiScanner; 27 import android.net.wifi.WifiSsid; 28 import android.os.Binder; 29 import android.os.RemoteException; 30 import android.util.Log; 31 32 import com.android.server.wifi.hotspot2.NetworkDetail; 33 import com.android.server.wifi.util.InformationElementUtil; 34 import com.android.server.wifi.util.NativeUtil; 35 import com.android.server.wifi.util.ScanResultUtil; 36 import com.android.server.wifi.wificond.ChannelSettings; 37 import com.android.server.wifi.wificond.HiddenNetwork; 38 import com.android.server.wifi.wificond.NativeScanResult; 39 import com.android.server.wifi.wificond.PnoNetwork; 40 import com.android.server.wifi.wificond.PnoSettings; 41 import com.android.server.wifi.wificond.SingleScanSettings; 42 43 import java.util.ArrayList; 44 import java.util.Set; 45 46 /** 47 * This class provides methods for WifiNative to send control commands to wificond. 48 * NOTE: This class should only be used from WifiNative. 49 */ 50 public class WificondControl { 51 private boolean mVerboseLoggingEnabled = false; 52 53 private static final String TAG = "WificondControl"; 54 55 /* Get scan results for a single scan */ 56 public static final int SCAN_TYPE_SINGLE_SCAN = 0; 57 58 /* Get scan results for Pno Scan */ 59 public static final int SCAN_TYPE_PNO_SCAN = 1; 60 61 private WifiInjector mWifiInjector; 62 private WifiMonitor mWifiMonitor; 63 private final CarrierNetworkConfig mCarrierNetworkConfig; 64 65 // Cached wificond binder handlers. 66 private IWificond mWificond; 67 private IClientInterface mClientInterface; 68 private IApInterface mApInterface; 69 private IWifiScannerImpl mWificondScanner; 70 private IScanEvent mScanEventHandler; 71 private IPnoScanEvent mPnoScanEventHandler; 72 73 private String mClientInterfaceName; 74 75 76 private class ScanEventHandler extends IScanEvent.Stub { 77 @Override OnScanResultReady()78 public void OnScanResultReady() { 79 Log.d(TAG, "Scan result ready event"); 80 mWifiMonitor.broadcastScanResultEvent(mClientInterfaceName); 81 } 82 83 @Override OnScanFailed()84 public void OnScanFailed() { 85 Log.d(TAG, "Scan failed event"); 86 mWifiMonitor.broadcastScanFailedEvent(mClientInterfaceName); 87 } 88 } 89 WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor, CarrierNetworkConfig carrierNetworkConfig)90 WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor, 91 CarrierNetworkConfig carrierNetworkConfig) { 92 mWifiInjector = wifiInjector; 93 mWifiMonitor = wifiMonitor; 94 mCarrierNetworkConfig = carrierNetworkConfig; 95 } 96 97 private class PnoScanEventHandler extends IPnoScanEvent.Stub { 98 @Override OnPnoNetworkFound()99 public void OnPnoNetworkFound() { 100 Log.d(TAG, "Pno scan result event"); 101 mWifiMonitor.broadcastPnoScanResultEvent(mClientInterfaceName); 102 mWifiInjector.getWifiMetrics().incrementPnoFoundNetworkEventCount(); 103 } 104 105 @Override OnPnoScanFailed()106 public void OnPnoScanFailed() { 107 Log.d(TAG, "Pno Scan failed event"); 108 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount(); 109 } 110 111 @Override OnPnoScanOverOffloadStarted()112 public void OnPnoScanOverOffloadStarted() { 113 Log.d(TAG, "Pno scan over offload started"); 114 mWifiInjector.getWifiMetrics().incrementPnoScanStartedOverOffloadCount(); 115 } 116 117 @Override OnPnoScanOverOffloadFailed(int reason)118 public void OnPnoScanOverOffloadFailed(int reason) { 119 Log.d(TAG, "Pno scan over offload failed"); 120 mWifiInjector.getWifiMetrics().incrementPnoScanFailedOverOffloadCount(); 121 } 122 } 123 124 /** Enable or disable verbose logging of WificondControl. 125 * @param enable True to enable verbose logging. False to disable verbose logging. 126 */ enableVerboseLogging(boolean enable)127 public void enableVerboseLogging(boolean enable) { 128 mVerboseLoggingEnabled = enable; 129 } 130 131 /** 132 * Setup driver for client mode via wificond. 133 * @return An IClientInterface as wificond client interface binder handler. 134 * Returns null on failure. 135 */ setupDriverForClientMode()136 public IClientInterface setupDriverForClientMode() { 137 Log.d(TAG, "Setting up driver for client mode"); 138 mWificond = mWifiInjector.makeWificond(); 139 if (mWificond == null) { 140 Log.e(TAG, "Failed to get reference to wificond"); 141 return null; 142 } 143 144 IClientInterface clientInterface = null; 145 try { 146 clientInterface = mWificond.createClientInterface(); 147 } catch (RemoteException e1) { 148 Log.e(TAG, "Failed to get IClientInterface due to remote exception"); 149 return null; 150 } 151 152 if (clientInterface == null) { 153 Log.e(TAG, "Could not get IClientInterface instance from wificond"); 154 return null; 155 } 156 Binder.allowBlocking(clientInterface.asBinder()); 157 158 // Refresh Handlers 159 mClientInterface = clientInterface; 160 try { 161 mClientInterfaceName = clientInterface.getInterfaceName(); 162 mWificondScanner = mClientInterface.getWifiScannerImpl(); 163 if (mWificondScanner == null) { 164 Log.e(TAG, "Failed to get WificondScannerImpl"); 165 return null; 166 } 167 Binder.allowBlocking(mWificondScanner.asBinder()); 168 mScanEventHandler = new ScanEventHandler(); 169 mWificondScanner.subscribeScanEvents(mScanEventHandler); 170 mPnoScanEventHandler = new PnoScanEventHandler(); 171 mWificondScanner.subscribePnoScanEvents(mPnoScanEventHandler); 172 } catch (RemoteException e) { 173 Log.e(TAG, "Failed to refresh wificond scanner due to remote exception"); 174 } 175 176 return clientInterface; 177 } 178 179 /** 180 * Setup driver for softAp mode via wificond. 181 * @return An IApInterface as wificond Ap interface binder handler. 182 * Returns null on failure. 183 */ setupDriverForSoftApMode()184 public IApInterface setupDriverForSoftApMode() { 185 Log.d(TAG, "Setting up driver for soft ap mode"); 186 mWificond = mWifiInjector.makeWificond(); 187 if (mWificond == null) { 188 Log.e(TAG, "Failed to get reference to wificond"); 189 return null; 190 } 191 192 IApInterface apInterface = null; 193 try { 194 apInterface = mWificond.createApInterface(); 195 } catch (RemoteException e1) { 196 Log.e(TAG, "Failed to get IApInterface due to remote exception"); 197 return null; 198 } 199 200 if (apInterface == null) { 201 Log.e(TAG, "Could not get IApInterface instance from wificond"); 202 return null; 203 } 204 Binder.allowBlocking(apInterface.asBinder()); 205 206 // Refresh Handlers 207 mApInterface = apInterface; 208 209 return apInterface; 210 } 211 212 /** 213 * Teardown all interfaces configured in wificond. 214 * @return Returns true on success. 215 */ tearDownInterfaces()216 public boolean tearDownInterfaces() { 217 Log.d(TAG, "tearing down interfaces in wificond"); 218 // Explicitly refresh the wificodn handler because |tearDownInterfaces()| 219 // could be used to cleanup before we setup any interfaces. 220 mWificond = mWifiInjector.makeWificond(); 221 if (mWificond == null) { 222 Log.e(TAG, "Failed to get reference to wificond"); 223 return false; 224 } 225 226 try { 227 if (mWificondScanner != null) { 228 mWificondScanner.unsubscribeScanEvents(); 229 mWificondScanner.unsubscribePnoScanEvents(); 230 } 231 mWificond.tearDownInterfaces(); 232 233 // Refresh handlers 234 mClientInterface = null; 235 mWificondScanner = null; 236 mPnoScanEventHandler = null; 237 mScanEventHandler = null; 238 mApInterface = null; 239 240 return true; 241 } catch (RemoteException e) { 242 Log.e(TAG, "Failed to tear down interfaces due to remote exception"); 243 } 244 245 return false; 246 } 247 248 /** 249 * Disable wpa_supplicant via wificond. 250 * @return Returns true on success. 251 */ disableSupplicant()252 public boolean disableSupplicant() { 253 if (mClientInterface == null) { 254 Log.e(TAG, "No valid wificond client interface handler"); 255 return false; 256 } 257 try { 258 return mClientInterface.disableSupplicant(); 259 } catch (RemoteException e) { 260 Log.e(TAG, "Failed to disable supplicant due to remote exception"); 261 } 262 return false; 263 } 264 265 /** 266 * Enable wpa_supplicant via wificond. 267 * @return Returns true on success. 268 */ enableSupplicant()269 public boolean enableSupplicant() { 270 if (mClientInterface == null) { 271 Log.e(TAG, "No valid wificond client interface handler"); 272 return false; 273 } 274 275 try { 276 return mClientInterface.enableSupplicant(); 277 } catch (RemoteException e) { 278 Log.e(TAG, "Failed to enable supplicant due to remote exception"); 279 } 280 return false; 281 } 282 283 /** 284 * Request signal polling to wificond. 285 * Returns an SignalPollResult object. 286 * Returns null on failure. 287 */ signalPoll()288 public WifiNative.SignalPollResult signalPoll() { 289 if (mClientInterface == null) { 290 Log.e(TAG, "No valid wificond client interface handler"); 291 return null; 292 } 293 294 int[] resultArray; 295 try { 296 resultArray = mClientInterface.signalPoll(); 297 if (resultArray == null || resultArray.length != 3) { 298 Log.e(TAG, "Invalid signal poll result from wificond"); 299 return null; 300 } 301 } catch (RemoteException e) { 302 Log.e(TAG, "Failed to do signal polling due to remote exception"); 303 return null; 304 } 305 WifiNative.SignalPollResult pollResult = new WifiNative.SignalPollResult(); 306 pollResult.currentRssi = resultArray[0]; 307 pollResult.txBitrate = resultArray[1]; 308 pollResult.associationFrequency = resultArray[2]; 309 return pollResult; 310 } 311 312 /** 313 * Fetch TX packet counters on current connection from wificond. 314 * Returns an TxPacketCounters object. 315 * Returns null on failure. 316 */ getTxPacketCounters()317 public WifiNative.TxPacketCounters getTxPacketCounters() { 318 if (mClientInterface == null) { 319 Log.e(TAG, "No valid wificond client interface handler"); 320 return null; 321 } 322 323 int[] resultArray; 324 try { 325 resultArray = mClientInterface.getPacketCounters(); 326 if (resultArray == null || resultArray.length != 2) { 327 Log.e(TAG, "Invalid signal poll result from wificond"); 328 return null; 329 } 330 } catch (RemoteException e) { 331 Log.e(TAG, "Failed to do signal polling due to remote exception"); 332 return null; 333 } 334 WifiNative.TxPacketCounters counters = new WifiNative.TxPacketCounters(); 335 counters.txSucceeded = resultArray[0]; 336 counters.txFailed = resultArray[1]; 337 return counters; 338 } 339 340 /** 341 * Fetch the latest scan result from kernel via wificond. 342 * @return Returns an ArrayList of ScanDetail. 343 * Returns an empty ArrayList on failure. 344 */ getScanResults(int scanType)345 public ArrayList<ScanDetail> getScanResults(int scanType) { 346 ArrayList<ScanDetail> results = new ArrayList<>(); 347 if (mWificondScanner == null) { 348 Log.e(TAG, "No valid wificond scanner interface handler"); 349 return results; 350 } 351 try { 352 NativeScanResult[] nativeResults; 353 if (scanType == SCAN_TYPE_SINGLE_SCAN) { 354 nativeResults = mWificondScanner.getScanResults(); 355 } else { 356 nativeResults = mWificondScanner.getPnoScanResults(); 357 } 358 for (NativeScanResult result : nativeResults) { 359 WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid); 360 String bssid; 361 try { 362 bssid = NativeUtil.macAddressFromByteArray(result.bssid); 363 } catch (IllegalArgumentException e) { 364 Log.e(TAG, "Illegal argument " + result.bssid, e); 365 continue; 366 } 367 if (bssid == null) { 368 Log.e(TAG, "Illegal null bssid"); 369 continue; 370 } 371 ScanResult.InformationElement[] ies = 372 InformationElementUtil.parseInformationElements(result.infoElement); 373 InformationElementUtil.Capabilities capabilities = 374 new InformationElementUtil.Capabilities(); 375 capabilities.from(ies, result.capability); 376 String flags = capabilities.generateCapabilitiesString(); 377 NetworkDetail networkDetail; 378 try { 379 networkDetail = new NetworkDetail(bssid, ies, null, result.frequency); 380 } catch (IllegalArgumentException e) { 381 Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e); 382 continue; 383 } 384 385 ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags, 386 result.signalMbm / 100, result.frequency, result.tsf, ies, null); 387 // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi 388 // network and it uses EAP. 389 if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult()) 390 && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) { 391 scanDetail.getScanResult().isCarrierAp = true; 392 scanDetail.getScanResult().carrierApEapType = 393 mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString()); 394 scanDetail.getScanResult().carrierName = 395 mCarrierNetworkConfig.getCarrierName(wifiSsid.toString()); 396 } 397 results.add(scanDetail); 398 } 399 } catch (RemoteException e1) { 400 Log.e(TAG, "Failed to create ScanDetail ArrayList"); 401 } 402 if (mVerboseLoggingEnabled) { 403 Log.d(TAG, "get " + results.size() + " scan results from wificond"); 404 } 405 406 return results; 407 } 408 409 /** 410 * Start a scan using wificond for the given parameters. 411 * @param freqs list of frequencies to scan for, if null scan all supported channels. 412 * @param hiddenNetworkSSIDs List of hidden networks to be scanned for. 413 * @return Returns true on success. 414 */ scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs)415 public boolean scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) { 416 if (mWificondScanner == null) { 417 Log.e(TAG, "No valid wificond scanner interface handler"); 418 return false; 419 } 420 SingleScanSettings settings = new SingleScanSettings(); 421 settings.channelSettings = new ArrayList<>(); 422 settings.hiddenNetworks = new ArrayList<>(); 423 424 if (freqs != null) { 425 for (Integer freq : freqs) { 426 ChannelSettings channel = new ChannelSettings(); 427 channel.frequency = freq; 428 settings.channelSettings.add(channel); 429 } 430 } 431 if (hiddenNetworkSSIDs != null) { 432 for (String ssid : hiddenNetworkSSIDs) { 433 HiddenNetwork network = new HiddenNetwork(); 434 try { 435 network.ssid = NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid)); 436 } catch (IllegalArgumentException e) { 437 Log.e(TAG, "Illegal argument " + ssid, e); 438 continue; 439 } 440 settings.hiddenNetworks.add(network); 441 } 442 } 443 444 try { 445 return mWificondScanner.scan(settings); 446 } catch (RemoteException e1) { 447 Log.e(TAG, "Failed to request scan due to remote exception"); 448 } 449 return false; 450 } 451 452 /** 453 * Start PNO scan. 454 * @param pnoSettings Pno scan configuration. 455 * @return true on success. 456 */ startPnoScan(WifiNative.PnoSettings pnoSettings)457 public boolean startPnoScan(WifiNative.PnoSettings pnoSettings) { 458 if (mWificondScanner == null) { 459 Log.e(TAG, "No valid wificond scanner interface handler"); 460 return false; 461 } 462 PnoSettings settings = new PnoSettings(); 463 settings.pnoNetworks = new ArrayList<>(); 464 settings.intervalMs = pnoSettings.periodInMs; 465 settings.min2gRssi = pnoSettings.min24GHzRssi; 466 settings.min5gRssi = pnoSettings.min5GHzRssi; 467 if (pnoSettings.networkList != null) { 468 for (WifiNative.PnoNetwork network : pnoSettings.networkList) { 469 PnoNetwork condNetwork = new PnoNetwork(); 470 condNetwork.isHidden = (network.flags 471 & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0; 472 try { 473 condNetwork.ssid = 474 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(network.ssid)); 475 } catch (IllegalArgumentException e) { 476 Log.e(TAG, "Illegal argument " + network.ssid, e); 477 continue; 478 } 479 settings.pnoNetworks.add(condNetwork); 480 } 481 } 482 483 try { 484 boolean success = mWificondScanner.startPnoScan(settings); 485 mWifiInjector.getWifiMetrics().incrementPnoScanStartAttempCount(); 486 if (!success) { 487 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount(); 488 } 489 return success; 490 } catch (RemoteException e1) { 491 Log.e(TAG, "Failed to start pno scan due to remote exception"); 492 } 493 return false; 494 } 495 496 /** 497 * Stop PNO scan. 498 * @return true on success. 499 */ stopPnoScan()500 public boolean stopPnoScan() { 501 if (mWificondScanner == null) { 502 Log.e(TAG, "No valid wificond scanner interface handler"); 503 return false; 504 } 505 try { 506 return mWificondScanner.stopPnoScan(); 507 } catch (RemoteException e1) { 508 Log.e(TAG, "Failed to stop pno scan due to remote exception"); 509 } 510 return false; 511 } 512 513 /** 514 * Abort ongoing single scan. 515 */ abortScan()516 public void abortScan() { 517 if (mWificondScanner == null) { 518 Log.e(TAG, "No valid wificond scanner interface handler"); 519 return; 520 } 521 try { 522 mWificondScanner.abortScan(); 523 } catch (RemoteException e1) { 524 Log.e(TAG, "Failed to request abortScan due to remote exception"); 525 } 526 } 527 528 } 529