1 /*
2  * Copyright (C) 2022 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 #include <jni.h>
18 #include <nativehelper/JNIHelp.h>
19 #include <nativehelper/scoped_utf_chars.h>
20 #include <tcutils/tcutils.h>
21 
22 #define BPF_FD_JUST_USE_INT
23 #include "BpfSyscallWrappers.h"
24 
25 namespace android {
26 
throwIOException(JNIEnv * env,const char * msg,int error)27 static void throwIOException(JNIEnv *env, const char *msg, int error) {
28   jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg,
29                        strerror(error));
30 }
31 
com_android_net_module_util_TcUtils_isEthernet(JNIEnv * env,jclass clazz,jstring iface)32 static jboolean com_android_net_module_util_TcUtils_isEthernet(JNIEnv *env,
33                                                                jclass clazz,
34                                                                jstring iface) {
35   ScopedUtfChars interface(env, iface);
36   bool result = false;
37   int error = isEthernet(interface.c_str(), result);
38   if (error) {
39     throwIOException(
40         env, "com_android_net_module_util_TcUtils_isEthernet error: ", -error);
41   }
42   // result is not touched when error is returned; leave false.
43   return result;
44 }
45 
46 // tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned
47 // /sys/fs/bpf/... direct-action
com_android_net_module_util_TcUtils_tcFilterAddDevBpf(JNIEnv * env,jclass clazz,jint ifIndex,jboolean ingress,jshort prio,jshort proto,jstring bpfProgPath)48 static void com_android_net_module_util_TcUtils_tcFilterAddDevBpf(
49     JNIEnv *env, jclass clazz, jint ifIndex, jboolean ingress, jshort prio,
50     jshort proto, jstring bpfProgPath) {
51   ScopedUtfChars pathname(env, bpfProgPath);
52   int error = tcAddBpfFilter(ifIndex, ingress, prio, proto, pathname.c_str());
53   if (error) {
54     throwIOException(
55         env,
56         "com_android_net_module_util_TcUtils_tcFilterAddDevBpf error: ", -error);
57   }
58 }
59 
60 // tc filter add dev .. ingress prio .. protocol .. matchall \
61 //     action police rate .. burst .. conform-exceed pipe/continue \
62 //     action bpf object-pinned .. \
63 //     drop
com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice(JNIEnv * env,jclass clazz,jint ifIndex,jshort prio,jshort proto,jint rateInBytesPerSec,jstring bpfProgPath)64 static void com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice(
65     JNIEnv *env, jclass clazz, jint ifIndex, jshort prio, jshort proto,
66     jint rateInBytesPerSec, jstring bpfProgPath) {
67   ScopedUtfChars pathname(env, bpfProgPath);
68   int error = tcAddIngressPoliceFilter(ifIndex, prio, proto, rateInBytesPerSec,
69                                        pathname.c_str());
70   if (error) {
71     throwIOException(env,
72                      "com_android_net_module_util_TcUtils_"
73                      "tcFilterAddDevIngressPolice error: ",
74                      -error);
75   }
76 }
77 
78 // tc filter del dev .. in/egress prio .. protocol ..
com_android_net_module_util_TcUtils_tcFilterDelDev(JNIEnv * env,jclass clazz,jint ifIndex,jboolean ingress,jshort prio,jshort proto)79 static void com_android_net_module_util_TcUtils_tcFilterDelDev(
80     JNIEnv *env, jclass clazz, jint ifIndex, jboolean ingress, jshort prio,
81     jshort proto) {
82   int error = tcDeleteFilter(ifIndex, ingress, prio, proto);
83   if (error) {
84     throwIOException(
85         env,
86         "com_android_net_module_util_TcUtils_tcFilterDelDev error: ", -error);
87   }
88 }
89 
90 // tc qdisc add dev .. clsact
com_android_net_module_util_TcUtils_tcQdiscAddDevClsact(JNIEnv * env,jclass clazz,jint ifIndex)91 static void com_android_net_module_util_TcUtils_tcQdiscAddDevClsact(JNIEnv *env,
92                                                                     jclass clazz,
93                                                                     jint ifIndex) {
94   int error = tcAddQdiscClsact(ifIndex);
95   if (error) {
96     throwIOException(
97         env,
98         "com_android_net_module_util_TcUtils_tcQdiscAddDevClsact error: ", -error);
99   }
100 }
101 
com_android_net_module_util_TcUtils_isBpfProgramUsable(JNIEnv * env,jclass clazz,jstring bpfProgPath)102 static jboolean com_android_net_module_util_TcUtils_isBpfProgramUsable(JNIEnv *env,
103                                                                        jclass clazz,
104                                                                        jstring bpfProgPath) {
105     ScopedUtfChars pathname(env, bpfProgPath);
106     return bpf::usableProgram(pathname.c_str());
107 }
108 
109 
110 /*
111  * JNI registration.
112  */
113 static const JNINativeMethod gMethods[] = {
114     /* name, signature, funcPtr */
115     {"isEthernet", "(Ljava/lang/String;)Z",
116      (void *)com_android_net_module_util_TcUtils_isEthernet},
117     {"tcFilterAddDevBpf", "(IZSSLjava/lang/String;)V",
118      (void *)com_android_net_module_util_TcUtils_tcFilterAddDevBpf},
119     {"tcFilterAddDevIngressPolice", "(ISSILjava/lang/String;)V",
120      (void *)com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice},
121     {"tcFilterDelDev", "(IZSS)V",
122      (void *)com_android_net_module_util_TcUtils_tcFilterDelDev},
123     {"tcQdiscAddDevClsact", "(I)V",
124      (void *)com_android_net_module_util_TcUtils_tcQdiscAddDevClsact},
125     {"isBpfProgramUsable", "(Ljava/lang/String;)Z",
126      (void *)com_android_net_module_util_TcUtils_isBpfProgramUsable},
127 };
128 
register_com_android_net_module_util_TcUtils(JNIEnv * env,char const * class_name)129 int register_com_android_net_module_util_TcUtils(JNIEnv *env,
130                                                  char const *class_name) {
131   return jniRegisterNativeMethods(env, class_name, gMethods, NELEM(gMethods));
132 }
133 
134 }; // namespace android
135