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 "NetUtils"
18
19#include "jni.h"
20#include <utils/misc.h>
21#include <android_runtime/AndroidRuntime.h>
22#include <utils/Log.h>
23#include <arpa/inet.h>
24#include <cutils/properties.h>
25
26extern "C" {
27int ifc_enable(const char *ifname);
28int ifc_disable(const char *ifname);
29int ifc_reset_connections(const char *ifname, int reset_mask);
30
31int dhcp_do_request(const char * const ifname,
32                    const char *ipaddr,
33                    const char *gateway,
34                    uint32_t *prefixLength,
35                    const char *dns[],
36                    const char *server,
37                    uint32_t *lease,
38                    const char *vendorInfo,
39                    const char *domains);
40
41int dhcp_do_request_renew(const char * const ifname,
42                    const char *ipaddr,
43                    const char *gateway,
44                    uint32_t *prefixLength,
45                    const char *dns[],
46                    const char *server,
47                    uint32_t *lease,
48                    const char *vendorInfo,
49                    const char *domains);
50
51int dhcp_stop(const char *ifname);
52int dhcp_release_lease(const char *ifname);
53char *dhcp_get_errmsg();
54}
55
56#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
57
58namespace android {
59
60/*
61 * The following remembers the jfieldID's of the fields
62 * of the DhcpInfo Java object, so that we don't have
63 * to look them up every time.
64 */
65static struct fieldIds {
66    jmethodID clear;
67    jmethodID setInterfaceName;
68    jmethodID addLinkAddress;
69    jmethodID addGateway;
70    jmethodID addDns;
71    jmethodID setDomains;
72    jmethodID setServerAddress;
73    jmethodID setLeaseDuration;
74    jmethodID setVendorInfo;
75} dhcpResultsFieldIds;
76
77static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
78{
79    int result;
80
81    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
82    result = ::ifc_enable(nameStr);
83    env->ReleaseStringUTFChars(ifname, nameStr);
84    return (jint)result;
85}
86
87static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
88{
89    int result;
90
91    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
92    result = ::ifc_disable(nameStr);
93    env->ReleaseStringUTFChars(ifname, nameStr);
94    return (jint)result;
95}
96
97static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
98      jstring ifname, jint mask)
99{
100    int result;
101
102    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
103
104    ALOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
105          env, clazz, nameStr, mask);
106
107    result = ::ifc_reset_connections(nameStr, mask);
108    env->ReleaseStringUTFChars(ifname, nameStr);
109    return (jint)result;
110}
111
112static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
113        jobject dhcpResults, bool renew)
114{
115    int result;
116    char  ipaddr[PROPERTY_VALUE_MAX];
117    uint32_t prefixLength;
118    char gateway[PROPERTY_VALUE_MAX];
119    char    dns1[PROPERTY_VALUE_MAX];
120    char    dns2[PROPERTY_VALUE_MAX];
121    char    dns3[PROPERTY_VALUE_MAX];
122    char    dns4[PROPERTY_VALUE_MAX];
123    const char *dns[5] = {dns1, dns2, dns3, dns4, NULL};
124    char  server[PROPERTY_VALUE_MAX];
125    uint32_t lease;
126    char vendorInfo[PROPERTY_VALUE_MAX];
127    char domains[PROPERTY_VALUE_MAX];
128
129    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
130    if (nameStr == NULL) return (jboolean)false;
131
132    if (renew) {
133        result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
134                dns, server, &lease, vendorInfo, domains);
135    } else {
136        result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
137                dns, server, &lease, vendorInfo, domains);
138    }
139    if (result != 0) {
140        ALOGD("dhcp_do_request failed");
141    }
142
143    env->ReleaseStringUTFChars(ifname, nameStr);
144    if (result == 0) {
145        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
146
147        // set mIfaceName
148        // dhcpResults->setInterfaceName(ifname)
149        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setInterfaceName, ifname);
150
151        // set the linkAddress
152        // dhcpResults->addLinkAddress(inetAddress, prefixLength)
153        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addLinkAddress,
154                env->NewStringUTF(ipaddr), prefixLength);
155    }
156
157    if (result == 0) {
158        // set the gateway
159        // dhcpResults->addGateway(gateway)
160        result = env->CallBooleanMethod(dhcpResults,
161                dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway));
162    }
163
164    if (result == 0) {
165        // dhcpResults->addDns(new InetAddress(dns1))
166        result = env->CallBooleanMethod(dhcpResults,
167                dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1));
168    }
169
170    if (result == 0) {
171        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains,
172                env->NewStringUTF(domains));
173
174        result = env->CallBooleanMethod(dhcpResults,
175                dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2));
176
177        if (result == 0) {
178            result = env->CallBooleanMethod(dhcpResults,
179                    dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3));
180            if (result == 0) {
181                result = env->CallBooleanMethod(dhcpResults,
182                        dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4));
183            }
184        }
185    }
186
187    if (result == 0) {
188        // dhcpResults->setServerAddress(new InetAddress(server))
189        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress,
190                env->NewStringUTF(server));
191    }
192
193    if (result == 0) {
194        // dhcpResults->setLeaseDuration(lease)
195        env->CallVoidMethod(dhcpResults,
196                dhcpResultsFieldIds.setLeaseDuration, lease);
197
198        // dhcpResults->setVendorInfo(vendorInfo)
199        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo,
200                env->NewStringUTF(vendorInfo));
201    }
202    return (jboolean)(result == 0);
203}
204
205
206static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
207{
208    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
209}
210
211static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
212{
213    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
214}
215
216
217static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
218{
219    int result;
220
221    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
222    result = ::dhcp_stop(nameStr);
223    env->ReleaseStringUTFChars(ifname, nameStr);
224    return (jboolean)(result == 0);
225}
226
227static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
228{
229    int result;
230
231    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
232    result = ::dhcp_release_lease(nameStr);
233    env->ReleaseStringUTFChars(ifname, nameStr);
234    return (jboolean)(result == 0);
235}
236
237static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
238{
239    return env->NewStringUTF(::dhcp_get_errmsg());
240}
241
242// ----------------------------------------------------------------------------
243
244/*
245 * JNI registration.
246 */
247static JNINativeMethod gNetworkUtilMethods[] = {
248    /* name, signature, funcPtr */
249
250    { "enableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_enableInterface },
251    { "disableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_disableInterface },
252    { "resetConnections", "(Ljava/lang/String;I)I",  (void *)android_net_utils_resetConnections },
253    { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z",  (void *)android_net_utils_runDhcp },
254    { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z",  (void *)android_net_utils_runDhcpRenew },
255    { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
256    { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
257    { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
258};
259
260int register_android_net_NetworkUtils(JNIEnv* env)
261{
262    jclass dhcpResultsClass = env->FindClass("android/net/DhcpResults");
263    LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults");
264    dhcpResultsFieldIds.clear =
265            env->GetMethodID(dhcpResultsClass, "clear", "()V");
266    dhcpResultsFieldIds.setInterfaceName =
267            env->GetMethodID(dhcpResultsClass, "setInterfaceName", "(Ljava/lang/String;)V");
268    dhcpResultsFieldIds.addLinkAddress =
269            env->GetMethodID(dhcpResultsClass, "addLinkAddress", "(Ljava/lang/String;I)Z");
270    dhcpResultsFieldIds.addGateway =
271            env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z");
272    dhcpResultsFieldIds.addDns =
273            env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z");
274    dhcpResultsFieldIds.setDomains =
275            env->GetMethodID(dhcpResultsClass, "setDomains", "(Ljava/lang/String;)V");
276    dhcpResultsFieldIds.setServerAddress =
277            env->GetMethodID(dhcpResultsClass, "setServerAddress", "(Ljava/lang/String;)Z");
278    dhcpResultsFieldIds.setLeaseDuration =
279            env->GetMethodID(dhcpResultsClass, "setLeaseDuration", "(I)V");
280    dhcpResultsFieldIds.setVendorInfo =
281            env->GetMethodID(dhcpResultsClass, "setVendorInfo", "(Ljava/lang/String;)V");
282
283    return AndroidRuntime::registerNativeMethods(env,
284            NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
285}
286
287}; // namespace android
288