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