1190214Srpaulo/* 2190214Srpaulo * Copyright (c) 2006 Paolo Abeni (Italy) 3190214Srpaulo * All rights reserved. 4190214Srpaulo * 5190214Srpaulo * Redistribution and use in source and binary forms, with or without 6190214Srpaulo * modification, are permitted provided that the following conditions 7190214Srpaulo * are met: 8190214Srpaulo * 9190214Srpaulo * 1. Redistributions of source code must retain the above copyright 10190214Srpaulo * notice, this list of conditions and the following disclaimer. 11190214Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 12190214Srpaulo * notice, this list of conditions and the following disclaimer in the 13190214Srpaulo * documentation and/or other materials provided with the distribution. 14190214Srpaulo * 3. The name of the author may not be used to endorse or promote 15190214Srpaulo * products derived from this software without specific prior written 16190214Srpaulo * permission. 17190214Srpaulo * 18190214Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19190214Srpaulo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20190214Srpaulo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21190214Srpaulo * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22190214Srpaulo * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23190214Srpaulo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24190214Srpaulo * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25190214Srpaulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26190214Srpaulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27190214Srpaulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28190214Srpaulo * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29190214Srpaulo * 30190214Srpaulo * Bluetooth sniffing API implementation for Linux platform 31190214Srpaulo * By Paolo Abeni <paolo.abeni@email.it> 32190214Srpaulo * 33190214Srpaulo */ 34190214Srpaulo#ifndef lint 35190214Srpaulostatic const char rcsid[] _U_ = 36214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/pcap-bt-linux.c,v 1.15 2008-07-01 07:05:54 guy Exp $ (LBL)"; 37190214Srpaulo#endif 38190214Srpaulo 39190214Srpaulo#ifdef HAVE_CONFIG_H 40190214Srpaulo#include "config.h" 41190214Srpaulo#endif 42190214Srpaulo 43190214Srpaulo#include "pcap-int.h" 44190214Srpaulo#include "pcap-bt-linux.h" 45190214Srpaulo#include "pcap/bluetooth.h" 46190214Srpaulo 47190214Srpaulo#ifdef NEED_STRERROR_H 48190214Srpaulo#include "strerror.h" 49190214Srpaulo#endif 50190214Srpaulo 51190214Srpaulo#include <errno.h> 52190214Srpaulo#include <stdlib.h> 53190214Srpaulo#include <unistd.h> 54190214Srpaulo#include <fcntl.h> 55190214Srpaulo#include <string.h> 56190214Srpaulo#include <sys/ioctl.h> 57190214Srpaulo#include <sys/socket.h> 58190214Srpaulo#include <arpa/inet.h> 59190214Srpaulo 60190214Srpaulo#include <bluetooth/bluetooth.h> 61190214Srpaulo#include <bluetooth/hci.h> 62190214Srpaulo 63190214Srpaulo#define BT_IFACE "bluetooth" 64190214Srpaulo#define BT_CTRL_SIZE 128 65190214Srpaulo 66190214Srpaulo/* forward declaration */ 67190214Srpaulostatic int bt_activate(pcap_t *); 68190214Srpaulostatic int bt_read_linux(pcap_t *, int , pcap_handler , u_char *); 69190214Srpaulostatic int bt_inject_linux(pcap_t *, const void *, size_t); 70190214Srpaulostatic int bt_setdirection_linux(pcap_t *, pcap_direction_t); 71190214Srpaulostatic int bt_stats_linux(pcap_t *, struct pcap_stat *); 72190214Srpaulo 73190214Srpauloint 74251129Sdelphijbt_findalldevs(pcap_if_t **alldevsp, char *err_str) 75190214Srpaulo{ 76190214Srpaulo pcap_if_t *found_dev = *alldevsp; 77190214Srpaulo struct hci_dev_list_req *dev_list; 78190214Srpaulo struct hci_dev_req *dev_req; 79190214Srpaulo int i, sock; 80190214Srpaulo int ret = 0; 81251129Sdelphij 82190214Srpaulo sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 83190214Srpaulo if (sock < 0) 84190214Srpaulo { 85190214Srpaulo /* if bluetooth is not supported this this is not fatal*/ 86190214Srpaulo if (errno == EAFNOSUPPORT) 87190214Srpaulo return 0; 88235426Sdelphij snprintf(err_str, PCAP_ERRBUF_SIZE, 89235426Sdelphij "Can't open raw Bluetooth socket: %s", strerror(errno)); 90190214Srpaulo return -1; 91190214Srpaulo } 92190214Srpaulo 93190214Srpaulo dev_list = malloc(HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); 94190214Srpaulo if (!dev_list) 95190214Srpaulo { 96190214Srpaulo snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list", 97190214Srpaulo HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); 98190214Srpaulo ret = -1; 99190214Srpaulo goto done; 100190214Srpaulo } 101190214Srpaulo 102190214Srpaulo dev_list->dev_num = HCI_MAX_DEV; 103190214Srpaulo 104190214Srpaulo if (ioctl(sock, HCIGETDEVLIST, (void *) dev_list) < 0) 105190214Srpaulo { 106235426Sdelphij snprintf(err_str, PCAP_ERRBUF_SIZE, 107235426Sdelphij "Can't get Bluetooth device list via ioctl: %s", 108235426Sdelphij strerror(errno)); 109190214Srpaulo ret = -1; 110190214Srpaulo goto free; 111190214Srpaulo } 112190214Srpaulo 113190214Srpaulo dev_req = dev_list->dev_req; 114190214Srpaulo for (i = 0; i < dev_list->dev_num; i++, dev_req++) { 115190214Srpaulo char dev_name[20], dev_descr[30]; 116190214Srpaulo 117190214Srpaulo snprintf(dev_name, 20, BT_IFACE"%d", dev_req->dev_id); 118190214Srpaulo snprintf(dev_descr, 30, "Bluetooth adapter number %d", i); 119190214Srpaulo 120190214Srpaulo if (pcap_add_if(&found_dev, dev_name, 0, 121190214Srpaulo dev_descr, err_str) < 0) 122190214Srpaulo { 123190214Srpaulo ret = -1; 124190214Srpaulo break; 125190214Srpaulo } 126190214Srpaulo 127190214Srpaulo } 128190214Srpaulo 129190214Srpaulofree: 130190214Srpaulo free(dev_list); 131190214Srpaulo 132190214Srpaulodone: 133190214Srpaulo close(sock); 134190214Srpaulo return ret; 135190214Srpaulo} 136190214Srpaulo 137190214Srpaulopcap_t * 138251129Sdelphijbt_create(const char *device, char *ebuf, int *is_ours) 139190214Srpaulo{ 140251129Sdelphij const char *cp; 141251129Sdelphij char *cpend; 142251129Sdelphij long devnum; 143190214Srpaulo pcap_t *p; 144190214Srpaulo 145251129Sdelphij /* Does this look like a Bluetooth device? */ 146251129Sdelphij cp = strrchr(device, '/'); 147251129Sdelphij if (cp == NULL) 148251129Sdelphij cp = device; 149251129Sdelphij /* Does it begin with BT_IFACE? */ 150251129Sdelphij if (strncmp(cp, BT_IFACE, sizeof BT_IFACE - 1) != 0) { 151251129Sdelphij /* Nope, doesn't begin with BT_IFACE */ 152251129Sdelphij *is_ours = 0; 153251129Sdelphij return NULL; 154251129Sdelphij } 155251129Sdelphij /* Yes - is BT_IFACE followed by a number? */ 156251129Sdelphij cp += sizeof BT_IFACE - 1; 157251129Sdelphij devnum = strtol(cp, &cpend, 10); 158251129Sdelphij if (cpend == cp || *cpend != '\0') { 159251129Sdelphij /* Not followed by a number. */ 160251129Sdelphij *is_ours = 0; 161251129Sdelphij return NULL; 162251129Sdelphij } 163251129Sdelphij if (devnum < 0) { 164251129Sdelphij /* Followed by a non-valid number. */ 165251129Sdelphij *is_ours = 0; 166251129Sdelphij return NULL; 167251129Sdelphij } 168251129Sdelphij 169251129Sdelphij /* OK, it's probably ours. */ 170251129Sdelphij *is_ours = 1; 171251129Sdelphij 172190214Srpaulo p = pcap_create_common(device, ebuf); 173190214Srpaulo if (p == NULL) 174190214Srpaulo return (NULL); 175190214Srpaulo 176190214Srpaulo p->activate_op = bt_activate; 177190214Srpaulo return (p); 178190214Srpaulo} 179190214Srpaulo 180190214Srpaulostatic int 181190214Srpaulobt_activate(pcap_t* handle) 182190214Srpaulo{ 183190214Srpaulo struct sockaddr_hci addr; 184190214Srpaulo int opt; 185190214Srpaulo int dev_id; 186190214Srpaulo struct hci_filter flt; 187190214Srpaulo int err = PCAP_ERROR; 188190214Srpaulo 189190214Srpaulo /* get bt interface id */ 190190214Srpaulo if (sscanf(handle->opt.source, BT_IFACE"%d", &dev_id) != 1) 191190214Srpaulo { 192190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 193190214Srpaulo "Can't get Bluetooth device index from %s", 194190214Srpaulo handle->opt.source); 195190214Srpaulo return PCAP_ERROR; 196190214Srpaulo } 197190214Srpaulo 198190214Srpaulo /* Initialize some components of the pcap structure. */ 199190214Srpaulo handle->bufsize = handle->snapshot+BT_CTRL_SIZE+sizeof(pcap_bluetooth_h4_header); 200190214Srpaulo handle->offset = BT_CTRL_SIZE; 201190214Srpaulo handle->linktype = DLT_BLUETOOTH_HCI_H4_WITH_PHDR; 202190214Srpaulo 203190214Srpaulo handle->read_op = bt_read_linux; 204190214Srpaulo handle->inject_op = bt_inject_linux; 205235426Sdelphij handle->setfilter_op = install_bpf_program; /* no kernel filtering */ 206190214Srpaulo handle->setdirection_op = bt_setdirection_linux; 207190214Srpaulo handle->set_datalink_op = NULL; /* can't change data link type */ 208190214Srpaulo handle->getnonblock_op = pcap_getnonblock_fd; 209190214Srpaulo handle->setnonblock_op = pcap_setnonblock_fd; 210190214Srpaulo handle->stats_op = bt_stats_linux; 211190214Srpaulo handle->md.ifindex = dev_id; 212190214Srpaulo 213190214Srpaulo /* Create HCI socket */ 214190214Srpaulo handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 215190214Srpaulo if (handle->fd < 0) { 216235426Sdelphij snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 217235426Sdelphij "Can't create raw socket: %s", strerror(errno)); 218190214Srpaulo return PCAP_ERROR; 219190214Srpaulo } 220190214Srpaulo 221190214Srpaulo handle->buffer = malloc(handle->bufsize); 222190214Srpaulo if (!handle->buffer) { 223190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", 224190214Srpaulo pcap_strerror(errno)); 225190214Srpaulo goto close_fail; 226190214Srpaulo } 227190214Srpaulo 228190214Srpaulo opt = 1; 229190214Srpaulo if (setsockopt(handle->fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { 230235426Sdelphij snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 231235426Sdelphij "Can't enable data direction info: %s", strerror(errno)); 232190214Srpaulo goto close_fail; 233190214Srpaulo } 234190214Srpaulo 235190214Srpaulo opt = 1; 236190214Srpaulo if (setsockopt(handle->fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { 237235426Sdelphij snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 238235426Sdelphij "Can't enable time stamp: %s", strerror(errno)); 239190214Srpaulo goto close_fail; 240190214Srpaulo } 241190214Srpaulo 242190214Srpaulo /* Setup filter, do not call hci function to avoid dependence on 243190214Srpaulo * external libs */ 244190214Srpaulo memset(&flt, 0, sizeof(flt)); 245190214Srpaulo memset((void *) &flt.type_mask, 0xff, sizeof(flt.type_mask)); 246190214Srpaulo memset((void *) &flt.event_mask, 0xff, sizeof(flt.event_mask)); 247190214Srpaulo if (setsockopt(handle->fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { 248235426Sdelphij snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 249235426Sdelphij "Can't set filter: %s", strerror(errno)); 250190214Srpaulo goto close_fail; 251190214Srpaulo } 252190214Srpaulo 253190214Srpaulo 254190214Srpaulo /* Bind socket to the HCI device */ 255190214Srpaulo addr.hci_family = AF_BLUETOOTH; 256190214Srpaulo addr.hci_dev = handle->md.ifindex; 257251129Sdelphij#ifdef SOCKADDR_HCI_HAS_HCI_CHANNEL 258251129Sdelphij addr.hci_channel = HCI_CHANNEL_RAW; 259251129Sdelphij#endif 260190214Srpaulo if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 261235426Sdelphij snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 262235426Sdelphij "Can't attach to device %d: %s", handle->md.ifindex, 263235426Sdelphij strerror(errno)); 264190214Srpaulo goto close_fail; 265190214Srpaulo } 266190214Srpaulo 267190214Srpaulo if (handle->opt.rfmon) { 268190214Srpaulo /* 269190214Srpaulo * Monitor mode doesn't apply to Bluetooth devices. 270190214Srpaulo */ 271190214Srpaulo err = PCAP_ERROR_RFMON_NOTSUP; 272190214Srpaulo goto close_fail; 273190214Srpaulo } 274190214Srpaulo 275235426Sdelphij if (handle->opt.buffer_size != 0) { 276190214Srpaulo /* 277190214Srpaulo * Set the socket buffer size to the specified value. 278190214Srpaulo */ 279190214Srpaulo if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, 280190214Srpaulo &handle->opt.buffer_size, 281190214Srpaulo sizeof(handle->opt.buffer_size)) == -1) { 282190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 283190214Srpaulo "SO_RCVBUF: %s", pcap_strerror(errno)); 284190214Srpaulo goto close_fail; 285190214Srpaulo } 286190214Srpaulo } 287190214Srpaulo 288190214Srpaulo handle->selectable_fd = handle->fd; 289190214Srpaulo return 0; 290190214Srpaulo 291190214Srpauloclose_fail: 292190214Srpaulo pcap_cleanup_live_common(handle); 293190214Srpaulo return err; 294190214Srpaulo} 295190214Srpaulo 296190214Srpaulostatic int 297190214Srpaulobt_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 298190214Srpaulo{ 299190214Srpaulo struct cmsghdr *cmsg; 300190214Srpaulo struct msghdr msg; 301190214Srpaulo struct iovec iv; 302235426Sdelphij ssize_t ret; 303190214Srpaulo struct pcap_pkthdr pkth; 304190214Srpaulo pcap_bluetooth_h4_header* bthdr; 305190214Srpaulo 306190214Srpaulo bthdr = (pcap_bluetooth_h4_header*) &handle->buffer[handle->offset]; 307190214Srpaulo iv.iov_base = &handle->buffer[handle->offset+sizeof(pcap_bluetooth_h4_header)]; 308190214Srpaulo iv.iov_len = handle->snapshot; 309190214Srpaulo 310190214Srpaulo memset(&msg, 0, sizeof(msg)); 311190214Srpaulo msg.msg_iov = &iv; 312190214Srpaulo msg.msg_iovlen = 1; 313190214Srpaulo msg.msg_control = handle->buffer; 314190214Srpaulo msg.msg_controllen = handle->offset; 315190214Srpaulo 316190214Srpaulo /* ignore interrupt system call error */ 317190214Srpaulo do { 318235426Sdelphij ret = recvmsg(handle->fd, &msg, 0); 319190214Srpaulo if (handle->break_loop) 320190214Srpaulo { 321190214Srpaulo handle->break_loop = 0; 322190214Srpaulo return -2; 323190214Srpaulo } 324235426Sdelphij } while ((ret == -1) && (errno == EINTR)); 325190214Srpaulo 326235426Sdelphij if (ret < 0) { 327235426Sdelphij snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 328235426Sdelphij "Can't receive packet: %s", strerror(errno)); 329190214Srpaulo return -1; 330190214Srpaulo } 331190214Srpaulo 332235426Sdelphij pkth.caplen = ret; 333235426Sdelphij 334190214Srpaulo /* get direction and timestamp*/ 335190214Srpaulo cmsg = CMSG_FIRSTHDR(&msg); 336190214Srpaulo int in=0; 337190214Srpaulo while (cmsg) { 338190214Srpaulo switch (cmsg->cmsg_type) { 339190214Srpaulo case HCI_CMSG_DIR: 340235426Sdelphij memcpy(&in, CMSG_DATA(cmsg), sizeof in); 341190214Srpaulo break; 342190214Srpaulo case HCI_CMSG_TSTAMP: 343235426Sdelphij memcpy(&pkth.ts, CMSG_DATA(cmsg), 344235426Sdelphij sizeof pkth.ts); 345190214Srpaulo break; 346190214Srpaulo } 347190214Srpaulo cmsg = CMSG_NXTHDR(&msg, cmsg); 348190214Srpaulo } 349190214Srpaulo if ((in && (handle->direction == PCAP_D_OUT)) || 350190214Srpaulo ((!in) && (handle->direction == PCAP_D_IN))) 351190214Srpaulo return 0; 352190214Srpaulo 353190214Srpaulo bthdr->direction = htonl(in != 0); 354190214Srpaulo pkth.caplen+=sizeof(pcap_bluetooth_h4_header); 355190214Srpaulo pkth.len = pkth.caplen; 356235426Sdelphij if (handle->fcode.bf_insns == NULL || 357235426Sdelphij bpf_filter(handle->fcode.bf_insns, &handle->buffer[handle->offset], 358235426Sdelphij pkth.len, pkth.caplen)) { 359235426Sdelphij callback(user, &pkth, &handle->buffer[handle->offset]); 360235426Sdelphij return 1; 361235426Sdelphij } 362235426Sdelphij return 0; /* didn't pass filter */ 363190214Srpaulo} 364190214Srpaulo 365190214Srpaulostatic int 366190214Srpaulobt_inject_linux(pcap_t *handle, const void *buf, size_t size) 367190214Srpaulo{ 368190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " 369190214Srpaulo "bluetooth devices"); 370190214Srpaulo return (-1); 371190214Srpaulo} 372190214Srpaulo 373190214Srpaulo 374190214Srpaulostatic int 375190214Srpaulobt_stats_linux(pcap_t *handle, struct pcap_stat *stats) 376190214Srpaulo{ 377190214Srpaulo int ret; 378190214Srpaulo struct hci_dev_info dev_info; 379190214Srpaulo struct hci_dev_stats * s = &dev_info.stat; 380190214Srpaulo dev_info.dev_id = handle->md.ifindex; 381190214Srpaulo 382235426Sdelphij /* ignore eintr */ 383190214Srpaulo do { 384190214Srpaulo ret = ioctl(handle->fd, HCIGETDEVINFO, (void *)&dev_info); 385190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 386190214Srpaulo 387190214Srpaulo if (ret < 0) { 388235426Sdelphij snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 389235426Sdelphij "Can't get stats via ioctl: %s", strerror(errno)); 390190214Srpaulo return (-1); 391190214Srpaulo 392190214Srpaulo } 393190214Srpaulo 394190214Srpaulo /* we receive both rx and tx frames, so comulate all stats */ 395190214Srpaulo stats->ps_recv = s->evt_rx + s->acl_rx + s->sco_rx + s->cmd_tx + 396190214Srpaulo s->acl_tx +s->sco_tx; 397190214Srpaulo stats->ps_drop = s->err_rx + s->err_tx; 398190214Srpaulo stats->ps_ifdrop = 0; 399190214Srpaulo return 0; 400190214Srpaulo} 401190214Srpaulo 402190214Srpaulostatic int 403190214Srpaulobt_setdirection_linux(pcap_t *p, pcap_direction_t d) 404190214Srpaulo{ 405190214Srpaulo p->direction = d; 406190214Srpaulo return 0; 407190214Srpaulo} 408