1681ed54cSXin LI /*
2681ed54cSXin LI * Copyright (c) 2014 Michal Labedzki for Tieto Corporation
3681ed54cSXin LI * All rights reserved.
4681ed54cSXin LI *
5681ed54cSXin LI * Redistribution and use in source and binary forms, with or without
6681ed54cSXin LI * modification, are permitted provided that the following conditions
7681ed54cSXin LI * are met:
8681ed54cSXin LI *
9681ed54cSXin LI * 1. Redistributions of source code must retain the above copyright
10681ed54cSXin LI * notice, this list of conditions and the following disclaimer.
11681ed54cSXin LI * 2. Redistributions in binary form must reproduce the above copyright
12681ed54cSXin LI * notice, this list of conditions and the following disclaimer in the
13681ed54cSXin LI * documentation and/or other materials provided with the distribution.
14681ed54cSXin LI * 3. The name of the author may not be used to endorse or promote
15681ed54cSXin LI * products derived from this software without specific prior written
16681ed54cSXin LI * permission.
17681ed54cSXin LI *
18681ed54cSXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19681ed54cSXin LI * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20681ed54cSXin LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21681ed54cSXin LI * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22681ed54cSXin LI * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23681ed54cSXin LI * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24681ed54cSXin LI * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25681ed54cSXin LI * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26681ed54cSXin LI * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27681ed54cSXin LI * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28681ed54cSXin LI * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29681ed54cSXin LI *
30681ed54cSXin LI */
31681ed54cSXin LI
32b00ab754SHans Petter Selasky #include <config.h>
33681ed54cSXin LI
34681ed54cSXin LI #include <errno.h>
35ada6f083SXin LI #include <stdint.h>
36681ed54cSXin LI #include <stdlib.h>
37681ed54cSXin LI #include <string.h>
38681ed54cSXin LI
39681ed54cSXin LI #include <bluetooth/bluetooth.h>
40681ed54cSXin LI #include <bluetooth/hci.h>
41681ed54cSXin LI
42681ed54cSXin LI #include "pcap/bluetooth.h"
43681ed54cSXin LI #include "pcap-int.h"
44*afdbf109SJoseph Mingrone #include "diag-control.h"
45681ed54cSXin LI
46ada6f083SXin LI #include "pcap-bt-monitor-linux.h"
47ada6f083SXin LI
48681ed54cSXin LI #define BT_CONTROL_SIZE 32
49681ed54cSXin LI #define INTERFACE_NAME "bluetooth-monitor"
50681ed54cSXin LI
51ada6f083SXin LI /*
526f9cba8fSJoseph Mingrone * Private data.
536f9cba8fSJoseph Mingrone * Currently contains nothing.
546f9cba8fSJoseph Mingrone */
556f9cba8fSJoseph Mingrone struct pcap_bt_monitor {
566f9cba8fSJoseph Mingrone int dummy;
576f9cba8fSJoseph Mingrone };
586f9cba8fSJoseph Mingrone
596f9cba8fSJoseph Mingrone /*
60ada6f083SXin LI * Fields and alignment must match the declaration in the Linux kernel 3.4+.
61ada6f083SXin LI * See struct hci_mon_hdr in include/net/bluetooth/hci_mon.h.
62ada6f083SXin LI */
63ada6f083SXin LI struct hci_mon_hdr {
64ada6f083SXin LI uint16_t opcode;
65ada6f083SXin LI uint16_t index;
66ada6f083SXin LI uint16_t len;
67ada6f083SXin LI } __attribute__((packed));
68ada6f083SXin LI
69681ed54cSXin LI int
bt_monitor_findalldevs(pcap_if_list_t * devlistp,char * err_str)70b00ab754SHans Petter Selasky bt_monitor_findalldevs(pcap_if_list_t *devlistp, char *err_str)
71681ed54cSXin LI {
72681ed54cSXin LI int ret = 0;
73681ed54cSXin LI
74b00ab754SHans Petter Selasky /*
75b00ab754SHans Petter Selasky * Bluetooth is a wireless technology.
76b00ab754SHans Petter Selasky *
77b00ab754SHans Petter Selasky * This is a device to monitor all Bluetooth interfaces, so
78b00ab754SHans Petter Selasky * there's no notion of "connected" or "disconnected", any
79b00ab754SHans Petter Selasky * more than there's a notion of "connected" or "disconnected"
80b00ab754SHans Petter Selasky * for the "any" device.
81b00ab754SHans Petter Selasky */
82*afdbf109SJoseph Mingrone if (pcapint_add_dev(devlistp, INTERFACE_NAME,
83b00ab754SHans Petter Selasky PCAP_IF_WIRELESS|PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
84b00ab754SHans Petter Selasky "Bluetooth Linux Monitor", err_str) == NULL)
85681ed54cSXin LI {
86*afdbf109SJoseph Mingrone ret = PCAP_ERROR;
87681ed54cSXin LI }
88681ed54cSXin LI
89681ed54cSXin LI return ret;
90681ed54cSXin LI }
91681ed54cSXin LI
92681ed54cSXin LI static int
bt_monitor_read(pcap_t * handle,int max_packets _U_,pcap_handler callback,u_char * user)93681ed54cSXin LI bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user)
94681ed54cSXin LI {
95681ed54cSXin LI struct cmsghdr *cmsg;
96681ed54cSXin LI struct msghdr msg;
97681ed54cSXin LI struct iovec iv[2];
98681ed54cSXin LI ssize_t ret;
99681ed54cSXin LI struct pcap_pkthdr pkth;
100681ed54cSXin LI pcap_bluetooth_linux_monitor_header *bthdr;
101ada6f083SXin LI u_char *pktd;
102ada6f083SXin LI struct hci_mon_hdr hdr;
103681ed54cSXin LI
104ada6f083SXin LI pktd = (u_char *)handle->buffer + BT_CONTROL_SIZE;
105ada6f083SXin LI bthdr = (pcap_bluetooth_linux_monitor_header*)(void *)pktd;
106681ed54cSXin LI
107681ed54cSXin LI iv[0].iov_base = &hdr;
108ada6f083SXin LI iv[0].iov_len = sizeof(hdr);
109ada6f083SXin LI iv[1].iov_base = pktd + sizeof(pcap_bluetooth_linux_monitor_header);
110681ed54cSXin LI iv[1].iov_len = handle->snapshot;
111681ed54cSXin LI
112681ed54cSXin LI memset(&pkth.ts, 0, sizeof(pkth.ts));
113681ed54cSXin LI memset(&msg, 0, sizeof(msg));
114681ed54cSXin LI msg.msg_iov = iv;
115681ed54cSXin LI msg.msg_iovlen = 2;
116681ed54cSXin LI msg.msg_control = handle->buffer;
117ada6f083SXin LI msg.msg_controllen = BT_CONTROL_SIZE;
118681ed54cSXin LI
119681ed54cSXin LI do {
120681ed54cSXin LI if (handle->break_loop)
121681ed54cSXin LI {
122681ed54cSXin LI handle->break_loop = 0;
123*afdbf109SJoseph Mingrone return PCAP_ERROR_BREAK;
124681ed54cSXin LI }
125*afdbf109SJoseph Mingrone ret = recvmsg(handle->fd, &msg, 0);
126681ed54cSXin LI } while ((ret == -1) && (errno == EINTR));
127681ed54cSXin LI
128681ed54cSXin LI if (ret < 0) {
1296f9cba8fSJoseph Mingrone if (errno == EAGAIN || errno == EWOULDBLOCK) {
1306f9cba8fSJoseph Mingrone /* Nonblocking mode, no data */
1316f9cba8fSJoseph Mingrone return 0;
1326f9cba8fSJoseph Mingrone }
133*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
134b00ab754SHans Petter Selasky errno, "Can't receive packet");
135*afdbf109SJoseph Mingrone return PCAP_ERROR;
136681ed54cSXin LI }
137681ed54cSXin LI
1386f9cba8fSJoseph Mingrone pkth.caplen = (bpf_u_int32)(ret - sizeof(hdr) + sizeof(pcap_bluetooth_linux_monitor_header));
139681ed54cSXin LI pkth.len = pkth.caplen;
140681ed54cSXin LI
141*afdbf109SJoseph Mingrone // for musl libc CMSG_NXTHDR()
142*afdbf109SJoseph Mingrone DIAG_OFF_SIGN_COMPARE
143681ed54cSXin LI for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
144*afdbf109SJoseph Mingrone DIAG_ON_SIGN_COMPARE
145681ed54cSXin LI if (cmsg->cmsg_level != SOL_SOCKET) continue;
146681ed54cSXin LI
147681ed54cSXin LI if (cmsg->cmsg_type == SCM_TIMESTAMP) {
148681ed54cSXin LI memcpy(&pkth.ts, CMSG_DATA(cmsg), sizeof(pkth.ts));
149681ed54cSXin LI }
150681ed54cSXin LI }
151681ed54cSXin LI
152681ed54cSXin LI bthdr->adapter_id = htons(hdr.index);
153681ed54cSXin LI bthdr->opcode = htons(hdr.opcode);
154681ed54cSXin LI
155681ed54cSXin LI if (handle->fcode.bf_insns == NULL ||
156*afdbf109SJoseph Mingrone pcapint_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
157ada6f083SXin LI callback(user, &pkth, pktd);
158681ed54cSXin LI return 1;
159681ed54cSXin LI }
160681ed54cSXin LI return 0; /* didn't pass filter */
161681ed54cSXin LI }
162681ed54cSXin LI
163681ed54cSXin LI static int
bt_monitor_inject(pcap_t * handle,const void * buf _U_,int size _U_)1646f9cba8fSJoseph Mingrone bt_monitor_inject(pcap_t *handle, const void *buf _U_, int size _U_)
165681ed54cSXin LI {
1666f9cba8fSJoseph Mingrone snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
16757e22627SCy Schubert "Packet injection is not supported yet on Bluetooth monitor devices");
168*afdbf109SJoseph Mingrone return PCAP_ERROR;
169681ed54cSXin LI }
170681ed54cSXin LI
171681ed54cSXin LI static int
bt_monitor_stats(pcap_t * handle _U_,struct pcap_stat * stats)172681ed54cSXin LI bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats)
173681ed54cSXin LI {
174681ed54cSXin LI stats->ps_recv = 0;
175681ed54cSXin LI stats->ps_drop = 0;
176681ed54cSXin LI stats->ps_ifdrop = 0;
177681ed54cSXin LI
178681ed54cSXin LI return 0;
179681ed54cSXin LI }
180681ed54cSXin LI
181681ed54cSXin LI static int
bt_monitor_activate(pcap_t * handle)182681ed54cSXin LI bt_monitor_activate(pcap_t* handle)
183681ed54cSXin LI {
184681ed54cSXin LI struct sockaddr_hci addr;
185681ed54cSXin LI int err = PCAP_ERROR;
186681ed54cSXin LI int opt;
187681ed54cSXin LI
188681ed54cSXin LI if (handle->opt.rfmon) {
189681ed54cSXin LI /* monitor mode doesn't apply here */
190681ed54cSXin LI return PCAP_ERROR_RFMON_NOTSUP;
191681ed54cSXin LI }
192681ed54cSXin LI
193b00ab754SHans Petter Selasky /*
194b00ab754SHans Petter Selasky * Turn a negative snapshot value (invalid), a snapshot value of
195b00ab754SHans Petter Selasky * 0 (unspecified), or a value bigger than the normal maximum
196b00ab754SHans Petter Selasky * value, into the maximum allowed value.
197b00ab754SHans Petter Selasky *
198b00ab754SHans Petter Selasky * If some application really *needs* a bigger snapshot
199b00ab754SHans Petter Selasky * length, we should just increase MAXIMUM_SNAPLEN.
200b00ab754SHans Petter Selasky */
201b00ab754SHans Petter Selasky if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
202b00ab754SHans Petter Selasky handle->snapshot = MAXIMUM_SNAPLEN;
203b00ab754SHans Petter Selasky
204ada6f083SXin LI handle->bufsize = BT_CONTROL_SIZE + sizeof(pcap_bluetooth_linux_monitor_header) + handle->snapshot;
205681ed54cSXin LI handle->linktype = DLT_BLUETOOTH_LINUX_MONITOR;
206681ed54cSXin LI
207681ed54cSXin LI handle->read_op = bt_monitor_read;
208681ed54cSXin LI handle->inject_op = bt_monitor_inject;
209*afdbf109SJoseph Mingrone handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */
2106f9cba8fSJoseph Mingrone handle->setdirection_op = NULL; /* Not implemented */
211681ed54cSXin LI handle->set_datalink_op = NULL; /* can't change data link type */
212*afdbf109SJoseph Mingrone handle->getnonblock_op = pcapint_getnonblock_fd;
213*afdbf109SJoseph Mingrone handle->setnonblock_op = pcapint_setnonblock_fd;
214681ed54cSXin LI handle->stats_op = bt_monitor_stats;
215681ed54cSXin LI
216681ed54cSXin LI handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
217681ed54cSXin LI if (handle->fd < 0) {
218*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
219b00ab754SHans Petter Selasky errno, "Can't create raw socket");
220681ed54cSXin LI return PCAP_ERROR;
221681ed54cSXin LI }
222681ed54cSXin LI
223681ed54cSXin LI handle->buffer = malloc(handle->bufsize);
224681ed54cSXin LI if (!handle->buffer) {
225*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
226b00ab754SHans Petter Selasky errno, "Can't allocate dump buffer");
227681ed54cSXin LI goto close_fail;
228681ed54cSXin LI }
229681ed54cSXin LI
230681ed54cSXin LI /* Bind socket to the HCI device */
231681ed54cSXin LI addr.hci_family = AF_BLUETOOTH;
232681ed54cSXin LI addr.hci_dev = HCI_DEV_NONE;
233681ed54cSXin LI addr.hci_channel = HCI_CHANNEL_MONITOR;
234681ed54cSXin LI
235681ed54cSXin LI if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
236*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
237b00ab754SHans Petter Selasky errno, "Can't attach to interface");
238681ed54cSXin LI goto close_fail;
239681ed54cSXin LI }
240681ed54cSXin LI
241681ed54cSXin LI opt = 1;
242681ed54cSXin LI if (setsockopt(handle->fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) {
243*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
244b00ab754SHans Petter Selasky errno, "Can't enable time stamp");
245681ed54cSXin LI goto close_fail;
246681ed54cSXin LI }
247681ed54cSXin LI
248681ed54cSXin LI handle->selectable_fd = handle->fd;
249681ed54cSXin LI
250681ed54cSXin LI return 0;
251681ed54cSXin LI
252681ed54cSXin LI close_fail:
253*afdbf109SJoseph Mingrone pcapint_cleanup_live_common(handle);
254681ed54cSXin LI return err;
255681ed54cSXin LI }
256681ed54cSXin LI
257681ed54cSXin LI pcap_t *
bt_monitor_create(const char * device,char * ebuf,int * is_ours)258681ed54cSXin LI bt_monitor_create(const char *device, char *ebuf, int *is_ours)
259681ed54cSXin LI {
260681ed54cSXin LI pcap_t *p;
261681ed54cSXin LI const char *cp;
262681ed54cSXin LI
263681ed54cSXin LI cp = strrchr(device, '/');
264681ed54cSXin LI if (cp == NULL)
265681ed54cSXin LI cp = device;
266681ed54cSXin LI
267681ed54cSXin LI if (strcmp(cp, INTERFACE_NAME) != 0) {
268681ed54cSXin LI *is_ours = 0;
269681ed54cSXin LI return NULL;
270681ed54cSXin LI }
271681ed54cSXin LI
272681ed54cSXin LI *is_ours = 1;
2736f9cba8fSJoseph Mingrone p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt_monitor);
274681ed54cSXin LI if (p == NULL)
275681ed54cSXin LI return NULL;
276681ed54cSXin LI
277681ed54cSXin LI p->activate_op = bt_monitor_activate;
278681ed54cSXin LI
279681ed54cSXin LI return p;
280681ed54cSXin LI }
281