1 /* 2 * Copyright (C) 2017 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 <errno.h> 18 #include <error.h> 19 #include <hidl/HidlSupport.h> 20 #include <jni.h> 21 #include <nativehelper/JNIHelp.h> 22 #include <linux/netfilter/nfnetlink.h> 23 #include <linux/netlink.h> 24 #include <sys/socket.h> 25 #include <android-base/unique_fd.h> 26 #include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h> 27 28 #define LOG_TAG "OffloadHardwareInterface" 29 #include <utils/Log.h> 30 31 namespace android { 32 33 using hardware::hidl_handle; 34 using hardware::hidl_string; 35 using hardware::tetheroffload::config::V1_0::IOffloadConfig; 36 37 namespace { 38 39 inline const sockaddr * asSockaddr(const sockaddr_nl *nladdr) { 40 return reinterpret_cast<const sockaddr *>(nladdr); 41 } 42 43 int conntrackSocket(unsigned groups) { 44 base::unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER)); 45 if (s.get() < 0) return -errno; 46 47 const struct sockaddr_nl bind_addr = { 48 .nl_family = AF_NETLINK, 49 .nl_pad = 0, 50 .nl_pid = 0, 51 .nl_groups = groups, 52 }; 53 if (bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) { 54 return -errno; 55 } 56 57 const struct sockaddr_nl kernel_addr = { 58 .nl_family = AF_NETLINK, 59 .nl_pad = 0, 60 .nl_pid = 0, 61 .nl_groups = groups, 62 }; 63 if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) { 64 return -errno; 65 } 66 67 return s.release(); 68 } 69 70 // Return a hidl_handle that owns the file descriptor owned by fd, and will 71 // auto-close it (otherwise there would be double-close problems). 72 // 73 // Rely upon the compiler to eliminate the constexprs used for clarity. 74 hidl_handle handleFromFileDescriptor(base::unique_fd fd) { 75 hidl_handle h; 76 77 static constexpr int kNumFds = 1; 78 static constexpr int kNumInts = 0; 79 native_handle_t *nh = native_handle_create(kNumFds, kNumInts); 80 nh->data[0] = fd.release(); 81 82 static constexpr bool kTakeOwnership = true; 83 h.setTo(nh, kTakeOwnership); 84 85 return h; 86 } 87 88 } // namespace 89 90 static jboolean android_server_connectivity_tethering_OffloadHardwareInterface_configOffload( 91 JNIEnv* /* env */) { 92 sp<IOffloadConfig> configInterface = IOffloadConfig::getService(); 93 if (configInterface.get() == nullptr) { 94 ALOGD("Could not find IOffloadConfig service."); 95 return false; 96 } 97 98 // Per the IConfigOffload definition: 99 // 100 // fd1 A file descriptor bound to the following netlink groups 101 // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY). 102 // 103 // fd2 A file descriptor bound to the following netlink groups 104 // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). 105 base::unique_fd 106 fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY)), 107 fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY)); 108 if (fd1.get() < 0 || fd2.get() < 0) { 109 ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno)); 110 return false; 111 } 112 113 hidl_handle h1(handleFromFileDescriptor(std::move(fd1))), 114 h2(handleFromFileDescriptor(std::move(fd2))); 115 116 bool rval(false); 117 hidl_string msg; 118 const auto status = configInterface->setHandles(h1, h2, 119 [&rval, &msg](bool success, const hidl_string& errMsg) { 120 rval = success; 121 msg = errMsg; 122 }); 123 if (!status.isOk() || !rval) { 124 ALOGE("IOffloadConfig::setHandles() error: '%s' / '%s'", 125 status.description().c_str(), msg.c_str()); 126 // If status is somehow not ok, make sure rval captures this too. 127 rval = false; 128 } 129 130 return rval; 131 } 132 133 /* 134 * JNI registration. 135 */ 136 static const JNINativeMethod gMethods[] = { 137 /* name, signature, funcPtr */ 138 { "configOffload", "()Z", 139 (void*) android_server_connectivity_tethering_OffloadHardwareInterface_configOffload }, 140 }; 141 142 int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv* env) { 143 return jniRegisterNativeMethods(env, 144 "com/android/server/connectivity/tethering/OffloadHardwareInterface", 145 gMethods, NELEM(gMethods)); 146 } 147 148 }; // namespace android 149