xref: /libbtbb/lib/src/pcap.c (revision 25d64f63a355f4c01d10cf4f69da1c2246b040d9)
1 /* -*- c -*- */
2 /*
3  * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com
4  *
5  * This file is part of libbtbb
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with libbtbb; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 #include "bluetooth_le_packet.h"
23 #include "bluetooth_packet.h"
24 #include "btbb.h"
25 #include "pcap-common.h"
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 
31 typedef enum {
32 	PCAP_OK = 0,
33 	PCAP_INVALID_HANDLE,
34 	PCAP_FILE_NOT_ALLOWED,
35 	PCAP_NO_MEMORY,
36 } PCAP_RESULT;
37 
38 typedef struct __attribute__((packed)) pcap_hdr_s {
39 	uint32_t magic_number;   /* magic number */
40 	uint16_t version_major;  /* major version number */
41 	uint16_t version_minor;  /* minor version number */
42 	int32_t  thiszone;       /* GMT to local correction */
43 	uint32_t sigfigs;        /* accuracy of timestamps */
44 	uint32_t snaplen;        /* max length of captured packets, in octets */
45 	uint32_t network;        /* data link type */
46 } pcap_hdr_t;
47 
48 FILE *btbb_pcap_open(const char *filename, uint32_t dlt, uint32_t snaplen) {
49 	pcap_hdr_t pcap_header = {
50 		.magic_number = 0xa1b23c4d,
51 		.version_major = 2,
52 		.version_minor = 4,
53 		.thiszone = 0,
54 		.sigfigs = 0,
55 		.snaplen = snaplen,
56 		.network = dlt,
57 	};
58 
59 	FILE *pcap_file = fopen(filename, "w");
60 	if (pcap_file == NULL) return NULL;
61 
62 	fwrite(&pcap_header, sizeof(pcap_header), 1, pcap_file);
63 
64 	return pcap_file;
65 }
66 
67 /* BT BR/EDR support */
68 
69 struct btbb_pcap_handle {
70 	FILE *pcap_file;
71 };
72 
73 int
74 btbb_pcap_create_file(const char *filename, btbb_pcap_handle ** ph)
75 {
76 	int retval = 0;
77 	btbb_pcap_handle * handle = malloc( sizeof(btbb_pcap_handle) );
78 	if (handle) {
79 		memset(handle, 0, sizeof(*handle));
80 		handle->pcap_file = btbb_pcap_open(filename, DLT_BLUETOOTH_BREDR_BB,
81 											BREDR_MAX_PAYLOAD);
82 		if (handle->pcap_file) {
83 			*ph = handle;
84 		}
85 		else {
86 			perror("PCAP error:");
87 			retval = -PCAP_FILE_NOT_ALLOWED;
88 			goto fail;
89 		}
90 	}
91 	else {
92 		retval = -PCAP_NO_MEMORY;
93 		goto fail;
94 	}
95 	return retval;
96 fail:
97 	(void) btbb_pcap_close( handle );
98 	return retval;
99 }
100 
101 typedef struct __attribute__((packed)) pcaprec_hdr_s {
102 	uint32_t ts_sec;         /* timestamp seconds */
103 	uint32_t ts_usec;        /* timestamp microseconds */
104 	uint32_t incl_len;       /* number of octets of packet saved in file */
105 	uint32_t orig_len;       /* actual length of packet */
106 } pcaprec_hdr_t;
107 
108 typedef struct {
109 	pcaprec_hdr_t pcap_header;
110 	pcap_bluetooth_bredr_bb_header bredr_bb_header;
111 } pcap_bredr_packet;
112 
113 void btbb_pcap_dump(FILE *file, pcaprec_hdr_t *pcap_header, u_char *data) {
114 	fwrite(pcap_header, sizeof(*pcap_header), 1, file);
115 	fwrite(data, pcap_header->incl_len, 1, file);
116 	fflush(file);
117 }
118 
119 static void
120 assemble_pcapng_bredr_packet( pcap_bredr_packet * pkt,
121 			      const uint32_t interface_id __attribute__((unused)),
122 			      const uint64_t ns,
123 			      const uint32_t caplen,
124 			      const uint8_t rf_channel,
125 			      const int8_t signal_power,
126 			      const int8_t noise_power,
127 			      const uint8_t access_code_offenses,
128 			      const uint8_t payload_transport,
129 			      const uint8_t payload_rate,
130 			      const uint8_t corrected_header_bits,
131 			      const int16_t corrected_payload_bits,
132 			      const uint32_t lap,
133 			      const uint32_t ref_lap,
134 			      const uint8_t ref_uap,
135 			      const uint32_t bt_header,
136 			      const uint16_t flags,
137 			      const uint8_t * payload )
138 {
139 	uint32_t pcap_caplen = sizeof(pcap_bluetooth_bredr_bb_header) -
140 				sizeof(pkt->bredr_bb_header.bredr_payload)
141 				+ caplen;
142 	uint32_t reflapuap = (ref_lap&0xffffff) | (ref_uap<<24);
143 
144 	pkt->pcap_header.ts_sec  = ns / 1000000000ull;
145 	pkt->pcap_header.ts_usec = ns % 1000000000ull;
146 	pkt->pcap_header.incl_len = pcap_caplen;
147 	pkt->pcap_header.orig_len = pcap_caplen;
148 
149 	pkt->bredr_bb_header.rf_channel = rf_channel;
150 	pkt->bredr_bb_header.signal_power = signal_power;
151 	pkt->bredr_bb_header.noise_power = noise_power;
152 	pkt->bredr_bb_header.access_code_offenses = access_code_offenses;
153 	pkt->bredr_bb_header.payload_transport_rate =
154 		(payload_transport << 4) | payload_rate;
155 	pkt->bredr_bb_header.corrected_header_bits = corrected_header_bits;
156 	pkt->bredr_bb_header.corrected_payload_bits = htole16( corrected_payload_bits );
157 	pkt->bredr_bb_header.lap = htole32( lap );
158 	pkt->bredr_bb_header.ref_lap_uap = htole32( reflapuap );
159 	pkt->bredr_bb_header.bt_header = htole32( bt_header );
160 	pkt->bredr_bb_header.flags = htole16( flags );
161 	if (caplen) {
162 		assert(caplen <= sizeof(pkt->bredr_bb_header.bredr_payload)); // caller ensures this, but to be safe..
163 		(void) memcpy( &pkt->bredr_bb_header.bredr_payload[0], payload, caplen );
164 		pkt->bredr_bb_header.flags |= htole16( BREDR_PAYLOAD_PRESENT );
165 	}
166 	else {
167 		pkt->bredr_bb_header.flags &= htole16( ~BREDR_PAYLOAD_PRESENT );
168 	}
169 }
170 
171 int
172 btbb_pcap_append_packet(btbb_pcap_handle * h, const uint64_t ns,
173 			const int8_t sigdbm, const int8_t noisedbm,
174 			const uint32_t reflap, const uint8_t refuap,
175 			const btbb_packet *pkt)
176 {
177 	if (h && h->pcap_file) {
178 		uint16_t flags = BREDR_DEWHITENED | BREDR_SIGPOWER_VALID |
179 			((noisedbm < sigdbm) ? BREDR_NOISEPOWER_VALID : 0) |
180 			((reflap != LAP_ANY) ? BREDR_REFLAP_VALID : 0) |
181 			((refuap != UAP_ANY) ? BREDR_REFUAP_VALID : 0);
182 		uint32_t caplen = (uint32_t) btbb_packet_get_payload_length(pkt);
183 		uint8_t payload_bytes[caplen];
184 		btbb_get_payload_packed( pkt, (char *) &payload_bytes[0] );
185 		caplen = MIN(BREDR_MAX_PAYLOAD, caplen);
186 		pcap_bredr_packet pcap_pkt;
187 		assemble_pcapng_bredr_packet( &pcap_pkt,
188 					      0,
189 					      ns,
190 					      caplen,
191 					      btbb_packet_get_channel(pkt),
192 					      sigdbm,
193 					      noisedbm,
194 					      btbb_packet_get_ac_errors(pkt),
195 						  btbb_packet_get_transport(pkt),
196 						  btbb_packet_get_modulation(pkt),
197 					      0, /* TODO: corrected header bits */
198 					      0, /* TODO: corrected payload bits */
199 					      btbb_packet_get_lap(pkt),
200 					      reflap,
201 					      refuap,
202 					      btbb_packet_get_header_packed(pkt),
203 					      flags,
204 					      payload_bytes );
205 		btbb_pcap_dump(h->pcap_file, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.bredr_bb_header);
206 		return 0;
207 	}
208 	return -PCAP_INVALID_HANDLE;
209 }
210 
211 int
212 btbb_pcap_close(btbb_pcap_handle * h)
213 {
214 	if (h && h->pcap_file) {
215 		fclose(h->pcap_file);
216 	}
217 	if (h) {
218 		free(h);
219 		return 0;
220 	}
221 	return -PCAP_INVALID_HANDLE;
222 }
223 
224 /* BTLE support */
225 
226 struct lell_pcap_handle {
227 	FILE *pcap_file;
228 	int dlt;
229 	uint8_t btle_ppi_version;
230 };
231 
232 static int
233 lell_pcap_create_file_dlt(const char *filename, int dlt, lell_pcap_handle ** ph)
234 {
235 	int retval = 0;
236 	lell_pcap_handle * handle = malloc( sizeof(lell_pcap_handle) );
237 	if (handle) {
238 		memset(handle, 0, sizeof(*handle));
239 		handle->pcap_file = btbb_pcap_open(filename, dlt, BREDR_MAX_PAYLOAD);
240 		if (handle->pcap_file) {
241 			handle->dlt = dlt;
242 			*ph = handle;
243 		}
244 		else {
245 			retval = -PCAP_FILE_NOT_ALLOWED;
246 			goto fail;
247 		}
248 	}
249 	else {
250 		retval = -PCAP_NO_MEMORY;
251 		goto fail;
252 	}
253 	return retval;
254 fail:
255 	(void) lell_pcap_close( handle );
256 	return retval;
257 }
258 
259 int
260 lell_pcap_create_file(const char *filename, lell_pcap_handle ** ph)
261 {
262 	return lell_pcap_create_file_dlt(filename, DLT_BLUETOOTH_LE_LL_WITH_PHDR, ph);
263 }
264 
265 int
266 lell_pcap_ppi_create_file(const char *filename, int btle_ppi_version,
267 			  lell_pcap_handle ** ph)
268 {
269 	int retval = lell_pcap_create_file_dlt(filename, DLT_PPI, ph);
270 	if (!retval) {
271 		(*ph)->btle_ppi_version = btle_ppi_version;
272 	}
273 	return retval;
274 }
275 
276 typedef struct {
277 	pcaprec_hdr_t pcap_header;
278 	pcap_bluetooth_le_ll_header le_ll_header;
279 	uint8_t le_packet[LE_MAX_PAYLOAD];
280 } pcap_le_packet;
281 
282 static void
283 assemble_pcapng_le_packet( pcap_le_packet * pkt,
284 			   const uint32_t interface_id __attribute__((unused)),
285 			   const uint64_t ns,
286 			   const uint32_t caplen,
287 			   const uint8_t rf_channel,
288 			   const int8_t signal_power,
289 			   const int8_t noise_power,
290 			   const uint8_t access_address_offenses,
291 			   const uint32_t ref_access_address,
292 			   const uint16_t flags,
293 			   const uint8_t * lepkt )
294 {
295 	uint32_t incl_len = MIN(LE_MAX_PAYLOAD, caplen);
296 
297 	pkt->pcap_header.ts_sec  = ns / 1000000000ull;
298 	pkt->pcap_header.ts_usec = ns % 1000000000ull;
299 	pkt->pcap_header.incl_len = sizeof(pcap_bluetooth_le_ll_header)+caplen;
300 	pkt->pcap_header.orig_len = sizeof(pcap_bluetooth_le_ll_header)+incl_len;
301 
302 	pkt->le_ll_header.rf_channel = rf_channel;
303 	pkt->le_ll_header.signal_power = signal_power;
304 	pkt->le_ll_header.noise_power = noise_power;
305 	pkt->le_ll_header.access_address_offenses = access_address_offenses;
306 	pkt->le_ll_header.ref_access_address = htole32( ref_access_address );
307 	pkt->le_ll_header.flags = htole16( flags );
308 	(void) memcpy( &pkt->le_packet[0], lepkt, incl_len );
309 }
310 
311 int
312 lell_pcap_append_packet(lell_pcap_handle * h, const uint64_t ns,
313 			const int8_t sigdbm, const int8_t noisedbm,
314 			const uint32_t refAA, const lell_packet *pkt)
315 {
316 	if (h && h->pcap_file &&
317 	    (h->dlt == DLT_BLUETOOTH_LE_LL_WITH_PHDR)) {
318 		uint16_t flags = LE_DEWHITENED | LE_AA_OFFENSES_VALID |
319 			LE_SIGPOWER_VALID |
320 			((noisedbm < sigdbm) ? LE_NOISEPOWER_VALID : 0) |
321 			(lell_packet_is_data(pkt) ? 0 : LE_REF_AA_VALID);
322 		pcap_le_packet pcap_pkt;
323 		assemble_pcapng_le_packet( &pcap_pkt,
324 					   0,
325 					   ns,
326 					   pkt->length + 4 + 2 + 3, // AA + header + CRC
327 					   pkt->channel_k,
328 					   sigdbm,
329 					   noisedbm,
330 					   pkt->access_address_offenses,
331 					   refAA,
332 					   flags,
333 					   &pkt->symbols[0] );
334 		btbb_pcap_dump(h->pcap_file, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.le_ll_header);
335 		return 0;
336 	}
337 	return -PCAP_INVALID_HANDLE;
338 }
339 
340 #define PPI_BTLE 30006
341 
342 typedef struct __attribute__((packed)) {
343 	uint8_t pph_version;
344 	uint8_t pph_flags;
345 	uint16_t pph_len;
346 	uint32_t pph_dlt;
347 } ppi_packet_header_t;
348 
349 typedef struct __attribute__((packed)) {
350 	uint16_t pfh_type;
351 	uint16_t pfh_datalen;
352 } ppi_fieldheader_t;
353 
354 typedef struct __attribute__((packed)) {
355 	uint8_t btle_version;
356 	uint16_t btle_channel;
357 	uint8_t btle_clkn_high;
358 	uint32_t btle_clk100ns;
359 	int8_t rssi_max;
360 	int8_t rssi_min;
361 	int8_t rssi_avg;
362 	uint8_t rssi_count;
363 } ppi_btle_t;
364 
365 typedef struct __attribute__((packed)) {
366 	pcaprec_hdr_t pcap_header;
367         ppi_packet_header_t ppi_packet_header;
368 	ppi_fieldheader_t ppi_fieldheader;
369 	ppi_btle_t le_ll_ppi_header;
370 	uint8_t le_packet[LE_MAX_PAYLOAD];
371 } pcap_ppi_le_packet;
372 
373 int
374 lell_pcap_append_ppi_packet(lell_pcap_handle * h, const uint64_t ns,
375 			    const uint8_t clkn_high,
376 			    const int8_t rssi_min, const int8_t rssi_max,
377 			    const int8_t rssi_avg, const uint8_t rssi_count,
378 			    const lell_packet *pkt)
379 {
380 	if (h && h->pcap_file &&
381 	    (h->dlt == DLT_PPI)) {
382 		pcap_ppi_le_packet pcap_pkt;
383 		const uint16_t pcap_headerlen =
384 			sizeof(ppi_packet_header_t) +
385 			sizeof(ppi_fieldheader_t) +
386 			sizeof(ppi_btle_t);
387 		uint16_t MHz = 2402 + 2*lell_get_channel_k(pkt);
388 		unsigned packet_len = pkt->length + 4 + 2 + 3; // AA + header + CRC
389 		unsigned incl_len   = MIN(LE_MAX_PAYLOAD, packet_len);
390 
391 		pcap_pkt.pcap_header.ts_sec  = ns / 1000000000ull;
392 		pcap_pkt.pcap_header.ts_usec = ns % 1000000000ull;
393 		pcap_pkt.pcap_header.incl_len = pcap_headerlen + incl_len;
394 		pcap_pkt.pcap_header.orig_len = pcap_headerlen + packet_len;
395 
396 		pcap_pkt.ppi_packet_header.pph_version = 0;
397 		pcap_pkt.ppi_packet_header.pph_flags = 0;
398 		pcap_pkt.ppi_packet_header.pph_len = htole16(pcap_headerlen);
399 		pcap_pkt.ppi_packet_header.pph_dlt = htole32(DLT_USER0);
400 
401 		pcap_pkt.ppi_fieldheader.pfh_type = htole16(PPI_BTLE);
402 		pcap_pkt.ppi_fieldheader.pfh_datalen = htole16(sizeof(ppi_btle_t));
403 
404 		pcap_pkt.le_ll_ppi_header.btle_version = h->btle_ppi_version;
405 		pcap_pkt.le_ll_ppi_header.btle_channel = htole16(MHz);
406 		pcap_pkt.le_ll_ppi_header.btle_clkn_high = clkn_high;
407 		pcap_pkt.le_ll_ppi_header.btle_clk100ns = htole32(pkt->clk100ns);
408 		pcap_pkt.le_ll_ppi_header.rssi_max = rssi_max;
409 		pcap_pkt.le_ll_ppi_header.rssi_min = rssi_min;
410 		pcap_pkt.le_ll_ppi_header.rssi_avg = rssi_avg;
411 		pcap_pkt.le_ll_ppi_header.rssi_count = rssi_count;
412 		(void) memcpy( &pcap_pkt.le_packet[0], &pkt->symbols[0], incl_len);
413 		btbb_pcap_dump(h->pcap_file, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.ppi_packet_header);
414 		return 0;
415 	}
416 	return -PCAP_INVALID_HANDLE;
417 }
418 
419 int
420 lell_pcap_close(lell_pcap_handle *h)
421 {
422 	if (h && h->pcap_file) {
423 		fclose(h->pcap_file);
424 	}
425 	if (h) {
426 		free(h);
427 		return 0;
428 	}
429 	return -PCAP_INVALID_HANDLE;
430 }
431