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