1 /* userchan.c - HCI User Channel based Bluetooth driver */
2
3 /*
4 * Copyright (c) 2018 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr.h>
10 #include <device.h>
11 #include <init.h>
12 #include <sys/util.h>
13 #include <sys/byteorder.h>
14
15 #include <errno.h>
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <poll.h>
19 #include <errno.h>
20 #include <sys/socket.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include "soc.h"
25 #include "cmdline.h" /* native_posix command line options header */
26
27 #include <bluetooth/bluetooth.h>
28 #include <bluetooth/hci.h>
29 #include <drivers/bluetooth/hci_driver.h>
30
31 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
32 #define LOG_MODULE_NAME bt_driver
33 #include "common/log.h"
34
35 #define BTPROTO_HCI 1
36 struct sockaddr_hci {
37 sa_family_t hci_family;
38 unsigned short hci_dev;
39 unsigned short hci_channel;
40 };
41 #define HCI_CHANNEL_USER 1
42
43 #define SOL_HCI 0
44
45 #define H4_CMD 0x01
46 #define H4_ACL 0x02
47 #define H4_SCO 0x03
48 #define H4_EVT 0x04
49 #define H4_ISO 0x05
50
51 static K_KERNEL_STACK_DEFINE(rx_thread_stack,
52 CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);
53 static struct k_thread rx_thread_data;
54
55 static int uc_fd = -1;
56
57 static int bt_dev_index = -1;
58
get_rx(const uint8_t * buf)59 static struct net_buf *get_rx(const uint8_t *buf)
60 {
61 bool discardable = false;
62 k_timeout_t timeout = K_FOREVER;
63
64 switch (buf[0]) {
65 case H4_EVT:
66 if (buf[1] == BT_HCI_EVT_LE_META_EVENT &&
67 (buf[3] == BT_HCI_EVT_LE_ADVERTISING_REPORT ||
68 buf[3] == BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT)) {
69 discardable = true;
70 timeout = K_NO_WAIT;
71 }
72
73 return bt_buf_get_evt(buf[1], discardable, timeout);
74 case H4_ACL:
75 return bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
76 case H4_ISO:
77 if (IS_ENABLED(CONFIG_BT_ISO)) {
78 return bt_buf_get_rx(BT_BUF_ISO_IN, K_FOREVER);
79 }
80 __fallthrough;
81 default:
82 BT_ERR("Unknown packet type: %u", buf[0]);
83 }
84
85 return NULL;
86 }
87
uc_ready(void)88 static bool uc_ready(void)
89 {
90 struct pollfd pollfd = { .fd = uc_fd, .events = POLLIN };
91
92 return (poll(&pollfd, 1, 0) == 1);
93 }
94
rx_thread(void * p1,void * p2,void * p3)95 static void rx_thread(void *p1, void *p2, void *p3)
96 {
97 ARG_UNUSED(p1);
98 ARG_UNUSED(p2);
99 ARG_UNUSED(p3);
100
101 BT_DBG("started");
102
103 while (1) {
104 static uint8_t frame[512];
105 struct net_buf *buf;
106 ssize_t len;
107
108 if (!uc_ready()) {
109 k_sleep(K_MSEC(1));
110 continue;
111 }
112
113 BT_DBG("calling read()");
114
115 len = read(uc_fd, frame, sizeof(frame));
116 if (len < 0) {
117 if (errno == EINTR) {
118 k_yield();
119 continue;
120 }
121
122 BT_ERR("Reading socket failed, errno %d", errno);
123 close(uc_fd);
124 uc_fd = -1;
125 return;
126 }
127
128 buf = get_rx(frame);
129 if (!buf) {
130 BT_DBG("Discard adv report due to insufficient buf");
131 continue;
132 }
133
134 net_buf_add_mem(buf, &frame[1], len - 1);
135
136 BT_DBG("Calling bt_recv(%p)", buf);
137
138 bt_recv(buf);
139
140 k_yield();
141 }
142 }
143
uc_send(struct net_buf * buf)144 static int uc_send(struct net_buf *buf)
145 {
146 BT_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
147
148 if (uc_fd < 0) {
149 BT_ERR("User channel not open");
150 return -EIO;
151 }
152
153 switch (bt_buf_get_type(buf)) {
154 case BT_BUF_ACL_OUT:
155 net_buf_push_u8(buf, H4_ACL);
156 break;
157 case BT_BUF_CMD:
158 net_buf_push_u8(buf, H4_CMD);
159 break;
160 case BT_BUF_ISO_OUT:
161 if (IS_ENABLED(CONFIG_BT_ISO)) {
162 net_buf_push_u8(buf, H4_ISO);
163 break;
164 }
165 __fallthrough;
166 default:
167 BT_ERR("Unknown buffer type");
168 return -EINVAL;
169 }
170
171 if (write(uc_fd, buf->data, buf->len) < 0) {
172 return -errno;
173 }
174
175 net_buf_unref(buf);
176 return 0;
177 }
178
user_chan_open(uint16_t index)179 static int user_chan_open(uint16_t index)
180 {
181 struct sockaddr_hci addr;
182 int fd;
183
184 fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
185 BTPROTO_HCI);
186 if (fd < 0) {
187 return -errno;
188 }
189
190 (void)memset(&addr, 0, sizeof(addr));
191 addr.hci_family = AF_BLUETOOTH;
192 addr.hci_dev = index;
193 addr.hci_channel = HCI_CHANNEL_USER;
194
195 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
196 int err = -errno;
197
198 close(fd);
199 return err;
200 }
201
202 return fd;
203 }
204
uc_open(void)205 static int uc_open(void)
206 {
207 if (bt_dev_index < 0) {
208 BT_ERR("No Bluetooth device specified");
209 return -ENODEV;
210 }
211
212 BT_DBG("hci%d", bt_dev_index);
213
214 uc_fd = user_chan_open(bt_dev_index);
215 if (uc_fd < 0) {
216 return uc_fd;
217 }
218
219 BT_DBG("User Channel opened as fd %d", uc_fd);
220
221 k_thread_create(&rx_thread_data, rx_thread_stack,
222 K_KERNEL_STACK_SIZEOF(rx_thread_stack),
223 rx_thread, NULL, NULL, NULL,
224 K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO),
225 0, K_NO_WAIT);
226
227 BT_DBG("returning");
228
229 return 0;
230 }
231
232 static const struct bt_hci_driver drv = {
233 .name = "HCI User Channel",
234 .bus = BT_HCI_DRIVER_BUS_UART,
235 .open = uc_open,
236 .send = uc_send,
237 };
238
bt_uc_init(const struct device * unused)239 static int bt_uc_init(const struct device *unused)
240 {
241 ARG_UNUSED(unused);
242
243 bt_hci_driver_register(&drv);
244
245 return 0;
246 }
247
248 SYS_INIT(bt_uc_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
249
cmd_bt_dev_found(char * argv,int offset)250 static void cmd_bt_dev_found(char *argv, int offset)
251 {
252 if (strncmp(&argv[offset], "hci", 3) || strlen(&argv[offset]) < 4) {
253 posix_print_error_and_exit("Error: Invalid Bluetooth device "
254 "name '%s' (should be e.g. hci0)\n",
255 &argv[offset]);
256 return;
257 }
258
259 bt_dev_index = strtol(&argv[offset + 3], NULL, 10);
260 }
261
add_btuserchan_arg(void)262 static void add_btuserchan_arg(void)
263 {
264 static struct args_struct_t btuserchan_args[] = {
265 /*
266 * Fields:
267 * manual, mandatory, switch,
268 * option_name, var_name ,type,
269 * destination, callback,
270 * description
271 */
272 { false, true, false,
273 "bt-dev", "hciX", 's',
274 NULL, cmd_bt_dev_found,
275 "A local HCI device to be used for Bluetooth (e.g. hci0)" },
276 ARG_TABLE_ENDMARKER
277 };
278
279 native_add_command_line_opts(btuserchan_args);
280 }
281
btuserchan_check_arg(void)282 static void btuserchan_check_arg(void)
283 {
284 if (bt_dev_index < 0) {
285 posix_print_error_and_exit("Error: Bluetooth device missing. "
286 "Specify one using --bt-dev=hciN\n");
287 }
288 }
289
290 NATIVE_TASK(add_btuserchan_arg, PRE_BOOT_1, 10);
291 NATIVE_TASK(btuserchan_check_arg, PRE_BOOT_2, 10);
292