xref: /minix3/external/bsd/libpcap/dist/pcap-bt-linux.c (revision d56f51ea7d8b9045e5c8e2028422523d3f9a5840)
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