CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
orangepi-xunlong

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: orangepi-xunlong/orangepi-build
Path: blob/next/external/cache/sources/hcitools/monitor/hcidump.c
Views: 3959
1
/*
2
*
3
* BlueZ - Bluetooth protocol stack for Linux
4
*
5
* Copyright (C) 2011-2012 Intel Corporation
6
* Copyright (C) 2004-2010 Marcel Holtmann <[email protected]>
7
*
8
*
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
13
*
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
18
*
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
*
23
*/
24
25
#ifdef HAVE_CONFIG_H
26
#include <config.h>
27
#endif
28
29
#include <stdio.h>
30
#include <errno.h>
31
#include <unistd.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <fcntl.h>
35
#include <sys/types.h>
36
#include <sys/ioctl.h>
37
#include <sys/socket.h>
38
39
#include <bluetooth/bluetooth.h>
40
#include <bluetooth/hci.h>
41
#include <bluetooth/hci_lib.h>
42
43
#include "mainloop.h"
44
#include "packet.h"
45
#include "hcidump.h"
46
47
struct hcidump_data {
48
uint16_t index;
49
int fd;
50
};
51
52
static void free_data(void *user_data)
53
{
54
struct hcidump_data *data = user_data;
55
56
close(data->fd);
57
58
free(data);
59
}
60
61
static int open_hci_dev(uint16_t index)
62
{
63
struct sockaddr_hci addr;
64
struct hci_filter flt;
65
int fd, opt = 1;
66
67
fd = socket(AF_BLUETOOTH, SOCK_RAW | O_CLOEXEC, BTPROTO_HCI);
68
if (fd < 0) {
69
perror("Failed to open channel");
70
return -1;
71
}
72
73
/* Setup filter */
74
hci_filter_clear(&flt);
75
hci_filter_all_ptypes(&flt);
76
hci_filter_all_events(&flt);
77
78
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
79
perror("Failed to set HCI filter");
80
close(fd);
81
return -1;
82
}
83
84
if (setsockopt(fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
85
perror("Failed to enable HCI data direction info");
86
close(fd);
87
return -1;
88
}
89
90
if (setsockopt(fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
91
perror("Failed to enable HCI time stamps");
92
close(fd);
93
return -1;
94
}
95
96
memset(&addr, 0, sizeof(addr));
97
addr.hci_family = AF_BLUETOOTH;
98
addr.hci_dev = index;
99
addr.hci_channel = HCI_CHANNEL_RAW;
100
101
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
102
perror("Failed to bind channel");
103
close(fd);
104
return -1;
105
}
106
107
return fd;
108
}
109
110
static void device_callback(int fd, uint32_t events, void *user_data)
111
{
112
struct hcidump_data *data = user_data;
113
unsigned char buf[HCI_MAX_FRAME_SIZE * 2];
114
unsigned char control[64];
115
struct msghdr msg;
116
struct iovec iov;
117
118
if (events & (EPOLLERR | EPOLLHUP)) {
119
mainloop_remove_fd(fd);
120
return;
121
}
122
123
iov.iov_base = buf;
124
iov.iov_len = sizeof(buf);
125
126
memset(&msg, 0, sizeof(msg));
127
msg.msg_iov = &iov;
128
msg.msg_iovlen = 1;
129
msg.msg_control = control;
130
msg.msg_controllen = sizeof(control);
131
132
while (1) {
133
struct cmsghdr *cmsg;
134
struct timeval *tv = NULL;
135
struct timeval ctv;
136
int dir = -1;
137
ssize_t len;
138
139
len = recvmsg(fd, &msg, MSG_DONTWAIT);
140
if (len < 0)
141
break;
142
143
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
144
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
145
if (cmsg->cmsg_level != SOL_HCI)
146
continue;
147
148
switch (cmsg->cmsg_type) {
149
case HCI_DATA_DIR:
150
memcpy(&dir, CMSG_DATA(cmsg), sizeof(dir));
151
break;
152
case HCI_CMSG_TSTAMP:
153
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
154
tv = &ctv;
155
break;
156
}
157
}
158
159
if (dir < 0 || len < 1)
160
continue;
161
162
switch (buf[0]) {
163
case HCI_COMMAND_PKT:
164
packet_hci_command(tv, data->index, buf + 1, len - 1);
165
break;
166
case HCI_EVENT_PKT:
167
packet_hci_event(tv, data->index, buf + 1, len - 1);
168
break;
169
case HCI_ACLDATA_PKT:
170
packet_hci_acldata(tv, data->index, !!dir,
171
buf + 1, len - 1);
172
break;
173
case HCI_SCODATA_PKT:
174
packet_hci_scodata(tv, data->index, !!dir,
175
buf + 1, len - 1);
176
break;
177
}
178
}
179
}
180
181
static void open_device(uint16_t index)
182
{
183
struct hcidump_data *data;
184
185
data = malloc(sizeof(*data));
186
if (!data)
187
return;
188
189
memset(data, 0, sizeof(*data));
190
data->index = index;
191
192
data->fd = open_hci_dev(index);
193
if (data->fd < 0) {
194
free(data);
195
return;
196
}
197
198
mainloop_add_fd(data->fd, EPOLLIN, device_callback, data, free_data);
199
}
200
201
static void device_info(int fd, uint16_t index, uint8_t *type, uint8_t *bus,
202
bdaddr_t *bdaddr, char *name)
203
{
204
struct hci_dev_info di;
205
206
memset(&di, 0, sizeof(di));
207
di.dev_id = index;
208
209
if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0) {
210
perror("Failed to get device information");
211
return;
212
}
213
214
*type = di.type >> 4;
215
*bus = di.type & 0x0f;
216
217
bacpy(bdaddr, &di.bdaddr);
218
memcpy(name, di.name, 8);
219
}
220
221
static void device_list(int fd, int max_dev)
222
{
223
struct hci_dev_list_req *dl;
224
struct hci_dev_req *dr;
225
int i;
226
227
dl = malloc(max_dev * sizeof(*dr) + sizeof(*dl));
228
if (!dl) {
229
perror("Failed to allocate device list memory");
230
return;
231
}
232
233
memset(dl, 0, max_dev * sizeof(*dr) + sizeof(*dl));
234
dl->dev_num = max_dev;
235
236
dr = dl->dev_req;
237
238
if (ioctl(fd, HCIGETDEVLIST, (void *) dl) < 0) {
239
perror("Failed to get device list");
240
goto done;
241
}
242
243
for (i = 0; i < dl->dev_num; i++, dr++) {
244
struct timeval tmp_tv, *tv = NULL;
245
uint8_t type = 0xff, bus = 0xff;
246
char str[18], name[8] = "";
247
bdaddr_t bdaddr;
248
249
bacpy(&bdaddr, BDADDR_ANY);
250
251
if (!gettimeofday(&tmp_tv, NULL))
252
tv = &tmp_tv;
253
254
device_info(fd, dr->dev_id, &type, &bus, &bdaddr, name);
255
ba2str(&bdaddr, str);
256
packet_new_index(tv, dr->dev_id, str, type, bus, name);
257
open_device(dr->dev_id);
258
}
259
260
done:
261
free(dl);
262
}
263
264
static int open_stack_internal(void)
265
{
266
struct sockaddr_hci addr;
267
struct hci_filter flt;
268
int fd, opt = 1;
269
270
fd = socket(AF_BLUETOOTH, SOCK_RAW | O_CLOEXEC, BTPROTO_HCI);
271
if (fd < 0) {
272
perror("Failed to open channel");
273
return -1;
274
}
275
276
/* Setup filter */
277
hci_filter_clear(&flt);
278
hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
279
hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
280
281
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
282
perror("Failed to set HCI filter");
283
close(fd);
284
return -1;
285
}
286
287
if (setsockopt(fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
288
perror("Failed to enable HCI time stamps");
289
close(fd);
290
return -1;
291
}
292
293
memset(&addr, 0, sizeof(addr));
294
addr.hci_family = AF_BLUETOOTH;
295
addr.hci_dev = HCI_DEV_NONE;
296
addr.hci_channel = HCI_CHANNEL_RAW;
297
298
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
299
perror("Failed to bind channel");
300
close(fd);
301
return -1;
302
}
303
304
device_list(fd, HCI_MAX_DEV);
305
306
return fd;
307
}
308
309
static void stack_internal_callback(int fd, uint32_t events, void *user_data)
310
{
311
unsigned char buf[HCI_MAX_FRAME_SIZE];
312
unsigned char control[32];
313
struct msghdr msg;
314
struct iovec iov;
315
struct cmsghdr *cmsg;
316
ssize_t len;
317
hci_event_hdr *eh;
318
evt_stack_internal *si;
319
evt_si_device *sd;
320
struct timeval *tv = NULL;
321
struct timeval ctv;
322
uint8_t type = 0xff, bus = 0xff;
323
char str[18], name[8] = "";
324
bdaddr_t bdaddr;
325
326
bacpy(&bdaddr, BDADDR_ANY);
327
328
if (events & (EPOLLERR | EPOLLHUP)) {
329
mainloop_remove_fd(fd);
330
return;
331
}
332
333
iov.iov_base = buf;
334
iov.iov_len = sizeof(buf);
335
336
memset(&msg, 0, sizeof(msg));
337
msg.msg_iov = &iov;
338
msg.msg_iovlen = 1;
339
msg.msg_control = control;
340
msg.msg_controllen = sizeof(control);
341
342
len = recvmsg(fd, &msg, MSG_DONTWAIT);
343
if (len < 0)
344
return;
345
346
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
347
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
348
if (cmsg->cmsg_level != SOL_HCI)
349
continue;
350
351
switch (cmsg->cmsg_type) {
352
case HCI_CMSG_TSTAMP:
353
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
354
tv = &ctv;
355
break;
356
}
357
}
358
359
if (len < 1 + HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE +
360
EVT_SI_DEVICE_SIZE)
361
return;
362
363
if (buf[0] != HCI_EVENT_PKT)
364
return;
365
366
eh = (hci_event_hdr *) (buf + 1);
367
if (eh->evt != EVT_STACK_INTERNAL)
368
return;
369
370
si = (evt_stack_internal *) (buf + 1 + HCI_EVENT_HDR_SIZE);
371
if (si->type != EVT_SI_DEVICE)
372
return;
373
374
sd = (evt_si_device *) &si->data;
375
376
switch (sd->event) {
377
case HCI_DEV_REG:
378
device_info(fd, sd->dev_id, &type, &bus, &bdaddr, name);
379
ba2str(&bdaddr, str);
380
packet_new_index(tv, sd->dev_id, str, type, bus, name);
381
open_device(sd->dev_id);
382
break;
383
case HCI_DEV_UNREG:
384
ba2str(&bdaddr, str);
385
packet_del_index(tv, sd->dev_id, str);
386
break;
387
}
388
}
389
390
int hcidump_tracing(void)
391
{
392
struct hcidump_data *data;
393
394
data = malloc(sizeof(*data));
395
if (!data)
396
return -1;
397
398
memset(data, 0, sizeof(*data));
399
data->index = HCI_DEV_NONE;
400
401
data->fd = open_stack_internal();
402
if (data->fd < 0) {
403
free(data);
404
return -1;
405
}
406
407
mainloop_add_fd(data->fd, EPOLLIN, stack_internal_callback,
408
data, free_data);
409
410
return 0;
411
}
412
413