WifiNative.java revision 7ef73dd1b6e43c72b3841723504cd86dc402a134
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.WpsInfo; 21import android.net.wifi.p2p.WifiP2pConfig; 22import android.net.wifi.p2p.WifiP2pGroup; 23import android.text.TextUtils; 24import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; 25import android.util.LocalLog; 26import android.util.Log; 27 28import java.util.ArrayList; 29import java.util.List; 30import java.util.Locale; 31 32/** 33 * Native calls for bring up/shut down of the supplicant daemon and for 34 * sending requests to the supplicant daemon 35 * 36 * waitForEvent() is called on the monitor thread for events. All other methods 37 * must be serialized from the framework. 38 * 39 * {@hide} 40 */ 41public class WifiNative { 42 43 private static final boolean DBG = false; 44 private final String mTAG; 45 private static final int DEFAULT_GROUP_OWNER_INTENT = 6; 46 47 static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 48 static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 49 static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 50 51 static final int SCAN_WITHOUT_CONNECTION_SETUP = 1; 52 static final int SCAN_WITH_CONNECTION_SETUP = 2; 53 54 // Hold this lock before calling supplicant - it is required to 55 // mutually exclude access from Wifi and P2p state machines 56 static final Object mLock = new Object(); 57 58 public final String mInterfaceName; 59 public final String mInterfacePrefix; 60 61 private boolean mSuspendOptEnabled = false; 62 63 /* Register native functions */ 64 65 static { 66 /* Native functions are defined in libwifi-service.so */ 67 System.loadLibrary("wifi-service"); 68 registerNatives(); 69 } 70 71 private static native int registerNatives(); 72 73 public native static boolean loadDriver(); 74 75 public native static boolean isDriverLoaded(); 76 77 public native static boolean unloadDriver(); 78 79 public native static boolean startSupplicant(boolean p2pSupported); 80 81 /* Sends a kill signal to supplicant. To be used when we have lost connection 82 or when the supplicant is hung */ 83 public native static boolean killSupplicant(boolean p2pSupported); 84 85 private native boolean connectToSupplicantNative(); 86 87 private native void closeSupplicantConnectionNative(); 88 89 public native static boolean startHalNative(); 90 91 public native static void stopHalNative(); 92 93 public native static void waitForHalEventNative(); 94 95 /** 96 * Wait for the supplicant to send an event, returning the event string. 97 * @return the event string sent by the supplicant. 98 */ 99 private native String waitForEventNative(); 100 101 private native boolean doBooleanCommandNative(String command); 102 103 private native int doIntCommandNative(String command); 104 105 private native String doStringCommandNative(String command); 106 107 public WifiNative(String interfaceName) { 108 mInterfaceName = interfaceName; 109 mTAG = "WifiNative-" + interfaceName; 110 if (!interfaceName.equals("p2p0")) { 111 mInterfacePrefix = "IFNAME=" + interfaceName + " "; 112 } else { 113 // commands for p2p0 interface don't need prefix 114 mInterfacePrefix = ""; 115 } 116 } 117 118 private static final LocalLog mLocalLog = new LocalLog(1024); 119 120 // hold mLock before accessing mCmdIdLock 121 private int mCmdId; 122 123 public LocalLog getLocalLog() { 124 return mLocalLog; 125 } 126 127 private int getNewCmdIdLocked() { 128 return mCmdId++; 129 } 130 131 private void localLog(String s) { 132 if (mLocalLog != null) 133 mLocalLog.log(mInterfaceName + ": " + s); 134 } 135 136 public boolean connectToSupplicant() { 137 // No synchronization necessary .. it is implemented in WifiMonitor 138 localLog(mInterfacePrefix + "connectToSupplicant"); 139 return connectToSupplicantNative(); 140 } 141 142 public void closeSupplicantConnection() { 143 localLog(mInterfacePrefix + "closeSupplicantConnection"); 144 closeSupplicantConnectionNative(); 145 } 146 147 public String waitForEvent() { 148 // No synchronization necessary .. it is implemented in WifiMonitor 149 return waitForEventNative(); 150 } 151 152 private boolean doBooleanCommand(String command) { 153 if (DBG) Log.d(mTAG, "doBoolean: " + command); 154 synchronized (mLock) { 155 int cmdId = getNewCmdIdLocked(); 156 localLog(cmdId + "->" + mInterfacePrefix + command); 157 boolean result = doBooleanCommandNative(mInterfacePrefix + command); 158 localLog(cmdId + "<-" + result); 159 if (DBG) Log.d(mTAG, " returned " + result); 160 return result; 161 } 162 } 163 164 private int doIntCommand(String command) { 165 if (DBG) Log.d(mTAG, "doInt: " + command); 166 synchronized (mLock) { 167 int cmdId = getNewCmdIdLocked(); 168 localLog(cmdId + "->" + mInterfacePrefix + command); 169 int result = doIntCommandNative(mInterfacePrefix + command); 170 localLog(cmdId + "<-" + result); 171 if (DBG) Log.d(mTAG, " returned " + result); 172 return result; 173 } 174 } 175 176 private String doStringCommand(String command) { 177 if (DBG) Log.d(mTAG, "doString: " + command); 178 synchronized (mLock) { 179 int cmdId = getNewCmdIdLocked(); 180 localLog(cmdId + "->" + mInterfacePrefix + command); 181 String result = doStringCommandNative(mInterfacePrefix + command); 182 localLog(cmdId + "<-" + result); 183 if (DBG) Log.d(mTAG, " returned " + result); 184 return result; 185 } 186 } 187 188 private String doStringCommandWithoutLogging(String command) { 189 if (DBG) Log.d(mTAG, "doString: " + command); 190 synchronized (mLock) { 191 return doStringCommandNative(mInterfacePrefix + command); 192 } 193 } 194 195 public boolean ping() { 196 String pong = doStringCommand("PING"); 197 return (pong != null && pong.equals("PONG")); 198 } 199 200 public boolean scan(int type) { 201 if (type == SCAN_WITHOUT_CONNECTION_SETUP) { 202 return doBooleanCommand("SCAN TYPE=ONLY"); 203 } else if (type == SCAN_WITH_CONNECTION_SETUP) { 204 return doBooleanCommand("SCAN"); 205 } else { 206 throw new IllegalArgumentException("Invalid scan type"); 207 } 208 } 209 210 /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. 211 * 212 * Note that underneath we use a harsh-sounding "terminate" supplicant command 213 * for a graceful stop and a mild-sounding "stop" interface 214 * to kill the process 215 */ 216 public boolean stopSupplicant() { 217 return doBooleanCommand("TERMINATE"); 218 } 219 220 public String listNetworks() { 221 return doStringCommand("LIST_NETWORKS"); 222 } 223 224 public int addNetwork() { 225 return doIntCommand("ADD_NETWORK"); 226 } 227 228 public boolean setNetworkVariable(int netId, String name, String value) { 229 if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false; 230 return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value); 231 } 232 233 public String getNetworkVariable(int netId, String name) { 234 if (TextUtils.isEmpty(name)) return null; 235 236 // GET_NETWORK will likely flood the logs ... 237 return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name); 238 } 239 240 public boolean removeNetwork(int netId) { 241 return doBooleanCommand("REMOVE_NETWORK " + netId); 242 } 243 244 public boolean enableNetwork(int netId, boolean disableOthers) { 245 if (disableOthers) { 246 return doBooleanCommand("SELECT_NETWORK " + netId); 247 } else { 248 return doBooleanCommand("ENABLE_NETWORK " + netId); 249 } 250 } 251 252 public boolean disableNetwork(int netId) { 253 return doBooleanCommand("DISABLE_NETWORK " + netId); 254 } 255 256 public boolean reconnect() { 257 return doBooleanCommand("RECONNECT"); 258 } 259 260 public boolean reassociate() { 261 return doBooleanCommand("REASSOCIATE"); 262 } 263 264 public boolean disconnect() { 265 return doBooleanCommand("DISCONNECT"); 266 } 267 268 public String status() { 269 return doStringCommand("STATUS"); 270 } 271 272 public String getMacAddress() { 273 //Macaddr = XX.XX.XX.XX.XX.XX 274 String ret = doStringCommand("DRIVER MACADDR"); 275 if (!TextUtils.isEmpty(ret)) { 276 String[] tokens = ret.split(" = "); 277 if (tokens.length == 2) return tokens[1]; 278 } 279 return null; 280 } 281 282 /** 283 * Format of results: 284 * ================= 285 * id=1 286 * bssid=68:7f:74:d7:1b:6e 287 * freq=2412 288 * level=-43 289 * tsf=1344621975160944 290 * age=2623 291 * flags=[WPA2-PSK-CCMP][WPS][ESS] 292 * ssid=zubyb 293 * ==== 294 * 295 * RANGE=ALL gets all scan results 296 * RANGE=ID- gets results from ID 297 * MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details 298 */ 299 public String scanResults(int sid) { 300 return doStringCommandWithoutLogging("BSS RANGE=" + sid + "- MASK=0x21987"); 301 } 302 303 /** 304 * Format of command 305 * DRIVER WLS_BATCHING SET SCANFREQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s 306 * where x is an ascii representation of an integer number of seconds between scans 307 * r is an ascii representation of an integer number of scans per batch 308 * y is an ascii representation of an integer number of the max AP to remember per scan 309 * z, w, t represent a 1..n size list of channel numbers and/or 'A', 'B' values 310 * indicating entire ranges of channels 311 * s is an ascii representation of an integer number of highest-strength AP 312 * for which we'd like approximate distance reported 313 * 314 * The return value is an ascii integer representing a guess of the number of scans 315 * the firmware can remember before it runs out of buffer space or -1 on error 316 */ 317 public String setBatchedScanSettings(BatchedScanSettings settings) { 318 if (settings == null) { 319 return doStringCommand("DRIVER WLS_BATCHING STOP"); 320 } 321 String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec; 322 cmd += " MSCAN=" + settings.maxScansPerBatch; 323 if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) { 324 cmd += " BESTN=" + settings.maxApPerScan; 325 } 326 if (settings.channelSet != null && !settings.channelSet.isEmpty()) { 327 cmd += " CHANNEL=<"; 328 int i = 0; 329 for (String channel : settings.channelSet) { 330 cmd += (i > 0 ? "," : "") + channel; 331 ++i; 332 } 333 cmd += ">"; 334 } 335 if (settings.maxApForDistance != BatchedScanSettings.UNSPECIFIED) { 336 cmd += " RTT=" + settings.maxApForDistance; 337 } 338 return doStringCommand(cmd); 339 } 340 341 public String getBatchedScanResults() { 342 return doStringCommand("DRIVER WLS_BATCHING GET"); 343 } 344 345 public boolean startDriver() { 346 return doBooleanCommand("DRIVER START"); 347 } 348 349 public boolean stopDriver() { 350 return doBooleanCommand("DRIVER STOP"); 351 } 352 353 354 /** 355 * Start filtering out Multicast V4 packets 356 * @return {@code true} if the operation succeeded, {@code false} otherwise 357 * 358 * Multicast filtering rules work as follows: 359 * 360 * The driver can filter multicast (v4 and/or v6) and broadcast packets when in 361 * a power optimized mode (typically when screen goes off). 362 * 363 * In order to prevent the driver from filtering the multicast/broadcast packets, we have to 364 * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective 365 * 366 * DRIVER RXFILTER-ADD Num 367 * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 368 * 369 * and DRIVER RXFILTER-START 370 * In order to stop the usage of these rules, we do 371 * 372 * DRIVER RXFILTER-STOP 373 * DRIVER RXFILTER-REMOVE Num 374 * where Num is as described for RXFILTER-ADD 375 * 376 * The SETSUSPENDOPT driver command overrides the filtering rules 377 */ 378 public boolean startFilteringMulticastV4Packets() { 379 return doBooleanCommand("DRIVER RXFILTER-STOP") 380 && doBooleanCommand("DRIVER RXFILTER-REMOVE 2") 381 && doBooleanCommand("DRIVER RXFILTER-START"); 382 } 383 384 /** 385 * Stop filtering out Multicast V4 packets. 386 * @return {@code true} if the operation succeeded, {@code false} otherwise 387 */ 388 public boolean stopFilteringMulticastV4Packets() { 389 return doBooleanCommand("DRIVER RXFILTER-STOP") 390 && doBooleanCommand("DRIVER RXFILTER-ADD 2") 391 && doBooleanCommand("DRIVER RXFILTER-START"); 392 } 393 394 /** 395 * Start filtering out Multicast V6 packets 396 * @return {@code true} if the operation succeeded, {@code false} otherwise 397 */ 398 public boolean startFilteringMulticastV6Packets() { 399 return doBooleanCommand("DRIVER RXFILTER-STOP") 400 && doBooleanCommand("DRIVER RXFILTER-REMOVE 3") 401 && doBooleanCommand("DRIVER RXFILTER-START"); 402 } 403 404 /** 405 * Stop filtering out Multicast V6 packets. 406 * @return {@code true} if the operation succeeded, {@code false} otherwise 407 */ 408 public boolean stopFilteringMulticastV6Packets() { 409 return doBooleanCommand("DRIVER RXFILTER-STOP") 410 && doBooleanCommand("DRIVER RXFILTER-ADD 3") 411 && doBooleanCommand("DRIVER RXFILTER-START"); 412 } 413 414 public int getBand() { 415 String ret = doStringCommand("DRIVER GETBAND"); 416 if (!TextUtils.isEmpty(ret)) { 417 //reply is "BAND X" where X is the band 418 String[] tokens = ret.split(" "); 419 try { 420 if (tokens.length == 2) return Integer.parseInt(tokens[1]); 421 } catch (NumberFormatException e) { 422 return -1; 423 } 424 } 425 return -1; 426 } 427 428 public boolean setBand(int band) { 429 return doBooleanCommand("DRIVER SETBAND " + band); 430 } 431 432 /** 433 * Sets the bluetooth coexistence mode. 434 * 435 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 436 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 437 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 438 * @return Whether the mode was successfully set. 439 */ 440 public boolean setBluetoothCoexistenceMode(int mode) { 441 return doBooleanCommand("DRIVER BTCOEXMODE " + mode); 442 } 443 444 /** 445 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 446 * some of the low-level scan parameters used by the driver are changed to 447 * reduce interference with A2DP streaming. 448 * 449 * @param isSet whether to enable or disable this mode 450 * @return {@code true} if the command succeeded, {@code false} otherwise. 451 */ 452 public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) { 453 if (setCoexScanMode) { 454 return doBooleanCommand("DRIVER BTCOEXSCAN-START"); 455 } else { 456 return doBooleanCommand("DRIVER BTCOEXSCAN-STOP"); 457 } 458 } 459 460 public boolean saveConfig() { 461 return doBooleanCommand("SAVE_CONFIG"); 462 } 463 464 public boolean addToBlacklist(String bssid) { 465 if (TextUtils.isEmpty(bssid)) return false; 466 return doBooleanCommand("BLACKLIST " + bssid); 467 } 468 469 public boolean clearBlacklist() { 470 return doBooleanCommand("BLACKLIST clear"); 471 } 472 473 public boolean setSuspendOptimizations(boolean enabled) { 474 if (mSuspendOptEnabled == enabled) return true; 475 mSuspendOptEnabled = enabled; 476 if (enabled) { 477 return doBooleanCommand("DRIVER SETSUSPENDMODE 1"); 478 } else { 479 return doBooleanCommand("DRIVER SETSUSPENDMODE 0"); 480 } 481 } 482 483 public boolean setCountryCode(String countryCode) { 484 return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT)); 485 } 486 487 public void enableBackgroundScan(boolean enable) { 488 if (enable) { 489 doBooleanCommand("SET pno 1"); 490 } else { 491 doBooleanCommand("SET pno 0"); 492 } 493 } 494 495 public void setScanInterval(int scanInterval) { 496 doBooleanCommand("SCAN_INTERVAL " + scanInterval); 497 } 498 499 public void startTdls(String macAddr, boolean enable) { 500 if (enable) { 501 doBooleanCommand("TDLS_DISCOVER " + macAddr); 502 doBooleanCommand("TDLS_SETUP " + macAddr); 503 } else { 504 doBooleanCommand("TDLS_TEARDOWN " + macAddr); 505 } 506 } 507 508 /** Example output: 509 * RSSI=-65 510 * LINKSPEED=48 511 * NOISE=9999 512 * FREQUENCY=0 513 */ 514 public String signalPoll() { 515 return doStringCommandWithoutLogging("SIGNAL_POLL"); 516 } 517 518 /** Example outout: 519 * TXGOOD=396 520 * TXBAD=1 521 */ 522 public String pktcntPoll() { 523 return doStringCommand("PKTCNT_POLL"); 524 } 525 526 public void bssFlush() { 527 doBooleanCommand("BSS_FLUSH 0"); 528 } 529 530 public boolean startWpsPbc(String bssid) { 531 if (TextUtils.isEmpty(bssid)) { 532 return doBooleanCommand("WPS_PBC"); 533 } else { 534 return doBooleanCommand("WPS_PBC " + bssid); 535 } 536 } 537 538 public boolean startWpsPbc(String iface, String bssid) { 539 synchronized (mLock) { 540 if (TextUtils.isEmpty(bssid)) { 541 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC"); 542 } else { 543 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid); 544 } 545 } 546 } 547 548 public boolean startWpsPinKeypad(String pin) { 549 if (TextUtils.isEmpty(pin)) return false; 550 return doBooleanCommand("WPS_PIN any " + pin); 551 } 552 553 public boolean startWpsPinKeypad(String iface, String pin) { 554 if (TextUtils.isEmpty(pin)) return false; 555 synchronized (mLock) { 556 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin); 557 } 558 } 559 560 561 public String startWpsPinDisplay(String bssid) { 562 if (TextUtils.isEmpty(bssid)) { 563 return doStringCommand("WPS_PIN any"); 564 } else { 565 return doStringCommand("WPS_PIN " + bssid); 566 } 567 } 568 569 public String startWpsPinDisplay(String iface, String bssid) { 570 synchronized (mLock) { 571 if (TextUtils.isEmpty(bssid)) { 572 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any"); 573 } else { 574 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid); 575 } 576 } 577 } 578 579 /* Configures an access point connection */ 580 public boolean startWpsRegistrar(String bssid, String pin) { 581 if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false; 582 return doBooleanCommand("WPS_REG " + bssid + " " + pin); 583 } 584 585 public boolean cancelWps() { 586 return doBooleanCommand("WPS_CANCEL"); 587 } 588 589 public boolean setPersistentReconnect(boolean enabled) { 590 int value = (enabled == true) ? 1 : 0; 591 return doBooleanCommand("SET persistent_reconnect " + value); 592 } 593 594 public boolean setDeviceName(String name) { 595 return doBooleanCommand("SET device_name " + name); 596 } 597 598 public boolean setDeviceType(String type) { 599 return doBooleanCommand("SET device_type " + type); 600 } 601 602 public boolean setConfigMethods(String cfg) { 603 return doBooleanCommand("SET config_methods " + cfg); 604 } 605 606 public boolean setManufacturer(String value) { 607 return doBooleanCommand("SET manufacturer " + value); 608 } 609 610 public boolean setModelName(String value) { 611 return doBooleanCommand("SET model_name " + value); 612 } 613 614 public boolean setModelNumber(String value) { 615 return doBooleanCommand("SET model_number " + value); 616 } 617 618 public boolean setSerialNumber(String value) { 619 return doBooleanCommand("SET serial_number " + value); 620 } 621 622 public boolean setP2pSsidPostfix(String postfix) { 623 return doBooleanCommand("SET p2p_ssid_postfix " + postfix); 624 } 625 626 public boolean setP2pGroupIdle(String iface, int time) { 627 synchronized (mLock) { 628 return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time); 629 } 630 } 631 632 public void setPowerSave(boolean enabled) { 633 if (enabled) { 634 doBooleanCommand("SET ps 1"); 635 } else { 636 doBooleanCommand("SET ps 0"); 637 } 638 } 639 640 public boolean setP2pPowerSave(String iface, boolean enabled) { 641 synchronized (mLock) { 642 if (enabled) { 643 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1"); 644 } else { 645 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0"); 646 } 647 } 648 } 649 650 public boolean setWfdEnable(boolean enable) { 651 return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0")); 652 } 653 654 public boolean setWfdDeviceInfo(String hex) { 655 return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex); 656 } 657 658 /** 659 * "sta" prioritizes STA connection over P2P and "p2p" prioritizes 660 * P2P connection over STA 661 */ 662 public boolean setConcurrencyPriority(String s) { 663 return doBooleanCommand("P2P_SET conc_pref " + s); 664 } 665 666 public boolean p2pFind() { 667 return doBooleanCommand("P2P_FIND"); 668 } 669 670 public boolean p2pFind(int timeout) { 671 if (timeout <= 0) { 672 return p2pFind(); 673 } 674 return doBooleanCommand("P2P_FIND " + timeout); 675 } 676 677 public boolean p2pStopFind() { 678 return doBooleanCommand("P2P_STOP_FIND"); 679 } 680 681 public boolean p2pListen() { 682 return doBooleanCommand("P2P_LISTEN"); 683 } 684 685 public boolean p2pListen(int timeout) { 686 if (timeout <= 0) { 687 return p2pListen(); 688 } 689 return doBooleanCommand("P2P_LISTEN " + timeout); 690 } 691 692 public boolean p2pExtListen(boolean enable, int period, int interval) { 693 if (enable && interval < period) { 694 return false; 695 } 696 return doBooleanCommand("P2P_EXT_LISTEN" 697 + (enable ? (" " + period + " " + interval) : "")); 698 } 699 700 public boolean p2pSetChannel(int lc, int oc) { 701 if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc); 702 703 if (lc >=1 && lc <= 11) { 704 if (!doBooleanCommand("P2P_SET listen_channel " + lc)) { 705 return false; 706 } 707 } else if (lc != 0) { 708 return false; 709 } 710 711 if (oc >= 1 && oc <= 165 ) { 712 int freq = (oc <= 14 ? 2407 : 5000) + oc * 5; 713 return doBooleanCommand("P2P_SET disallow_freq 1000-" 714 + (freq - 5) + "," + (freq + 5) + "-6000"); 715 } else if (oc == 0) { 716 /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */ 717 return doBooleanCommand("P2P_SET disallow_freq \"\""); 718 } 719 720 return false; 721 } 722 723 public boolean p2pFlush() { 724 return doBooleanCommand("P2P_FLUSH"); 725 } 726 727 /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] 728 [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ 729 public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { 730 if (config == null) return null; 731 List<String> args = new ArrayList<String>(); 732 WpsInfo wps = config.wps; 733 args.add(config.deviceAddress); 734 735 switch (wps.setup) { 736 case WpsInfo.PBC: 737 args.add("pbc"); 738 break; 739 case WpsInfo.DISPLAY: 740 if (TextUtils.isEmpty(wps.pin)) { 741 args.add("pin"); 742 } else { 743 args.add(wps.pin); 744 } 745 args.add("display"); 746 break; 747 case WpsInfo.KEYPAD: 748 args.add(wps.pin); 749 args.add("keypad"); 750 break; 751 case WpsInfo.LABEL: 752 args.add(wps.pin); 753 args.add("label"); 754 default: 755 break; 756 } 757 758 if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) { 759 args.add("persistent"); 760 } 761 762 if (joinExistingGroup) { 763 args.add("join"); 764 } else { 765 //TODO: This can be adapted based on device plugged in state and 766 //device battery state 767 int groupOwnerIntent = config.groupOwnerIntent; 768 if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { 769 groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT; 770 } 771 args.add("go_intent=" + groupOwnerIntent); 772 } 773 774 String command = "P2P_CONNECT "; 775 for (String s : args) command += s + " "; 776 777 return doStringCommand(command); 778 } 779 780 public boolean p2pCancelConnect() { 781 return doBooleanCommand("P2P_CANCEL"); 782 } 783 784 public boolean p2pProvisionDiscovery(WifiP2pConfig config) { 785 if (config == null) return false; 786 787 switch (config.wps.setup) { 788 case WpsInfo.PBC: 789 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); 790 case WpsInfo.DISPLAY: 791 //We are doing display, so provision discovery is keypad 792 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); 793 case WpsInfo.KEYPAD: 794 //We are doing keypad, so provision discovery is display 795 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); 796 default: 797 break; 798 } 799 return false; 800 } 801 802 public boolean p2pGroupAdd(boolean persistent) { 803 if (persistent) { 804 return doBooleanCommand("P2P_GROUP_ADD persistent"); 805 } 806 return doBooleanCommand("P2P_GROUP_ADD"); 807 } 808 809 public boolean p2pGroupAdd(int netId) { 810 return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId); 811 } 812 813 public boolean p2pGroupRemove(String iface) { 814 if (TextUtils.isEmpty(iface)) return false; 815 synchronized (mLock) { 816 return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface); 817 } 818 } 819 820 public boolean p2pReject(String deviceAddress) { 821 return doBooleanCommand("P2P_REJECT " + deviceAddress); 822 } 823 824 /* Invite a peer to a group */ 825 public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { 826 if (TextUtils.isEmpty(deviceAddress)) return false; 827 828 if (group == null) { 829 return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); 830 } else { 831 return doBooleanCommand("P2P_INVITE group=" + group.getInterface() 832 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); 833 } 834 } 835 836 /* Reinvoke a persistent connection */ 837 public boolean p2pReinvoke(int netId, String deviceAddress) { 838 if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false; 839 840 return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); 841 } 842 843 public String p2pGetSsid(String deviceAddress) { 844 return p2pGetParam(deviceAddress, "oper_ssid"); 845 } 846 847 public String p2pGetDeviceAddress() { 848 String status = status(); 849 if (status == null) return ""; 850 851 String[] tokens = status.split("\n"); 852 for (String token : tokens) { 853 if (token.startsWith("p2p_device_address=")) { 854 String[] nameValue = token.split("="); 855 if (nameValue.length != 2) break; 856 return nameValue[1]; 857 } 858 } 859 return ""; 860 } 861 862 public int getGroupCapability(String deviceAddress) { 863 int gc = 0; 864 if (TextUtils.isEmpty(deviceAddress)) return gc; 865 String peerInfo = p2pPeer(deviceAddress); 866 if (TextUtils.isEmpty(peerInfo)) return gc; 867 868 String[] tokens = peerInfo.split("\n"); 869 for (String token : tokens) { 870 if (token.startsWith("group_capab=")) { 871 String[] nameValue = token.split("="); 872 if (nameValue.length != 2) break; 873 try { 874 return Integer.decode(nameValue[1]); 875 } catch(NumberFormatException e) { 876 return gc; 877 } 878 } 879 } 880 return gc; 881 } 882 883 public String p2pPeer(String deviceAddress) { 884 return doStringCommand("P2P_PEER " + deviceAddress); 885 } 886 887 private String p2pGetParam(String deviceAddress, String key) { 888 if (deviceAddress == null) return null; 889 890 String peerInfo = p2pPeer(deviceAddress); 891 if (peerInfo == null) return null; 892 String[] tokens= peerInfo.split("\n"); 893 894 key += "="; 895 for (String token : tokens) { 896 if (token.startsWith(key)) { 897 String[] nameValue = token.split("="); 898 if (nameValue.length != 2) break; 899 return nameValue[1]; 900 } 901 } 902 return null; 903 } 904 905 public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) { 906 /* 907 * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump> 908 * P2P_SERVICE_ADD upnp <version hex> <service> 909 * 910 * e.g) 911 * [Bonjour] 912 * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) 913 * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027 914 * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) 915 * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 916 * 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 917 * 918 * [UPnP] 919 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 920 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice 921 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp 922 * -org:device:InternetGatewayDevice:1 923 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp 924 * -org:service:ContentDirectory:2 925 */ 926 for (String s : servInfo.getSupplicantQueryList()) { 927 String command = "P2P_SERVICE_ADD"; 928 command += (" " + s); 929 if (!doBooleanCommand(command)) { 930 return false; 931 } 932 } 933 return true; 934 } 935 936 public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) { 937 /* 938 * P2P_SERVICE_DEL bonjour <query hexdump> 939 * P2P_SERVICE_DEL upnp <version hex> <service> 940 */ 941 for (String s : servInfo.getSupplicantQueryList()) { 942 String command = "P2P_SERVICE_DEL "; 943 944 String[] data = s.split(" "); 945 if (data.length < 2) { 946 return false; 947 } 948 if ("upnp".equals(data[0])) { 949 command += s; 950 } else if ("bonjour".equals(data[0])) { 951 command += data[0]; 952 command += (" " + data[1]); 953 } else { 954 return false; 955 } 956 if (!doBooleanCommand(command)) { 957 return false; 958 } 959 } 960 return true; 961 } 962 963 public boolean p2pServiceFlush() { 964 return doBooleanCommand("P2P_SERVICE_FLUSH"); 965 } 966 967 public String p2pServDiscReq(String addr, String query) { 968 String command = "P2P_SERV_DISC_REQ"; 969 command += (" " + addr); 970 command += (" " + query); 971 972 return doStringCommand(command); 973 } 974 975 public boolean p2pServDiscCancelReq(String id) { 976 return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id); 977 } 978 979 /* Set the current mode of miracast operation. 980 * 0 = disabled 981 * 1 = operating as source 982 * 2 = operating as sink 983 */ 984 public void setMiracastMode(int mode) { 985 // Note: optional feature on the driver. It is ok for this to fail. 986 doBooleanCommand("DRIVER MIRACAST " + mode); 987 } 988 989 public String getNfcWpsConfigurationToken(int netId) { 990 return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId); 991 } 992 993 994 private class MonitorThread extends Thread { 995 public void run() { 996 waitForHalEventNative(); 997 } 998 } 999 1000 public void startHal() { 1001 if (startHalNative()) { 1002 new MonitorThread().start(); 1003 } else { 1004 Log.i(mTAG, "Could not start hal"); 1005 } 1006 } 1007 1008 public void stopHal() { 1009 stopHalNative(); 1010 } 1011} 1012