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 #pragma once
18 
19 #if defined(__TRUSTY__) and !defined(__QL_TIPC__)
20 #include <assert.h>
21 #include <lib/tidl/android-base/unique_fd.h>
22 #include <lib/tipc/tipc.h>
23 #include <lib/tipc/tipc_srv.h>
24 #include <lk/compiler.h>
25 #include <lk/err_ptr.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <trusty_ipc.h>
31 #include <uapi/trusty_uuid.h>
32 
33 #include <array>
34 #include <type_traits>
35 #include <utility>
36 #endif
37 
38 #if defined(__QL_TIPC__)
39 #include <lib/tidl/tidl_ql_tipc.h>
40 #include <trusty/sysdeps.h>
41 #include <trusty/trusty_ipc.h>
42 #endif
43 
44 #define TIDL_PACKED_ATTR __PACKED
45 
46 namespace tidl {
47 
48 #if !defined(__QL_TIPC__)
49 template <typename T, size_t N>
50 using Array = std::array<T, N>;
51 
52 template <typename T>
move(T && x)53 auto&& move(T&& x) {
54     return std::move(x);
55 }
56 #endif
57 
58 using Handle = handle_t;
59 
60 #if defined(__QL_TIPC__)
61 class handle {
62 public:
handle()63     handle() : mFd(INVALID_IPC_HANDLE) {}
handle(Handle fd)64     handle(Handle fd) : mFd(fd) {}
~handle()65     ~handle() { (void)reset(); }
ok()66     bool ok() const { return mFd != INVALID_IPC_HANDLE; }
67     int reset();
68     int reset(Handle fd);
69     Handle get();
70 
71 private:
72     Handle mFd;
73 };
74 #endif  // #if defined(__QL_TIPC__)
75 
76 struct TIDL_PACKED_ATTR RequestHeader {
77     uint32_t cmd;
78     uint32_t resp_payload_size;
79 };
80 
81 struct TIDL_PACKED_ATTR ResponseHeader {
82     uint32_t cmd;
83     uint32_t resp_payload_size;
84     int32_t rc;
85 };
86 
87 #if !defined(__QL_TIPC__)
88 class TIDL_PACKED_ATTR ParcelFileDescriptor {
89 public:
90     android::base::unique_fd handle;
91 
92     // Handle methods
93     static constexpr uint32_t num_handles = 1;
send_handles(handle_t * & hptr)94     void send_handles(handle_t*& hptr) { *hptr++ = handle.release(); }
recv_handles(handle_t * & hptr)95     void recv_handles(handle_t*& hptr) { handle.reset(*hptr++); }
96 
97 private:
98     // struct trusty_shm from Android has 2 32-bit fields
99     // so we reserve the space for the second one here
100     __UNUSED uint32_t reserved;
101 };
102 STATIC_ASSERT(sizeof(ParcelFileDescriptor) == 2 * sizeof(uint32_t));
103 #endif
104 
105 // Default implementation for all types without handles
106 template <typename T, typename = void>
107 class HandleOps {
108 public:
109     static constexpr uint32_t num_handles = 0;
send_handles(void *,handle_t * & hptr)110     static void send_handles(void*, handle_t*& hptr) {}
recv_handles(void *,handle_t * & hptr)111     static void recv_handles(void*, handle_t*& hptr) {}
112 };
113 
114 // HasHandleMembers<T> is equal to void for all types T
115 // that have the 3 members we need for HandleOps, and
116 // doesn't exist for any other types (triggering SFINAE below)
117 #if !defined(__QL_TIPC__)
118 template <typename T>
119 using HasHandleMembers = std::void_t<
120         decltype(T::num_handles),
121         decltype(std::declval<T>().send_handles(std::declval<handle_t*&>())),
122         decltype(std::declval<T>().recv_handles(std::declval<handle_t*&>()))>;
123 
124 // Specialization for types that implement their own handle methods
125 template <typename T>
126 class HandleOps<T, HasHandleMembers<T>> {
127 public:
128     static constexpr uint32_t num_handles = T::num_handles;
send_handles(void * x,handle_t * & hptr)129     static void send_handles(void* x, handle_t*& hptr) {
130         reinterpret_cast<T*>(x)->send_handles(hptr);
131     }
recv_handles(void * x,handle_t * & hptr)132     static void recv_handles(void* x, handle_t*& hptr) {
133         reinterpret_cast<T*>(x)->recv_handles(hptr);
134     }
135 };
136 #endif
137 
138 class Payload {
139 public:
Payload()140     Payload() : mData(nullptr), mSize(0) {}
Payload(uint8_t * data,uint32_t size)141     Payload(uint8_t* data, uint32_t size) : mData(data), mSize(size) {}
142     Payload(const Payload&) = delete;
143     Payload& operator=(const Payload&) = delete;
144 
Payload(Payload && other)145     Payload(Payload&& other) : mData(other.mData), mSize(other.mSize) {
146         other.reset();
147     }
148 
149     Payload& operator=(Payload&& other) {
150         mData = other.mData;
151         mSize = other.mSize;
152         other.reset();
153         return *this;
154     }
155 
data()156     const uint8_t* data() const { return mData; }
157 
data()158     uint8_t* data() { return mData; }
159 
size()160     uint32_t size() const { return mSize; }
161 
resize(uint32_t size)162     void resize(uint32_t size) { mSize = size; }
163 
164 private:
165     uint8_t* mData;
166     uint32_t mSize;
167 
reset()168     void reset() {
169         mData = nullptr;
170         mSize = 0;
171     }
172 };
173 
174 template <uint32_t S>
175 class FixedPayload {
176     static const uint32_t mSize = S;
177 
178 public:
FixedPayload()179     FixedPayload() {}
FixedPayload(uint8_t * data)180     FixedPayload(uint8_t* data) { memcpy(mData, data, S); }
181 
FixedPayload(const FixedPayload<S> & payload)182     FixedPayload(const FixedPayload<S>& payload) {
183         memcpy(mData, payload.data(), S);
184     }
185 
186     FixedPayload& operator=(const FixedPayload<S>& payload) {
187         memcpy(mData, payload.data(), S);
188         return *this;
189     }
190 
191     FixedPayload<S>& operator=(FixedPayload<S>&& other) {
192         memcpy(mData, other.mData, S);
193         return *this;
194     }
195 
data()196     const uint8_t* data() const { return mData; }
197 
data()198     uint8_t* data() { return mData; }
199 
size()200     uint32_t size() const { return mSize; }
201 
202 private:
203     uint8_t mData[S];
204 };
205 
206 #if !defined(__QL_TIPC__)
207 class Service {
208 public:
209     using Port = struct tipc_port;
210     using PortAcl = struct tipc_port_acl;
211     using Ops = struct tipc_srv_ops;
212     using HandleSet = struct tipc_hset*;
213 
214     Service() = delete;
Service(const char *,const char * port_name,uint32_t msg_max_size,const PortAcl * acl,const Ops * ops)215     Service(const char*,
216             const char* port_name,
217             uint32_t msg_max_size,
218             const PortAcl* acl,
219             const Ops* ops)
220             : mPort(), mOpsPtr(ops) {
221         mPort.name = port_name;
222         mPort.msg_max_size = msg_max_size;
223         mPort.msg_queue_len = 1;
224         mPort.acl = acl;
225         mPort.priv = this;
226     }
227 
set_max_channels(uint32_t max_chan_cnt)228     void set_max_channels(uint32_t max_chan_cnt) {
229         mMaxChannels = max_chan_cnt;
230     }
231 
add_service(HandleSet hset)232     int add_service(HandleSet hset) {
233         return tipc_add_service(hset, &mPort, 1, mMaxChannels, mOpsPtr);
234     }
235 
run_service(void)236     int run_service(void) {
237         HandleSet hset = tipc_hset_create();
238         if (IS_ERR(hset)) {
239             return PTR_ERR(hset);
240         }
241         int rc = add_service(hset);
242         if (rc < 0) {
243             return rc;
244         }
245         return tipc_run_event_loop(hset);
246     }
247 
248 protected:
get_payload_buffer(Payload &,uint32_t size,bool)249     virtual int get_payload_buffer(Payload&, uint32_t size, bool) {
250         if (!size) {
251             return NO_ERROR;
252         }
253         return ERR_NOT_IMPLEMENTED;
254     }
255 
free_payload_buffer(Payload)256     virtual void free_payload_buffer(Payload) {}
257 
258     Port mPort;
259     uint32_t mMaxChannels = 1;
260 
261 private:
262     const Ops* mOpsPtr;
263 };
264 #endif  // #if !defined(__QL_TIPC__)
265 
266 namespace ipc {
267 
268 #if !defined(__QL_TIPC__)
269 int connect(const char* path, uint32_t flags, android::base::unique_fd& out_fd);
270 #else
271 int connect(const char* path, uint32_t flags, ::tidl::handle& out_fd);
272 #endif
273 
274 int send(handle_t chan,
275          const void* buf,
276          size_t len,
277          handle_t* handles,
278          uint32_t num_handles);
279 int recv(handle_t chan,
280          size_t min_sz,
281          void* buf,
282          size_t buf_sz,
283          handle_t* handles,
284          uint32_t num_handles);
285 int send(handle_t chan,
286          const void* hdr,
287          size_t hdr_len,
288          const void* payload1,
289          size_t payload1_len,
290          handle_t* handles,
291          uint32_t num_handles);
292 int recv(handle_t chan,
293          size_t min_sz,
294          void* buf1,
295          size_t buf1_sz,
296          void* buf2,
297          size_t buf2_sz,
298          handle_t* handles,
299          uint32_t num_handles);
300 int send(handle_t chan,
301          const void* hdr,
302          size_t hdr_len,
303          const void* payload1,
304          size_t payload1_len,
305          const void* payload2,
306          size_t payload2_len,
307          handle_t* handles,
308          uint32_t num_handles);
309 int recv(handle_t chan,
310          size_t min_sz,
311          void* buf1,
312          size_t buf1_sz,
313          void* buf2,
314          size_t buf2_sz,
315          void* buf3,
316          size_t buf3_sz,
317          handle_t* handles,
318          uint32_t num_handles);
319 int wait_for_msg(handle_t chan);
320 }  // namespace ipc
321 
322 }  // namespace tidl
323