3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2012 Intel Corporation. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include <sys/socket.h>
37 #include "monitor/bt.h"
38 #include "emulator/btdev.h"
39 #include "emulator/bthost.h"
45 enum btdev_type btdev_type;
46 struct bthost *host_stack;
47 struct btdev *master_dev;
48 struct btdev *client_dev;
52 GList *post_command_hooks;
56 struct hciemu_command_hook {
57 hciemu_command_func_t function;
61 static void destroy_command_hook(gpointer data, gpointer user_data)
63 struct hciemu_command_hook *hook = data;
68 static void master_command_callback(uint16_t opcode,
69 const void *data, uint8_t len,
70 btdev_callback callback, void *user_data)
72 struct hciemu *hciemu = user_data;
75 btdev_command_default(callback);
77 for (list = g_list_first(hciemu->post_command_hooks); list;
78 list = g_list_next(list)) {
79 struct hciemu_command_hook *hook = list->data;
82 hook->function(opcode, data, len, hook->user_data);
86 static void client_command_callback(uint16_t opcode,
87 const void *data, uint8_t len,
88 btdev_callback callback, void *user_data)
90 btdev_command_default(callback);
93 static void write_callback(const void *data, uint16_t len, void *user_data)
95 GIOChannel *channel = user_data;
99 fd = g_io_channel_unix_get_fd(channel);
101 written = write(fd, data, len);
106 static gboolean receive_bthost(GIOChannel *channel, GIOCondition condition,
109 struct bthost *bthost = user_data;
110 unsigned char buf[4096];
114 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
117 fd = g_io_channel_unix_get_fd(channel);
119 len = read(fd, buf, sizeof(buf));
123 bthost_receive_h4(bthost, buf, len);
128 static guint create_source_bthost(int fd, struct bthost *bthost)
133 channel = g_io_channel_unix_new(fd);
135 g_io_channel_set_close_on_unref(channel, TRUE);
136 g_io_channel_set_encoding(channel, NULL, NULL);
137 g_io_channel_set_buffered(channel, FALSE);
139 bthost_set_send_handler(bthost, write_callback, channel);
141 source = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
142 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
143 receive_bthost, bthost, NULL);
145 g_io_channel_unref(channel);
150 static gboolean receive_btdev(GIOChannel *channel, GIOCondition condition,
153 struct btdev *btdev = user_data;
154 unsigned char buf[4096];
158 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
161 fd = g_io_channel_unix_get_fd(channel);
163 len = read(fd, buf, sizeof(buf));
167 btdev_receive_h4(btdev, buf, len);
172 static guint create_source_btdev(int fd, struct btdev *btdev)
177 channel = g_io_channel_unix_new(fd);
179 g_io_channel_set_close_on_unref(channel, TRUE);
180 g_io_channel_set_encoding(channel, NULL, NULL);
181 g_io_channel_set_buffered(channel, FALSE);
183 btdev_set_send_handler(btdev, write_callback, channel);
185 source = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
186 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
187 receive_btdev, btdev, NULL);
189 g_io_channel_unref(channel);
194 static bool create_vhci(struct hciemu *hciemu)
199 btdev = btdev_create(hciemu->btdev_type, 0x00);
203 btdev_set_command_handler(btdev, master_command_callback, hciemu);
205 fd = open("/dev/vhci", O_RDWR | O_NONBLOCK | O_CLOEXEC);
207 btdev_destroy(btdev);
211 hciemu->master_dev = btdev;
213 hciemu->master_source = create_source_btdev(fd, btdev);
218 static bool create_stack(struct hciemu *hciemu)
221 struct bthost *bthost;
224 btdev = btdev_create(hciemu->btdev_type, 0x00);
228 bthost = bthost_create();
230 btdev_destroy(btdev);
234 btdev_set_command_handler(btdev, client_command_callback, hciemu);
236 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
238 bthost_destroy(bthost);
239 btdev_destroy(btdev);
243 hciemu->client_dev = btdev;
244 hciemu->host_stack = bthost;
246 hciemu->client_source = create_source_btdev(sv[0], btdev);
247 hciemu->host_source = create_source_bthost(sv[1], bthost);
252 static gboolean start_stack(gpointer user_data)
254 struct hciemu *hciemu = user_data;
256 bthost_start(hciemu->host_stack);
261 struct hciemu *hciemu_new(enum hciemu_type type)
263 struct hciemu *hciemu;
265 hciemu = g_try_new0(struct hciemu, 1);
270 case HCIEMU_TYPE_BREDRLE:
271 hciemu->btdev_type = BTDEV_TYPE_BREDRLE;
273 case HCIEMU_TYPE_BREDR:
274 hciemu->btdev_type = BTDEV_TYPE_BREDR;
277 hciemu->btdev_type = BTDEV_TYPE_LE;
283 if (!create_vhci(hciemu)) {
288 if (!create_stack(hciemu)) {
289 g_source_remove(hciemu->master_source);
290 btdev_destroy(hciemu->master_dev);
295 g_idle_add(start_stack, hciemu);
297 return hciemu_ref(hciemu);
300 struct hciemu *hciemu_ref(struct hciemu *hciemu)
305 __sync_fetch_and_add(&hciemu->ref_count, 1);
310 void hciemu_unref(struct hciemu *hciemu)
315 if (__sync_sub_and_fetch(&hciemu->ref_count, 1) > 0)
318 g_list_foreach(hciemu->post_command_hooks, destroy_command_hook, NULL);
319 g_list_free(hciemu->post_command_hooks);
321 bthost_stop(hciemu->host_stack);
323 g_source_remove(hciemu->host_source);
324 g_source_remove(hciemu->client_source);
325 g_source_remove(hciemu->master_source);
327 bthost_destroy(hciemu->host_stack);
328 btdev_destroy(hciemu->client_dev);
329 btdev_destroy(hciemu->master_dev);
334 const char *hciemu_get_address(struct hciemu *hciemu)
338 if (!hciemu || !hciemu->master_dev)
341 addr = btdev_get_bdaddr(hciemu->master_dev);
342 sprintf(hciemu->bdaddr_str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
343 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
344 return hciemu->bdaddr_str;
347 bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
348 hciemu_command_func_t function, void *user_data)
350 struct hciemu_command_hook *hook;
355 hook = g_try_new0(struct hciemu_command_hook, 1);
359 hook->function = function;
360 hook->user_data = user_data;
362 hciemu->post_command_hooks = g_list_append(hciemu->post_command_hooks,