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