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