nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (c) 2014 Michal Labedzki for Tieto Corporation |
||
3 | * All rights reserved. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions |
||
7 | * are met: |
||
8 | * |
||
9 | * 1. Redistributions of source code must retain the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer. |
||
11 | * 2. Redistributions in binary form must reproduce the above copyright |
||
12 | * notice, this list of conditions and the following disclaimer in the |
||
13 | * documentation and/or other materials provided with the distribution. |
||
14 | * 3. The name of the author may not be used to endorse or promote |
||
15 | * products derived from this software without specific prior written |
||
16 | * permission. |
||
17 | * |
||
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
29 | * |
||
30 | */ |
||
31 | |||
32 | #ifdef HAVE_CONFIG_H |
||
33 | #include "config.h" |
||
34 | #endif |
||
35 | |||
36 | #include <errno.h> |
||
37 | #include <stdlib.h> |
||
38 | #include <string.h> |
||
39 | |||
40 | #include <bluetooth/bluetooth.h> |
||
41 | #include <bluetooth/hci.h> |
||
42 | #include <bluetooth/mgmt.h> |
||
43 | |||
44 | #include "pcap/bluetooth.h" |
||
45 | #include "pcap-int.h" |
||
46 | |||
47 | #include "pcap-bt-monitor-linux.h" |
||
48 | |||
49 | #define BT_CONTROL_SIZE 32 |
||
50 | #define INTERFACE_NAME "bluetooth-monitor" |
||
51 | |||
52 | int |
||
53 | bt_monitor_findalldevs(pcap_if_t **alldevsp, char *err_str) |
||
54 | { |
||
55 | int ret = 0; |
||
56 | |||
57 | if (pcap_add_if(alldevsp, INTERFACE_NAME, 0, |
||
58 | "Bluetooth Linux Monitor", err_str) < 0) |
||
59 | { |
||
60 | ret = -1; |
||
61 | } |
||
62 | |||
63 | return ret; |
||
64 | } |
||
65 | |||
66 | static int |
||
67 | bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) |
||
68 | { |
||
69 | struct cmsghdr *cmsg; |
||
70 | struct msghdr msg; |
||
71 | struct iovec iv[2]; |
||
72 | ssize_t ret; |
||
73 | struct pcap_pkthdr pkth; |
||
74 | pcap_bluetooth_linux_monitor_header *bthdr; |
||
75 | struct mgmt_hdr hdr; |
||
76 | |||
77 | bthdr = (pcap_bluetooth_linux_monitor_header*) &handle->buffer[handle->offset]; |
||
78 | |||
79 | iv[0].iov_base = &hdr; |
||
80 | iv[0].iov_len = MGMT_HDR_SIZE; |
||
81 | iv[1].iov_base = &handle->buffer[handle->offset + sizeof(pcap_bluetooth_linux_monitor_header)]; |
||
82 | iv[1].iov_len = handle->snapshot; |
||
83 | |||
84 | memset(&pkth.ts, 0, sizeof(pkth.ts)); |
||
85 | memset(&msg, 0, sizeof(msg)); |
||
86 | msg.msg_iov = iv; |
||
87 | msg.msg_iovlen = 2; |
||
88 | msg.msg_control = handle->buffer; |
||
89 | msg.msg_controllen = handle->offset; |
||
90 | |||
91 | do { |
||
92 | ret = recvmsg(handle->fd, &msg, 0); |
||
93 | if (handle->break_loop) |
||
94 | { |
||
95 | handle->break_loop = 0; |
||
96 | return -2; |
||
97 | } |
||
98 | } while ((ret == -1) && (errno == EINTR)); |
||
99 | |||
100 | if (ret < 0) { |
||
101 | snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, |
||
102 | "Can't receive packet: %s", strerror(errno)); |
||
103 | return -1; |
||
104 | } |
||
105 | |||
106 | pkth.caplen = ret - MGMT_HDR_SIZE + sizeof(pcap_bluetooth_linux_monitor_header); |
||
107 | pkth.len = pkth.caplen; |
||
108 | |||
109 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
||
110 | if (cmsg->cmsg_level != SOL_SOCKET) continue; |
||
111 | |||
112 | if (cmsg->cmsg_type == SCM_TIMESTAMP) { |
||
113 | memcpy(&pkth.ts, CMSG_DATA(cmsg), sizeof(pkth.ts)); |
||
114 | } |
||
115 | } |
||
116 | |||
117 | bthdr->adapter_id = htons(hdr.index); |
||
118 | bthdr->opcode = htons(hdr.opcode); |
||
119 | |||
120 | if (handle->fcode.bf_insns == NULL || |
||
121 | bpf_filter(handle->fcode.bf_insns, &handle->buffer[handle->offset], |
||
122 | pkth.len, pkth.caplen)) { |
||
123 | callback(user, &pkth, &handle->buffer[handle->offset]); |
||
124 | return 1; |
||
125 | } |
||
126 | return 0; /* didn't pass filter */ |
||
127 | } |
||
128 | |||
129 | static int |
||
130 | bt_monitor_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) |
||
131 | { |
||
132 | snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported yet"); |
||
133 | return -1; |
||
134 | } |
||
135 | |||
136 | static int |
||
137 | bt_monitor_setdirection(pcap_t *p, pcap_direction_t d) |
||
138 | { |
||
139 | p->direction = d; |
||
140 | return 0; |
||
141 | } |
||
142 | |||
143 | static int |
||
144 | bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats) |
||
145 | { |
||
146 | stats->ps_recv = 0; |
||
147 | stats->ps_drop = 0; |
||
148 | stats->ps_ifdrop = 0; |
||
149 | |||
150 | return 0; |
||
151 | } |
||
152 | |||
153 | static int |
||
154 | bt_monitor_activate(pcap_t* handle) |
||
155 | { |
||
156 | struct sockaddr_hci addr; |
||
157 | int err = PCAP_ERROR; |
||
158 | int opt; |
||
159 | |||
160 | if (handle->opt.rfmon) { |
||
161 | /* monitor mode doesn't apply here */ |
||
162 | return PCAP_ERROR_RFMON_NOTSUP; |
||
163 | } |
||
164 | |||
165 | handle->bufsize = handle->snapshot + BT_CONTROL_SIZE + sizeof(pcap_bluetooth_linux_monitor_header); |
||
166 | handle->offset = BT_CONTROL_SIZE; |
||
167 | handle->linktype = DLT_BLUETOOTH_LINUX_MONITOR; |
||
168 | |||
169 | handle->read_op = bt_monitor_read; |
||
170 | handle->inject_op = bt_monitor_inject; |
||
171 | handle->setfilter_op = install_bpf_program; /* no kernel filtering */ |
||
172 | handle->setdirection_op = bt_monitor_setdirection; |
||
173 | handle->set_datalink_op = NULL; /* can't change data link type */ |
||
174 | handle->getnonblock_op = pcap_getnonblock_fd; |
||
175 | handle->setnonblock_op = pcap_setnonblock_fd; |
||
176 | handle->stats_op = bt_monitor_stats; |
||
177 | |||
178 | handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); |
||
179 | if (handle->fd < 0) { |
||
180 | snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, |
||
181 | "Can't create raw socket: %s", strerror(errno)); |
||
182 | return PCAP_ERROR; |
||
183 | } |
||
184 | |||
185 | handle->buffer = malloc(handle->bufsize); |
||
186 | if (!handle->buffer) { |
||
187 | snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", |
||
188 | pcap_strerror(errno)); |
||
189 | goto close_fail; |
||
190 | } |
||
191 | |||
192 | /* Bind socket to the HCI device */ |
||
193 | addr.hci_family = AF_BLUETOOTH; |
||
194 | addr.hci_dev = HCI_DEV_NONE; |
||
195 | addr.hci_channel = HCI_CHANNEL_MONITOR; |
||
196 | |||
197 | if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { |
||
198 | snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, |
||
199 | "Can't attach to interface: %s", strerror(errno)); |
||
200 | goto close_fail; |
||
201 | } |
||
202 | |||
203 | opt = 1; |
||
204 | if (setsockopt(handle->fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) { |
||
205 | snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, |
||
206 | "Can't enable time stamp: %s", strerror(errno)); |
||
207 | goto close_fail; |
||
208 | } |
||
209 | |||
210 | handle->selectable_fd = handle->fd; |
||
211 | |||
212 | return 0; |
||
213 | |||
214 | close_fail: |
||
215 | pcap_cleanup_live_common(handle); |
||
216 | return err; |
||
217 | } |
||
218 | |||
219 | pcap_t * |
||
220 | bt_monitor_create(const char *device, char *ebuf, int *is_ours) |
||
221 | { |
||
222 | pcap_t *p; |
||
223 | const char *cp; |
||
224 | |||
225 | cp = strrchr(device, '/'); |
||
226 | if (cp == NULL) |
||
227 | cp = device; |
||
228 | |||
229 | if (strcmp(cp, INTERFACE_NAME) != 0) { |
||
230 | *is_ours = 0; |
||
231 | return NULL; |
||
232 | } |
||
233 | |||
234 | *is_ours = 1; |
||
235 | p = pcap_create_common(device, ebuf, 0); |
||
236 | if (p == NULL) |
||
237 | return NULL; |
||
238 | |||
239 | p->activate_op = bt_monitor_activate; |
||
240 | |||
241 | return p; |
||
242 | } |