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