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 #define LOG_TAG "VtsOffloadConfigV1_0TargetTest"
18
19 #include <VtsHalHidlTargetTestBase.h>
20 #include <VtsHalHidlTargetTestEnvBase.h>
21 #include <android-base/stringprintf.h>
22 #include <android-base/unique_fd.h>
23 #include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
24 #include <linux/netfilter/nfnetlink.h>
25 #include <linux/netlink.h>
26 #include <linux/rtnetlink.h>
27 #include <log/log.h>
28 #include <sys/socket.h>
29 #include <unistd.h>
30 #include <set>
31
32 using android::base::StringPrintf;
33 using android::base::unique_fd;
34 using android::hardware::hidl_handle;
35 using android::hardware::hidl_string;
36 using android::hardware::Return;
37 using android::hardware::tetheroffload::config::V1_0::IOffloadConfig;
38 using android::hardware::Void;
39 using android::sp;
40
41 #define ASSERT_TRUE_CALLBACK \
42 [&](bool success, const hidl_string& errMsg) { ASSERT_TRUE(success) << errMsg.c_str(); }
43
44 #define ASSERT_FALSE_CALLBACK \
45 [&](bool success, const hidl_string& errMsg) { ASSERT_FALSE(success) << errMsg.c_str(); }
46
47 const unsigned kFd1Groups = NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY;
48 const unsigned kFd2Groups = NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY;
49
asSockaddr(const sockaddr_nl * nladdr)50 inline const sockaddr* asSockaddr(const sockaddr_nl* nladdr) {
51 return reinterpret_cast<const sockaddr*>(nladdr);
52 }
53
netlinkSocket(int protocol,unsigned groups)54 int netlinkSocket(int protocol, unsigned groups) {
55 unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, protocol));
56 if (s.get() < 0) {
57 return -errno;
58 }
59
60 const struct sockaddr_nl bind_addr = {
61 .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups,
62 };
63 if (::bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) {
64 return -errno;
65 }
66
67 const struct sockaddr_nl kernel_addr = {
68 .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups,
69 };
70 if (::connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
71 return -errno;
72 }
73
74 return s.release();
75 }
76
netlinkSocket(unsigned groups)77 int netlinkSocket(unsigned groups) {
78 return netlinkSocket(NETLINK_NETFILTER, groups);
79 }
80
81 // Test environment for OffloadConfig HIDL HAL.
82 class OffloadConfigHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
83 public:
84 // get the test environment singleton
Instance()85 static OffloadConfigHidlEnvironment* Instance() {
86 static OffloadConfigHidlEnvironment* instance = new OffloadConfigHidlEnvironment;
87 return instance;
88 }
89
registerTestServices()90 virtual void registerTestServices() override { registerTestService<IOffloadConfig>(); }
91 private:
OffloadConfigHidlEnvironment()92 OffloadConfigHidlEnvironment() {}
93 };
94
95 class OffloadConfigHidlTest : public testing::VtsHalHidlTargetTestBase {
96 public:
SetUp()97 virtual void SetUp() override {
98 config = testing::VtsHalHidlTargetTestBase::getService<IOffloadConfig>(
99 OffloadConfigHidlEnvironment::Instance()->getServiceName<IOffloadConfig>());
100 ASSERT_NE(nullptr, config.get()) << "Could not get HIDL instance";
101 }
102
TearDown()103 virtual void TearDown() override {}
104
105 sp<IOffloadConfig> config;
106 };
107
108 // Ensure handles can be set with correct socket options.
TEST_F(OffloadConfigHidlTest,TestSetHandles)109 TEST_F(OffloadConfigHidlTest, TestSetHandles) {
110 // Try multiple times in a row to see if it provokes file descriptor leaks.
111 for (int i = 0; i < 1024; i++) {
112 unique_fd fd1(netlinkSocket(kFd1Groups));
113 if (fd1.get() < 0) {
114 ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
115 FAIL();
116 }
117 native_handle_t* const nativeHandle1 = native_handle_create(1, 0);
118 nativeHandle1->data[0] = fd1.release();
119 hidl_handle h1;
120 h1.setTo(nativeHandle1, true);
121
122 unique_fd fd2(netlinkSocket(kFd2Groups));
123 if (fd2.get() < 0) {
124 ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
125 FAIL();
126 }
127 native_handle_t* const nativeHandle2 = native_handle_create(1, 0);
128 nativeHandle2->data[0] = fd2.release();
129 hidl_handle h2;
130 h2.setTo(nativeHandle2, true);
131
132 const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK);
133 ASSERT_TRUE(ret.isOk());
134 }
135 }
136
137 // Passing a handle without an associated file descriptor should return an error
138 // (e.g. "Failed Input Checks"). Check that this occurs when both FDs are empty.
TEST_F(OffloadConfigHidlTest,TestSetHandleNone)139 TEST_F(OffloadConfigHidlTest, TestSetHandleNone) {
140 native_handle_t* const nativeHandle1 = native_handle_create(0, 0);
141 hidl_handle h1;
142 h1.setTo(nativeHandle1, true);
143 native_handle_t* const nativeHandle2 = native_handle_create(0, 0);
144 hidl_handle h2;
145 h2.setTo(nativeHandle2, true);
146
147 const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK);
148 ASSERT_TRUE(ret.isOk());
149 }
150
151 // Passing a handle without an associated file descriptor should return an error
152 // (e.g. "Failed Input Checks"). Check that this occurs when FD2 is empty.
TEST_F(OffloadConfigHidlTest,TestSetHandle1Only)153 TEST_F(OffloadConfigHidlTest, TestSetHandle1Only) {
154 unique_fd fd1(netlinkSocket(kFd1Groups));
155 if (fd1.get() < 0) {
156 ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
157 FAIL();
158 }
159 native_handle_t* const nativeHandle1 = native_handle_create(1, 0);
160 nativeHandle1->data[0] = fd1.release();
161 hidl_handle h1;
162 h1.setTo(nativeHandle1, true);
163
164 native_handle_t* const nativeHandle2 = native_handle_create(0, 0);
165 hidl_handle h2;
166 h2.setTo(nativeHandle2, true);
167
168 const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK);
169 ASSERT_TRUE(ret.isOk());
170 }
171
172 // Passing a handle without an associated file descriptor should return an error
173 // (e.g. "Failed Input Checks"). Check that this occurs when FD1 is empty.
TEST_F(OffloadConfigHidlTest,TestSetHandle2OnlyNotOk)174 TEST_F(OffloadConfigHidlTest, TestSetHandle2OnlyNotOk) {
175 native_handle_t* const nativeHandle1 = native_handle_create(0, 0);
176 hidl_handle h1;
177 h1.setTo(nativeHandle1, true);
178
179 unique_fd fd2(netlinkSocket(kFd2Groups));
180 if (fd2.get() < 0) {
181 ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
182 FAIL();
183 }
184 native_handle_t* const nativeHandle2 = native_handle_create(1, 0);
185 nativeHandle2->data[0] = fd2.release();
186 hidl_handle h2;
187 h2.setTo(nativeHandle2, true);
188
189 const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK);
190 ASSERT_TRUE(ret.isOk());
191 }
192
main(int argc,char ** argv)193 int main(int argc, char** argv) {
194 ::testing::AddGlobalTestEnvironment(OffloadConfigHidlEnvironment::Instance());
195 ::testing::InitGoogleTest(&argc, argv);
196 OffloadConfigHidlEnvironment::Instance()->init(&argc, argv);
197 int status = RUN_ALL_TESTS();
198 ALOGE("Test result with status=%d", status);
199 return status;
200 }
201