WifiNative.java revision f20f5757ad97c9e2cf3920ff7e861358a576053b
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import android.net.wifi.BatchedScanSettings; 20import android.net.wifi.RttManager; 21import android.net.wifi.ScanResult; 22import android.net.wifi.WifiConfiguration; 23import android.net.wifi.WifiLinkLayerStats; 24import android.net.wifi.WifiManager; 25import android.net.wifi.WifiScanner; 26import android.net.wifi.RttManager; 27import android.net.wifi.WifiSsid; 28import android.net.wifi.WpsInfo; 29import android.net.wifi.p2p.WifiP2pConfig; 30import android.net.wifi.p2p.WifiP2pGroup; 31import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; 32import android.net.wifi.WifiEnterpriseConfig; 33import android.os.SystemClock; 34import android.text.TextUtils; 35import android.util.Base64; 36import android.util.LocalLog; 37import android.util.Log; 38import android.content.Context; 39import android.content.Intent; 40import android.app.PendingIntent; 41import android.content.IntentFilter; 42import android.content.BroadcastReceiver; 43import com.android.server.connectivity.KeepalivePacketData; 44 45import java.io.ByteArrayOutputStream; 46import java.io.IOException; 47import java.nio.ByteBuffer; 48import java.nio.CharBuffer; 49import java.nio.charset.CharacterCodingException; 50import java.nio.charset.CharsetDecoder; 51import java.nio.charset.StandardCharsets; 52import java.util.ArrayList; 53import java.util.List; 54import java.util.Locale; 55import java.util.zip.Deflater; 56import libcore.util.HexEncoding; 57import android.app.AlarmManager; 58/** 59 * Native calls for bring up/shut down of the supplicant daemon and for 60 * sending requests to the supplicant daemon 61 * 62 * waitForEvent() is called on the monitor thread for events. All other methods 63 * must be serialized from the framework. 64 * 65 * {@hide} 66 */ 67public class WifiNative { 68 69 private static boolean DBG = false; 70 private final String mTAG; 71 private static final int DEFAULT_GROUP_OWNER_INTENT = 6; 72 73 static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 74 static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 75 static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 76 77 static final int SCAN_WITHOUT_CONNECTION_SETUP = 1; 78 static final int SCAN_WITH_CONNECTION_SETUP = 2; 79 80 // Hold this lock before calling supplicant - it is required to 81 // mutually exclude access from Wifi and P2p state machines 82 static final Object mLock = new Object(); 83 84 public final String mInterfaceName; 85 public final String mInterfacePrefix; 86 87 private boolean mSuspendOptEnabled = false; 88 89 private static final int EID_HT_OPERATION = 61; 90 private static final int EID_VHT_OPERATION = 192; 91 private static final int EID_EXTENDED_CAPS = 127; 92 private static final int RTT_RESP_ENABLE_BIT = 70; 93 /* Register native functions */ 94 95 static { 96 /* Native functions are defined in libwifi-service.so */ 97 System.loadLibrary("wifi-service"); 98 registerNatives(); 99 } 100 101 private static native int registerNatives(); 102 103 public native static boolean loadDriver(); 104 105 public native static boolean isDriverLoaded(); 106 107 public native static boolean unloadDriver(); 108 109 public native static boolean startSupplicant(boolean p2pSupported); 110 111 /* Sends a kill signal to supplicant. To be used when we have lost connection 112 or when the supplicant is hung */ 113 public native static boolean killSupplicant(boolean p2pSupported); 114 115 private native boolean connectToSupplicantNative(); 116 117 private native void closeSupplicantConnectionNative(); 118 119 /** 120 * Wait for the supplicant to send an event, returning the event string. 121 * @return the event string sent by the supplicant. 122 */ 123 private native String waitForEventNative(); 124 125 private native boolean doBooleanCommandNative(String command); 126 127 private native int doIntCommandNative(String command); 128 129 private native String doStringCommandNative(String command); 130 131 private final Context mContext; 132 private final PnoMonitor mPnoMonitor; 133 public WifiNative(String interfaceName, Context context) { 134 mInterfaceName = interfaceName; 135 mContext = context; 136 mTAG = "WifiNative-" + interfaceName; 137 if (mContext != null) { 138 mPnoMonitor = new PnoMonitor(); 139 } else { 140 mPnoMonitor = null; 141 } 142 143 if (!interfaceName.equals("p2p0")) { 144 mInterfacePrefix = "IFNAME=" + interfaceName + " "; 145 } else { 146 // commands for p2p0 interface don't need prefix 147 mInterfacePrefix = ""; 148 } 149 } 150 151 public WifiNative(String interfaceName) { 152 this(interfaceName, null); 153 } 154 155 void enableVerboseLogging(int verbose) { 156 if (verbose > 0) { 157 DBG = true; 158 } else { 159 DBG = false; 160 } 161 } 162 163 private static final LocalLog mLocalLog = new LocalLog(16384); 164 165 // hold mLock before accessing mCmdIdLock 166 private static int sCmdId; 167 168 public static LocalLog getLocalLog() { 169 return mLocalLog; 170 } 171 172 private static int getNewCmdIdLocked() { 173 return sCmdId++; 174 } 175 176 private void localLog(String s) { 177 if (mLocalLog != null) 178 mLocalLog.log(mInterfaceName + ": " + s); 179 } 180 181 public boolean connectToSupplicant() { 182 synchronized(mLock) { 183 localLog(mInterfacePrefix + "connectToSupplicant"); 184 return connectToSupplicantNative(); 185 } 186 } 187 188 public void closeSupplicantConnection() { 189 synchronized(mLock) { 190 localLog(mInterfacePrefix + "closeSupplicantConnection"); 191 closeSupplicantConnectionNative(); 192 } 193 } 194 195 public String waitForEvent() { 196 // No synchronization necessary .. it is implemented in WifiMonitor 197 return waitForEventNative(); 198 } 199 200 private boolean doBooleanCommand(String command) { 201 if (DBG) Log.d(mTAG, "doBoolean: " + command); 202 synchronized (mLock) { 203 int cmdId = getNewCmdIdLocked(); 204 String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command; 205 boolean result = doBooleanCommandNative(mInterfacePrefix + command); 206 localLog(toLog + " -> " + result); 207 if (DBG) Log.d(mTAG, command + ": returned " + result); 208 return result; 209 } 210 } 211 212 private boolean doBooleanCommandWithoutLogging(String command) { 213 if (DBG) Log.d(mTAG, "doBooleanCommandWithoutLogging: " + command); 214 synchronized (mLock) { 215 int cmdId = getNewCmdIdLocked(); 216 boolean result = doBooleanCommandNative(mInterfacePrefix + command); 217 if (DBG) Log.d(mTAG, command + ": returned " + result); 218 return result; 219 } 220 } 221 222 private int doIntCommand(String command) { 223 if (DBG) Log.d(mTAG, "doInt: " + command); 224 synchronized (mLock) { 225 int cmdId = getNewCmdIdLocked(); 226 String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command; 227 int result = doIntCommandNative(mInterfacePrefix + command); 228 localLog(toLog + " -> " + result); 229 if (DBG) Log.d(mTAG, " returned " + result); 230 return result; 231 } 232 } 233 234 private String doStringCommand(String command) { 235 if (DBG) { 236 //GET_NETWORK commands flood the logs 237 if (!command.startsWith("GET_NETWORK")) { 238 Log.d(mTAG, "doString: [" + command + "]"); 239 } 240 } 241 synchronized (mLock) { 242 int cmdId = getNewCmdIdLocked(); 243 String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command; 244 String result = doStringCommandNative(mInterfacePrefix + command); 245 if (result == null) { 246 if (DBG) Log.d(mTAG, "doStringCommandNative no result"); 247 } else { 248 if (!command.startsWith("STATUS-")) { 249 localLog(toLog + " -> " + result); 250 } 251 if (DBG) Log.d(mTAG, " returned " + result.replace("\n", " ")); 252 } 253 return result; 254 } 255 } 256 257 private String doStringCommandWithoutLogging(String command) { 258 if (DBG) { 259 //GET_NETWORK commands flood the logs 260 if (!command.startsWith("GET_NETWORK")) { 261 Log.d(mTAG, "doString: [" + command + "]"); 262 } 263 } 264 synchronized (mLock) { 265 return doStringCommandNative(mInterfacePrefix + command); 266 } 267 } 268 269 public boolean ping() { 270 String pong = doStringCommand("PING"); 271 return (pong != null && pong.equals("PONG")); 272 } 273 274 public void setSupplicantLogLevel(String level) { 275 doStringCommand("LOG_LEVEL " + level); 276 } 277 278 public String getFreqCapability() { 279 return doStringCommand("GET_CAPABILITY freq"); 280 } 281 282 public boolean scan(int type, String freqList) { 283 if (type == SCAN_WITHOUT_CONNECTION_SETUP) { 284 if (freqList == null) return doBooleanCommand("SCAN TYPE=ONLY"); 285 else return doBooleanCommand("SCAN TYPE=ONLY freq=" + freqList); 286 } else if (type == SCAN_WITH_CONNECTION_SETUP) { 287 if (freqList == null) return doBooleanCommand("SCAN"); 288 else return doBooleanCommand("SCAN freq=" + freqList); 289 } else { 290 throw new IllegalArgumentException("Invalid scan type"); 291 } 292 } 293 294 /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. 295 * 296 * Note that underneath we use a harsh-sounding "terminate" supplicant command 297 * for a graceful stop and a mild-sounding "stop" interface 298 * to kill the process 299 */ 300 public boolean stopSupplicant() { 301 return doBooleanCommand("TERMINATE"); 302 } 303 304 public String listNetworks() { 305 return doStringCommand("LIST_NETWORKS"); 306 } 307 308 public String listNetworks(int last_id) { 309 return doStringCommand("LIST_NETWORKS LAST_ID=" + last_id); 310 } 311 312 public int addNetwork() { 313 return doIntCommand("ADD_NETWORK"); 314 } 315 316 public boolean setNetworkVariable(int netId, String name, String value) { 317 if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false; 318 if (name.equals(WifiConfiguration.pskVarName) 319 || name.equals(WifiEnterpriseConfig.PASSWORD_KEY) 320 || name.equals(WifiEnterpriseConfig.IDENTITY_KEY) 321 || name.equals(WifiEnterpriseConfig.ANON_IDENTITY_KEY)) { 322 return doBooleanCommandWithoutLogging("SET_NETWORK " + netId + " " + name + " " + value); 323 } else { 324 return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value); 325 } 326 } 327 328 public String getNetworkVariable(int netId, String name) { 329 if (TextUtils.isEmpty(name)) return null; 330 331 // GET_NETWORK will likely flood the logs ... 332 return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name); 333 } 334 335 public boolean removeNetwork(int netId) { 336 return doBooleanCommand("REMOVE_NETWORK " + netId); 337 } 338 339 340 private void logDbg(String debug) { 341 long now = SystemClock.elapsedRealtimeNanos(); 342 String ts = String.format("[%,d us] ", now/1000); 343 Log.e("WifiNative: ", ts+debug+ " stack:" 344 + Thread.currentThread().getStackTrace()[2].getMethodName() +" - " 345 + Thread.currentThread().getStackTrace()[3].getMethodName() +" - " 346 + Thread.currentThread().getStackTrace()[4].getMethodName() +" - " 347 + Thread.currentThread().getStackTrace()[5].getMethodName()+" - " 348 + Thread.currentThread().getStackTrace()[6].getMethodName()); 349 350 } 351 public boolean enableNetwork(int netId, boolean disableOthers) { 352 if (DBG) logDbg("enableNetwork nid=" + Integer.toString(netId) 353 + " disableOthers=" + disableOthers); 354 if (disableOthers) { 355 return doBooleanCommand("SELECT_NETWORK " + netId); 356 } else { 357 return doBooleanCommand("ENABLE_NETWORK " + netId); 358 } 359 } 360 361 public boolean disableNetwork(int netId) { 362 if (DBG) logDbg("disableNetwork nid=" + Integer.toString(netId)); 363 return doBooleanCommand("DISABLE_NETWORK " + netId); 364 } 365 366 public boolean selectNetwork(int netId) { 367 if (DBG) logDbg("selectNetwork nid=" + Integer.toString(netId)); 368 return doBooleanCommand("SELECT_NETWORK " + netId); 369 } 370 371 public boolean reconnect() { 372 if (DBG) logDbg("RECONNECT "); 373 return doBooleanCommand("RECONNECT"); 374 } 375 376 public boolean reassociate() { 377 if (DBG) logDbg("REASSOCIATE "); 378 return doBooleanCommand("REASSOCIATE"); 379 } 380 381 public boolean disconnect() { 382 if (DBG) logDbg("DISCONNECT "); 383 return doBooleanCommand("DISCONNECT"); 384 } 385 386 public String status() { 387 return status(false); 388 } 389 390 public String status(boolean noEvents) { 391 if (noEvents) { 392 return doStringCommand("STATUS-NO_EVENTS"); 393 } else { 394 return doStringCommand("STATUS"); 395 } 396 } 397 398 public String getMacAddress() { 399 //Macaddr = XX.XX.XX.XX.XX.XX 400 String ret = doStringCommand("DRIVER MACADDR"); 401 if (!TextUtils.isEmpty(ret)) { 402 String[] tokens = ret.split(" = "); 403 if (tokens.length == 2) return tokens[1]; 404 } 405 return null; 406 } 407 408 409 410 /** 411 * Format of results: 412 * ================= 413 * id=1 414 * bssid=68:7f:74:d7:1b:6e 415 * freq=2412 416 * level=-43 417 * tsf=1344621975160944 418 * age=2623 419 * flags=[WPA2-PSK-CCMP][WPS][ESS] 420 * ssid=zubyb 421 * ==== 422 * 423 * RANGE=ALL gets all scan results 424 * RANGE=ID- gets results from ID 425 * MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details 426 * 0 0 1 0 2 427 * WPA_BSS_MASK_MESH_SCAN | WPA_BSS_MASK_DELIM | WPA_BSS_MASK_WIFI_DISPLAY 428 * 0 0 0 1 1 -> 9 429 * WPA_BSS_MASK_INTERNETW | WPA_BSS_MASK_P2P_SCAN | WPA_BSS_MASK_WPS_SCAN | WPA_BSS_MASK_SSID 430 * 1 0 0 1 9 -> d 431 * WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_IE | WPA_BSS_MASK_AGE | WPA_BSS_MASK_TSF 432 * 1 0 0 0 8 433 * WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_NOISE | WPA_BSS_MASK_QUAL | WPA_BSS_MASK_CAPABILITIES 434 * 0 1 1 1 7 435 * WPA_BSS_MASK_BEACON_INT | WPA_BSS_MASK_FREQ | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_ID 436 * 437 * WPA_BSS_MASK_INTERNETW adds ANQP info (ctrl_iface:4151-4176) 438 * 439 * ctrl_iface.c:wpa_supplicant_ctrl_iface_process:7884 440 * wpa_supplicant_ctrl_iface_bss:4315 441 * print_bss_info 442 */ 443 public String scanResults(int sid) { 444 return doStringCommandWithoutLogging("BSS RANGE=" + sid + "- MASK=0x29d87"); 445 } 446 447 public String doCustomCommand(String command) { 448 return doStringCommand(command); 449 } 450 451 /** 452 * Format of result: 453 * id=1016 454 * bssid=00:03:7f:40:84:10 455 * freq=2462 456 * beacon_int=200 457 * capabilities=0x0431 458 * qual=0 459 * noise=0 460 * level=-46 461 * tsf=0000002669008476 462 * age=5 463 * ie=00105143412d485332302d52322d54455354010882848b960c12182403010b0706555... 464 * flags=[WPA2-EAP-CCMP][ESS][P2P][HS20] 465 * ssid=QCA-HS20-R2-TEST 466 * p2p_device_name= 467 * p2p_config_methods=0x0SET_NE 468 * anqp_venue_name=02083d656e6757692d466920416c6c69616e63650a3239383920436f... 469 * anqp_network_auth_type=010000 470 * anqp_roaming_consortium=03506f9a05001bc504bd 471 * anqp_ip_addr_type_availability=0c 472 * anqp_nai_realm=0200300000246d61696c2e6578616d706c652e636f6d3b636973636f2... 473 * anqp_3gpp=000600040132f465 474 * anqp_domain_name=0b65786d61706c652e636f6d 475 * hs20_operator_friendly_name=11656e6757692d466920416c6c69616e63650e636869... 476 * hs20_wan_metrics=01c40900008001000000000a00 477 * hs20_connection_capability=0100000006140001061600000650000106bb010106bb0... 478 * hs20_osu_providers_list=0b5143412d4f53552d425353010901310015656e6757692d... 479 */ 480 public String scanResult(String bssid) { 481 return doStringCommand("BSS " + bssid); 482 } 483 484 /** 485 * Format of command 486 * DRIVER WLS_BATCHING SET SCANFREQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s 487 * where x is an ascii representation of an integer number of seconds between scans 488 * r is an ascii representation of an integer number of scans per batch 489 * y is an ascii representation of an integer number of the max AP to remember per scan 490 * z, w, t represent a 1..n size list of channel numbers and/or 'A', 'B' values 491 * indicating entire ranges of channels 492 * s is an ascii representation of an integer number of highest-strength AP 493 * for which we'd like approximate distance reported 494 * 495 * The return value is an ascii integer representing a guess of the number of scans 496 * the firmware can remember before it runs out of buffer space or -1 on error 497 */ 498 public String setBatchedScanSettings(BatchedScanSettings settings) { 499 if (settings == null) { 500 return doStringCommand("DRIVER WLS_BATCHING STOP"); 501 } 502 String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec; 503 cmd += " MSCAN=" + settings.maxScansPerBatch; 504 if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) { 505 cmd += " BESTN=" + settings.maxApPerScan; 506 } 507 if (settings.channelSet != null && !settings.channelSet.isEmpty()) { 508 cmd += " CHANNEL=<"; 509 int i = 0; 510 for (String channel : settings.channelSet) { 511 cmd += (i > 0 ? "," : "") + channel; 512 ++i; 513 } 514 cmd += ">"; 515 } 516 if (settings.maxApForDistance != BatchedScanSettings.UNSPECIFIED) { 517 cmd += " RTT=" + settings.maxApForDistance; 518 } 519 return doStringCommand(cmd); 520 } 521 522 public String getBatchedScanResults() { 523 return doStringCommand("DRIVER WLS_BATCHING GET"); 524 } 525 526 public boolean startDriver() { 527 return doBooleanCommand("DRIVER START"); 528 } 529 530 public boolean stopDriver() { 531 return doBooleanCommand("DRIVER STOP"); 532 } 533 534 535 /** 536 * Start filtering out Multicast V4 packets 537 * @return {@code true} if the operation succeeded, {@code false} otherwise 538 * 539 * Multicast filtering rules work as follows: 540 * 541 * The driver can filter multicast (v4 and/or v6) and broadcast packets when in 542 * a power optimized mode (typically when screen goes off). 543 * 544 * In order to prevent the driver from filtering the multicast/broadcast packets, we have to 545 * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective 546 * 547 * DRIVER RXFILTER-ADD Num 548 * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 549 * 550 * and DRIVER RXFILTER-START 551 * In order to stop the usage of these rules, we do 552 * 553 * DRIVER RXFILTER-STOP 554 * DRIVER RXFILTER-REMOVE Num 555 * where Num is as described for RXFILTER-ADD 556 * 557 * The SETSUSPENDOPT driver command overrides the filtering rules 558 */ 559 public boolean startFilteringMulticastV4Packets() { 560 return doBooleanCommand("DRIVER RXFILTER-STOP") 561 && doBooleanCommand("DRIVER RXFILTER-REMOVE 2") 562 && doBooleanCommand("DRIVER RXFILTER-START"); 563 } 564 565 /** 566 * Stop filtering out Multicast V4 packets. 567 * @return {@code true} if the operation succeeded, {@code false} otherwise 568 */ 569 public boolean stopFilteringMulticastV4Packets() { 570 return doBooleanCommand("DRIVER RXFILTER-STOP") 571 && doBooleanCommand("DRIVER RXFILTER-ADD 2") 572 && doBooleanCommand("DRIVER RXFILTER-START"); 573 } 574 575 /** 576 * Start filtering out Multicast V6 packets 577 * @return {@code true} if the operation succeeded, {@code false} otherwise 578 */ 579 public boolean startFilteringMulticastV6Packets() { 580 return doBooleanCommand("DRIVER RXFILTER-STOP") 581 && doBooleanCommand("DRIVER RXFILTER-REMOVE 3") 582 && doBooleanCommand("DRIVER RXFILTER-START"); 583 } 584 585 /** 586 * Stop filtering out Multicast V6 packets. 587 * @return {@code true} if the operation succeeded, {@code false} otherwise 588 */ 589 public boolean stopFilteringMulticastV6Packets() { 590 return doBooleanCommand("DRIVER RXFILTER-STOP") 591 && doBooleanCommand("DRIVER RXFILTER-ADD 3") 592 && doBooleanCommand("DRIVER RXFILTER-START"); 593 } 594 595 /** 596 * Set the operational frequency band 597 * @param band One of 598 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO}, 599 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ}, 600 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ}, 601 * @return {@code true} if the operation succeeded, {@code false} otherwise 602 */ 603 public boolean setBand(int band) { 604 String bandstr; 605 606 if (band == WifiManager.WIFI_FREQUENCY_BAND_5GHZ) 607 bandstr = "5G"; 608 else if (band == WifiManager.WIFI_FREQUENCY_BAND_2GHZ) 609 bandstr = "2G"; 610 else 611 bandstr = "AUTO"; 612 return doBooleanCommand("SET SETBAND " + bandstr); 613 } 614 615 /** 616 * Sets the bluetooth coexistence mode. 617 * 618 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 619 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 620 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 621 * @return Whether the mode was successfully set. 622 */ 623 public boolean setBluetoothCoexistenceMode(int mode) { 624 return doBooleanCommand("DRIVER BTCOEXMODE " + mode); 625 } 626 627 /** 628 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 629 * some of the low-level scan parameters used by the driver are changed to 630 * reduce interference with A2DP streaming. 631 * 632 * @param isSet whether to enable or disable this mode 633 * @return {@code true} if the command succeeded, {@code false} otherwise. 634 */ 635 public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) { 636 if (setCoexScanMode) { 637 return doBooleanCommand("DRIVER BTCOEXSCAN-START"); 638 } else { 639 return doBooleanCommand("DRIVER BTCOEXSCAN-STOP"); 640 } 641 } 642 643 public void enableSaveConfig() { 644 doBooleanCommand("SET update_config 1"); 645 } 646 647 public boolean saveConfig() { 648 return doBooleanCommand("SAVE_CONFIG"); 649 } 650 651 public boolean addToBlacklist(String bssid) { 652 if (TextUtils.isEmpty(bssid)) return false; 653 return doBooleanCommand("BLACKLIST " + bssid); 654 } 655 656 public boolean clearBlacklist() { 657 return doBooleanCommand("BLACKLIST clear"); 658 } 659 660 public boolean setSuspendOptimizations(boolean enabled) { 661 // if (mSuspendOptEnabled == enabled) return true; 662 mSuspendOptEnabled = enabled; 663 664 Log.e("native", "do suspend " + enabled); 665 if (enabled) { 666 return doBooleanCommand("DRIVER SETSUSPENDMODE 1"); 667 } else { 668 return doBooleanCommand("DRIVER SETSUSPENDMODE 0"); 669 } 670 } 671 672 public boolean setCountryCode(String countryCode) { 673 if (countryCode != null) 674 return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT)); 675 else 676 return doBooleanCommand("DRIVER COUNTRY"); 677 } 678 679 //PNO Monitor 680 private class PnoMonitor { 681 private static final int MINIMUM_PNO_GAP = 5 * 1000; 682 private static final String ACTION_TOGGLE_PNO = 683 "com.android.server.Wifi.action.TOGGLE_PNO"; 684 long mLastPnoChangeTimeStamp = -1L; 685 boolean mExpectedPnoState = false; 686 boolean mCurrentPnoState = false;; 687 boolean mWaitForTimer = false; 688 final Object mPnoLock = new Object(); 689 private final AlarmManager mAlarmManager = 690 (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 691 private final PendingIntent mPnoIntent; 692 693 public PnoMonitor() { 694 Intent intent = new Intent(ACTION_TOGGLE_PNO, null); 695 intent.setPackage("android"); 696 mPnoIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 697 698 mContext.registerReceiver( 699 new BroadcastReceiver() { 700 @Override 701 public void onReceive(Context context, Intent intent) { 702 synchronized(mPnoLock) { 703 if (DBG) Log.d(mTAG, "PNO timer expire, PNO should change to " + 704 mExpectedPnoState); 705 if (mCurrentPnoState != mExpectedPnoState) { 706 if (DBG) Log.d(mTAG, "change PNO from " + mCurrentPnoState + " to " 707 + mExpectedPnoState); 708 boolean ret = setPno(mExpectedPnoState); 709 if (!ret) { 710 Log.e(mTAG, "set PNO failure"); 711 } 712 } else { 713 if (DBG) Log.d(mTAG, "Do not change PNO since current is expected"); 714 } 715 mWaitForTimer = false; 716 } 717 } 718 }, 719 new IntentFilter(ACTION_TOGGLE_PNO)); 720 } 721 722 private boolean setPno(boolean enable) { 723 String cmd = enable ? "SET pno 1" : "SET pno 0"; 724 boolean ret = doBooleanCommand(cmd); 725 mLastPnoChangeTimeStamp = System.currentTimeMillis(); 726 if (ret) { 727 mCurrentPnoState = enable; 728 } 729 return ret; 730 } 731 732 public boolean enableBackgroundScan(boolean enable) { 733 synchronized(mPnoLock) { 734 if (mWaitForTimer) { 735 //already has a timer 736 mExpectedPnoState = enable; 737 if (DBG) Log.d(mTAG, "update expected PNO to " + mExpectedPnoState); 738 } else { 739 if (mCurrentPnoState == enable) { 740 return true; 741 } 742 long timeDifference = System.currentTimeMillis() - mLastPnoChangeTimeStamp; 743 if (timeDifference >= MINIMUM_PNO_GAP) { 744 return setPno(enable); 745 } else { 746 mExpectedPnoState = enable; 747 mWaitForTimer = true; 748 if (DBG) Log.d(mTAG, "start PNO timer with delay:" + timeDifference); 749 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 750 System.currentTimeMillis() + timeDifference, mPnoIntent); 751 } 752 } 753 return true; 754 } 755 } 756 } 757 758 public boolean enableBackgroundScan(boolean enable) { 759 if (mPnoMonitor != null) { 760 return mPnoMonitor.enableBackgroundScan(enable); 761 } else { 762 return false; 763 } 764 } 765 766 public void enableAutoConnect(boolean enable) { 767 if (enable) { 768 doBooleanCommand("STA_AUTOCONNECT 1"); 769 } else { 770 doBooleanCommand("STA_AUTOCONNECT 0"); 771 } 772 } 773 774 public void setScanInterval(int scanInterval) { 775 doBooleanCommand("SCAN_INTERVAL " + scanInterval); 776 } 777 778 public void setHs20(boolean hs20) { 779 if (hs20) { 780 doBooleanCommand("SET HS20 1"); 781 } else { 782 doBooleanCommand("SET HS20 0"); 783 } 784 } 785 786 public void startTdls(String macAddr, boolean enable) { 787 if (enable) { 788 doBooleanCommand("TDLS_DISCOVER " + macAddr); 789 doBooleanCommand("TDLS_SETUP " + macAddr); 790 } else { 791 doBooleanCommand("TDLS_TEARDOWN " + macAddr); 792 } 793 } 794 795 /** Example output: 796 * RSSI=-65 797 * LINKSPEED=48 798 * NOISE=9999 799 * FREQUENCY=0 800 */ 801 public String signalPoll() { 802 return doStringCommandWithoutLogging("SIGNAL_POLL"); 803 } 804 805 /** Example outout: 806 * TXGOOD=396 807 * TXBAD=1 808 */ 809 public String pktcntPoll() { 810 return doStringCommand("PKTCNT_POLL"); 811 } 812 813 public void bssFlush() { 814 doBooleanCommand("BSS_FLUSH 0"); 815 } 816 817 public boolean startWpsPbc(String bssid) { 818 if (TextUtils.isEmpty(bssid)) { 819 return doBooleanCommand("WPS_PBC"); 820 } else { 821 return doBooleanCommand("WPS_PBC " + bssid); 822 } 823 } 824 825 public boolean startWpsPbc(String iface, String bssid) { 826 synchronized (mLock) { 827 if (TextUtils.isEmpty(bssid)) { 828 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC"); 829 } else { 830 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid); 831 } 832 } 833 } 834 835 public boolean startWpsPinKeypad(String pin) { 836 if (TextUtils.isEmpty(pin)) return false; 837 return doBooleanCommand("WPS_PIN any " + pin); 838 } 839 840 public boolean startWpsPinKeypad(String iface, String pin) { 841 if (TextUtils.isEmpty(pin)) return false; 842 synchronized (mLock) { 843 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin); 844 } 845 } 846 847 848 public String startWpsPinDisplay(String bssid) { 849 if (TextUtils.isEmpty(bssid)) { 850 return doStringCommand("WPS_PIN any"); 851 } else { 852 return doStringCommand("WPS_PIN " + bssid); 853 } 854 } 855 856 public String startWpsPinDisplay(String iface, String bssid) { 857 synchronized (mLock) { 858 if (TextUtils.isEmpty(bssid)) { 859 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any"); 860 } else { 861 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid); 862 } 863 } 864 } 865 866 public boolean setExternalSim(boolean external) { 867 synchronized (mLock) { 868 String value = external ? "1" : "0"; 869 Log.d(TAG, "Setting external_sim to " + value); 870 return doBooleanCommand("SET external_sim " + value); 871 } 872 } 873 874 public boolean simAuthResponse(int id, String type, String response) { 875 // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS 876 synchronized (mLock) { 877 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response); 878 } 879 } 880 881 public boolean simAuthFailedResponse(int id) { 882 // should be used with type GSM-AUTH 883 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":GSM-FAIL"); 884 } 885 886 public boolean umtsAuthFailedResponse(int id) { 887 // should be used with type UMTS-AUTH 888 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":UMTS-FAIL"); 889 } 890 891 public boolean simIdentityResponse(int id, String response) { 892 synchronized (mLock) { 893 return doBooleanCommand("CTRL-RSP-IDENTITY-" + id + ":" + response); 894 } 895 } 896 897 /* Configures an access point connection */ 898 public boolean startWpsRegistrar(String bssid, String pin) { 899 if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false; 900 return doBooleanCommand("WPS_REG " + bssid + " " + pin); 901 } 902 903 public boolean cancelWps() { 904 return doBooleanCommand("WPS_CANCEL"); 905 } 906 907 public boolean setPersistentReconnect(boolean enabled) { 908 int value = (enabled == true) ? 1 : 0; 909 return doBooleanCommand("SET persistent_reconnect " + value); 910 } 911 912 public boolean setDeviceName(String name) { 913 return doBooleanCommand("SET device_name " + name); 914 } 915 916 public boolean setDeviceType(String type) { 917 return doBooleanCommand("SET device_type " + type); 918 } 919 920 public boolean setConfigMethods(String cfg) { 921 return doBooleanCommand("SET config_methods " + cfg); 922 } 923 924 public boolean setManufacturer(String value) { 925 return doBooleanCommand("SET manufacturer " + value); 926 } 927 928 public boolean setModelName(String value) { 929 return doBooleanCommand("SET model_name " + value); 930 } 931 932 public boolean setModelNumber(String value) { 933 return doBooleanCommand("SET model_number " + value); 934 } 935 936 public boolean setSerialNumber(String value) { 937 return doBooleanCommand("SET serial_number " + value); 938 } 939 940 public boolean setP2pSsidPostfix(String postfix) { 941 return doBooleanCommand("SET p2p_ssid_postfix " + postfix); 942 } 943 944 public boolean setP2pGroupIdle(String iface, int time) { 945 synchronized (mLock) { 946 return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time); 947 } 948 } 949 950 public void setPowerSave(boolean enabled) { 951 if (enabled) { 952 doBooleanCommand("SET ps 1"); 953 } else { 954 doBooleanCommand("SET ps 0"); 955 } 956 } 957 958 public boolean setP2pPowerSave(String iface, boolean enabled) { 959 synchronized (mLock) { 960 if (enabled) { 961 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1"); 962 } else { 963 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0"); 964 } 965 } 966 } 967 968 public boolean setWfdEnable(boolean enable) { 969 return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0")); 970 } 971 972 public boolean setWfdDeviceInfo(String hex) { 973 return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex); 974 } 975 976 /** 977 * "sta" prioritizes STA connection over P2P and "p2p" prioritizes 978 * P2P connection over STA 979 */ 980 public boolean setConcurrencyPriority(String s) { 981 return doBooleanCommand("P2P_SET conc_pref " + s); 982 } 983 984 public boolean p2pFind() { 985 return doBooleanCommand("P2P_FIND"); 986 } 987 988 public boolean p2pFind(int timeout) { 989 if (timeout <= 0) { 990 return p2pFind(); 991 } 992 return doBooleanCommand("P2P_FIND " + timeout); 993 } 994 995 public boolean p2pStopFind() { 996 return doBooleanCommand("P2P_STOP_FIND"); 997 } 998 999 public boolean p2pListen() { 1000 return doBooleanCommand("P2P_LISTEN"); 1001 } 1002 1003 public boolean p2pListen(int timeout) { 1004 if (timeout <= 0) { 1005 return p2pListen(); 1006 } 1007 return doBooleanCommand("P2P_LISTEN " + timeout); 1008 } 1009 1010 public boolean p2pExtListen(boolean enable, int period, int interval) { 1011 if (enable && interval < period) { 1012 return false; 1013 } 1014 return doBooleanCommand("P2P_EXT_LISTEN" 1015 + (enable ? (" " + period + " " + interval) : "")); 1016 } 1017 1018 public boolean p2pSetChannel(int lc, int oc) { 1019 if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc); 1020 1021 if (lc >=1 && lc <= 11) { 1022 if (!doBooleanCommand("P2P_SET listen_channel " + lc)) { 1023 return false; 1024 } 1025 } else if (lc != 0) { 1026 return false; 1027 } 1028 1029 if (oc >= 1 && oc <= 165 ) { 1030 int freq = (oc <= 14 ? 2407 : 5000) + oc * 5; 1031 return doBooleanCommand("P2P_SET disallow_freq 1000-" 1032 + (freq - 5) + "," + (freq + 5) + "-6000"); 1033 } else if (oc == 0) { 1034 /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */ 1035 return doBooleanCommand("P2P_SET disallow_freq \"\""); 1036 } 1037 1038 return false; 1039 } 1040 1041 public boolean p2pFlush() { 1042 return doBooleanCommand("P2P_FLUSH"); 1043 } 1044 1045 /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] 1046 [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ 1047 public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { 1048 if (config == null) return null; 1049 List<String> args = new ArrayList<String>(); 1050 WpsInfo wps = config.wps; 1051 args.add(config.deviceAddress); 1052 1053 switch (wps.setup) { 1054 case WpsInfo.PBC: 1055 args.add("pbc"); 1056 break; 1057 case WpsInfo.DISPLAY: 1058 if (TextUtils.isEmpty(wps.pin)) { 1059 args.add("pin"); 1060 } else { 1061 args.add(wps.pin); 1062 } 1063 args.add("display"); 1064 break; 1065 case WpsInfo.KEYPAD: 1066 args.add(wps.pin); 1067 args.add("keypad"); 1068 break; 1069 case WpsInfo.LABEL: 1070 args.add(wps.pin); 1071 args.add("label"); 1072 default: 1073 break; 1074 } 1075 1076 if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) { 1077 args.add("persistent"); 1078 } 1079 1080 if (joinExistingGroup) { 1081 args.add("join"); 1082 } else { 1083 //TODO: This can be adapted based on device plugged in state and 1084 //device battery state 1085 int groupOwnerIntent = config.groupOwnerIntent; 1086 if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { 1087 groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT; 1088 } 1089 args.add("go_intent=" + groupOwnerIntent); 1090 } 1091 1092 String command = "P2P_CONNECT "; 1093 for (String s : args) command += s + " "; 1094 1095 return doStringCommand(command); 1096 } 1097 1098 public boolean p2pCancelConnect() { 1099 return doBooleanCommand("P2P_CANCEL"); 1100 } 1101 1102 public boolean p2pProvisionDiscovery(WifiP2pConfig config) { 1103 if (config == null) return false; 1104 1105 switch (config.wps.setup) { 1106 case WpsInfo.PBC: 1107 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); 1108 case WpsInfo.DISPLAY: 1109 //We are doing display, so provision discovery is keypad 1110 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); 1111 case WpsInfo.KEYPAD: 1112 //We are doing keypad, so provision discovery is display 1113 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); 1114 default: 1115 break; 1116 } 1117 return false; 1118 } 1119 1120 public boolean p2pGroupAdd(boolean persistent) { 1121 if (persistent) { 1122 return doBooleanCommand("P2P_GROUP_ADD persistent"); 1123 } 1124 return doBooleanCommand("P2P_GROUP_ADD"); 1125 } 1126 1127 public boolean p2pGroupAdd(int netId) { 1128 return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId); 1129 } 1130 1131 public boolean p2pGroupRemove(String iface) { 1132 if (TextUtils.isEmpty(iface)) return false; 1133 synchronized (mLock) { 1134 return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface); 1135 } 1136 } 1137 1138 public boolean p2pReject(String deviceAddress) { 1139 return doBooleanCommand("P2P_REJECT " + deviceAddress); 1140 } 1141 1142 /* Invite a peer to a group */ 1143 public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { 1144 if (TextUtils.isEmpty(deviceAddress)) return false; 1145 1146 if (group == null) { 1147 return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); 1148 } else { 1149 return doBooleanCommand("P2P_INVITE group=" + group.getInterface() 1150 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); 1151 } 1152 } 1153 1154 /* Reinvoke a persistent connection */ 1155 public boolean p2pReinvoke(int netId, String deviceAddress) { 1156 if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false; 1157 1158 return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); 1159 } 1160 1161 public String p2pGetSsid(String deviceAddress) { 1162 return p2pGetParam(deviceAddress, "oper_ssid"); 1163 } 1164 1165 public String p2pGetDeviceAddress() { 1166 1167 Log.d(TAG, "p2pGetDeviceAddress"); 1168 1169 String status = null; 1170 1171 /* Explicitly calling the API without IFNAME= prefix to take care of the devices that 1172 don't have p2p0 interface. Supplicant seems to be returning the correct address anyway. */ 1173 1174 synchronized (mLock) { 1175 status = doStringCommandNative("STATUS"); 1176 } 1177 1178 String result = ""; 1179 if (status != null) { 1180 String[] tokens = status.split("\n"); 1181 for (String token : tokens) { 1182 if (token.startsWith("p2p_device_address=")) { 1183 String[] nameValue = token.split("="); 1184 if (nameValue.length != 2) 1185 break; 1186 result = nameValue[1]; 1187 } 1188 } 1189 } 1190 1191 Log.d(TAG, "p2pGetDeviceAddress returning " + result); 1192 return result; 1193 } 1194 1195 public int getGroupCapability(String deviceAddress) { 1196 int gc = 0; 1197 if (TextUtils.isEmpty(deviceAddress)) return gc; 1198 String peerInfo = p2pPeer(deviceAddress); 1199 if (TextUtils.isEmpty(peerInfo)) return gc; 1200 1201 String[] tokens = peerInfo.split("\n"); 1202 for (String token : tokens) { 1203 if (token.startsWith("group_capab=")) { 1204 String[] nameValue = token.split("="); 1205 if (nameValue.length != 2) break; 1206 try { 1207 return Integer.decode(nameValue[1]); 1208 } catch(NumberFormatException e) { 1209 return gc; 1210 } 1211 } 1212 } 1213 return gc; 1214 } 1215 1216 public String p2pPeer(String deviceAddress) { 1217 return doStringCommand("P2P_PEER " + deviceAddress); 1218 } 1219 1220 private String p2pGetParam(String deviceAddress, String key) { 1221 if (deviceAddress == null) return null; 1222 1223 String peerInfo = p2pPeer(deviceAddress); 1224 if (peerInfo == null) return null; 1225 String[] tokens= peerInfo.split("\n"); 1226 1227 key += "="; 1228 for (String token : tokens) { 1229 if (token.startsWith(key)) { 1230 String[] nameValue = token.split("="); 1231 if (nameValue.length != 2) break; 1232 return nameValue[1]; 1233 } 1234 } 1235 return null; 1236 } 1237 1238 public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) { 1239 /* 1240 * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump> 1241 * P2P_SERVICE_ADD upnp <version hex> <service> 1242 * 1243 * e.g) 1244 * [Bonjour] 1245 * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) 1246 * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027 1247 * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) 1248 * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 1249 * 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 1250 * 1251 * [UPnP] 1252 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 1253 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice 1254 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp 1255 * -org:device:InternetGatewayDevice:1 1256 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp 1257 * -org:service:ContentDirectory:2 1258 */ 1259 for (String s : servInfo.getSupplicantQueryList()) { 1260 String command = "P2P_SERVICE_ADD"; 1261 command += (" " + s); 1262 if (!doBooleanCommand(command)) { 1263 return false; 1264 } 1265 } 1266 return true; 1267 } 1268 1269 public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) { 1270 /* 1271 * P2P_SERVICE_DEL bonjour <query hexdump> 1272 * P2P_SERVICE_DEL upnp <version hex> <service> 1273 */ 1274 for (String s : servInfo.getSupplicantQueryList()) { 1275 String command = "P2P_SERVICE_DEL "; 1276 1277 String[] data = s.split(" "); 1278 if (data.length < 2) { 1279 return false; 1280 } 1281 if ("upnp".equals(data[0])) { 1282 command += s; 1283 } else if ("bonjour".equals(data[0])) { 1284 command += data[0]; 1285 command += (" " + data[1]); 1286 } else { 1287 return false; 1288 } 1289 if (!doBooleanCommand(command)) { 1290 return false; 1291 } 1292 } 1293 return true; 1294 } 1295 1296 public boolean p2pServiceFlush() { 1297 return doBooleanCommand("P2P_SERVICE_FLUSH"); 1298 } 1299 1300 public String p2pServDiscReq(String addr, String query) { 1301 String command = "P2P_SERV_DISC_REQ"; 1302 command += (" " + addr); 1303 command += (" " + query); 1304 1305 return doStringCommand(command); 1306 } 1307 1308 public boolean p2pServDiscCancelReq(String id) { 1309 return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id); 1310 } 1311 1312 /* Set the current mode of miracast operation. 1313 * 0 = disabled 1314 * 1 = operating as source 1315 * 2 = operating as sink 1316 */ 1317 public void setMiracastMode(int mode) { 1318 // Note: optional feature on the driver. It is ok for this to fail. 1319 doBooleanCommand("DRIVER MIRACAST " + mode); 1320 } 1321 1322 public boolean fetchAnqp(String bssid, String subtypes) { 1323 return doBooleanCommand("ANQP_GET " + bssid + " " + subtypes); 1324 } 1325 1326 /* 1327 * NFC-related calls 1328 */ 1329 public String getNfcWpsConfigurationToken(int netId) { 1330 return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId); 1331 } 1332 1333 public String getNfcHandoverRequest() { 1334 return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR"); 1335 } 1336 1337 public String getNfcHandoverSelect() { 1338 return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR"); 1339 } 1340 1341 public boolean initiatorReportNfcHandover(String selectMessage) { 1342 return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage); 1343 } 1344 1345 public boolean responderReportNfcHandover(String requestMessage) { 1346 return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00"); 1347 } 1348 1349 /* WIFI HAL support */ 1350 1351 private static final String TAG = "WifiNative-HAL"; 1352 private static long sWifiHalHandle = 0; /* used by JNI to save wifi_handle */ 1353 private static long[] sWifiIfaceHandles = null; /* used by JNI to save interface handles */ 1354 private static int sWlan0Index = -1; 1355 private static int sP2p0Index = -1; 1356 private static MonitorThread sThread; 1357 private static final int STOP_HAL_TIMEOUT_MS = 1000; 1358 1359 private static native boolean startHalNative(); 1360 private static native void stopHalNative(); 1361 private static native void waitForHalEventNative(); 1362 1363 private static class MonitorThread extends Thread { 1364 public void run() { 1365 Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle)); 1366 waitForHalEventNative(); 1367 } 1368 } 1369 1370 synchronized public static boolean startHal() { 1371 1372 String debugLog = "startHal stack: "; 1373 java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 1374 for (int i = 2; i < elements.length && i <= 7; i++ ) { 1375 debugLog = debugLog + " - " + elements[i].getMethodName(); 1376 } 1377 1378 mLocalLog.log(debugLog); 1379 1380 synchronized (mLock) { 1381 if (startHalNative() && (getInterfaces() != 0) && (sWlan0Index != -1)) { 1382 sThread = new MonitorThread(); 1383 sThread.start(); 1384 return true; 1385 } else { 1386 if (DBG) mLocalLog.log("Could not start hal"); 1387 Log.e(TAG, "Could not start hal"); 1388 return false; 1389 } 1390 } 1391 } 1392 1393 synchronized public static void stopHal() { 1394 synchronized (mLock) { 1395 if (isHalStarted()) { 1396 stopHalNative(); 1397 try { 1398 sThread.join(STOP_HAL_TIMEOUT_MS); 1399 Log.d(TAG, "HAL event thread stopped successfully"); 1400 } catch (InterruptedException e) { 1401 Log.e(TAG, "Could not stop HAL cleanly"); 1402 } 1403 sThread = null; 1404 sWifiHalHandle = 0; 1405 sWifiIfaceHandles = null; 1406 sWlan0Index = -1; 1407 sP2p0Index = -1; 1408 } 1409 } 1410 } 1411 1412 public static boolean isHalStarted() { 1413 return (sWifiHalHandle != 0); 1414 } 1415 private static native int getInterfacesNative(); 1416 1417 synchronized public static int getInterfaces() { 1418 synchronized (mLock) { 1419 if (isHalStarted()) { 1420 if (sWifiIfaceHandles == null) { 1421 int num = getInterfacesNative(); 1422 int wifi_num = 0; 1423 for (int i = 0; i < num; i++) { 1424 String name = getInterfaceNameNative(i); 1425 Log.i(TAG, "interface[" + i + "] = " + name); 1426 if (name.equals("wlan0")) { 1427 sWlan0Index = i; 1428 wifi_num++; 1429 } else if (name.equals("p2p0")) { 1430 sP2p0Index = i; 1431 wifi_num++; 1432 } 1433 } 1434 return wifi_num; 1435 } else { 1436 return sWifiIfaceHandles.length; 1437 } 1438 } else { 1439 return 0; 1440 } 1441 } 1442 } 1443 1444 private static native String getInterfaceNameNative(int index); 1445 synchronized public static String getInterfaceName(int index) { 1446 return getInterfaceNameNative(index); 1447 } 1448 1449 public static class ScanCapabilities { 1450 public int max_scan_cache_size; // in number of scan results?? 1451 public int max_scan_buckets; 1452 public int max_ap_cache_per_scan; 1453 public int max_rssi_sample_size; 1454 public int max_scan_reporting_threshold; // in number of scan results?? 1455 public int max_hotlist_bssids; 1456 public int max_significant_wifi_change_aps; 1457 } 1458 1459 synchronized public static boolean getScanCapabilities(ScanCapabilities capabilities) { 1460 synchronized (mLock) { 1461 return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities); 1462 } 1463 } 1464 1465 private static native boolean getScanCapabilitiesNative( 1466 int iface, ScanCapabilities capabilities); 1467 1468 private static native boolean startScanNative(int iface, int id, ScanSettings settings); 1469 private static native boolean stopScanNative(int iface, int id); 1470 private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush); 1471 private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface); 1472 private static native void setWifiLinkLayerStatsNative(int iface, int enable); 1473 1474 public static class ChannelSettings { 1475 int frequency; 1476 int dwell_time_ms; 1477 boolean passive; 1478 } 1479 1480 public static class BucketSettings { 1481 int bucket; 1482 int band; 1483 int period_ms; 1484 int report_events; 1485 int num_channels; 1486 ChannelSettings channels[]; 1487 } 1488 1489 public static class ScanSettings { 1490 int base_period_ms; 1491 int max_ap_per_scan; 1492 int report_threshold_percent; 1493 int report_threshold_num_scans; 1494 int num_buckets; 1495 BucketSettings buckets[]; 1496 } 1497 1498 public static interface ScanEventHandler { 1499 void onScanResultsAvailable(); 1500 void onFullScanResult(ScanResult fullScanResult); 1501 void onScanStatus(); 1502 void onScanPaused(WifiScanner.ScanData[] data); 1503 void onScanRestarted(); 1504 } 1505 1506 synchronized static void onScanResultsAvailable(int id) { 1507 if (sScanEventHandler != null) { 1508 sScanEventHandler.onScanResultsAvailable(); 1509 } 1510 } 1511 1512 /* scan status, keep these values in sync with gscan.h */ 1513 private static int WIFI_SCAN_BUFFER_FULL = 0; 1514 private static int WIFI_SCAN_COMPLETE = 1; 1515 1516 synchronized static void onScanStatus(int status) { 1517 if (status == WIFI_SCAN_BUFFER_FULL) { 1518 /* we have a separate event to take care of this */ 1519 } else if (status == WIFI_SCAN_COMPLETE) { 1520 if (sScanEventHandler != null) { 1521 sScanEventHandler.onScanStatus(); 1522 } 1523 } 1524 } 1525 1526 public static WifiSsid createWifiSsid (byte[] rawSsid) { 1527 String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid)); 1528 1529 if (ssidHexString == null) { 1530 return null; 1531 } 1532 1533 WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString); 1534 1535 return wifiSsid; 1536 } 1537 1538 public static String ssidConvert(byte[] rawSsid) { 1539 String ssid; 1540 1541 CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 1542 try { 1543 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid)); 1544 ssid = decoded.toString(); 1545 } catch (CharacterCodingException cce) { 1546 ssid = null; 1547 } 1548 1549 if (ssid == null) { 1550 ssid = new String(rawSsid, StandardCharsets.ISO_8859_1); 1551 } 1552 1553 return ssid; 1554 } 1555 1556 public static boolean setSsid(byte[] rawSsid, ScanResult result) { 1557 if (rawSsid == null || rawSsid.length == 0 || result == null) { 1558 return false; 1559 } 1560 1561 result.SSID = ssidConvert(rawSsid); 1562 result.wifiSsid = createWifiSsid(rawSsid); 1563 return true; 1564 } 1565 1566 static void populateScanResult(ScanResult result, byte bytes[], String dbg) { 1567 int num = 0; 1568 if (bytes == null) return; 1569 if (dbg == null) dbg = ""; 1570 for (int i = 0; i < bytes.length - 1; ) { 1571 int type = bytes[i] & 0xFF; 1572 int len = bytes[i + 1] & 0xFF; 1573 if (i + len + 2 > bytes.length) { 1574 Log.w(TAG, dbg + "bad length " + len + " of IE " + type + " from " + result.BSSID); 1575 Log.w(TAG, dbg + "ignoring the rest of the IEs"); 1576 break; 1577 } 1578 num++; 1579 if (DBG) Log.i(TAG, dbg + "bytes[" + i + "] = [" + type + ", " + len + "]" + ", " + 1580 "next = " + (i + len + 2)); 1581 i += len + 2; 1582 } 1583 1584 int secondChanelOffset = 0; 1585 byte channelMode = 0; 1586 int centerFreqIndex1 = 0; 1587 int centerFreqIndex2 = 0; 1588 1589 boolean is80211McRTTResponder = false; 1590 1591 ScanResult.InformationElement elements[] = new ScanResult.InformationElement[num]; 1592 for (int i = 0, index = 0; i < num; i++) { 1593 int type = bytes[index] & 0xFF; 1594 int len = bytes[index + 1] & 0xFF; 1595 if (DBG) Log.i(TAG, dbg + "index = " + index + ", type = " + type + ", len = " + len); 1596 ScanResult.InformationElement elem = new ScanResult.InformationElement(); 1597 elem.id = type; 1598 elem.bytes = new byte[len]; 1599 for (int j = 0; j < len; j++) { 1600 elem.bytes[j] = bytes[index + j + 2]; 1601 } 1602 elements[i] = elem; 1603 int inforStart = index + 2; 1604 index += (len + 2); 1605 1606 if(type == EID_HT_OPERATION) { 1607 secondChanelOffset = bytes[inforStart + 1] & 0x3; 1608 } else if(type == EID_VHT_OPERATION) { 1609 channelMode = bytes[inforStart]; 1610 centerFreqIndex1 = bytes[inforStart + 1] & 0xFF; 1611 centerFreqIndex2 = bytes[inforStart + 2] & 0xFF; 1612 } else if (type == EID_EXTENDED_CAPS) { 1613 int tempIndex = RTT_RESP_ENABLE_BIT / 8; 1614 byte offset = RTT_RESP_ENABLE_BIT % 8; 1615 1616 if(len < tempIndex + 1) { 1617 is80211McRTTResponder = false; 1618 } else { 1619 if ((bytes[inforStart + tempIndex] & ((byte)0x1 << offset)) != 0) { 1620 is80211McRTTResponder = true; 1621 } else { 1622 is80211McRTTResponder = false; 1623 } 1624 } 1625 } 1626 } 1627 1628 if (is80211McRTTResponder) { 1629 result.setFlag(ScanResult.FLAG_80211mc_RESPONDER); 1630 } else { 1631 result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER); 1632 } 1633 1634 //handle RTT related information 1635 if (channelMode != 0) { 1636 // 80 or 160 MHz 1637 result.channelWidth = channelMode + 1; 1638 1639 //convert channel index to frequency in MHz, channel 36 is 5180MHz 1640 result.centerFreq0 = (centerFreqIndex1 - 36) * 5 + 5180; 1641 1642 if(channelMode > 1) { //160MHz 1643 result.centerFreq1 = (centerFreqIndex2 - 36) * 5 + 5180; 1644 } else { 1645 result.centerFreq1 = 0; 1646 } 1647 } else { 1648 //20 or 40 MHz 1649 if (secondChanelOffset != 0) {//40MHz 1650 result.channelWidth = 1; 1651 if (secondChanelOffset == 1) { 1652 result.centerFreq0 = result.frequency + 20; 1653 } else if (secondChanelOffset == 3) { 1654 result.centerFreq0 = result.frequency - 20; 1655 } else { 1656 result.centerFreq0 = 0; 1657 Log.e(TAG, dbg + ": Error on secondChanelOffset"); 1658 } 1659 } else { 1660 result.centerFreq0 = 0; 1661 result.centerFreq1 = 0; 1662 } 1663 result.centerFreq1 = 0; 1664 } 1665 if(DBG) { 1666 Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth + 1667 " PrimaryFreq: " + result.frequency +" mCenterfreq0: " + result.centerFreq0 + 1668 " mCenterfreq1: " + result.centerFreq1 + (is80211McRTTResponder ? 1669 "Support RTT reponder: " : "Do not support RTT responder")); 1670 } 1671 1672 result.informationElements = elements; 1673 } 1674 1675 synchronized static void onFullScanResult(int id, ScanResult result, byte bytes[]) { 1676 if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID + ", " + 1677 "num = " + bytes.length); 1678 1679 if (sScanEventHandler == null) { 1680 return; 1681 } 1682 populateScanResult(result, bytes, " onFullScanResult "); 1683 1684 sScanEventHandler.onFullScanResult(result); 1685 } 1686 1687 private static int sScanCmdId = 0; 1688 private static ScanEventHandler sScanEventHandler; 1689 private static ScanSettings sScanSettings; 1690 1691 synchronized public static boolean startScan( 1692 ScanSettings settings, ScanEventHandler eventHandler) { 1693 synchronized (mLock) { 1694 if (isHalStarted()) { 1695 1696 if (sScanCmdId != 0) { 1697 stopScan(); 1698 } else if (sScanSettings != null || sScanEventHandler != null) { 1699 /* current scan is paused; no need to stop it */ 1700 } 1701 1702 sScanCmdId = getNewCmdIdLocked(); 1703 1704 sScanSettings = settings; 1705 sScanEventHandler = eventHandler; 1706 1707 if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) { 1708 sScanEventHandler = null; 1709 sScanSettings = null; 1710 sScanCmdId = 0; 1711 return false; 1712 } 1713 1714 return true; 1715 } else { 1716 return false; 1717 } 1718 } 1719 } 1720 1721 synchronized public static void stopScan() { 1722 synchronized (mLock) { 1723 if (isHalStarted()) { 1724 if (sScanCmdId != 0) { 1725 stopScanNative(sWlan0Index, sScanCmdId); 1726 } 1727 sScanSettings = null; 1728 sScanEventHandler = null; 1729 sScanCmdId = 0; 1730 } 1731 } 1732 } 1733 1734 synchronized public static void pauseScan() { 1735 synchronized (mLock) { 1736 if (isHalStarted()) { 1737 if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) { 1738 Log.d(TAG, "Pausing scan"); 1739 WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true); 1740 stopScanNative(sWlan0Index, sScanCmdId); 1741 sScanCmdId = 0; 1742 sScanEventHandler.onScanPaused(scanData); 1743 } 1744 } 1745 } 1746 } 1747 1748 synchronized public static void restartScan() { 1749 synchronized (mLock) { 1750 if (isHalStarted()) { 1751 if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) { 1752 Log.d(TAG, "Restarting scan"); 1753 ScanEventHandler handler = sScanEventHandler; 1754 ScanSettings settings = sScanSettings; 1755 if (startScan(sScanSettings, sScanEventHandler)) { 1756 sScanEventHandler.onScanRestarted(); 1757 } else { 1758 /* we are still paused; don't change state */ 1759 sScanEventHandler = handler; 1760 sScanSettings = settings; 1761 } 1762 } 1763 } 1764 } 1765 } 1766 1767 synchronized public static WifiScanner.ScanData[] getScanResults(boolean flush) { 1768 synchronized (mLock) { 1769 WifiScanner.ScanData[] sd = null; 1770 if (isHalStarted()) { 1771 sd = getScanResultsNative(sWlan0Index, flush); 1772 } 1773 1774 if (sd != null) { 1775 return sd; 1776 } else { 1777 return new WifiScanner.ScanData[0]; 1778 } 1779 } 1780 } 1781 1782 public static interface HotlistEventHandler { 1783 void onHotlistApFound (ScanResult[] result); 1784 void onHotlistApLost (ScanResult[] result); 1785 } 1786 1787 private static int sHotlistCmdId = 0; 1788 private static HotlistEventHandler sHotlistEventHandler; 1789 1790 private native static boolean setHotlistNative(int iface, int id, 1791 WifiScanner.HotlistSettings settings); 1792 private native static boolean resetHotlistNative(int iface, int id); 1793 1794 synchronized public static boolean setHotlist(WifiScanner.HotlistSettings settings, 1795 HotlistEventHandler eventHandler) { 1796 synchronized (mLock) { 1797 if (isHalStarted()) { 1798 if (sHotlistCmdId != 0) { 1799 return false; 1800 } else { 1801 sHotlistCmdId = getNewCmdIdLocked(); 1802 } 1803 1804 sHotlistEventHandler = eventHandler; 1805 if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) { 1806 sHotlistEventHandler = null; 1807 return false; 1808 } 1809 1810 return true; 1811 } else { 1812 return false; 1813 } 1814 } 1815 } 1816 1817 synchronized public static void resetHotlist() { 1818 synchronized (mLock) { 1819 if (isHalStarted()) { 1820 if (sHotlistCmdId != 0) { 1821 resetHotlistNative(sWlan0Index, sHotlistCmdId); 1822 sHotlistCmdId = 0; 1823 sHotlistEventHandler = null; 1824 } 1825 } 1826 } 1827 } 1828 1829 synchronized public static void onHotlistApFound(int id, ScanResult[] results) { 1830 synchronized (mLock) { 1831 if (isHalStarted()) { 1832 if (sHotlistCmdId != 0) { 1833 sHotlistEventHandler.onHotlistApFound(results); 1834 } else { 1835 /* this can happen because of race conditions */ 1836 Log.d(TAG, "Ignoring hotlist AP found event"); 1837 } 1838 } 1839 } 1840 } 1841 1842 synchronized public static void onHotlistApLost(int id, ScanResult[] results) { 1843 synchronized (mLock) { 1844 if (isHalStarted()) { 1845 if (sHotlistCmdId != 0) { 1846 sHotlistEventHandler.onHotlistApLost(results); 1847 } else { 1848 /* this can happen because of race conditions */ 1849 Log.d(TAG, "Ignoring hotlist AP lost event"); 1850 } 1851 } 1852 } 1853 } 1854 1855 public static interface SignificantWifiChangeEventHandler { 1856 void onChangesFound(ScanResult[] result); 1857 } 1858 1859 private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler; 1860 private static int sSignificantWifiChangeCmdId; 1861 1862 private static native boolean trackSignificantWifiChangeNative( 1863 int iface, int id, WifiScanner.WifiChangeSettings settings); 1864 private static native boolean untrackSignificantWifiChangeNative(int iface, int id); 1865 1866 synchronized public static boolean trackSignificantWifiChange( 1867 WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) { 1868 synchronized (mLock) { 1869 if (isHalStarted()) { 1870 if (sSignificantWifiChangeCmdId != 0) { 1871 return false; 1872 } else { 1873 sSignificantWifiChangeCmdId = getNewCmdIdLocked(); 1874 } 1875 1876 sSignificantWifiChangeHandler = handler; 1877 if (trackSignificantWifiChangeNative(sWlan0Index, sScanCmdId, settings) == false) { 1878 sSignificantWifiChangeHandler = null; 1879 return false; 1880 } 1881 1882 return true; 1883 } else { 1884 return false; 1885 } 1886 1887 } 1888 } 1889 1890 synchronized static void untrackSignificantWifiChange() { 1891 synchronized (mLock) { 1892 if (isHalStarted()) { 1893 if (sSignificantWifiChangeCmdId != 0) { 1894 untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId); 1895 sSignificantWifiChangeCmdId = 0; 1896 sSignificantWifiChangeHandler = null; 1897 } 1898 } 1899 } 1900 } 1901 1902 synchronized static void onSignificantWifiChange(int id, ScanResult[] results) { 1903 synchronized (mLock) { 1904 if (sSignificantWifiChangeCmdId != 0) { 1905 sSignificantWifiChangeHandler.onChangesFound(results); 1906 } else { 1907 /* this can happen because of race conditions */ 1908 Log.d(TAG, "Ignoring significant wifi change"); 1909 } 1910 } 1911 } 1912 1913 synchronized public static WifiLinkLayerStats getWifiLinkLayerStats(String iface) { 1914 // TODO: use correct iface name to Index translation 1915 if (iface == null) return null; 1916 synchronized (mLock) { 1917 if (isHalStarted()) { 1918 return getWifiLinkLayerStatsNative(sWlan0Index); 1919 } else { 1920 return null; 1921 } 1922 } 1923 } 1924 1925 synchronized public static void setWifiLinkLayerStats(String iface, int enable) { 1926 if (iface == null) return; 1927 synchronized (mLock) { 1928 if (isHalStarted()) { 1929 setWifiLinkLayerStatsNative(sWlan0Index, enable); 1930 } 1931 } 1932 } 1933 1934 public static native int getSupportedFeatureSetNative(int iface); 1935 synchronized public static int getSupportedFeatureSet() { 1936 synchronized (mLock) { 1937 if (isHalStarted()) { 1938 return getSupportedFeatureSetNative(sWlan0Index); 1939 } else { 1940 Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started"); 1941 return 0; 1942 } 1943 } 1944 } 1945 1946 /* Rtt related commands/events */ 1947 public static interface RttEventHandler { 1948 void onRttResults(RttManager.RttResult[] result); 1949 } 1950 1951 private static RttEventHandler sRttEventHandler; 1952 private static int sRttCmdId; 1953 1954 synchronized private static void onRttResults(int id, RttManager.RttResult[] results) { 1955 if (id == sRttCmdId) { 1956 Log.d(TAG, "Received " + results.length + " rtt results"); 1957 sRttEventHandler.onRttResults(results); 1958 sRttCmdId = 0; 1959 } else { 1960 Log.d(TAG, "RTT Received event for unknown cmd = " + id + ", current id = " + sRttCmdId); 1961 } 1962 } 1963 1964 private static native boolean requestRangeNative( 1965 int iface, int id, RttManager.RttParams[] params); 1966 private static native boolean cancelRangeRequestNative( 1967 int iface, int id, RttManager.RttParams[] params); 1968 1969 synchronized public static boolean requestRtt( 1970 RttManager.RttParams[] params, RttEventHandler handler) { 1971 synchronized (mLock) { 1972 if (isHalStarted()) { 1973 if (sRttCmdId != 0) { 1974 Log.v("TAG", "Last one is still under measurement!"); 1975 return false; 1976 } else { 1977 sRttCmdId = getNewCmdIdLocked(); 1978 } 1979 sRttEventHandler = handler; 1980 Log.v(TAG, "native issue RTT request"); 1981 return requestRangeNative(sWlan0Index, sRttCmdId, params); 1982 } else { 1983 return false; 1984 } 1985 } 1986 } 1987 1988 synchronized public static boolean cancelRtt(RttManager.RttParams[] params) { 1989 synchronized(mLock) { 1990 if (isHalStarted()) { 1991 if (sRttCmdId == 0) { 1992 return false; 1993 } 1994 1995 sRttCmdId = 0; 1996 1997 if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) { 1998 sRttEventHandler = null; 1999 Log.v(TAG, "RTT cancel Request Successfully"); 2000 return true; 2001 } else { 2002 Log.e(TAG, "RTT cancel Request failed"); 2003 return false; 2004 } 2005 } else { 2006 return false; 2007 } 2008 } 2009 } 2010 2011 private static native boolean setScanningMacOuiNative(int iface, byte[] oui); 2012 2013 synchronized public static boolean setScanningMacOui(byte[] oui) { 2014 synchronized (mLock) { 2015 if (isHalStarted()) { 2016 return setScanningMacOuiNative(sWlan0Index, oui); 2017 } else { 2018 return false; 2019 } 2020 } 2021 } 2022 2023 private static native int[] getChannelsForBandNative( 2024 int iface, int band); 2025 2026 synchronized public static int [] getChannelsForBand(int band) { 2027 synchronized (mLock) { 2028 if (isHalStarted()) { 2029 return getChannelsForBandNative(sWlan0Index, band); 2030 } else { 2031 return null; 2032 } 2033 } 2034 } 2035 2036 private static native boolean isGetChannelsForBandSupportedNative(); 2037 synchronized public static boolean isGetChannelsForBandSupported(){ 2038 synchronized (mLock) { 2039 if (isHalStarted()) { 2040 return isGetChannelsForBandSupportedNative(); 2041 } else { 2042 return false; 2043 } 2044 } 2045 } 2046 2047 private static native boolean setDfsFlagNative(int iface, boolean dfsOn); 2048 synchronized public static boolean setDfsFlag(boolean dfsOn) { 2049 synchronized (mLock) { 2050 if (isHalStarted()) { 2051 return setDfsFlagNative(sWlan0Index, dfsOn); 2052 } else { 2053 return false; 2054 } 2055 } 2056 } 2057 2058 private static native boolean toggleInterfaceNative(int on); 2059 synchronized public static boolean toggleInterface(int on) { 2060 synchronized (mLock) { 2061 if (isHalStarted()) { 2062 return toggleInterfaceNative(0); 2063 } else { 2064 return false; 2065 } 2066 } 2067 } 2068 2069 private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface); 2070 synchronized public static RttManager.RttCapabilities getRttCapabilities() { 2071 synchronized (mLock) { 2072 if (isHalStarted()) { 2073 return getRttCapabilitiesNative(sWlan0Index); 2074 }else { 2075 return null; 2076 } 2077 } 2078 } 2079 2080 private static native boolean setCountryCodeHalNative(int iface, String CountryCode); 2081 synchronized public static boolean setCountryCodeHal( String CountryCode) { 2082 synchronized (mLock) { 2083 if (isHalStarted()) { 2084 return setCountryCodeHalNative(sWlan0Index, CountryCode); 2085 } else { 2086 return false; 2087 } 2088 } 2089 } 2090 2091 /* Rtt related commands/events */ 2092 public abstract class TdlsEventHandler { 2093 abstract public void onTdlsStatus(String macAddr, int status, int reason); 2094 } 2095 2096 private static TdlsEventHandler sTdlsEventHandler; 2097 2098 private static native boolean enableDisableTdlsNative(int iface, boolean enable, 2099 String macAddr); 2100 synchronized public static boolean enableDisableTdls(boolean enable, String macAdd, 2101 TdlsEventHandler tdlsCallBack) { 2102 synchronized (mLock) { 2103 sTdlsEventHandler = tdlsCallBack; 2104 return enableDisableTdlsNative(sWlan0Index, enable, macAdd); 2105 } 2106 } 2107 2108 // Once TDLS per mac and event feature is implemented, this class definition should be 2109 // moved to the right place, like WifiManager etc 2110 public static class TdlsStatus { 2111 int channel; 2112 int global_operating_class; 2113 int state; 2114 int reason; 2115 } 2116 private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr); 2117 synchronized public static TdlsStatus getTdlsStatus (String macAdd) { 2118 synchronized (mLock) { 2119 if (isHalStarted()) { 2120 return getTdlsStatusNative(sWlan0Index, macAdd); 2121 } else { 2122 return null; 2123 } 2124 } 2125 } 2126 2127 //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be 2128 // moved to the right place, like WifiStateMachine etc 2129 public static class TdlsCapabilities { 2130 /* Maximum TDLS session number can be supported by the Firmware and hardware */ 2131 int maxConcurrentTdlsSessionNumber; 2132 boolean isGlobalTdlsSupported; 2133 boolean isPerMacTdlsSupported; 2134 boolean isOffChannelTdlsSupported; 2135 } 2136 2137 2138 2139 private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface); 2140 synchronized public static TdlsCapabilities getTdlsCapabilities () { 2141 synchronized (mLock) { 2142 if (isHalStarted()) { 2143 return getTdlsCapabilitiesNative(sWlan0Index); 2144 } else { 2145 return null; 2146 } 2147 } 2148 } 2149 2150 synchronized private static boolean onTdlsStatus(String macAddr, int status, int reason) { 2151 if (sTdlsEventHandler == null) { 2152 return false; 2153 } else { 2154 sTdlsEventHandler.onTdlsStatus(macAddr, status, reason); 2155 return true; 2156 } 2157 } 2158 2159 //--------------------------------------------------------------------------------- 2160 2161 /* Wifi Logger commands/events */ 2162 2163 public static native boolean startLogging(int iface); 2164 2165 public static interface WifiLoggerEventHandler { 2166 void onRingBufferData(RingBufferStatus status, byte[] buffer); 2167 void onWifiAlert(int errorCode, byte[] buffer); 2168 } 2169 2170 private static WifiLoggerEventHandler sWifiLoggerEventHandler = null; 2171 2172 private static void onRingBufferData(RingBufferStatus status, byte[] buffer) { 2173 if (sWifiLoggerEventHandler != null) 2174 sWifiLoggerEventHandler.onRingBufferData(status, buffer); 2175 } 2176 2177 private static void onWifiAlert(byte[] buffer, int errorCode) { 2178 if (sWifiLoggerEventHandler != null) 2179 sWifiLoggerEventHandler.onWifiAlert(errorCode, buffer); 2180 } 2181 2182 private static int sLogCmdId = -1; 2183 private static native boolean setLoggingEventHandlerNative(int iface, int id); 2184 synchronized public static boolean setLoggingEventHandler(WifiLoggerEventHandler handler) { 2185 synchronized (mLock) { 2186 if (isHalStarted()) { 2187 int oldId = sLogCmdId; 2188 sLogCmdId = getNewCmdIdLocked(); 2189 if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) { 2190 sLogCmdId = oldId; 2191 return false; 2192 } 2193 sWifiLoggerEventHandler = handler; 2194 return true; 2195 } else { 2196 return false; 2197 } 2198 } 2199 } 2200 2201 private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel, 2202 int flags, int minIntervalSec ,int minDataSize, String ringName); 2203 synchronized public static boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval, 2204 int minDataSize, String ringName){ 2205 synchronized (mLock) { 2206 if (isHalStarted()) { 2207 return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval, 2208 minDataSize, ringName); 2209 } else { 2210 return false; 2211 } 2212 } 2213 } 2214 2215 private static native int getSupportedLoggerFeatureSetNative(int iface); 2216 synchronized public static int getSupportedLoggerFeatureSet() { 2217 synchronized (mLock) { 2218 if (isHalStarted()) { 2219 return getSupportedLoggerFeatureSetNative(sWlan0Index); 2220 } else { 2221 return 0; 2222 } 2223 } 2224 } 2225 2226 private static native boolean resetLogHandlerNative(int iface, int id); 2227 synchronized public static boolean resetLogHandler() { 2228 synchronized (mLock) { 2229 if (isHalStarted()) { 2230 if (sLogCmdId == -1) { 2231 Log.e(TAG,"Can not reset handler Before set any handler"); 2232 return false; 2233 } 2234 sWifiLoggerEventHandler = null; 2235 if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) { 2236 sLogCmdId = -1; 2237 return true; 2238 } else { 2239 return false; 2240 } 2241 } else { 2242 return false; 2243 } 2244 } 2245 } 2246 2247 private static native String getDriverVersionNative(int iface); 2248 synchronized public static String getDriverVersion() { 2249 synchronized (mLock) { 2250 if (isHalStarted()) { 2251 return getDriverVersionNative(sWlan0Index); 2252 } else { 2253 return ""; 2254 } 2255 } 2256 } 2257 2258 2259 private static native String getFirmwareVersionNative(int iface); 2260 synchronized public static String getFirmwareVersion() { 2261 synchronized (mLock) { 2262 if (isHalStarted()) { 2263 return getFirmwareVersionNative(sWlan0Index); 2264 } else { 2265 return ""; 2266 } 2267 } 2268 } 2269 2270 public static class RingBufferStatus{ 2271 String name; 2272 int flag; 2273 int ringBufferId; 2274 int ringBufferByteSize; 2275 int verboseLevel; 2276 int writtenBytes; 2277 int readBytes; 2278 int writtenRecords; 2279 2280 @Override 2281 public String toString() { 2282 return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId + 2283 " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel + 2284 " writtenBytes: " + writtenBytes + " readBytes: " + readBytes + 2285 " writtenRecords: " + writtenRecords; 2286 } 2287 } 2288 2289 private static native RingBufferStatus[] getRingBufferStatusNative(int iface); 2290 synchronized public static RingBufferStatus[] getRingBufferStatus() { 2291 synchronized (mLock) { 2292 if (isHalStarted()) { 2293 return getRingBufferStatusNative(sWlan0Index); 2294 } else { 2295 return null; 2296 } 2297 } 2298 } 2299 2300 private static native boolean getRingBufferDataNative(int iface, String ringName); 2301 synchronized public static boolean getRingBufferData(String ringName) { 2302 synchronized (mLock) { 2303 if (isHalStarted()) { 2304 return getRingBufferDataNative(sWlan0Index, ringName); 2305 } else { 2306 return false; 2307 } 2308 } 2309 } 2310 2311 static private byte[] mFwMemoryDump; 2312 private static void onWifiFwMemoryAvailable(byte[] buffer) { 2313 mFwMemoryDump = buffer; 2314 if (DBG) { 2315 Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " + 2316 (buffer == null ? 0 : buffer.length)); 2317 } 2318 } 2319 2320 private static native boolean getFwMemoryDumpNative(int iface); 2321 synchronized public static byte[] getFwMemoryDump() { 2322 synchronized (mLock) { 2323 if (isHalStarted()) { 2324 if(getFwMemoryDumpNative(sWlan0Index)) { 2325 byte[] fwMemoryDump = mFwMemoryDump; 2326 mFwMemoryDump = null; 2327 return fwMemoryDump; 2328 } else { 2329 return null; 2330 } 2331 } 2332 2333 return null; 2334 } 2335 } 2336 2337 //--------------------------------------------------------------------------------- 2338 /* Configure ePNO */ 2339 2340 public class WifiPnoNetwork { 2341 String SSID; 2342 int rssi_threshold; 2343 int flags; 2344 int auth; 2345 String configKey; // kept for reference 2346 2347 WifiPnoNetwork(WifiConfiguration config, int threshold) { 2348 if (config.SSID == null) { 2349 this.SSID = ""; 2350 this.flags = 1; 2351 } else { 2352 this.SSID = config.SSID; 2353 } 2354 this.rssi_threshold = threshold; 2355 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 2356 auth |= 2; 2357 } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) || 2358 config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) { 2359 auth |= 4; 2360 } else if (config.wepKeys[0] != null) { 2361 auth |= 1; 2362 } else { 2363 auth |= 1; 2364 } 2365// auth = 0; 2366 flags |= 6; //A and G 2367 configKey = config.configKey(); 2368 } 2369 2370 @Override 2371 public String toString() { 2372 StringBuilder sbuf = new StringBuilder(); 2373 sbuf.append(this.SSID); 2374 sbuf.append(" flags=").append(this.flags); 2375 sbuf.append(" rssi=").append(this.rssi_threshold); 2376 sbuf.append(" auth=").append(this.auth); 2377 return sbuf.toString(); 2378 } 2379 } 2380 2381 public static interface WifiPnoEventHandler { 2382 void onPnoNetworkFound(ScanResult results[]); 2383 } 2384 2385 private static WifiPnoEventHandler sWifiPnoEventHandler; 2386 2387 private static int sPnoCmdId = 0; 2388 2389 private native static boolean setPnoListNative(int iface, int id, WifiPnoNetwork list[]); 2390 2391 synchronized public static boolean setPnoList(WifiPnoNetwork list[], 2392 WifiPnoEventHandler eventHandler) { 2393 Log.e(TAG, "setPnoList cmd " + sPnoCmdId); 2394 2395 synchronized (mLock) { 2396 if (isHalStarted()) { 2397 2398 sPnoCmdId = getNewCmdIdLocked(); 2399 2400 sWifiPnoEventHandler = eventHandler; 2401 if (setPnoListNative(sWlan0Index, sPnoCmdId, list)) { 2402 return true; 2403 } 2404 } 2405 2406 sWifiPnoEventHandler = null; 2407 return false; 2408 } 2409 } 2410 2411 synchronized public static void onPnoNetworkFound(int id, ScanResult[] results) { 2412 2413 if (results == null) { 2414 Log.e(TAG, "onPnoNetworkFound null results"); 2415 return; 2416 2417 } 2418 Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length); 2419 2420 //Log.e(TAG, "onPnoNetworkFound length " + results.length); 2421 //return; 2422 for (int i=0; i<results.length; i++) { 2423 Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID 2424 + " " + results[i].level + " " + results[i].frequency); 2425 2426 populateScanResult(results[i], results[i].bytes, "onPnoNetworkFound "); 2427 results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID); 2428 } 2429 synchronized (mLock) { 2430 if (sPnoCmdId != 0 && sWifiPnoEventHandler != null) { 2431 sWifiPnoEventHandler.onPnoNetworkFound(results); 2432 } else { 2433 /* this can happen because of race conditions */ 2434 Log.d(TAG, "Ignoring Pno Network found event"); 2435 } 2436 } 2437 } 2438 2439 public class WifiLazyRoamParams { 2440 int A_band_boost_threshold; 2441 int A_band_penalty_threshold; 2442 int A_band_boost_factor; 2443 int A_band_penalty_factor; 2444 int A_band_max_boost; 2445 int lazy_roam_hysteresis; 2446 int alert_roam_rssi_trigger; 2447 2448 WifiLazyRoamParams() { 2449 } 2450 2451 @Override 2452 public String toString() { 2453 StringBuilder sbuf = new StringBuilder(); 2454 sbuf.append(" A_band_boost_threshold=").append(this.A_band_boost_threshold); 2455 sbuf.append(" A_band_penalty_threshold=").append(this.A_band_penalty_threshold); 2456 sbuf.append(" A_band_boost_factor=").append(this.A_band_boost_factor); 2457 sbuf.append(" A_band_penalty_factor=").append(this.A_band_penalty_factor); 2458 sbuf.append(" A_band_max_boost=").append(this.A_band_max_boost); 2459 sbuf.append(" lazy_roam_hysteresis=").append(this.lazy_roam_hysteresis); 2460 sbuf.append(" alert_roam_rssi_trigger=").append(this.alert_roam_rssi_trigger); 2461 return sbuf.toString(); 2462 } 2463 } 2464 2465 private native static boolean setLazyRoamNative(int iface, int id, 2466 boolean enabled, WifiLazyRoamParams param); 2467 2468 synchronized public static boolean setLazyRoam(boolean enabled, WifiLazyRoamParams params) { 2469 synchronized (mLock) { 2470 if (isHalStarted()) { 2471 sPnoCmdId = getNewCmdIdLocked(); 2472 return setLazyRoamNative(sWlan0Index, sPnoCmdId, enabled, params); 2473 } else { 2474 return false; 2475 } 2476 } 2477 } 2478 2479 private native static boolean setBssidBlacklistNative(int iface, int id, 2480 String list[]); 2481 2482 synchronized public static boolean setBssidBlacklist(String list[]) { 2483 int size = 0; 2484 if (list != null) { 2485 size = list.length; 2486 } 2487 Log.e(TAG, "setBssidBlacklist cmd " + sPnoCmdId + " size " + size); 2488 2489 synchronized (mLock) { 2490 if (isHalStarted()) { 2491 sPnoCmdId = getNewCmdIdLocked(); 2492 return setBssidBlacklistNative(sWlan0Index, sPnoCmdId, list); 2493 } else { 2494 return false; 2495 } 2496 } 2497 } 2498 2499 private native static boolean setSsidWhitelistNative(int iface, int id, String list[]); 2500 2501 synchronized public static boolean setSsidWhitelist(String list[]) { 2502 int size = 0; 2503 if (list != null) { 2504 size = list.length; 2505 } 2506 Log.e(TAG, "setSsidWhitelist cmd " + sPnoCmdId + " size " + size); 2507 2508 synchronized (mLock) { 2509 if (isHalStarted()) { 2510 sPnoCmdId = getNewCmdIdLocked(); 2511 2512 return setSsidWhitelistNative(sWlan0Index, sPnoCmdId, list); 2513 } else { 2514 return false; 2515 } 2516 } 2517 } 2518 2519 private native static int startSendingOffloadedPacketNative(int iface, int idx, 2520 byte[] srcMac, byte[] dstMac, byte[] pktData, int period); 2521 2522 synchronized public int 2523 startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) { 2524 Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period); 2525 2526 String[] macAddrStr = getMacAddress().split(":"); 2527 byte[] srcMac = new byte[6]; 2528 for(int i = 0; i < 6; i++) { 2529 Integer hexVal = Integer.parseInt(macAddrStr[i], 16); 2530 srcMac[i] = hexVal.byteValue(); 2531 } 2532 synchronized (mLock) { 2533 if (isHalStarted()) { 2534 return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac, 2535 keepAlivePacket.dstMac, keepAlivePacket.data, period); 2536 } else { 2537 return -1; 2538 } 2539 } 2540 } 2541 2542 private native static int stopSendingOffloadedPacketNative(int iface, int idx); 2543 2544 synchronized public int 2545 stopSendingOffloadedPacket(int slot) { 2546 Log.d(TAG, "stopSendingOffloadedPacket " + slot); 2547 synchronized (mLock) { 2548 if (isHalStarted()) { 2549 return stopSendingOffloadedPacketNative(sWlan0Index, slot); 2550 } else { 2551 return -1; 2552 } 2553 } 2554 } 2555 2556 public static interface WifiRssiEventHandler { 2557 void onRssiThresholdBreached(byte curRssi); 2558 } 2559 2560 private static WifiRssiEventHandler sWifiRssiEventHandler; 2561 2562 synchronized static void onRssiThresholdBreached(int id, byte curRssi) { 2563 sWifiRssiEventHandler.onRssiThresholdBreached(curRssi); 2564 } 2565 2566 private native static int startRssiMonitoringNative(int iface, int id, 2567 byte maxRssi, byte minRssi); 2568 2569 private static int sRssiMonitorCmdId = 0; 2570 2571 synchronized public int startRssiMonitoring(byte maxRssi, byte minRssi, 2572 WifiRssiEventHandler rssiEventHandler) { 2573 Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi); 2574 sWifiRssiEventHandler = rssiEventHandler; 2575 synchronized (mLock) { 2576 if (isHalStarted()) { 2577 if (sRssiMonitorCmdId != 0) { 2578 stopRssiMonitoring(); 2579 } 2580 2581 sRssiMonitorCmdId = getNewCmdIdLocked(); 2582 Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId); 2583 int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId, 2584 maxRssi, minRssi); 2585 if (ret != 0) { // if not success 2586 sRssiMonitorCmdId = 0; 2587 } 2588 return ret; 2589 } else { 2590 return -1; 2591 } 2592 } 2593 } 2594 2595 private native static int stopRssiMonitoringNative(int iface, int idx); 2596 2597 synchronized public int stopRssiMonitoring() { 2598 Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId); 2599 synchronized (mLock) { 2600 if (isHalStarted()) { 2601 int ret = 0; 2602 if (sRssiMonitorCmdId != 0) { 2603 ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId); 2604 } 2605 sRssiMonitorCmdId = 0; 2606 return ret; 2607 } else { 2608 return -1; 2609 } 2610 } 2611 } 2612} 2613