WifiNative.java revision 633fe60b78665979109d4796ba22430b7b1cd758
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 android.net.wifi; 18 19import android.net.wifi.p2p.WifiP2pConfig; 20import android.net.wifi.p2p.WifiP2pGroup; 21import android.net.wifi.p2p.WifiP2pDevice; 22import android.text.TextUtils; 23import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; 24import android.net.wifi.p2p.nsd.WifiP2pServiceRequest; 25import android.util.Log; 26 27import java.io.InputStream; 28import java.lang.Process; 29import java.util.ArrayList; 30import java.util.List; 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 = 7; 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 String mInterface = ""; 52 private boolean mSuspendOptEnabled = false; 53 54 public native static boolean loadDriver(); 55 56 public native static boolean isDriverLoaded(); 57 58 public native static boolean unloadDriver(); 59 60 public native static boolean startSupplicant(boolean p2pSupported); 61 62 /* Sends a kill signal to supplicant. To be used when we have lost connection 63 or when the supplicant is hung */ 64 public native static boolean killSupplicant(); 65 66 private native boolean connectToSupplicant(String iface); 67 68 private native void closeSupplicantConnection(String iface); 69 70 /** 71 * Wait for the supplicant to send an event, returning the event string. 72 * @return the event string sent by the supplicant. 73 */ 74 private native String waitForEvent(String iface); 75 76 private native boolean doBooleanCommand(String iface, String command); 77 78 private native int doIntCommand(String iface, String command); 79 80 private native String doStringCommand(String iface, String command); 81 82 public WifiNative(String iface) { 83 mInterface = iface; 84 mTAG = "WifiNative-" + iface; 85 } 86 87 public boolean connectToSupplicant() { 88 return connectToSupplicant(mInterface); 89 } 90 91 public void closeSupplicantConnection() { 92 closeSupplicantConnection(mInterface); 93 } 94 95 public String waitForEvent() { 96 return waitForEvent(mInterface); 97 } 98 99 private boolean doBooleanCommand(String command) { 100 if (DBG) Log.d(mTAG, "doBoolean: " + command); 101 return doBooleanCommand(mInterface, command); 102 } 103 104 private int doIntCommand(String command) { 105 if (DBG) Log.d(mTAG, "doInt: " + command); 106 return doIntCommand(mInterface, command); 107 } 108 109 private String doStringCommand(String command) { 110 if (DBG) Log.d(mTAG, "doString: " + command); 111 return doStringCommand(mInterface, command); 112 } 113 114 public boolean ping() { 115 String pong = doStringCommand("PING"); 116 return (pong != null && pong.equals("PONG")); 117 } 118 119 public boolean scan() { 120 return doBooleanCommand("SCAN"); 121 } 122 123 public boolean setScanMode(boolean setActive) { 124 if (setActive) { 125 return doBooleanCommand("DRIVER SCAN-ACTIVE"); 126 } else { 127 return doBooleanCommand("DRIVER SCAN-PASSIVE"); 128 } 129 } 130 131 /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. 132 * 133 * Note that underneath we use a harsh-sounding "terminate" supplicant command 134 * for a graceful stop and a mild-sounding "stop" interface 135 * to kill the process 136 */ 137 public boolean stopSupplicant() { 138 return doBooleanCommand("TERMINATE"); 139 } 140 141 public String listNetworks() { 142 return doStringCommand("LIST_NETWORKS"); 143 } 144 145 public int addNetwork() { 146 return doIntCommand("ADD_NETWORK"); 147 } 148 149 public boolean setNetworkVariable(int netId, String name, String value) { 150 if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false; 151 return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value); 152 } 153 154 public String getNetworkVariable(int netId, String name) { 155 if (TextUtils.isEmpty(name)) return null; 156 return doStringCommand("GET_NETWORK " + netId + " " + name); 157 } 158 159 public boolean removeNetwork(int netId) { 160 return doBooleanCommand("REMOVE_NETWORK " + netId); 161 } 162 163 public boolean enableNetwork(int netId, boolean disableOthers) { 164 if (disableOthers) { 165 return doBooleanCommand("SELECT_NETWORK " + netId); 166 } else { 167 return doBooleanCommand("ENABLE_NETWORK " + netId); 168 } 169 } 170 171 public boolean disableNetwork(int netId) { 172 return doBooleanCommand("DISABLE_NETWORK " + netId); 173 } 174 175 public boolean reconnect() { 176 return doBooleanCommand("RECONNECT"); 177 } 178 179 public boolean reassociate() { 180 return doBooleanCommand("REASSOCIATE"); 181 } 182 183 public boolean disconnect() { 184 return doBooleanCommand("DISCONNECT"); 185 } 186 187 public String status() { 188 return doStringCommand("STATUS"); 189 } 190 191 public String getMacAddress() { 192 //Macaddr = XX.XX.XX.XX.XX.XX 193 String ret = doStringCommand("DRIVER MACADDR"); 194 if (!TextUtils.isEmpty(ret)) { 195 String[] tokens = ret.split(" = "); 196 if (tokens.length == 2) return tokens[1]; 197 } 198 return null; 199 } 200 201 /** 202 * Format of results: 203 * ================= 204 * bssid=68:7f:74:d7:1b:6e 205 * freq=2412 206 * level=-43 207 * tsf=1344621975160944 208 * age=2623 209 * flags=[WPA2-PSK-CCMP][WPS][ESS] 210 * ssid=zubyb 211 * 212 * RANGE=ALL gets all scan results 213 * MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details 214 */ 215 public String scanResults() { 216 return doStringCommand("BSS RANGE=ALL MASK=0x1986"); 217 } 218 219 public boolean startDriver() { 220 return doBooleanCommand("DRIVER START"); 221 } 222 223 public boolean stopDriver() { 224 return doBooleanCommand("DRIVER STOP"); 225 } 226 227 228 /** 229 * Start filtering out Multicast V4 packets 230 * @return {@code true} if the operation succeeded, {@code false} otherwise 231 * 232 * Multicast filtering rules work as follows: 233 * 234 * The driver can filter multicast (v4 and/or v6) and broadcast packets when in 235 * a power optimized mode (typically when screen goes off). 236 * 237 * In order to prevent the driver from filtering the multicast/broadcast packets, we have to 238 * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective 239 * 240 * DRIVER RXFILTER-ADD Num 241 * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 242 * 243 * and DRIVER RXFILTER-START 244 * In order to stop the usage of these rules, we do 245 * 246 * DRIVER RXFILTER-STOP 247 * DRIVER RXFILTER-REMOVE Num 248 * where Num is as described for RXFILTER-ADD 249 * 250 * The SETSUSPENDOPT driver command overrides the filtering rules 251 */ 252 public boolean startFilteringMulticastV4Packets() { 253 return doBooleanCommand("DRIVER RXFILTER-STOP") 254 && doBooleanCommand("DRIVER RXFILTER-REMOVE 2") 255 && doBooleanCommand("DRIVER RXFILTER-START"); 256 } 257 258 /** 259 * Stop filtering out Multicast V4 packets. 260 * @return {@code true} if the operation succeeded, {@code false} otherwise 261 */ 262 public boolean stopFilteringMulticastV4Packets() { 263 return doBooleanCommand("DRIVER RXFILTER-STOP") 264 && doBooleanCommand("DRIVER RXFILTER-ADD 2") 265 && doBooleanCommand("DRIVER RXFILTER-START"); 266 } 267 268 /** 269 * Start filtering out Multicast V6 packets 270 * @return {@code true} if the operation succeeded, {@code false} otherwise 271 */ 272 public boolean startFilteringMulticastV6Packets() { 273 return doBooleanCommand("DRIVER RXFILTER-STOP") 274 && doBooleanCommand("DRIVER RXFILTER-REMOVE 3") 275 && doBooleanCommand("DRIVER RXFILTER-START"); 276 } 277 278 /** 279 * Stop filtering out Multicast V6 packets. 280 * @return {@code true} if the operation succeeded, {@code false} otherwise 281 */ 282 public boolean stopFilteringMulticastV6Packets() { 283 return doBooleanCommand("DRIVER RXFILTER-STOP") 284 && doBooleanCommand("DRIVER RXFILTER-ADD 3") 285 && doBooleanCommand("DRIVER RXFILTER-START"); 286 } 287 288 public int getBand() { 289 String ret = doStringCommand("DRIVER GETBAND"); 290 if (!TextUtils.isEmpty(ret)) { 291 //reply is "BAND X" where X is the band 292 String[] tokens = ret.split(" "); 293 try { 294 if (tokens.length == 2) return Integer.parseInt(tokens[1]); 295 } catch (NumberFormatException e) { 296 return -1; 297 } 298 } 299 return -1; 300 } 301 302 public boolean setBand(int band) { 303 return doBooleanCommand("DRIVER SETBAND " + band); 304 } 305 306 /** 307 * Sets the bluetooth coexistence mode. 308 * 309 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 310 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 311 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 312 * @return Whether the mode was successfully set. 313 */ 314 public boolean setBluetoothCoexistenceMode(int mode) { 315 return doBooleanCommand("DRIVER BTCOEXMODE " + mode); 316 } 317 318 /** 319 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 320 * some of the low-level scan parameters used by the driver are changed to 321 * reduce interference with A2DP streaming. 322 * 323 * @param isSet whether to enable or disable this mode 324 * @return {@code true} if the command succeeded, {@code false} otherwise. 325 */ 326 public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) { 327 if (setCoexScanMode) { 328 return doBooleanCommand("DRIVER BTCOEXSCAN-START"); 329 } else { 330 return doBooleanCommand("DRIVER BTCOEXSCAN-STOP"); 331 } 332 } 333 334 public boolean saveConfig() { 335 // Make sure we never write out a value for AP_SCAN other than 1 336 return doBooleanCommand("AP_SCAN 1") && doBooleanCommand("SAVE_CONFIG"); 337 } 338 339 public boolean setScanResultHandling(int mode) { 340 return doBooleanCommand("AP_SCAN " + mode); 341 } 342 343 public boolean addToBlacklist(String bssid) { 344 if (TextUtils.isEmpty(bssid)) return false; 345 return doBooleanCommand("BLACKLIST " + bssid); 346 } 347 348 public boolean clearBlacklist() { 349 return doBooleanCommand("BLACKLIST clear"); 350 } 351 352 public boolean setSuspendOptimizations(boolean enabled) { 353 if (mSuspendOptEnabled == enabled) return true; 354 mSuspendOptEnabled = enabled; 355 if (enabled) { 356 return doBooleanCommand("DRIVER SETSUSPENDMODE 1"); 357 } else { 358 return doBooleanCommand("DRIVER SETSUSPENDMODE 0"); 359 } 360 } 361 362 public boolean setCountryCode(String countryCode) { 363 return doBooleanCommand("DRIVER COUNTRY " + countryCode); 364 } 365 366 public void enableBackgroundScan(boolean enable) { 367 if (enable) { 368 doBooleanCommand("SET pno 1"); 369 } else { 370 doBooleanCommand("SET pno 0"); 371 } 372 } 373 374 public void setScanInterval(int scanInterval) { 375 doBooleanCommand("SCAN_INTERVAL " + scanInterval); 376 } 377 378 /** Example output: 379 * RSSI=-65 380 * LINKSPEED=48 381 * NOISE=9999 382 * FREQUENCY=0 383 */ 384 public String signalPoll() { 385 return doStringCommand("SIGNAL_POLL"); 386 } 387 388 /** Example outout: 389 * TXGOOD=396 390 * TXBAD=1 391 */ 392 public String pktcntPoll() { 393 return doStringCommand("PKTCNT_POLL"); 394 } 395 396 public boolean startWpsPbc(String bssid) { 397 if (TextUtils.isEmpty(bssid)) { 398 return doBooleanCommand("WPS_PBC"); 399 } else { 400 return doBooleanCommand("WPS_PBC " + bssid); 401 } 402 } 403 404 public boolean startWpsPbc(String iface, String bssid) { 405 if (TextUtils.isEmpty(bssid)) { 406 return doBooleanCommand("WPS_PBC interface=" + iface); 407 } else { 408 return doBooleanCommand("WPS_PBC interface=" + iface + " " + bssid); 409 } 410 } 411 412 public boolean startWpsPinKeypad(String pin) { 413 if (TextUtils.isEmpty(pin)) return false; 414 return doBooleanCommand("WPS_PIN any " + pin); 415 } 416 417 public boolean startWpsPinKeypad(String iface, String pin) { 418 if (TextUtils.isEmpty(pin)) return false; 419 return doBooleanCommand("WPS_PIN interface=" + iface + " any " + pin); 420 } 421 422 423 public String startWpsPinDisplay(String bssid) { 424 if (TextUtils.isEmpty(bssid)) { 425 return doStringCommand("WPS_PIN any"); 426 } else { 427 return doStringCommand("WPS_PIN " + bssid); 428 } 429 } 430 431 public String startWpsPinDisplay(String iface, String bssid) { 432 if (TextUtils.isEmpty(bssid)) { 433 return doStringCommand("WPS_PIN interface=" + iface + " any"); 434 } else { 435 return doStringCommand("WPS_PIN interface=" + iface + " " + bssid); 436 } 437 } 438 439 /* Configures an access point connection */ 440 public boolean startWpsRegistrar(String bssid, String pin) { 441 if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false; 442 return doBooleanCommand("WPS_REG " + bssid + " " + pin); 443 } 444 445 public boolean cancelWps() { 446 return doBooleanCommand("WPS_CANCEL"); 447 } 448 449 public boolean setPersistentReconnect(boolean enabled) { 450 int value = (enabled == true) ? 1 : 0; 451 return doBooleanCommand("SET persistent_reconnect " + value); 452 } 453 454 public boolean setDeviceName(String name) { 455 return doBooleanCommand("SET device_name " + name); 456 } 457 458 public boolean setDeviceType(String type) { 459 return doBooleanCommand("SET device_type " + type); 460 } 461 462 public boolean setConfigMethods(String cfg) { 463 return doBooleanCommand("SET config_methods " + cfg); 464 } 465 466 public boolean setManufacturer(String value) { 467 return doBooleanCommand("SET manufacturer " + value); 468 } 469 470 public boolean setModelName(String value) { 471 return doBooleanCommand("SET model_name " + value); 472 } 473 474 public boolean setModelNumber(String value) { 475 return doBooleanCommand("SET model_number " + value); 476 } 477 478 public boolean setSerialNumber(String value) { 479 return doBooleanCommand("SET serial_number " + value); 480 } 481 482 public boolean setP2pSsidPostfix(String postfix) { 483 return doBooleanCommand("SET p2p_ssid_postfix " + postfix); 484 } 485 486 public boolean setP2pGroupIdle(String iface, int time) { 487 return doBooleanCommand("SET interface=" + iface + " p2p_group_idle " + time); 488 } 489 490 public void setPowerSave(boolean enabled) { 491 if (enabled) { 492 doBooleanCommand("SET ps 1"); 493 } else { 494 doBooleanCommand("SET ps 0"); 495 } 496 } 497 498 public boolean setP2pPowerSave(String iface, boolean enabled) { 499 if (enabled) { 500 return doBooleanCommand("P2P_SET interface=" + iface + " ps 1"); 501 } else { 502 return doBooleanCommand("P2P_SET interface=" + iface + " ps 0"); 503 } 504 } 505 506 public boolean setWfdEnable(boolean enable) { 507 return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0")); 508 } 509 510 public boolean setWfdDeviceInfo(String hex) { 511 return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex); 512 } 513 514 /** 515 * "sta" prioritizes STA connection over P2P and "p2p" prioritizes 516 * P2P connection over STA 517 */ 518 public boolean setConcurrencyPriority(String s) { 519 return doBooleanCommand("P2P_SET conc_pref " + s); 520 } 521 522 public boolean p2pFind() { 523 return doBooleanCommand("P2P_FIND"); 524 } 525 526 public boolean p2pFind(int timeout) { 527 if (timeout <= 0) { 528 return p2pFind(); 529 } 530 return doBooleanCommand("P2P_FIND " + timeout); 531 } 532 533 public boolean p2pStopFind() { 534 return doBooleanCommand("P2P_STOP_FIND"); 535 } 536 537 public boolean p2pListen() { 538 return doBooleanCommand("P2P_LISTEN"); 539 } 540 541 public boolean p2pListen(int timeout) { 542 if (timeout <= 0) { 543 return p2pListen(); 544 } 545 return doBooleanCommand("P2P_LISTEN " + timeout); 546 } 547 548 public boolean p2pFlush() { 549 return doBooleanCommand("P2P_FLUSH"); 550 } 551 552 /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] 553 [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ 554 public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { 555 if (config == null) return null; 556 List<String> args = new ArrayList<String>(); 557 WpsInfo wps = config.wps; 558 args.add(config.deviceAddress); 559 560 switch (wps.setup) { 561 case WpsInfo.PBC: 562 args.add("pbc"); 563 break; 564 case WpsInfo.DISPLAY: 565 if (TextUtils.isEmpty(wps.pin)) { 566 args.add("pin"); 567 } else { 568 args.add(wps.pin); 569 } 570 args.add("display"); 571 break; 572 case WpsInfo.KEYPAD: 573 args.add(wps.pin); 574 args.add("keypad"); 575 break; 576 case WpsInfo.LABEL: 577 args.add(wps.pin); 578 args.add("label"); 579 default: 580 break; 581 } 582 583 if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) { 584 args.add("persistent"); 585 } 586 587 if (joinExistingGroup) { 588 args.add("join"); 589 } else { 590 //TODO: This can be adapted based on device plugged in state and 591 //device battery state 592 int groupOwnerIntent = config.groupOwnerIntent; 593 if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { 594 groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT; 595 } 596 args.add("go_intent=" + groupOwnerIntent); 597 } 598 599 String command = "P2P_CONNECT "; 600 for (String s : args) command += s + " "; 601 602 return doStringCommand(command); 603 } 604 605 public boolean p2pCancelConnect() { 606 return doBooleanCommand("P2P_CANCEL"); 607 } 608 609 public boolean p2pProvisionDiscovery(WifiP2pConfig config) { 610 if (config == null) return false; 611 612 switch (config.wps.setup) { 613 case WpsInfo.PBC: 614 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); 615 case WpsInfo.DISPLAY: 616 //We are doing display, so provision discovery is keypad 617 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); 618 case WpsInfo.KEYPAD: 619 //We are doing keypad, so provision discovery is display 620 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); 621 default: 622 break; 623 } 624 return false; 625 } 626 627 public boolean p2pGroupAdd(boolean persistent) { 628 if (persistent) { 629 return doBooleanCommand("P2P_GROUP_ADD persistent"); 630 } 631 return doBooleanCommand("P2P_GROUP_ADD"); 632 } 633 634 public boolean p2pGroupAdd(int netId) { 635 return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId); 636 } 637 638 public boolean p2pGroupRemove(String iface) { 639 if (TextUtils.isEmpty(iface)) return false; 640 return doBooleanCommand("P2P_GROUP_REMOVE " + iface); 641 } 642 643 public boolean p2pReject(String deviceAddress) { 644 return doBooleanCommand("P2P_REJECT " + deviceAddress); 645 } 646 647 /* Invite a peer to a group */ 648 public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { 649 if (TextUtils.isEmpty(deviceAddress)) return false; 650 651 if (group == null) { 652 return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); 653 } else { 654 return doBooleanCommand("P2P_INVITE group=" + group.getInterface() 655 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); 656 } 657 } 658 659 /* Reinvoke a persistent connection */ 660 public boolean p2pReinvoke(int netId, String deviceAddress) { 661 if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false; 662 663 return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); 664 } 665 666 public String p2pGetSsid(String deviceAddress) { 667 return p2pGetParam(deviceAddress, "oper_ssid"); 668 } 669 670 public String p2pGetDeviceAddress() { 671 String status = status(); 672 if (status == null) return ""; 673 674 String[] tokens = status.split("\n"); 675 for (String token : tokens) { 676 if (token.startsWith("p2p_device_address=")) { 677 String[] nameValue = token.split("="); 678 if (nameValue.length != 2) break; 679 return nameValue[1]; 680 } 681 } 682 return ""; 683 } 684 685 public int getGroupCapability(String deviceAddress) { 686 int gc = 0; 687 if (TextUtils.isEmpty(deviceAddress)) return gc; 688 String peerInfo = p2pPeer(deviceAddress); 689 if (TextUtils.isEmpty(peerInfo)) return gc; 690 691 String[] tokens = peerInfo.split("\n"); 692 for (String token : tokens) { 693 if (token.startsWith("group_capab=")) { 694 String[] nameValue = token.split("="); 695 if (nameValue.length != 2) break; 696 try { 697 return Integer.decode(nameValue[1]); 698 } catch(NumberFormatException e) { 699 return gc; 700 } 701 } 702 } 703 return gc; 704 } 705 706 public String p2pPeer(String deviceAddress) { 707 return doStringCommand("P2P_PEER " + deviceAddress); 708 } 709 710 private String p2pGetParam(String deviceAddress, String key) { 711 if (deviceAddress == null) return null; 712 713 String peerInfo = p2pPeer(deviceAddress); 714 if (peerInfo == null) return null; 715 String[] tokens= peerInfo.split("\n"); 716 717 key += "="; 718 for (String token : tokens) { 719 if (token.startsWith(key)) { 720 String[] nameValue = token.split("="); 721 if (nameValue.length != 2) break; 722 return nameValue[1]; 723 } 724 } 725 return null; 726 } 727 728 public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) { 729 /* 730 * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump> 731 * P2P_SERVICE_ADD upnp <version hex> <service> 732 * 733 * e.g) 734 * [Bonjour] 735 * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) 736 * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027 737 * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) 738 * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 739 * 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 740 * 741 * [UPnP] 742 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 743 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice 744 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp 745 * -org:device:InternetGatewayDevice:1 746 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp 747 * -org:service:ContentDirectory:2 748 */ 749 for (String s : servInfo.getSupplicantQueryList()) { 750 String command = "P2P_SERVICE_ADD"; 751 command += (" " + s); 752 if (!doBooleanCommand(command)) { 753 return false; 754 } 755 } 756 return true; 757 } 758 759 public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) { 760 /* 761 * P2P_SERVICE_DEL bonjour <query hexdump> 762 * P2P_SERVICE_DEL upnp <version hex> <service> 763 */ 764 for (String s : servInfo.getSupplicantQueryList()) { 765 String command = "P2P_SERVICE_DEL "; 766 767 String[] data = s.split(" "); 768 if (data.length < 2) { 769 return false; 770 } 771 if ("upnp".equals(data[0])) { 772 command += s; 773 } else if ("bonjour".equals(data[0])) { 774 command += data[0]; 775 command += (" " + data[1]); 776 } else { 777 return false; 778 } 779 if (!doBooleanCommand(command)) { 780 return false; 781 } 782 } 783 return true; 784 } 785 786 public boolean p2pServiceFlush() { 787 return doBooleanCommand("P2P_SERVICE_FLUSH"); 788 } 789 790 public String p2pServDiscReq(String addr, String query) { 791 String command = "P2P_SERV_DISC_REQ"; 792 command += (" " + addr); 793 command += (" " + query); 794 795 return doStringCommand(command); 796 } 797 798 public boolean p2pServDiscCancelReq(String id) { 799 return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id); 800 } 801} 802