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 17 package android.net.wifi; 18 19 import android.net.wifi.p2p.WifiP2pConfig; 20 import android.net.wifi.p2p.WifiP2pGroup; 21 import android.net.wifi.p2p.WifiP2pDevice; 22 import android.util.Log; 23 24 import java.io.InputStream; 25 import java.lang.Process; 26 import java.util.ArrayList; 27 import java.util.List; 28 29 /** 30 * Native calls for sending requests to the supplicant daemon, and for 31 * receiving asynchronous events. All methods of the form "xxxxCommand()" 32 * must be single-threaded, to avoid requests and responses initiated 33 * from multiple threads from being intermingled. 34 * <p/> 35 * Note that methods whose names are not of the form "xxxCommand()" do 36 * not talk to the supplicant daemon. 37 * Also, note that all WifiNative calls should happen in the 38 * WifiStateTracker class except for waitForEvent() call which is 39 * on a separate monitor channel for WifiMonitor 40 * 41 * TODO: clean up the API and move the functionality from JNI to here. We should 42 * be able to get everything done with doBooleanCommand, doIntCommand and 43 * doStringCommand native commands 44 * 45 * {@hide} 46 */ 47 public class WifiNative { 48 49 static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 50 static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 51 static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 52 53 public native static String getErrorString(int errorCode); 54 55 public native static boolean loadDriver(); 56 57 public native static boolean isDriverLoaded(); 58 59 public native static boolean unloadDriver(); 60 61 public native static boolean startSupplicant(); 62 63 public native static boolean startP2pSupplicant(); 64 65 /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. 66 * 67 * Note that underneath we use a harsh-sounding "terminate" supplicant command 68 * for a graceful stop and a mild-sounding "stop" interface 69 * to kill the process 70 */ 71 public native static boolean stopSupplicant(); 72 73 /* Sends a kill signal to supplicant. To be used when we have lost connection 74 or when the supplicant is hung */ 75 public native static boolean killSupplicant(); 76 77 public native static boolean connectToSupplicant(); 78 79 public native static void closeSupplicantConnection(); 80 81 public native static boolean pingCommand(); 82 83 public native static boolean scanCommand(boolean forceActive); 84 85 public native static boolean setScanModeCommand(boolean setActive); 86 87 public native static String listNetworksCommand(); 88 89 public native static int addNetworkCommand(); 90 91 public native static boolean setNetworkVariableCommand(int netId, String name, String value); 92 93 public native static String getNetworkVariableCommand(int netId, String name); 94 95 public native static boolean removeNetworkCommand(int netId); 96 97 public native static boolean enableNetworkCommand(int netId, boolean disableOthers); 98 99 public native static boolean disableNetworkCommand(int netId); 100 101 public native static boolean reconnectCommand(); 102 103 public native static boolean reassociateCommand(); 104 105 public native static boolean disconnectCommand(); 106 107 public native static String statusCommand(); 108 109 public native static String getMacAddressCommand(); 110 111 public native static String scanResultsCommand(); 112 113 public native static boolean startDriverCommand(); 114 115 public native static boolean stopDriverCommand(); 116 117 118 /** 119 * Start filtering out Multicast V4 packets 120 * @return {@code true} if the operation succeeded, {@code false} otherwise 121 */ 122 public native static boolean startFilteringMulticastV4Packets(); 123 124 /** 125 * Stop filtering out Multicast V4 packets. 126 * @return {@code true} if the operation succeeded, {@code false} otherwise 127 */ 128 public native static boolean stopFilteringMulticastV4Packets(); 129 130 /** 131 * Start filtering out Multicast V6 packets 132 * @return {@code true} if the operation succeeded, {@code false} otherwise 133 */ 134 public native static boolean startFilteringMulticastV6Packets(); 135 136 /** 137 * Stop filtering out Multicast V6 packets. 138 * @return {@code true} if the operation succeeded, {@code false} otherwise 139 */ 140 public native static boolean stopFilteringMulticastV6Packets(); 141 142 public native static boolean setPowerModeCommand(int mode); 143 144 public native static int getBandCommand(); 145 146 public native static boolean setBandCommand(int band); 147 148 public native static int getPowerModeCommand(); 149 150 /** 151 * Sets the bluetooth coexistence mode. 152 * 153 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 154 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 155 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 156 * @return Whether the mode was successfully set. 157 */ 158 public native static boolean setBluetoothCoexistenceModeCommand(int mode); 159 160 /** 161 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 162 * some of the low-level scan parameters used by the driver are changed to 163 * reduce interference with A2DP streaming. 164 * 165 * @param isSet whether to enable or disable this mode 166 * @return {@code true} if the command succeeded, {@code false} otherwise. 167 */ 168 public native static boolean setBluetoothCoexistenceScanModeCommand(boolean setCoexScanMode); 169 170 public native static boolean saveConfigCommand(); 171 172 public native static boolean reloadConfigCommand(); 173 174 public native static boolean setScanResultHandlingCommand(int mode); 175 176 public native static boolean addToBlacklistCommand(String bssid); 177 178 public native static boolean clearBlacklistCommand(); 179 180 public native static boolean startWpsPbcCommand(String bssid); 181 182 public native static boolean startWpsWithPinFromAccessPointCommand(String bssid, String apPin); 183 184 public native static String startWpsWithPinFromDeviceCommand(String bssid); 185 186 public native static boolean setSuspendOptimizationsCommand(boolean enabled); 187 188 public native static boolean setCountryCodeCommand(String countryCode); 189 190 /** 191 * Wait for the supplicant to send an event, returning the event string. 192 * @return the event string sent by the supplicant. 193 */ 194 public native static String waitForEvent(); 195 196 public native static void enableBackgroundScanCommand(boolean enable); 197 198 public native static void setScanIntervalCommand(int scanInterval); 199 200 private native static boolean doBooleanCommand(String command); 201 202 private native static int doIntCommand(String command); 203 204 private native static String doStringCommand(String command); 205 206 /** Example output: 207 * RSSI=-65 208 * LINKSPEED=48 209 * NOISE=9999 210 * FREQUENCY=0 211 */ 212 public static String signalPoll() { 213 return doStringCommand("SIGNAL_POLL"); 214 } 215 216 public static boolean wpsPbc() { 217 return doBooleanCommand("WPS_PBC"); 218 } 219 220 public static boolean wpsPin(String pin) { 221 return doBooleanCommand("WPS_PIN any " + pin); 222 } 223 224 public static boolean setPersistentReconnect(boolean enabled) { 225 int value = (enabled == true) ? 1 : 0; 226 return WifiNative.doBooleanCommand("SET persistent_reconnect " + value); 227 } 228 229 public static boolean setDeviceName(String name) { 230 return WifiNative.doBooleanCommand("SET device_name " + name); 231 } 232 233 public static boolean setDeviceType(String type) { 234 return WifiNative.doBooleanCommand("SET device_type " + type); 235 } 236 237 public static boolean p2pFind() { 238 return doBooleanCommand("P2P_FIND"); 239 } 240 241 public static boolean p2pFind(int timeout) { 242 if (timeout <= 0) { 243 return p2pFind(); 244 } 245 return doBooleanCommand("P2P_FIND " + timeout); 246 } 247 248 public static boolean p2pListen() { 249 return doBooleanCommand("P2P_LISTEN"); 250 } 251 252 public static boolean p2pListen(int timeout) { 253 if (timeout <= 0) { 254 return p2pListen(); 255 } 256 return doBooleanCommand("P2P_LISTEN " + timeout); 257 } 258 259 public static boolean p2pFlush() { 260 return doBooleanCommand("P2P_FLUSH"); 261 } 262 263 /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] 264 [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ 265 public static String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { 266 if (config == null) return null; 267 List<String> args = new ArrayList<String>(); 268 WpsInfo wps = config.wps; 269 args.add(config.deviceAddress); 270 271 switch (wps.setup) { 272 case WpsInfo.PBC: 273 args.add("pbc"); 274 break; 275 case WpsInfo.DISPLAY: 276 //TODO: pass the pin back for display 277 args.add("pin"); 278 args.add("display"); 279 break; 280 case WpsInfo.KEYPAD: 281 args.add(wps.pin); 282 args.add("keypad"); 283 break; 284 case WpsInfo.LABEL: 285 args.add(wps.pin); 286 args.add("label"); 287 default: 288 break; 289 } 290 291 //TODO: Add persist behavior once the supplicant interaction is fixed for both 292 // group and client scenarios 293 /* Persist unless there is an explicit request to not do so*/ 294 //if (config.persist != WifiP2pConfig.Persist.NO) args.add("persistent"); 295 296 if (joinExistingGroup) args.add("join"); 297 298 int groupOwnerIntent = config.groupOwnerIntent; 299 if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { 300 groupOwnerIntent = 3; //default value 301 } 302 args.add("go_intent=" + groupOwnerIntent); 303 304 String command = "P2P_CONNECT "; 305 for (String s : args) command += s + " "; 306 307 return doStringCommand(command); 308 } 309 310 public static boolean p2pCancelConnect() { 311 return doBooleanCommand("P2P_CANCEL"); 312 } 313 314 public static boolean p2pGroupAdd() { 315 return doBooleanCommand("P2P_GROUP_ADD"); 316 } 317 318 public static boolean p2pGroupRemove(String iface) { 319 if (iface == null) return false; 320 return doBooleanCommand("P2P_GROUP_REMOVE " + iface); 321 } 322 323 public static boolean p2pReject(String deviceAddress) { 324 return doBooleanCommand("P2P_REJECT " + deviceAddress); 325 } 326 327 /* Invite a peer to a group */ 328 public static boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { 329 if (deviceAddress == null) return false; 330 331 if (group == null) { 332 return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); 333 } else { 334 return doBooleanCommand("P2P_INVITE group=" + group.getInterface() 335 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); 336 } 337 } 338 339 /* Reinvoke a persistent connection */ 340 public static boolean p2pReinvoke(int netId, String deviceAddress) { 341 if (deviceAddress == null || netId < 0) return false; 342 343 return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); 344 } 345 346 347 public static String p2pGetInterfaceAddress(String deviceAddress) { 348 if (deviceAddress == null) return null; 349 350 // "p2p_peer deviceAddress" returns a multi-line result containing 351 // intended_addr=fa:7b:7a:42:82:13 352 String peerInfo = p2pPeer(deviceAddress); 353 if (peerInfo == null) return null; 354 String[] tokens= peerInfo.split("\n"); 355 356 for (String token : tokens) { 357 //TODO: update from interface_addr when wpa_supplicant implementation is fixed 358 if (token.startsWith("intended_addr=")) { 359 String[] nameValue = token.split("="); 360 if (nameValue.length != 2) break; 361 return nameValue[1]; 362 } 363 } 364 return null; 365 } 366 367 public static String p2pGetDeviceAddress() { 368 String status = statusCommand(); 369 if (status == null) return ""; 370 371 String[] tokens = status.split("\n"); 372 for (String token : tokens) { 373 if (token.startsWith("p2p_device_address=")) { 374 String[] nameValue = token.split("="); 375 if (nameValue.length != 2) break; 376 return nameValue[1]; 377 } 378 } 379 return ""; 380 } 381 382 public static String p2pPeer(String deviceAddress) { 383 return doStringCommand("P2P_PEER " + deviceAddress); 384 } 385 } 386