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 <ScopedUtfChars.h>
21#include <utils/misc.h>
22#include <android_runtime/AndroidRuntime.h>
23#include <utils/Log.h>
24#include <utils/String16.h>
25
26#include "wifi.h"
27
28#define WIFI_PKG_NAME "android/net/wifi/WifiNative"
29#define BUF_SIZE 256
30#define EVENT_BUF_SIZE 2048
31
32namespace android {
33
34static jint DBG = false;
35
36static int doCommand(const char *ifname, const char *cmd, char *replybuf, int replybuflen)
37{
38    size_t reply_len = replybuflen - 1;
39
40    if (::wifi_command(ifname, cmd, replybuf, &reply_len) != 0)
41        return -1;
42    else {
43        // Strip off trailing newline
44        if (reply_len > 0 && replybuf[reply_len-1] == '\n')
45            replybuf[reply_len-1] = '\0';
46        else
47            replybuf[reply_len] = '\0';
48        return 0;
49    }
50}
51
52static jint doIntCommand(const char *ifname, const char* fmt, ...)
53{
54    char buf[BUF_SIZE];
55    va_list args;
56    va_start(args, fmt);
57    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
58    va_end(args);
59    if (byteCount < 0 || byteCount >= BUF_SIZE) {
60        return -1;
61    }
62    char reply[BUF_SIZE];
63    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
64        return -1;
65    }
66    return static_cast<jint>(atoi(reply));
67}
68
69static jboolean doBooleanCommand(const char *ifname, const char* expect, const char* fmt, ...)
70{
71    char buf[BUF_SIZE];
72    va_list args;
73    va_start(args, fmt);
74    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
75    va_end(args);
76    if (byteCount < 0 || byteCount >= BUF_SIZE) {
77        return JNI_FALSE;
78    }
79    char reply[BUF_SIZE];
80    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
81        return JNI_FALSE;
82    }
83    return (strcmp(reply, expect) == 0);
84}
85
86// Send a command to the supplicant, and return the reply as a String
87static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt, ...) {
88    char buf[BUF_SIZE];
89    va_list args;
90    va_start(args, fmt);
91    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
92    va_end(args);
93    if (byteCount < 0 || byteCount >= BUF_SIZE) {
94        return NULL;
95    }
96    char reply[4096];
97    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
98        return NULL;
99    }
100    // TODO: why not just NewStringUTF?
101    String16 str((char *)reply);
102    return env->NewString((const jchar *)str.string(), str.size());
103}
104
105static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject)
106{
107    return (jboolean)(::is_wifi_driver_loaded() == 1);
108}
109
110static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
111{
112    return (jboolean)(::wifi_load_driver() == 0);
113}
114
115static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject)
116{
117    return (jboolean)(::wifi_unload_driver() == 0);
118}
119
120static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
121{
122    return (jboolean)(::wifi_start_supplicant(p2pSupported) == 0);
123}
124
125static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject)
126{
127    return (jboolean)(::wifi_stop_supplicant() == 0);
128}
129
130static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface)
131{
132    ScopedUtfChars ifname(env, jIface);
133    return (jboolean)(::wifi_connect_to_supplicant(ifname.c_str()) == 0);
134}
135
136static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject, jstring jIface)
137{
138    ScopedUtfChars ifname(env, jIface);
139    ::wifi_close_supplicant_connection(ifname.c_str());
140}
141
142static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIface)
143{
144    char buf[EVENT_BUF_SIZE];
145    ScopedUtfChars ifname(env, jIface);
146    int nread = ::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf);
147    if (nread > 0) {
148        return env->NewStringUTF(buf);
149    } else {
150        return NULL;
151    }
152}
153
154static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jIface,
155        jstring jCommand)
156{
157    ScopedUtfChars ifname(env, jIface);
158    ScopedUtfChars command(env, jCommand);
159
160    if (command.c_str() == NULL) {
161        return JNI_FALSE;
162    }
163    if (DBG) ALOGD("doBoolean: %s", command.c_str());
164    return doBooleanCommand(ifname.c_str(), "OK", "%s", command.c_str());
165}
166
167static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jIface,
168        jstring jCommand)
169{
170    ScopedUtfChars ifname(env, jIface);
171    ScopedUtfChars command(env, jCommand);
172
173    if (command.c_str() == NULL) {
174        return -1;
175    }
176    if (DBG) ALOGD("doInt: %s", command.c_str());
177    return doIntCommand(ifname.c_str(), "%s", command.c_str());
178}
179
180static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jIface,
181        jstring jCommand)
182{
183    ScopedUtfChars ifname(env, jIface);
184
185    ScopedUtfChars command(env, jCommand);
186    if (command.c_str() == NULL) {
187        return NULL;
188    }
189    if (DBG) ALOGD("doString: %s", command.c_str());
190    return doStringCommand(env, ifname.c_str(), "%s", command.c_str());
191}
192
193
194
195// ----------------------------------------------------------------------------
196
197/*
198 * JNI registration.
199 */
200static JNINativeMethod gWifiMethods[] = {
201    /* name, signature, funcPtr */
202
203    { "loadDriver", "()Z",  (void *)android_net_wifi_loadDriver },
204    { "isDriverLoaded", "()Z",  (void *)android_net_wifi_isDriverLoaded },
205    { "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },
206    { "startSupplicant", "(Z)Z",  (void *)android_net_wifi_startSupplicant },
207    { "killSupplicant", "()Z",  (void *)android_net_wifi_killSupplicant },
208    { "connectToSupplicant", "(Ljava/lang/String;)Z",
209            (void *)android_net_wifi_connectToSupplicant },
210    { "closeSupplicantConnection", "(Ljava/lang/String;)V",
211            (void *)android_net_wifi_closeSupplicantConnection },
212    { "waitForEvent", "(Ljava/lang/String;)Ljava/lang/String;",
213            (void*) android_net_wifi_waitForEvent },
214    { "doBooleanCommand", "(Ljava/lang/String;Ljava/lang/String;)Z",
215            (void*) android_net_wifi_doBooleanCommand },
216    { "doIntCommand", "(Ljava/lang/String;Ljava/lang/String;)I",
217            (void*) android_net_wifi_doIntCommand },
218    { "doStringCommand", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
219            (void*) android_net_wifi_doStringCommand },
220};
221
222int register_android_net_wifi_WifiManager(JNIEnv* env)
223{
224    return AndroidRuntime::registerNativeMethods(env,
225            WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));
226}
227
228}; // namespace android
229