android_net_wifi_Wifi.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* 2 * Copyright 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#define LOG_TAG "wifi" 18 19#include "jni.h" 20#include <utils/misc.h> 21#include <android_runtime/AndroidRuntime.h> 22#include <utils/Log.h> 23 24#include "wifi.h" 25 26#define WIFI_PKG_NAME "android/net/wifi/WifiNative" 27 28namespace android { 29 30/* 31 * The following remembers the jfieldID's of the fields 32 * of the DhcpInfo Java object, so that we don't have 33 * to look them up every time. 34 */ 35static struct fieldIds { 36 jclass dhcpInfoClass; 37 jmethodID constructorId; 38 jfieldID ipaddress; 39 jfieldID gateway; 40 jfieldID netmask; 41 jfieldID dns1; 42 jfieldID dns2; 43 jfieldID serverAddress; 44 jfieldID leaseDuration; 45} dhcpInfoFieldIds; 46 47static int doCommand(const char *cmd, char *replybuf, int replybuflen) 48{ 49 size_t reply_len = replybuflen - 1; 50 51 if (::wifi_command(cmd, replybuf, &reply_len) != 0) 52 return -1; 53 else { 54 // Strip off trailing newline 55 if (reply_len > 0 && replybuf[reply_len-1] == '\n') 56 replybuf[reply_len-1] = '\0'; 57 else 58 replybuf[reply_len] = '\0'; 59 return 0; 60 } 61} 62 63static jint doIntCommand(const char *cmd) 64{ 65 char reply[256]; 66 67 if (doCommand(cmd, reply, sizeof(reply)) != 0) { 68 return (jint)-1; 69 } else { 70 return (jint)atoi(reply); 71 } 72} 73 74static jboolean doBooleanCommand(const char *cmd, const char *expect) 75{ 76 char reply[256]; 77 78 if (doCommand(cmd, reply, sizeof(reply)) != 0) { 79 return (jboolean)JNI_FALSE; 80 } else { 81 return (jboolean)(strcmp(reply, expect) == 0); 82 } 83} 84 85// Send a command to the supplicant, and return the reply as a String 86static jstring doStringCommand(JNIEnv *env, const char *cmd) 87{ 88 char reply[4096]; 89 90 if (doCommand(cmd, reply, sizeof(reply)) != 0) { 91 return env->NewStringUTF(NULL); 92 } else { 93 return env->NewStringUTF(reply); 94 } 95} 96 97static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject clazz) 98{ 99 return (jboolean)(::wifi_load_driver() == 0); 100} 101 102static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject clazz) 103{ 104 return (jboolean)(::wifi_unload_driver() == 0); 105} 106 107static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject clazz) 108{ 109 return (jboolean)(::wifi_start_supplicant() == 0); 110} 111 112static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject clazz) 113{ 114 return (jboolean)(::wifi_stop_supplicant() == 0); 115} 116 117static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject clazz) 118{ 119 return (jboolean)(::wifi_connect_to_supplicant() == 0); 120} 121 122static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject clazz) 123{ 124 ::wifi_close_supplicant_connection(); 125} 126 127static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject clazz) 128{ 129 char buf[256]; 130 131 int nread = ::wifi_wait_for_event(buf, sizeof buf); 132 if (nread > 0) { 133 return env->NewStringUTF(buf); 134 } else { 135 return env->NewStringUTF(NULL); 136 } 137} 138 139static jstring android_net_wifi_listNetworksCommand(JNIEnv* env, jobject clazz) 140{ 141 return doStringCommand(env, "LIST_NETWORKS"); 142} 143 144static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject clazz) 145{ 146 return doIntCommand("ADD_NETWORK"); 147} 148 149static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env, 150 jobject clazz, 151 jint netId, 152 jstring name, 153 jstring value) 154{ 155 char cmdstr[256]; 156 jboolean isCopy; 157 158 const char *nameStr = env->GetStringUTFChars(name, &isCopy); 159 const char *valueStr = env->GetStringUTFChars(value, &isCopy); 160 161 if (nameStr == NULL || valueStr == NULL) 162 return JNI_FALSE; 163 164 int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "SET_NETWORK %d %s %s", 165 netId, nameStr, valueStr) >= (int)sizeof(cmdstr); 166 167 env->ReleaseStringUTFChars(name, nameStr); 168 env->ReleaseStringUTFChars(value, valueStr); 169 170 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 171} 172 173static jstring android_net_wifi_getNetworkVariableCommand(JNIEnv* env, 174 jobject clazz, 175 jint netId, 176 jstring name) 177{ 178 char cmdstr[256]; 179 jboolean isCopy; 180 181 const char *nameStr = env->GetStringUTFChars(name, &isCopy); 182 183 if (nameStr == NULL) 184 return env->NewStringUTF(NULL); 185 186 int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "GET_NETWORK %d %s", 187 netId, nameStr) >= (int)sizeof(cmdstr); 188 189 env->ReleaseStringUTFChars(name, nameStr); 190 191 return cmdTooLong ? env->NewStringUTF(NULL) : doStringCommand(env, cmdstr); 192} 193 194static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject clazz, jint netId) 195{ 196 char cmdstr[256]; 197 198 int numWritten = snprintf(cmdstr, sizeof(cmdstr), "REMOVE_NETWORK %d", netId); 199 int cmdTooLong = numWritten >= (int)sizeof(cmdstr); 200 201 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 202} 203 204static jboolean android_net_wifi_enableNetworkCommand(JNIEnv* env, 205 jobject clazz, 206 jint netId, 207 jboolean disableOthers) 208{ 209 char cmdstr[256]; 210 const char *cmd = disableOthers ? "SELECT_NETWORK" : "ENABLE_NETWORK"; 211 212 int numWritten = snprintf(cmdstr, sizeof(cmdstr), "%s %d", cmd, netId); 213 int cmdTooLong = numWritten >= (int)sizeof(cmdstr); 214 215 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 216} 217 218static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject clazz, jint netId) 219{ 220 char cmdstr[256]; 221 222 int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DISABLE_NETWORK %d", netId); 223 int cmdTooLong = numWritten >= (int)sizeof(cmdstr); 224 225 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 226} 227 228static jstring android_net_wifi_statusCommand(JNIEnv* env, jobject clazz) 229{ 230 return doStringCommand(env, "STATUS"); 231} 232 233static jboolean android_net_wifi_pingCommand(JNIEnv* env, jobject clazz) 234{ 235 return doBooleanCommand("PING", "PONG"); 236} 237 238static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject clazz) 239{ 240 return doStringCommand(env, "SCAN_RESULTS"); 241} 242 243static jboolean android_net_wifi_disconnectCommand(JNIEnv* env, jobject clazz) 244{ 245 return doBooleanCommand("DISCONNECT", "OK"); 246} 247 248static jboolean android_net_wifi_reconnectCommand(JNIEnv* env, jobject clazz) 249{ 250 return doBooleanCommand("RECONNECT", "OK"); 251} 252static jboolean android_net_wifi_reassociateCommand(JNIEnv* env, jobject clazz) 253{ 254 return doBooleanCommand("REASSOCIATE", "OK"); 255} 256 257static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz) 258{ 259 jboolean result; 260 // Ignore any error from setting the scan mode. 261 // The scan will still work. 262 (void)doBooleanCommand("DRIVER SCAN-ACTIVE", "OK"); 263 result = doBooleanCommand("SCAN", "OK"); 264 (void)doBooleanCommand("DRIVER SCAN-PASSIVE", "OK"); 265 return result; 266} 267 268static jboolean android_net_wifi_setScanModeCommand(JNIEnv* env, jobject clazz, jboolean setActive) 269{ 270 jboolean result; 271 // Ignore any error from setting the scan mode. 272 // The scan will still work. 273 if (setActive) { 274 return doBooleanCommand("DRIVER SCAN-ACTIVE", "OK"); 275 } else { 276 return doBooleanCommand("DRIVER SCAN-PASSIVE", "OK"); 277 } 278} 279 280static jboolean android_net_wifi_startDriverCommand(JNIEnv* env, jobject clazz) 281{ 282 return doBooleanCommand("DRIVER START", "OK"); 283} 284 285static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject clazz) 286{ 287 return doBooleanCommand("DRIVER STOP", "OK"); 288} 289 290static jboolean android_net_wifi_startPacketFiltering(JNIEnv* env, jobject clazz) 291{ 292 return doBooleanCommand("DRIVER RXFILTER-ADD 0", "OK") 293 && doBooleanCommand("DRIVER RXFILTER-ADD 1", "OK") 294 && doBooleanCommand("DRIVER RXFILTER-START", "OK"); 295} 296 297static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject clazz) 298{ 299 jboolean result = doBooleanCommand("DRIVER RXFILTER-STOP", "OK"); 300 if (result) { 301 (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 1", "OK"); 302 (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 0", "OK"); 303 } 304 305 return result; 306} 307 308static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz) 309{ 310 char reply[256]; 311 int rssi = -200; 312 313 if (doCommand("DRIVER RSSI", reply, sizeof(reply)) != 0) { 314 return (jint)-1; 315 } 316 // reply comes back in the form "<SSID> rssi XX" where XX is the 317 // number we're interested in. if we're associating, it returns "OK". 318 if (strcmp(reply, "OK") != 0) { 319 sscanf(reply, "%*s %*s %d", &rssi); 320 } 321 return (jint)rssi; 322} 323 324static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz) 325{ 326 char reply[256]; 327 int linkspeed; 328 329 if (doCommand("DRIVER LINKSPEED", reply, sizeof(reply)) != 0) { 330 return (jint)-1; 331 } 332 // reply comes back in the form "LinkSpeed XX" where XX is the 333 // number we're interested in. 334 sscanf(reply, "%*s %u", &linkspeed); 335 return (jint)linkspeed; 336} 337 338static jstring android_net_wifi_getMacAddressCommand(JNIEnv* env, jobject clazz) 339{ 340 char reply[256]; 341 char buf[256]; 342 343 if (doCommand("DRIVER MACADDR", reply, sizeof(reply)) != 0) { 344 return env->NewStringUTF(NULL); 345 } 346 // reply comes back in the form "Macaddr = XX.XX.XX.XX.XX.XX" where XX 347 // is the part of the string we're interested in. 348 if (sscanf(reply, "%*s = %255s", buf) == 1) 349 return env->NewStringUTF(buf); 350 else 351 return env->NewStringUTF(NULL); 352} 353 354static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode) 355{ 356 char cmdstr[256]; 357 358 int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER POWERMODE %d", mode); 359 int cmdTooLong = numWritten >= (int)sizeof(cmdstr); 360 361 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 362} 363 364static jboolean android_net_wifi_setNumAllowedChannelsCommand(JNIEnv* env, jobject clazz, jint numChannels) 365{ 366 char cmdstr[256]; 367 368 int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER SCAN-CHANNELS %u", numChannels); 369 int cmdTooLong = numWritten >= (int)sizeof(cmdstr); 370 371 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 372} 373 374static jint android_net_wifi_getNumAllowedChannelsCommand(JNIEnv* env, jobject clazz) 375{ 376 char reply[256]; 377 int numChannels; 378 379 if (doCommand("DRIVER SCAN-CHANNELS", reply, sizeof(reply)) != 0) { 380 return -1; 381 } 382 // reply comes back in the form "Scan-Channels = X" where X is the 383 // number of channels 384 if (sscanf(reply, "%*s = %u", &numChannels) == 1) 385 return numChannels; 386 else 387 return -1; 388} 389 390static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject clazz, jint mode) 391{ 392 char cmdstr[256]; 393 394 int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXMODE %d", mode); 395 int cmdTooLong = numWritten >= (int)sizeof(cmdstr); 396 397 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 398} 399 400static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject clazz) 401{ 402 // Make sure we never write out a value for AP_SCAN other than 1 403 (void)doBooleanCommand("AP_SCAN 1", "OK"); 404 return doBooleanCommand("SAVE_CONFIG", "OK"); 405} 406 407static jboolean android_net_wifi_reloadConfigCommand(JNIEnv* env, jobject clazz) 408{ 409 return doBooleanCommand("RECONFIGURE", "OK"); 410} 411 412static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject clazz, jint mode) 413{ 414 char cmdstr[256]; 415 416 int numWritten = snprintf(cmdstr, sizeof(cmdstr), "AP_SCAN %d", mode); 417 int cmdTooLong = numWritten >= (int)sizeof(cmdstr); 418 419 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 420} 421 422static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject clazz, jstring bssid) 423{ 424 char cmdstr[256]; 425 jboolean isCopy; 426 427 const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy); 428 429 int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= (int)sizeof(cmdstr); 430 431 env->ReleaseStringUTFChars(bssid, bssidStr); 432 433 return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); 434} 435 436static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject clazz) 437{ 438 return doBooleanCommand("BLACKLIST clear", "OK"); 439} 440 441static jboolean android_net_wifi_doDhcpRequest(JNIEnv* env, jobject clazz, jobject info) 442{ 443 jint ipaddr, gateway, mask, dns1, dns2, server, lease; 444 jboolean succeeded = ((jboolean)::do_dhcp_request(&ipaddr, &gateway, &mask, 445 &dns1, &dns2, &server, &lease) == 0); 446 if (succeeded && dhcpInfoFieldIds.dhcpInfoClass != NULL) { 447 env->SetIntField(info, dhcpInfoFieldIds.ipaddress, ipaddr); 448 env->SetIntField(info, dhcpInfoFieldIds.gateway, gateway); 449 env->SetIntField(info, dhcpInfoFieldIds.netmask, mask); 450 env->SetIntField(info, dhcpInfoFieldIds.dns1, dns1); 451 env->SetIntField(info, dhcpInfoFieldIds.dns2, dns2); 452 env->SetIntField(info, dhcpInfoFieldIds.serverAddress, server); 453 env->SetIntField(info, dhcpInfoFieldIds.leaseDuration, lease); 454 } 455 return succeeded; 456} 457 458static jstring android_net_wifi_getDhcpError(JNIEnv* env, jobject clazz) 459{ 460 return env->NewStringUTF(::get_dhcp_error_string()); 461} 462 463// ---------------------------------------------------------------------------- 464 465/* 466 * JNI registration. 467 */ 468static JNINativeMethod gWifiMethods[] = { 469 /* name, signature, funcPtr */ 470 471 { "loadDriver", "()Z", (void *)android_net_wifi_loadDriver }, 472 { "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver }, 473 { "startSupplicant", "()Z", (void *)android_net_wifi_startSupplicant }, 474 { "stopSupplicant", "()Z", (void *)android_net_wifi_stopSupplicant }, 475 { "connectToSupplicant", "()Z", (void *)android_net_wifi_connectToSupplicant }, 476 { "closeSupplicantConnection", "()V", (void *)android_net_wifi_closeSupplicantConnection }, 477 478 { "listNetworksCommand", "()Ljava/lang/String;", 479 (void*) android_net_wifi_listNetworksCommand }, 480 { "addNetworkCommand", "()I", (void*) android_net_wifi_addNetworkCommand }, 481 { "setNetworkVariableCommand", "(ILjava/lang/String;Ljava/lang/String;)Z", 482 (void*) android_net_wifi_setNetworkVariableCommand }, 483 { "getNetworkVariableCommand", "(ILjava/lang/String;)Ljava/lang/String;", 484 (void*) android_net_wifi_getNetworkVariableCommand }, 485 { "removeNetworkCommand", "(I)Z", (void*) android_net_wifi_removeNetworkCommand }, 486 { "enableNetworkCommand", "(IZ)Z", (void*) android_net_wifi_enableNetworkCommand }, 487 { "disableNetworkCommand", "(I)Z", (void*) android_net_wifi_disableNetworkCommand }, 488 { "waitForEvent", "()Ljava/lang/String;", (void*) android_net_wifi_waitForEvent }, 489 { "statusCommand", "()Ljava/lang/String;", (void*) android_net_wifi_statusCommand }, 490 { "scanResultsCommand", "()Ljava/lang/String;", (void*) android_net_wifi_scanResultsCommand }, 491 { "pingCommand", "()Z", (void *)android_net_wifi_pingCommand }, 492 { "disconnectCommand", "()Z", (void *)android_net_wifi_disconnectCommand }, 493 { "reconnectCommand", "()Z", (void *)android_net_wifi_reconnectCommand }, 494 { "reassociateCommand", "()Z", (void *)android_net_wifi_reassociateCommand }, 495 { "scanCommand", "()Z", (void*) android_net_wifi_scanCommand }, 496 { "setScanModeCommand", "(Z)Z", (void*) android_net_wifi_setScanModeCommand }, 497 { "startDriverCommand", "()Z", (void*) android_net_wifi_startDriverCommand }, 498 { "stopDriverCommand", "()Z", (void*) android_net_wifi_stopDriverCommand }, 499 { "startPacketFiltering", "()Z", (void*) android_net_wifi_startPacketFiltering }, 500 { "stopPacketFiltering", "()Z", (void*) android_net_wifi_stopPacketFiltering }, 501 { "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand }, 502 { "setNumAllowedChannelsCommand", "(I)Z", (void*) android_net_wifi_setNumAllowedChannelsCommand }, 503 { "getNumAllowedChannelsCommand", "()I", (void*) android_net_wifi_getNumAllowedChannelsCommand }, 504 { "setBluetoothCoexistenceModeCommand", "(I)Z", 505 (void*) android_net_wifi_setBluetoothCoexistenceModeCommand }, 506 { "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand }, 507 { "getLinkSpeedCommand", "()I", (void*) android_net_wifi_getLinkSpeedCommand }, 508 { "getMacAddressCommand", "()Ljava/lang/String;", (void*) android_net_wifi_getMacAddressCommand }, 509 { "saveConfigCommand", "()Z", (void*) android_net_wifi_saveConfigCommand }, 510 { "reloadConfigCommand", "()Z", (void*) android_net_wifi_reloadConfigCommand }, 511 { "setScanResultHandlingCommand", "(I)Z", (void*) android_net_wifi_setScanResultHandlingCommand }, 512 { "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand }, 513 { "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand }, 514 515 { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest }, 516 { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError }, 517}; 518 519int register_android_net_wifi_WifiManager(JNIEnv* env) 520{ 521 jclass wifi = env->FindClass(WIFI_PKG_NAME); 522 LOG_FATAL_IF(wifi == NULL, "Unable to find class " WIFI_PKG_NAME); 523 524 dhcpInfoFieldIds.dhcpInfoClass = env->FindClass("android/net/DhcpInfo"); 525 if (dhcpInfoFieldIds.dhcpInfoClass != NULL) { 526 dhcpInfoFieldIds.constructorId = env->GetMethodID(dhcpInfoFieldIds.dhcpInfoClass, "<init>", "()V"); 527 dhcpInfoFieldIds.ipaddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "ipAddress", "I"); 528 dhcpInfoFieldIds.gateway = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "gateway", "I"); 529 dhcpInfoFieldIds.netmask = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "netmask", "I"); 530 dhcpInfoFieldIds.dns1 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns1", "I"); 531 dhcpInfoFieldIds.dns2 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns2", "I"); 532 dhcpInfoFieldIds.serverAddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "serverAddress", "I"); 533 dhcpInfoFieldIds.leaseDuration = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "leaseDuration", "I"); 534 } 535 536 return AndroidRuntime::registerNativeMethods(env, 537 WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods)); 538} 539 540}; // namespace android 541