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