diff -urN --exclude 'CVS*' --exclude '*configure' lp/config.h.in libpcap/config.h.in --- lp/config.h.in 2006-10-04 18:48:11.000000000 +0200 +++ libpcap/config.h.in 2006-10-11 14:54:30.000000000 +0200 @@ -164,6 +164,9 @@ /* target host supports USB sniffing */ #undef PCAP_SUPPORT_USB +/* target host supports bluetooth sniffing */ +#undef PCAP_SUPPORT_BT + /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS diff -urN --exclude 'CVS*' --exclude '*configure' lp/configure.in libpcap/configure.in --- lp/configure.in 2006-10-04 18:46:31.000000000 +0200 +++ libpcap/configure.in 2006-10-11 15:24:40.000000000 +0200 @@ -806,6 +806,25 @@ AC_SUBST(PCAP_SUPPORT_USB) AC_SUBST(USB_SRC) +dnl check for usb sniffing support +case "$host_os" in +linux*) + AC_CHECK_HEADER(bluetooth/bluetooth.h, + [ + AC_DEFINE(PCAP_SUPPORT_BT, 1, [target host supports bluetooth sniffing]) + BT_SRC=pcap-bt-linux.c + AC_MSG_NOTICE(bt sniffing is supported ) + ], + AC_MSG_NOTICE(bt sniffing is not supported; install bluez-lib devel to enable it) + ) + ;; +*) + AC_MSG_NOTICE(no bt sniffing support) + ;; +esac +AC_SUBST(PCAP_SUPPORT_BT) +AC_SUBST(BT_SRC) + AC_PROG_INSTALL AC_CONFIG_HEADER(config.h) diff -urN --exclude 'CVS*' --exclude '*configure' lp/inet.c libpcap/inet.c --- lp/inet.c 2006-10-13 11:15:29.000000000 +0200 +++ libpcap/inet.c 2006-10-13 11:55:23.000000000 +0200 @@ -582,6 +582,9 @@ #ifdef HAVE_SEPTEL_API || strstr(device, "septel") != NULL #endif +#ifdef PCAP_SUPPORT_BT + || strstr(device, "bluetooth") != NULL +#endif #ifdef PCAP_SUPPORT_USB || strstr(device, "usb") != NULL #endif diff -urN --exclude 'CVS*' --exclude '*configure' lp/Makefile.in libpcap/Makefile.in --- lp/Makefile.in 2006-10-04 20:09:22.000000000 +0200 +++ libpcap/Makefile.in 2006-10-11 14:40:41.000000000 +0200 @@ -72,7 +72,7 @@ @rm -f $@ $(CC) $(CFLAGS) -c $(srcdir)/$*.c -PSRC = pcap-@V_PCAP@.c @USB_SRC@ +PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ FSRC = fad-@V_FINDALLDEVS@.c SSRC = @SSRC@ CSRC = pcap.c inet.c gencode.c optimize.c nametoaddr.c \ diff -urN --exclude 'CVS*' --exclude '*configure' lp/pcap-bt-linux.c libpcap/pcap-bt-linux.c --- lp/pcap-bt-linux.c 1970-01-01 01:00:00.000000000 +0100 +++ libpcap/pcap-bt-linux.c 2006-10-13 11:55:58.000000000 +0200 @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * USB sniffig API implementation for linux platform + * By Paolo Abeni + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pcap-int.h" + +#ifdef NEED_STRERROR_H +#include "strerror.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define BT_IFACE "bluetooth" +#define BT_CTRL_SIZE 128 + +/* forward declaration */ +static int bt_read_linux(pcap_t *, int , pcap_handler , u_char *); +static int bt_inject_linux(pcap_t *, const void *, size_t); +static int bt_setfilter_linux(pcap_t *, struct bpf_program *); +static int bt_setdirection_linux(pcap_t *, pcap_direction_t); +static int bt_stats_linux(pcap_t *, struct pcap_stat *); +static void bt_close_linux(pcap_t *); + +int +bt_platform_finddevs(pcap_if_t **alldevsp, char *err_str) +{ + pcap_if_t *found_dev = *alldevsp; + struct hci_dev_list_req *dev_list; + struct hci_dev_req *dev_req; + int i, sock; + int ret = 0; + + sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (sock < 0) + { + snprintf(err_str, PCAP_ERRBUF_SIZE, "can't open raw by socket %d:%s", + errno, strerror(errno)); + return -1; + } + + dev_list = malloc(HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); + if (!dev_list) + { + snprintf(err_str, PCAP_ERRBUF_SIZE, "can't allocate %d bytes for dev cache", + HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); + ret = -1; + goto done; + } + + dev_list->dev_num = HCI_MAX_DEV; + + if (ioctl(sock, HCIGETDEVLIST, (void *) dev_list) < 0) + { + snprintf(err_str, PCAP_ERRBUF_SIZE, "can't get dev list via ioctl %d:%s", + errno, strerror(errno)); + ret = -1; + goto free; + } + + dev_req = dev_list->dev_req; + for (i = 0; i < dev_list->dev_num; i++, dev_req++) { + char dev_name[20], dev_descr[30]; + + snprintf(dev_name, 20, BT_IFACE"%d", dev_req->dev_id); + snprintf(dev_descr, 30, "bluetooth adapter number %d", i); + + if (pcap_add_if(&found_dev, dev_name, 0, + dev_descr, err_str) < 0) + { + ret = -1; + break; + } + + } + +free: + free(dev_list); + +done: + close(sock); + return ret; +} + +pcap_t* +bt_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errmsg) +{ + struct sockaddr_hci addr; + int opt; + pcap_t *handle; + int dev_id; + struct hci_filter flt; + + /* get bt interface id */ + if (sscanf(bus, BT_IFACE"%d", &dev_id) != 1) + { + snprintf(errmsg, PCAP_ERRBUF_SIZE, + "Can't get usb bus index from %s", bus); + return NULL; + } + + /* Allocate a handle for this session. */ + handle = malloc(sizeof(*handle)); + if (handle == NULL) { + snprintf(errmsg, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + return NULL; + } + + /* Initialize some components of the pcap structure. */ + memset(handle, 0, sizeof(*handle)); + handle->snapshot = snaplen; + handle->md.timeout = to_ms; + handle->bufsize = snaplen+BT_CTRL_SIZE; + handle->offset = BT_CTRL_SIZE; + handle->linktype = DLT_BLUETOOTH_HCI_H4; + + handle->read_op = bt_read_linux; + handle->inject_op = bt_inject_linux; + handle->setfilter_op = bt_setfilter_linux; + handle->setdirection_op = bt_setdirection_linux; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = bt_stats_linux; + handle->close_op = bt_close_linux; + handle->md.ifindex = dev_id; + + /* Create HCI socket */ + handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (handle->fd < 0) { + snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", + errno, strerror(errno)); + free(handle); + return NULL; + } + + handle->buffer = malloc(snaplen+BT_CTRL_SIZE); + if (!handle->buffer) { + snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", + pcap_strerror(errno)); + pcap_close(handle); + return NULL; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { + snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't enable data direction info %d:%s", + errno, strerror(errno)); + pcap_close(handle); + return NULL; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { + snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't enable time stamp %d:%s", + errno, strerror(errno)); + pcap_close(handle); + return NULL; + } + + /* Setup filter, do not call hci function to avoid dependence on + * external libs */ + memset(&flt, 0, sizeof(flt)); + memset((void *) &flt.type_mask, 0xff, sizeof(flt.type_mask)); + memset((void *) &flt.event_mask, 0xff, sizeof(flt.event_mask)); + if (setsockopt(handle->fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { + snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't set filter %d:%s", + errno, strerror(errno)); + pcap_close(handle); + return NULL; + } + + + /* Bind socket to the HCI device */ + addr.hci_family = AF_BLUETOOTH; + addr.hci_dev = handle->md.ifindex; + if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't attach to device %d %d:%s", + handle->md.ifindex, errno, strerror(errno)); + pcap_close(handle); + return NULL; + } + handle->selectable_fd = handle->fd; + + return handle; +} + +static int +bt_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct cmsghdr *cmsg; + struct msghdr msg; + struct iovec iv; + struct pcap_pkthdr pkth; + + iv.iov_base = &handle->buffer[handle->offset]; + iv.iov_len = handle->snapshot; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = handle->buffer; + msg.msg_controllen = handle->offset; + + /* ignore interrupt system call error */ + do { + pkth.caplen = recvmsg(handle->fd, &msg, 0); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((pkth.caplen == -1) && (errno == EINTR)); + + + if (pkth.caplen < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", + handle->md.ifindex, errno, strerror(errno)); + return -1; + } + + /* get direction and timestamp*/ + cmsg = CMSG_FIRSTHDR(&msg); + while (cmsg) { + int in; + switch (cmsg->cmsg_type) { + case HCI_CMSG_DIR: + in = *((int *) CMSG_DATA(cmsg)); + break; + case HCI_CMSG_TSTAMP: + pkth.ts = *((struct timeval *) CMSG_DATA(cmsg)); + break; + } + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + pkth.len = pkth.caplen; + callback(user, &pkth, iv.iov_base); + return 1; +} + +static int +bt_inject_linux(pcap_t *handle, const void *buf, size_t size) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " + "bluetooth devices"); + return (-1); +} + + +static void +bt_close_linux(pcap_t* handle) +{ + close(handle->fd); + free(handle->buffer); +} + + +static int +bt_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + int ret; + struct hci_dev_info dev_info; + struct hci_dev_stats * s = &dev_info.stat; + dev_info.dev_id = handle->md.ifindex; + + /* ingnore eintr */ + do { + ret = ioctl(handle->fd, HCIGETDEVINFO, (void *)&dev_info); + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can get stats" + " via ioctl %d:%s", errno, strerror(errno)); + return (-1); + + } + + /* we receive both rx and tx frames, so comulate all stats */ + stats->ps_recv = s->evt_rx + s->acl_rx + s->sco_rx + s->cmd_tx + + s->acl_tx +s->sco_tx; + stats->ps_drop = s->err_rx + s->err_tx; + stats->ps_ifdrop = 0; + return 0; +} + +static int +bt_setfilter_linux(pcap_t *p, struct bpf_program *fp) +{ + return 0; +} + + +static int +bt_setdirection_linux(pcap_t *p, pcap_direction_t d) +{ + p->direction = d; + return 0; +} diff -urN --exclude 'CVS*' --exclude '*configure' lp/pcap-linux.c libpcap/pcap-linux.c --- lp/pcap-linux.c 2006-10-12 19:26:06.000000000 +0200 +++ libpcap/pcap-linux.c 2006-10-13 10:27:42.000000000 +0200 @@ -190,6 +190,11 @@ int usb_platform_finddevs(pcap_if_t **alldevsp, char *err_str); pcap_t* usb_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errmsg); +#ifdef PCAP_SUPPORT_BT +int bt_platform_finddevs(pcap_if_t **alldevsp, char *err_str); +pcap_t* bt_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errmsg); +#endif + /* * Prototypes for internal functions @@ -262,9 +267,16 @@ } #endif /* HAVE_SEPTEL_API */ - if (strstr(device, "usb")) { - return usb_open_live(device, snaplen, promisc, to_ms, ebuf); - } +#ifdef PCAP_SUPPORT_BT + if (strstr(device, "bluetooth")) { + return bt_open_live(device, snaplen, promisc, to_ms, ebuf); + } +#endif + + if (strstr(device, "usb")) { + return usb_open_live(device, snaplen, promisc, to_ms, ebuf); + } + /* Allocate a handle for this session. */ @@ -926,6 +938,11 @@ return (-1); #endif /* HAVE_SEPTEL_API */ +#ifdef PCAP_SUPPORT_BT + if (bt_platform_finddevs(alldevsp, errbuf) < 0) + return (-1); +#endif + if (usb_platform_finddevs(alldevsp, errbuf) < 0) return (-1); diff -urN --exclude 'CVS*' --exclude '*configure' lp/pcap-usb-linux.c libpcap/pcap-usb-linux.c --- lp/pcap-usb-linux.c 2006-10-12 10:04:08.000000000 +0200 +++ libpcap/pcap-usb-linux.c 2006-10-13 11:23:23.000000000 +0200 @@ -406,7 +406,8 @@ if (fd < 0) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "Can't open usb stats file %s: %s", string, strerror(errno)); + "Can't open usb stats file %s: %s", + string, strerror(errno)); return -1; } @@ -429,7 +430,8 @@ if (ret != 2) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "Can't parse stat line '%s' expected 2 token got %d", string, ret); + "Can't parse stat line '%s' expected 2 token got %d", + string, ret); return -1; }