1 /* $NetBSD: pcap-bt-linux.c,v 1.8 2024/09/02 15:33:37 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Paolo Abeni (Italy) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * Bluetooth sniffing API implementation for Linux platform 33 * By Paolo Abeni <paolo.abeni@email.it> 34 * 35 */ 36 #include <sys/cdefs.h> 37 __RCSID("$NetBSD: pcap-bt-linux.c,v 1.8 2024/09/02 15:33:37 christos Exp $"); 38 39 #include <config.h> 40 41 #include "pcap-int.h" 42 #include "pcap-bt-linux.h" 43 #include "pcap/bluetooth.h" 44 #include "diag-control.h" 45 46 #include <errno.h> 47 #include <stdlib.h> 48 #include <unistd.h> 49 #include <fcntl.h> 50 #include <string.h> 51 #include <sys/ioctl.h> 52 #include <sys/socket.h> 53 #include <arpa/inet.h> 54 55 #include <bluetooth/bluetooth.h> 56 #include <bluetooth/hci.h> 57 58 #define BT_IFACE "bluetooth" 59 #define BT_CTRL_SIZE 128 60 61 /* forward declaration */ 62 static int bt_activate(pcap_t *); 63 static int bt_read_linux(pcap_t *, int , pcap_handler , u_char *); 64 static int bt_inject_linux(pcap_t *, const void *, int); 65 static int bt_setdirection_linux(pcap_t *, pcap_direction_t); 66 static int bt_stats_linux(pcap_t *, struct pcap_stat *); 67 68 /* 69 * Private data for capturing on Linux Bluetooth devices. 70 */ 71 struct pcap_bt { 72 int dev_id; /* device ID of device we're bound to */ 73 }; 74 75 int 76 bt_findalldevs(pcap_if_list_t *devlistp, char *err_str) 77 { 78 struct hci_dev_list_req *dev_list; 79 struct hci_dev_req *dev_req; 80 int sock; 81 unsigned i; 82 int ret = 0; 83 84 sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 85 if (sock < 0) 86 { 87 /* if bluetooth is not supported this is not fatal*/ 88 if (errno == EAFNOSUPPORT) 89 return 0; 90 pcapint_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, 91 errno, "Can't open raw Bluetooth socket"); 92 return PCAP_ERROR; 93 } 94 95 dev_list = malloc(HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); 96 if (!dev_list) 97 { 98 snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list", 99 HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); 100 ret = PCAP_ERROR; 101 goto done; 102 } 103 104 /* 105 * Zero the complete header, which is larger than dev_num because of tail 106 * padding, to silence Valgrind, which overshoots validating that dev_num 107 * has been set. 108 * https://github.com/the-tcpdump-group/libpcap/issues/1083 109 * https://bugs.kde.org/show_bug.cgi?id=448464 110 */ 111 memset(dev_list, 0, sizeof(*dev_list)); 112 dev_list->dev_num = HCI_MAX_DEV; 113 114 if (ioctl(sock, HCIGETDEVLIST, (void *) dev_list) < 0) 115 { 116 pcapint_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, 117 errno, "Can't get Bluetooth device list via ioctl"); 118 ret = PCAP_ERROR; 119 goto free; 120 } 121 122 dev_req = dev_list->dev_req; 123 for (i = 0; i < dev_list->dev_num; i++, dev_req++) { 124 char dev_name[20], dev_descr[40]; 125 126 snprintf(dev_name, sizeof(dev_name), BT_IFACE"%u", dev_req->dev_id); 127 snprintf(dev_descr, sizeof(dev_descr), "Bluetooth adapter number %u", i); 128 129 /* 130 * Bluetooth is a wireless technology. 131 * XXX - if there's the notion of associating with a 132 * network, and we can determine whether the interface 133 * is associated with a network, check that and set 134 * the status to PCAP_IF_CONNECTION_STATUS_CONNECTED 135 * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED. 136 */ 137 if (pcapint_add_dev(devlistp, dev_name, PCAP_IF_WIRELESS, dev_descr, err_str) == NULL) 138 { 139 ret = PCAP_ERROR; 140 break; 141 } 142 } 143 144 free: 145 free(dev_list); 146 147 done: 148 close(sock); 149 return ret; 150 } 151 152 pcap_t * 153 bt_create(const char *device, char *ebuf, int *is_ours) 154 { 155 const char *cp; 156 char *cpend; 157 long devnum; 158 pcap_t *p; 159 160 /* Does this look like a Bluetooth device? */ 161 cp = strrchr(device, '/'); 162 if (cp == NULL) 163 cp = device; 164 /* Does it begin with BT_IFACE? */ 165 if (strncmp(cp, BT_IFACE, sizeof BT_IFACE - 1) != 0) { 166 /* Nope, doesn't begin with BT_IFACE */ 167 *is_ours = 0; 168 return NULL; 169 } 170 /* Yes - is BT_IFACE followed by a number? */ 171 cp += sizeof BT_IFACE - 1; 172 devnum = strtol(cp, &cpend, 10); 173 if (cpend == cp || *cpend != '\0') { 174 /* Not followed by a number. */ 175 *is_ours = 0; 176 return NULL; 177 } 178 if (devnum < 0) { 179 /* Followed by a non-valid number. */ 180 *is_ours = 0; 181 return NULL; 182 } 183 184 /* OK, it's probably ours. */ 185 *is_ours = 1; 186 187 p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt); 188 if (p == NULL) 189 return (NULL); 190 191 p->activate_op = bt_activate; 192 return (p); 193 } 194 195 static int 196 bt_activate(pcap_t* handle) 197 { 198 struct pcap_bt *handlep = handle->priv; 199 struct sockaddr_hci addr; 200 int opt; 201 int dev_id; 202 struct hci_filter flt; 203 int err = PCAP_ERROR; 204 205 /* get bt interface id */ 206 if (sscanf(handle->opt.device, BT_IFACE"%d", &dev_id) != 1) 207 { 208 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 209 "Can't get Bluetooth device index from %s", 210 handle->opt.device); 211 return PCAP_ERROR; 212 } 213 214 /* 215 * Turn a negative snapshot value (invalid), a snapshot value of 216 * 0 (unspecified), or a value bigger than the normal maximum 217 * value, into the maximum allowed value. 218 * 219 * If some application really *needs* a bigger snapshot 220 * length, we should just increase MAXIMUM_SNAPLEN. 221 */ 222 if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) 223 handle->snapshot = MAXIMUM_SNAPLEN; 224 225 /* Initialize some components of the pcap structure. */ 226 handle->bufsize = BT_CTRL_SIZE+sizeof(pcap_bluetooth_h4_header)+handle->snapshot; 227 handle->linktype = DLT_BLUETOOTH_HCI_H4_WITH_PHDR; 228 229 handle->read_op = bt_read_linux; 230 handle->inject_op = bt_inject_linux; 231 handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ 232 handle->setdirection_op = bt_setdirection_linux; 233 handle->set_datalink_op = NULL; /* can't change data link type */ 234 handle->getnonblock_op = pcapint_getnonblock_fd; 235 handle->setnonblock_op = pcapint_setnonblock_fd; 236 handle->stats_op = bt_stats_linux; 237 handlep->dev_id = dev_id; 238 239 /* Create HCI socket */ 240 handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 241 if (handle->fd < 0) { 242 pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 243 errno, "Can't create raw socket"); 244 return PCAP_ERROR; 245 } 246 247 handle->buffer = malloc(handle->bufsize); 248 if (!handle->buffer) { 249 pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 250 errno, "Can't allocate dump buffer"); 251 goto close_fail; 252 } 253 254 opt = 1; 255 if (setsockopt(handle->fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { 256 pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 257 errno, "Can't enable data direction info"); 258 goto close_fail; 259 } 260 261 opt = 1; 262 if (setsockopt(handle->fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { 263 pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 264 errno, "Can't enable time stamp"); 265 goto close_fail; 266 } 267 268 /* Setup filter, do not call hci function to avoid dependence on 269 * external libs */ 270 memset(&flt, 0, sizeof(flt)); 271 memset((void *) &flt.type_mask, 0xff, sizeof(flt.type_mask)); 272 memset((void *) &flt.event_mask, 0xff, sizeof(flt.event_mask)); 273 if (setsockopt(handle->fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { 274 pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 275 errno, "Can't set filter"); 276 goto close_fail; 277 } 278 279 280 /* Bind socket to the HCI device */ 281 addr.hci_family = AF_BLUETOOTH; 282 addr.hci_dev = handlep->dev_id; 283 #ifdef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL 284 addr.hci_channel = HCI_CHANNEL_RAW; 285 #endif 286 if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 287 pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 288 errno, "Can't attach to device %d", handlep->dev_id); 289 goto close_fail; 290 } 291 292 if (handle->opt.rfmon) { 293 /* 294 * Monitor mode doesn't apply to Bluetooth devices. 295 */ 296 err = PCAP_ERROR_RFMON_NOTSUP; 297 goto close_fail; 298 } 299 300 if (handle->opt.buffer_size != 0) { 301 /* 302 * Set the socket buffer size to the specified value. 303 */ 304 if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, 305 &handle->opt.buffer_size, 306 sizeof(handle->opt.buffer_size)) == -1) { 307 pcapint_fmt_errmsg_for_errno(handle->errbuf, 308 errno, PCAP_ERRBUF_SIZE, "SO_RCVBUF"); 309 goto close_fail; 310 } 311 } 312 313 handle->selectable_fd = handle->fd; 314 return 0; 315 316 close_fail: 317 pcapint_cleanup_live_common(handle); 318 return err; 319 } 320 321 static int 322 bt_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) 323 { 324 struct cmsghdr *cmsg; 325 struct msghdr msg; 326 struct iovec iv; 327 ssize_t ret; 328 struct pcap_pkthdr pkth; 329 pcap_bluetooth_h4_header* bthdr; 330 u_char *pktd; 331 int in = 0; 332 333 pktd = (u_char *)handle->buffer + BT_CTRL_SIZE; 334 bthdr = (pcap_bluetooth_h4_header*)(void *)pktd; 335 iv.iov_base = pktd + sizeof(pcap_bluetooth_h4_header); 336 iv.iov_len = handle->snapshot; 337 338 memset(&msg, 0, sizeof(msg)); 339 msg.msg_iov = &iv; 340 msg.msg_iovlen = 1; 341 msg.msg_control = handle->buffer; 342 msg.msg_controllen = BT_CTRL_SIZE; 343 344 /* ignore interrupt system call error */ 345 do { 346 if (handle->break_loop) 347 { 348 handle->break_loop = 0; 349 return PCAP_ERROR_BREAK; 350 } 351 ret = recvmsg(handle->fd, &msg, 0); 352 } while ((ret == -1) && (errno == EINTR)); 353 354 if (ret < 0) { 355 if (errno == EAGAIN || errno == EWOULDBLOCK) { 356 /* Nonblocking mode, no data */ 357 return 0; 358 } 359 pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 360 errno, "Can't receive packet"); 361 return PCAP_ERROR; 362 } 363 364 pkth.caplen = (bpf_u_int32)ret; 365 366 /* get direction and timestamp*/ 367 cmsg = CMSG_FIRSTHDR(&msg); 368 while (cmsg) { 369 switch (cmsg->cmsg_type) { 370 case HCI_CMSG_DIR: 371 memcpy(&in, CMSG_DATA(cmsg), sizeof in); 372 break; 373 case HCI_CMSG_TSTAMP: 374 memcpy(&pkth.ts, CMSG_DATA(cmsg), 375 sizeof pkth.ts); 376 break; 377 } 378 // for musl libc CMSG_NXTHDR() 379 DIAG_OFF_SIGN_COMPARE 380 cmsg = CMSG_NXTHDR(&msg, cmsg); 381 DIAG_ON_SIGN_COMPARE 382 } 383 switch (handle->direction) { 384 385 case PCAP_D_IN: 386 if (!in) 387 return 0; 388 break; 389 390 case PCAP_D_OUT: 391 if (in) 392 return 0; 393 break; 394 395 default: 396 break; 397 } 398 399 bthdr->direction = htonl(in != 0); 400 pkth.caplen+=sizeof(pcap_bluetooth_h4_header); 401 pkth.len = pkth.caplen; 402 if (handle->fcode.bf_insns == NULL || 403 pcapint_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) { 404 callback(user, &pkth, pktd); 405 return 1; 406 } 407 return 0; /* didn't pass filter */ 408 } 409 410 static int 411 bt_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_) 412 { 413 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 414 "Packet injection is not supported on Bluetooth devices"); 415 return (-1); 416 } 417 418 419 static int 420 bt_stats_linux(pcap_t *handle, struct pcap_stat *stats) 421 { 422 struct pcap_bt *handlep = handle->priv; 423 int ret; 424 struct hci_dev_info dev_info; 425 struct hci_dev_stats * s = &dev_info.stat; 426 dev_info.dev_id = handlep->dev_id; 427 428 /* ignore eintr */ 429 do { 430 ret = ioctl(handle->fd, HCIGETDEVINFO, (void *)&dev_info); 431 } while ((ret == -1) && (errno == EINTR)); 432 433 if (ret < 0) { 434 pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 435 errno, "Can't get stats via ioctl"); 436 return (-1); 437 438 } 439 440 /* we receive both rx and tx frames, so cumulate all stats */ 441 stats->ps_recv = s->evt_rx + s->acl_rx + s->sco_rx + s->cmd_tx + 442 s->acl_tx +s->sco_tx; 443 stats->ps_drop = s->err_rx + s->err_tx; 444 stats->ps_ifdrop = 0; 445 return 0; 446 } 447 448 static int 449 bt_setdirection_linux(pcap_t *p, pcap_direction_t d) 450 { 451 /* 452 * It's guaranteed, at this point, that d is a valid 453 * direction value. 454 */ 455 p->direction = d; 456 return 0; 457 } 458