hciemu: Call btdev_receive_h4 unconditionally
[platform/upstream/bluez.git] / emulator / vhci.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2011-2014  Intel Corporation
7  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
8  *
9  *
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #include <stdio.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/uio.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <dirent.h>
26
27 #include "lib/bluetooth.h"
28 #include "lib/hci.h"
29
30 #include "src/shared/io.h"
31 #include "monitor/bt.h"
32 #include "btdev.h"
33 #include "vhci.h"
34
35 #define DEBUGFS_PATH "/sys/kernel/debug/bluetooth"
36 #define DEVCORE_PATH "/sys/class/devcoredump"
37
38 struct vhci {
39         enum btdev_type type;
40         uint16_t index;
41         struct io *io;
42         struct btdev *btdev;
43 };
44
45 static void vhci_destroy(void *user_data)
46 {
47         struct vhci *vhci = user_data;
48
49         btdev_destroy(vhci->btdev);
50         io_destroy(vhci->io);
51
52         free(vhci);
53 }
54
55 static void vhci_write_callback(const struct iovec *iov, int iovlen,
56                                                         void *user_data)
57 {
58         struct vhci *vhci = user_data;
59         ssize_t written;
60
61         written = io_send(vhci->io, iov, iovlen);
62         if (written < 0)
63                 return;
64 }
65
66 static bool vhci_read_callback(struct io *io, void *user_data)
67 {
68         struct vhci *vhci = user_data;
69         int fd = io_get_fd(vhci->io);
70         unsigned char buf[4096];
71         ssize_t len;
72
73         len = read(fd, buf, sizeof(buf));
74         if (len < 1)
75                 return false;
76
77         btdev_receive_h4(vhci->btdev, buf, len);
78
79         return true;
80 }
81
82 bool vhci_set_debug(struct vhci *vhci, vhci_debug_func_t callback,
83                         void *user_data, vhci_destroy_func_t destroy)
84 {
85         if (!vhci)
86                 return false;
87
88         return btdev_set_debug(vhci->btdev, callback, user_data, destroy);
89 }
90
91 struct vhci_create_req {
92         uint8_t  pkt_type;
93         uint8_t  opcode;
94 } __attribute__((packed));
95
96 struct vhci_create_rsp {
97         uint8_t  pkt_type;
98         uint8_t  opcode;
99         uint16_t index;
100 } __attribute__((packed));
101
102 struct vhci *vhci_open(uint8_t type)
103 {
104         struct vhci *vhci;
105         struct vhci_create_req req;
106         struct vhci_create_rsp rsp;
107         int fd;
108
109         fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
110         if (fd < 0)
111                 return NULL;
112
113         memset(&req, 0, sizeof(req));
114         req.pkt_type = HCI_VENDOR_PKT;
115
116         switch (type) {
117         case BTDEV_TYPE_AMP:
118                 req.opcode = HCI_AMP;
119                 break;
120         default:
121                 req.opcode = HCI_PRIMARY;
122                 break;
123         }
124
125         if (write(fd, &req, sizeof(req)) < 0) {
126                 close(fd);
127                 return NULL;
128         }
129
130         memset(&rsp, 0, sizeof(rsp));
131
132         if (read(fd, &rsp, sizeof(rsp)) < 0) {
133                 close(fd);
134                 return NULL;
135         }
136
137         vhci = malloc(sizeof(*vhci));
138         if (!vhci) {
139                 close(fd);
140                 return NULL;
141         }
142
143         memset(vhci, 0, sizeof(*vhci));
144         vhci->type = type;
145         vhci->index = rsp.index;
146         vhci->io = io_new(fd);
147
148         io_set_close_on_destroy(vhci->io, true);
149
150         vhci->btdev = btdev_create(type, rsp.index);
151         if (!vhci->btdev) {
152                 vhci_destroy(vhci);
153                 return NULL;
154         }
155
156         btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci);
157
158         if (!io_set_read_handler(vhci->io, vhci_read_callback, vhci, NULL)) {
159                 vhci_destroy(vhci);
160                 return NULL;
161         }
162
163         return vhci;
164 }
165
166 void vhci_close(struct vhci *vhci)
167 {
168         if (!vhci)
169                 return;
170
171         vhci_destroy(vhci);
172 }
173
174 bool vhci_pause_input(struct vhci *vhci, bool paused)
175 {
176         if (paused)
177                 return io_set_read_handler(vhci->io, NULL, NULL, NULL);
178         else
179                 return io_set_read_handler(vhci->io, vhci_read_callback, vhci,
180                                                                         NULL);
181 }
182
183 struct btdev *vhci_get_btdev(struct vhci *vhci)
184 {
185         if (!vhci)
186                 return NULL;
187
188         return vhci->btdev;
189 }
190
191 static int vhci_debugfs_write(struct vhci *vhci, char *option, const void *data,
192                               size_t len)
193 {
194         char path[64];
195         int fd, err;
196         size_t n;
197
198         if (!vhci)
199                 return -EINVAL;
200
201         memset(path, 0, sizeof(path));
202         sprintf(path, DEBUGFS_PATH "/hci%d/%s", vhci->index, option);
203
204         fd = open(path, O_RDWR);
205         if (fd < 0)
206                 return -errno;
207
208         n = write(fd, data, len);
209         if (n == len)
210                 err = 0;
211         else
212                 err = -errno;
213
214         close(fd);
215
216         return err;
217 }
218
219 int vhci_set_force_suspend(struct vhci *vhci, bool enable)
220 {
221         char val;
222
223         val = (enable) ? 'Y' : 'N';
224
225         return vhci_debugfs_write(vhci, "force_suspend", &val, sizeof(val));
226 }
227
228 int vhci_set_force_wakeup(struct vhci *vhci, bool enable)
229 {
230         char val;
231
232         val = (enable) ? 'Y' : 'N';
233
234         return vhci_debugfs_write(vhci, "force_wakeup", &val, sizeof(val));
235 }
236
237 int vhci_set_msft_opcode(struct vhci *vhci, uint16_t opcode)
238 {
239         int err;
240         char val[7];
241
242         snprintf(val, sizeof(val), "0x%4x", opcode);
243
244         err = vhci_debugfs_write(vhci, "msft_opcode", &val, sizeof(val));
245         if (err)
246                 return err;
247
248         return btdev_set_msft_opcode(vhci->btdev, opcode);
249 }
250
251 int vhci_set_aosp_capable(struct vhci *vhci, bool enable)
252 {
253         char val;
254
255         val = (enable) ? 'Y' : 'N';
256
257         return vhci_debugfs_write(vhci, "aosp_capable", &val, sizeof(val));
258 }
259
260 int vhci_set_emu_opcode(struct vhci *vhci, uint16_t opcode)
261 {
262         return btdev_set_emu_opcode(vhci->btdev, opcode);
263 }
264
265 int vhci_set_force_static_address(struct vhci *vhci, bool enable)
266 {
267         char val;
268
269         val = (enable) ? 'Y' : 'N';
270
271         return vhci_debugfs_write(vhci, "force_static_address", &val,
272                                                         sizeof(val));
273 }
274
275 int vhci_force_devcd(struct vhci *vhci, const void *data, size_t len)
276 {
277         return vhci_debugfs_write(vhci, "force_devcoredump", data, len);
278 }
279
280 int vhci_read_devcd(struct vhci *vhci, void *buf, size_t size)
281 {
282         DIR *dir;
283         struct dirent *entry;
284         char filename[PATH_MAX];
285         int fd;
286         int ret;
287
288         dir = opendir(DEVCORE_PATH);
289         if (dir == NULL)
290                 return -errno;
291
292         while ((entry = readdir(dir)) != NULL) {
293                 if (strstr(entry->d_name, "devcd"))
294                         break;
295         }
296
297         if (entry == NULL) {
298                 ret = -ENOENT;
299                 goto close_dir;
300         }
301
302         sprintf(filename, DEVCORE_PATH "/%s/data", entry->d_name);
303         fd  = open(filename, O_RDWR);
304         if (fd < 0) {
305                 ret = -errno;
306                 goto close_dir;
307         }
308
309         ret = read(fd, buf, size);
310         if (ret < 0) {
311                 ret = -errno;
312                 goto close_file;
313         }
314
315         /* Once the devcoredump is read, write anything to it to mark it for
316          * cleanup.
317          */
318         if (write(fd, "0", 1) < 0) {
319                 ret = -errno;
320                 goto close_file;
321         }
322
323 close_file:
324         close(fd);
325
326 close_dir:
327         closedir(dir);
328
329         return ret;
330 }