1ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/*
2ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Copyright (C) 2011 The Android Open Source Project
3ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh *
4ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
5ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * you may not use this file except in compliance with the License.
6ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * You may obtain a copy of the License at
7ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh *
8ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
9ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh *
10ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
11ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
12ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * See the License for the specific language governing permissions and
14ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * limitations under the License.
15ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */
16ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
17ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#define LOG_NDEBUG 0
18ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
19ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#define LOG_TAG "VpnJni"
20ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <cutils/log.h>
21ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
22ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <stdio.h>
23ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <string.h>
24ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <sys/ioctl.h>
25ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <sys/types.h>
26ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <sys/stat.h>
27ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <sys/socket.h>
28ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <netinet/in.h>
29ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <arpa/inet.h>
30ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <errno.h>
31ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <fcntl.h>
32ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
33ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <linux/if.h>
34ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <linux/if_tun.h>
35ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <linux/route.h>
36ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <linux/ipv6_route.h>
37ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
38ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include "jni.h"
39ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include "JNIHelp.h"
40ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
41ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehnamespace android
42ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
43ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
44f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int inet4 = -1;
45f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int inet6 = -1;
46f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
47ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic inline in_addr_t *as_in_addr(sockaddr *sa) {
48ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return &((sockaddr_in *)sa)->sin_addr.s_addr;
49ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
50ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
51ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh//------------------------------------------------------------------------------
52ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
53ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#define SYSTEM_ERROR -1
54ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#define BAD_ARGUMENT -2
55ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
5697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic int create_interface(int mtu)
57ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
58f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
59ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
60ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifreq ifr4;
61ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&ifr4, 0, sizeof(ifr4));
62ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
63ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    // Allocate interface.
646224b5ec3857d78e92bbc21075717eaa228ff891Chia-chi Yeh    ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
65ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (ioctl(tun, TUNSETIFF, &ifr4)) {
663762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot allocate TUN: %s", strerror(errno));
67ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        goto error;
68ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
69ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
70ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    // Activate interface.
71ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifr4.ifr_flags = IFF_UP;
72ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) {
733762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno));
74ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        goto error;
75ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
76ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
773663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh    // Set MTU if it is specified.
783663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh    ifr4.ifr_mtu = mtu;
793663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh    if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
803762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
813663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh        goto error;
823663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh    }
833663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh
84ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return tun;
85ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
86ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeherror:
87ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    close(tun);
88ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return SYSTEM_ERROR;
89ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
90ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
9197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic int get_interface_name(char *name, int tun)
9297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh{
9397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    ifreq ifr4;
9497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (ioctl(tun, TUNGETIFF, &ifr4)) {
953762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot get interface name: %s", strerror(errno));
9697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        return SYSTEM_ERROR;
9797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
9897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    strncpy(name, ifr4.ifr_name, IFNAMSIZ);
9997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    return 0;
10097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh}
10197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh
10297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic int get_interface_index(const char *name)
103f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh{
104f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    ifreq ifr4;
10597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
10697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
1073762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot get index of %s: %s", name, strerror(errno));
10897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        return SYSTEM_ERROR;
10997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
11097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    return ifr4.ifr_ifindex;
11197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh}
11297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh
11397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic int set_addresses(const char *name, const char *addresses)
11497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh{
11597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    int index = get_interface_index(name);
11697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (index < 0) {
11797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        return index;
11897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
11997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh
12097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    ifreq ifr4;
121ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&ifr4, 0, sizeof(ifr4));
122f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
12336673698078cb47e777418cadc4115a65bc5947dChia-chi Yeh    ifr4.ifr_addr.sa_family = AF_INET;
12497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    ifr4.ifr_netmask.sa_family = AF_INET;
125ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
126ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    in6_ifreq ifr6;
127ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&ifr6, 0, sizeof(ifr6));
128ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifr6.ifr6_ifindex = index;
129ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
130ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    char address[65];
131ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int prefix;
132ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int chars;
133ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int count = 0;
134ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
135ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
136ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        addresses += chars;
137ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
138ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        if (strchr(address, ':')) {
139ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            // Add an IPv6 address.
140ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 ||
141ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                    prefix < 0 || prefix > 128) {
142ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = BAD_ARGUMENT;
143ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
144ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
145ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
146ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            ifr6.ifr6_prefixlen = prefix;
147ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (ioctl(inet6, SIOCSIFADDR, &ifr6)) {
148ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
149ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
150ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
151ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        } else {
152ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            // Add an IPv4 address.
153ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 ||
154ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                    prefix < 0 || prefix > 32) {
155ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = BAD_ARGUMENT;
156ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
157ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
158ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
159ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (count) {
160ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                sprintf(ifr4.ifr_name, "%s:%d", name, count);
161ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
162ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (ioctl(inet4, SIOCSIFADDR, &ifr4)) {
163ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
164ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
165ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
166ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
167ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
16897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh            *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
169ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
170ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
171ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
172ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
173ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        }
1745baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Address added on %s: %s/%d", name, address, prefix);
175ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        ++count;
176ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
177ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
178ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (count == BAD_ARGUMENT) {
1793762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Invalid address: %s/%d", address, prefix);
180ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else if (count == SYSTEM_ERROR) {
1813762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno));
182ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else if (*addresses) {
1833762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Invalid address: %s", addresses);
184ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        count = BAD_ARGUMENT;
185ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
186ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
187ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return count;
188ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
189ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
19097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic int set_routes(const char *name, const char *routes)
191ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
19297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    int index = get_interface_index(name);
19397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (index < 0) {
19497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        return index;
19597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
19697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh
197ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rtentry rt4;
198ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&rt4, 0, sizeof(rt4));
199ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rt4.rt_dev = (char *)name;
200ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rt4.rt_flags = RTF_UP;
20136673698078cb47e777418cadc4115a65bc5947dChia-chi Yeh    rt4.rt_dst.sa_family = AF_INET;
20236673698078cb47e777418cadc4115a65bc5947dChia-chi Yeh    rt4.rt_genmask.sa_family = AF_INET;
203ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
204ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    in6_rtmsg rt6;
205ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&rt6, 0, sizeof(rt6));
206ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rt6.rtmsg_ifindex = index;
207ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rt6.rtmsg_flags = RTF_UP;
208ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
209ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    char address[65];
210ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int prefix;
211ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int chars;
212ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int count = 0;
213ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
2148ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh    while (sscanf(routes, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
215ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        routes += chars;
216ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
217ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        if (strchr(address, ':')) {
218ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            // Add an IPv6 route.
2198ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh            if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 ||
220f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    prefix < 0 || prefix > 128) {
221ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = BAD_ARGUMENT;
222ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
223ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
224ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
225f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            rt6.rtmsg_dst_len = prefix ? prefix : 1;
22623a5e4bcdcf7d3fef9aaa6c4a20f9f08f22ca9a6Chia-chi Yeh            if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
227ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
228ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
229ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
230f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
231f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            if (!prefix) {
232f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                // Split the route instead of replacing the default route.
233f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                rt6.rtmsg_dst.s6_addr[0] ^= 0x80;
234f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
235f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    count = SYSTEM_ERROR;
236f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    break;
237f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                }
238f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            }
239ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        } else {
240ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            // Add an IPv4 route.
2418ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh            if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 ||
242f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    prefix < 0 || prefix > 32) {
243ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = BAD_ARGUMENT;
244ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
245ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
246ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
2479c0835fd7262c50cf6a91380df1654daffe2c977Chia-chi Yeh            in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000;
248ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            *as_in_addr(&rt4.rt_genmask) = htonl(mask);
24923a5e4bcdcf7d3fef9aaa6c4a20f9f08f22ca9a6Chia-chi Yeh            if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
250ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
251ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
252ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
253f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
254f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            if (!prefix) {
255f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                // Split the route instead of replacing the default route.
256f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000);
257f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
258f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    count = SYSTEM_ERROR;
259f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    break;
260f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                }
261f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            }
262ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        }
2635baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Route added on %s: %s/%d", name, address, prefix);
264ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        ++count;
265ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
266ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
267ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (count == BAD_ARGUMENT) {
2683762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Invalid route: %s/%d", address, prefix);
269ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else if (count == SYSTEM_ERROR) {
2703762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot add route: %s/%d: %s",
2718ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh                address, prefix, strerror(errno));
272ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else if (*routes) {
2733762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Invalid route: %s", routes);
274ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        count = BAD_ARGUMENT;
275ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
276ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
277ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return count;
278ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
279ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
280ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic int reset_interface(const char *name)
281ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
282ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifreq ifr4;
283ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
284f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    ifr4.ifr_flags = 0;
285ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
286ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
2873762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot reset %s: %s", name, strerror(errno));
288ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return SYSTEM_ERROR;
289ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
290ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return 0;
291ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
292ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
293ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic int check_interface(const char *name)
294ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
295ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifreq ifr4;
296ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
2976ddd57491a06da3ee56056b088424500c144063aChia-chi Yeh    ifr4.ifr_flags = 0;
298ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
299ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
3003762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot check %s: %s", name, strerror(errno));
301ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
302ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return ifr4.ifr_flags;
303ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
304ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
305c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yehstatic int bind_to_interface(int socket, const char *name)
306ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
307c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh    if (setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
3083762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Cannot bind socket to %s: %s", name, strerror(errno));
309ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return SYSTEM_ERROR;
310ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
311ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return 0;
312ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
313ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
314ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh//------------------------------------------------------------------------------
315ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
316ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic void throwException(JNIEnv *env, int error, const char *message)
317ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
318ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (error == SYSTEM_ERROR) {
319ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException", message);
320ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else {
321ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", message);
322ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
323ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
324ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
32597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic jint create(JNIEnv *env, jobject thiz, jint mtu)
326ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
32797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    int tun = create_interface(mtu);
328ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (tun < 0) {
329ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        throwException(env, tun, "Cannot create interface");
33036673698078cb47e777418cadc4115a65bc5947dChia-chi Yeh        return -1;
331ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
33297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    return tun;
33397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh}
334ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
33597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic jstring getName(JNIEnv *env, jobject thiz, jint tun)
33697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh{
33797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    char name[IFNAMSIZ];
33897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (get_interface_name(name, tun) < 0) {
33997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        throwException(env, SYSTEM_ERROR, "Cannot get interface name");
34097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        return NULL;
34197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
34297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    return env->NewStringUTF(name);
34397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh}
34497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh
34597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
34697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        jstring jAddresses)
34797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh{
34897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    const char *name = NULL;
349f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *addresses = NULL;
35097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    int count = -1;
351f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
35297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
35397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (!name) {
35497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        jniThrowNullPointerException(env, "name");
35597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        goto error;
35697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
357ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
358ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (!addresses) {
35997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        jniThrowNullPointerException(env, "addresses");
360ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        goto error;
361ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
36297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    count = set_addresses(name, addresses);
36397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (count < 0) {
364ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        throwException(env, count, "Cannot set address");
36597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        count = -1;
366ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
3673281034c1c458b4eecd867d20b64dc5edd68ec14Chia-chi Yeh
368f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeherror:
36997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (name) {
37097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        env->ReleaseStringUTFChars(jName, name);
37197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
37297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (addresses) {
37397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        env->ReleaseStringUTFChars(jAddresses, addresses);
37497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
37597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    return count;
3763281034c1c458b4eecd867d20b64dc5edd68ec14Chia-chi Yeh}
3773281034c1c458b4eecd867d20b64dc5edd68ec14Chia-chi Yeh
37897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehstatic jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
37997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        jstring jRoutes)
3803281034c1c458b4eecd867d20b64dc5edd68ec14Chia-chi Yeh{
38197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    const char *name = NULL;
38297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    const char *routes = NULL;
38397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    int count = -1;
38497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh
38597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
38697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (!name) {
38797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        jniThrowNullPointerException(env, "name");
38897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        goto error;
389f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
39097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
39197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (!routes) {
39297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        jniThrowNullPointerException(env, "routes");
39397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        goto error;
39497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
39597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    count = set_routes(name, routes);
39697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (count < 0) {
39797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        throwException(env, count, "Cannot set route");
39897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        count = -1;
39997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
40097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh
40197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeherror:
40297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (name) {
40397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        env->ReleaseStringUTFChars(jName, name);
40497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
40597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    if (routes) {
40697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh        env->ReleaseStringUTFChars(jRoutes, routes);
40797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    }
40897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    return count;
409ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
410ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
411c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yehstatic void reset(JNIEnv *env, jobject thiz, jstring jName)
412ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
413f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
414ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (!name) {
415ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowNullPointerException(env, "name");
416ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return;
417ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
418ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (reset_interface(name) < 0) {
419ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        throwException(env, SYSTEM_ERROR, "Cannot reset interface");
420ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
421ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    env->ReleaseStringUTFChars(jName, name);
422ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
423ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
424c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yehstatic jint check(JNIEnv *env, jobject thiz, jstring jName)
425ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
426f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
427ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (!name) {
428ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowNullPointerException(env, "name");
429ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return 0;
430ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
431ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int flags = check_interface(name);
432ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    env->ReleaseStringUTFChars(jName, name);
433ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return flags;
434ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
435ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
436c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yehstatic void protect(JNIEnv *env, jobject thiz, jint socket, jstring jName)
437ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
438f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
439ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (!name) {
440ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowNullPointerException(env, "name");
441ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return;
442ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
443c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh    if (bind_to_interface(socket, name) < 0) {
444ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        throwException(env, SYSTEM_ERROR, "Cannot protect socket");
445ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
446ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    env->ReleaseStringUTFChars(jName, name);
447ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
448ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
449ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh//------------------------------------------------------------------------------
450ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
451ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic JNINativeMethod gMethods[] = {
45297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    {"jniCreate", "(I)I", (void *)create},
453c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh    {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
45497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
45597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh    {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
456c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh    {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
457c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh    {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
458c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh    {"jniProtect", "(ILjava/lang/String;)V", (void *)protect},
459ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh};
460ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
461ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehint register_android_server_connectivity_Vpn(JNIEnv *env)
462ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
463f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (inet4 == -1) {
464f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        inet4 = socket(AF_INET, SOCK_DGRAM, 0);
465f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
466f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (inet6 == -1) {
467f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
468f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
469ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
470ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            gMethods, NELEM(gMethods));
471ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
472ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
473ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh};
474