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