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