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
29 extern "C" {
30 int ifc_enable(const char *ifname);
31 int ifc_disable(const char *ifname);
32 int ifc_reset_connections(const char *ifname, int reset_mask);
33
34 int 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
45 int 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
56 int dhcp_stop(const char *ifname);
57 int dhcp_release_lease(const char *ifname);
58 char *dhcp_get_errmsg();
59 }
60
61 #define NETUTILS_PKG_NAME "android/net/NetworkUtils"
62
63 namespace 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 */
70 static struct fieldIds {
71 jmethodID clear;
72 jmethodID setInterfaceName;
73 jmethodID addLinkAddress;
74 jmethodID addGateway;
75 jmethodID addDns;
76 jmethodID setDomains;
77 jmethodID setServerAddress;
78 jmethodID setLeaseDuration;
79 jmethodID setVendorInfo;
80 } dhcpResultsFieldIds;
81
android_net_utils_enableInterface(JNIEnv * env,jobject clazz,jstring ifname)82 static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
83 {
84 int result;
85
86 const char *nameStr = env->GetStringUTFChars(ifname, NULL);
87 result = ::ifc_enable(nameStr);
88 env->ReleaseStringUTFChars(ifname, nameStr);
89 return (jint)result;
90 }
91
android_net_utils_disableInterface(JNIEnv * env,jobject clazz,jstring ifname)92 static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
93 {
94 int result;
95
96 const char *nameStr = env->GetStringUTFChars(ifname, NULL);
97 result = ::ifc_disable(nameStr);
98 env->ReleaseStringUTFChars(ifname, nameStr);
99 return (jint)result;
100 }
101
android_net_utils_resetConnections(JNIEnv * env,jobject clazz,jstring ifname,jint mask)102 static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
103 jstring ifname, jint mask)
104 {
105 int result;
106
107 const char *nameStr = env->GetStringUTFChars(ifname, NULL);
108
109 LOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
110 env, clazz, nameStr, mask);
111
112 result = ::ifc_reset_connections(nameStr, mask);
113 env->ReleaseStringUTFChars(ifname, nameStr);
114 return (jint)result;
115 }
116
android_net_utils_runDhcpCommon(JNIEnv * env,jobject clazz,jstring ifname,jobject dhcpResults,bool renew)117 static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
118 jobject dhcpResults, bool renew)
119 {
120 int result;
121 char ipaddr[PROPERTY_VALUE_MAX];
122 uint32_t prefixLength;
123 char gateway[PROPERTY_VALUE_MAX];
124 char dns1[PROPERTY_VALUE_MAX];
125 char dns2[PROPERTY_VALUE_MAX];
126 char dns3[PROPERTY_VALUE_MAX];
127 char dns4[PROPERTY_VALUE_MAX];
128 const char *dns[5] = {dns1, dns2, dns3, dns4, NULL};
129 char server[PROPERTY_VALUE_MAX];
130 uint32_t lease;
131 char vendorInfo[PROPERTY_VALUE_MAX];
132 char domains[PROPERTY_VALUE_MAX];
133 char mtu[PROPERTY_VALUE_MAX];
134
135 const char *nameStr = env->GetStringUTFChars(ifname, NULL);
136 if (nameStr == NULL) return (jboolean)false;
137
138 if (renew) {
139 result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
140 dns, server, &lease, vendorInfo, domains, mtu);
141 } else {
142 result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
143 dns, server, &lease, vendorInfo, domains, mtu);
144 }
145 if (result != 0) {
146 ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new");
147 }
148
149 env->ReleaseStringUTFChars(ifname, nameStr);
150 if (result == 0) {
151 env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
152
153 // set mIfaceName
154 // dhcpResults->setInterfaceName(ifname)
155 env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setInterfaceName, ifname);
156
157 // set the linkAddress
158 // dhcpResults->addLinkAddress(inetAddress, prefixLength)
159 result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addLinkAddress,
160 env->NewStringUTF(ipaddr), prefixLength);
161 }
162
163 if (result == 0) {
164 // set the gateway
165 // dhcpResults->addGateway(gateway)
166 result = env->CallBooleanMethod(dhcpResults,
167 dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway));
168 }
169
170 if (result == 0) {
171 // dhcpResults->addDns(new InetAddress(dns1))
172 result = env->CallBooleanMethod(dhcpResults,
173 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1));
174 }
175
176 if (result == 0) {
177 env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains,
178 env->NewStringUTF(domains));
179
180 result = env->CallBooleanMethod(dhcpResults,
181 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2));
182
183 if (result == 0) {
184 result = env->CallBooleanMethod(dhcpResults,
185 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3));
186 if (result == 0) {
187 result = env->CallBooleanMethod(dhcpResults,
188 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4));
189 }
190 }
191 }
192
193 if (result == 0) {
194 // dhcpResults->setServerAddress(new InetAddress(server))
195 result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress,
196 env->NewStringUTF(server));
197 }
198
199 if (result == 0) {
200 // dhcpResults->setLeaseDuration(lease)
201 env->CallVoidMethod(dhcpResults,
202 dhcpResultsFieldIds.setLeaseDuration, lease);
203
204 // dhcpResults->setVendorInfo(vendorInfo)
205 env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo,
206 env->NewStringUTF(vendorInfo));
207 }
208 return (jboolean)(result == 0);
209 }
210
211
android_net_utils_runDhcp(JNIEnv * env,jobject clazz,jstring ifname,jobject info)212 static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
213 {
214 return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
215 }
216
android_net_utils_runDhcpRenew(JNIEnv * env,jobject clazz,jstring ifname,jobject info)217 static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
218 {
219 return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
220 }
221
222
android_net_utils_stopDhcp(JNIEnv * env,jobject clazz,jstring ifname)223 static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
224 {
225 int result;
226
227 const char *nameStr = env->GetStringUTFChars(ifname, NULL);
228 result = ::dhcp_stop(nameStr);
229 env->ReleaseStringUTFChars(ifname, nameStr);
230 return (jboolean)(result == 0);
231 }
232
android_net_utils_releaseDhcpLease(JNIEnv * env,jobject clazz,jstring ifname)233 static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
234 {
235 int result;
236
237 const char *nameStr = env->GetStringUTFChars(ifname, NULL);
238 result = ::dhcp_release_lease(nameStr);
239 env->ReleaseStringUTFChars(ifname, nameStr);
240 return (jboolean)(result == 0);
241 }
242
android_net_utils_getDhcpError(JNIEnv * env,jobject clazz)243 static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
244 {
245 return env->NewStringUTF(::dhcp_get_errmsg());
246 }
247
android_net_utils_markSocket(JNIEnv * env,jobject thiz,jint socket,jint mark)248 static void android_net_utils_markSocket(JNIEnv *env, jobject thiz, jint socket, jint mark)
249 {
250 if (setsockopt(socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
251 jniThrowException(env, "java/lang/IllegalStateException", "Error marking socket");
252 }
253 }
254
android_net_utils_bindProcessToNetwork(JNIEnv * env,jobject thiz,jint netId)255 static void android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
256 {
257 setNetworkForProcess(netId);
258 }
259
android_net_utils_unbindProcessToNetwork(JNIEnv * env,jobject thiz)260 static void android_net_utils_unbindProcessToNetwork(JNIEnv *env, jobject thiz)
261 {
262 setNetworkForProcess(NETID_UNSET);
263 }
264
android_net_utils_getNetworkBoundToProcess(JNIEnv * env,jobject thiz)265 static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz)
266 {
267 return getNetworkForProcess();
268 }
269
android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv * env,jobject thiz,jint netId)270 static void android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz, jint netId)
271 {
272 setNetworkForResolv(netId);
273 }
274
android_net_utils_unbindProcessToNetworkForHostResolution(JNIEnv * env,jobject thiz)275 static void android_net_utils_unbindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz)
276 {
277 setNetworkForResolv(NETID_UNSET);
278 }
279
android_net_utils_bindSocketToNetwork(JNIEnv * env,jobject thiz,jint socket,jint netId)280 static void android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket, jint netId)
281 {
282 setNetworkForSocket(netId, socket);
283 }
284
285 // ----------------------------------------------------------------------------
286
287 /*
288 * JNI registration.
289 */
290 static JNINativeMethod gNetworkUtilMethods[] = {
291 /* name, signature, funcPtr */
292
293 { "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
294 { "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
295 { "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
296 { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_runDhcp },
297 { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_runDhcpRenew },
298 { "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
299 { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
300 { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
301 { "markSocket", "(II)V", (void*) android_net_utils_markSocket },
302 { "bindProcessToNetwork", "(I)V", (void*) android_net_utils_bindProcessToNetwork },
303 { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess },
304 { "unbindProcessToNetwork", "()V", (void*) android_net_utils_unbindProcessToNetwork },
305 { "bindProcessToNetworkForHostResolution", "(I)V", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
306 { "unbindProcessToNetworkForHostResolution", "()V", (void*) android_net_utils_unbindProcessToNetworkForHostResolution },
307 { "bindSocketToNetwork", "(II)V", (void*) android_net_utils_bindSocketToNetwork },
308 };
309
register_android_net_NetworkUtils(JNIEnv * env)310 int register_android_net_NetworkUtils(JNIEnv* env)
311 {
312 jclass dhcpResultsClass = env->FindClass("android/net/DhcpResults");
313 LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults");
314 dhcpResultsFieldIds.clear =
315 env->GetMethodID(dhcpResultsClass, "clear", "()V");
316 dhcpResultsFieldIds.setInterfaceName =
317 env->GetMethodID(dhcpResultsClass, "setInterfaceName", "(Ljava/lang/String;)V");
318 dhcpResultsFieldIds.addLinkAddress =
319 env->GetMethodID(dhcpResultsClass, "addLinkAddress", "(Ljava/lang/String;I)Z");
320 dhcpResultsFieldIds.addGateway =
321 env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z");
322 dhcpResultsFieldIds.addDns =
323 env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z");
324 dhcpResultsFieldIds.setDomains =
325 env->GetMethodID(dhcpResultsClass, "setDomains", "(Ljava/lang/String;)V");
326 dhcpResultsFieldIds.setServerAddress =
327 env->GetMethodID(dhcpResultsClass, "setServerAddress", "(Ljava/lang/String;)Z");
328 dhcpResultsFieldIds.setLeaseDuration =
329 env->GetMethodID(dhcpResultsClass, "setLeaseDuration", "(I)V");
330 dhcpResultsFieldIds.setVendorInfo =
331 env->GetMethodID(dhcpResultsClass, "setVendorInfo", "(Ljava/lang/String;)V");
332
333 return AndroidRuntime::registerNativeMethods(env,
334 NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
335 }
336
337 }; // namespace android
338