xref: /libbtbb/lib/src/pcapng-bt.c (revision 8f3e7eea1eae731e517c4fd7ac22f1ce3ad3cd5f)
1*8f3e7eeaSChristopher Kilgour /* -*- c -*- */
2*8f3e7eeaSChristopher Kilgour /*
3*8f3e7eeaSChristopher Kilgour  * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com
4*8f3e7eeaSChristopher Kilgour  *
5*8f3e7eeaSChristopher Kilgour  * This file is part of libbtbb
6*8f3e7eeaSChristopher Kilgour  *
7*8f3e7eeaSChristopher Kilgour  * This program is free software; you can redistribute it and/or modify
8*8f3e7eeaSChristopher Kilgour  * it under the terms of the GNU General Public License as published by
9*8f3e7eeaSChristopher Kilgour  * the Free Software Foundation; either version 2, or (at your option)
10*8f3e7eeaSChristopher Kilgour  * any later version.
11*8f3e7eeaSChristopher Kilgour  *
12*8f3e7eeaSChristopher Kilgour  * This program is distributed in the hope that it will be useful,
13*8f3e7eeaSChristopher Kilgour  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*8f3e7eeaSChristopher Kilgour  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*8f3e7eeaSChristopher Kilgour  * GNU General Public License for more details.
16*8f3e7eeaSChristopher Kilgour  *
17*8f3e7eeaSChristopher Kilgour  * You should have received a copy of the GNU General Public License
18*8f3e7eeaSChristopher Kilgour  * along with libbtbb; see the file COPYING.  If not, write to
19*8f3e7eeaSChristopher Kilgour  * the Free Software Foundation, Inc., 51 Franklin Street,
20*8f3e7eeaSChristopher Kilgour  * Boston, MA 02110-1301, USA.
21*8f3e7eeaSChristopher Kilgour  */
22*8f3e7eeaSChristopher Kilgour 
23*8f3e7eeaSChristopher Kilgour #include "btbb.h"
24*8f3e7eeaSChristopher Kilgour #include "bluetooth_le_packet.h"
25*8f3e7eeaSChristopher Kilgour #include "pcapng-bt.h"
26*8f3e7eeaSChristopher Kilgour #include <stdlib.h>
27*8f3e7eeaSChristopher Kilgour #include <string.h>
28*8f3e7eeaSChristopher Kilgour #include <time.h>
29*8f3e7eeaSChristopher Kilgour #include <unistd.h>
30*8f3e7eeaSChristopher Kilgour 
31*8f3e7eeaSChristopher Kilgour /* generic section options indicating libbtbb */
32*8f3e7eeaSChristopher Kilgour const struct {
33*8f3e7eeaSChristopher Kilgour 	struct {
34*8f3e7eeaSChristopher Kilgour 		option_header hdr;
35*8f3e7eeaSChristopher Kilgour 		char libname[8];
36*8f3e7eeaSChristopher Kilgour 	} libopt;
37*8f3e7eeaSChristopher Kilgour 	struct {
38*8f3e7eeaSChristopher Kilgour 		option_header hdr;
39*8f3e7eeaSChristopher Kilgour 	} termopt;
40*8f3e7eeaSChristopher Kilgour } libbtbb_section_options = {
41*8f3e7eeaSChristopher Kilgour 	.libopt = {
42*8f3e7eeaSChristopher Kilgour 		.hdr = {
43*8f3e7eeaSChristopher Kilgour 			.option_code = SHB_USERAPPL,
44*8f3e7eeaSChristopher Kilgour 			.option_length = 7 },
45*8f3e7eeaSChristopher Kilgour 		.libname = "libbtbb"
46*8f3e7eeaSChristopher Kilgour 	},
47*8f3e7eeaSChristopher Kilgour 	.termopt = {
48*8f3e7eeaSChristopher Kilgour 		.hdr = {
49*8f3e7eeaSChristopher Kilgour 			.option_code = OPT_ENDOFOPT,
50*8f3e7eeaSChristopher Kilgour 			.option_length = 0
51*8f3e7eeaSChristopher Kilgour 		}
52*8f3e7eeaSChristopher Kilgour 	}
53*8f3e7eeaSChristopher Kilgour };
54*8f3e7eeaSChristopher Kilgour 
55*8f3e7eeaSChristopher Kilgour static PCAPNG_RESULT
56*8f3e7eeaSChristopher Kilgour check_and_fix_tsresol( PCAPNG_HANDLE * handle,
57*8f3e7eeaSChristopher Kilgour 		       const option_header * interface_options )
58*8f3e7eeaSChristopher Kilgour {
59*8f3e7eeaSChristopher Kilgour 	PCAPNG_RESULT retval = PCAPNG_OK;
60*8f3e7eeaSChristopher Kilgour 	int got_tsresol = 0;
61*8f3e7eeaSChristopher Kilgour 
62*8f3e7eeaSChristopher Kilgour 	while( !got_tsresol &&
63*8f3e7eeaSChristopher Kilgour 	       interface_options &&
64*8f3e7eeaSChristopher Kilgour 	       interface_options->option_code &&
65*8f3e7eeaSChristopher Kilgour 	       interface_options->option_length) {
66*8f3e7eeaSChristopher Kilgour 		if (interface_options->option_code == IF_TSRESOL) {
67*8f3e7eeaSChristopher Kilgour 			got_tsresol = 1;
68*8f3e7eeaSChristopher Kilgour 		}
69*8f3e7eeaSChristopher Kilgour 		else {
70*8f3e7eeaSChristopher Kilgour 			size_t step = 4+4*((interface_options->option_length+3)/4);
71*8f3e7eeaSChristopher Kilgour 			uint8_t * next = &((uint8_t *)interface_options)[step];
72*8f3e7eeaSChristopher Kilgour 			interface_options = (const option_header *) next;
73*8f3e7eeaSChristopher Kilgour 		}
74*8f3e7eeaSChristopher Kilgour 	}
75*8f3e7eeaSChristopher Kilgour 
76*8f3e7eeaSChristopher Kilgour 	if (!got_tsresol) {
77*8f3e7eeaSChristopher Kilgour 		const struct {
78*8f3e7eeaSChristopher Kilgour 			option_header hdr;
79*8f3e7eeaSChristopher Kilgour 			uint8_t resol;
80*8f3e7eeaSChristopher Kilgour 		} tsresol = {
81*8f3e7eeaSChristopher Kilgour 			.hdr = {
82*8f3e7eeaSChristopher Kilgour 				.option_code = IF_TSRESOL,
83*8f3e7eeaSChristopher Kilgour 				.option_length = 1,
84*8f3e7eeaSChristopher Kilgour 			},
85*8f3e7eeaSChristopher Kilgour 			.resol = 9 /* 10^-9 is nanoseconds */
86*8f3e7eeaSChristopher Kilgour 		};
87*8f3e7eeaSChristopher Kilgour 
88*8f3e7eeaSChristopher Kilgour 		retval = pcapng_append_interface_option( handle,
89*8f3e7eeaSChristopher Kilgour 							 (const option_header *) &tsresol );
90*8f3e7eeaSChristopher Kilgour 	}
91*8f3e7eeaSChristopher Kilgour 
92*8f3e7eeaSChristopher Kilgour 	return retval;
93*8f3e7eeaSChristopher Kilgour }
94*8f3e7eeaSChristopher Kilgour 
95*8f3e7eeaSChristopher Kilgour /* --------------------------------- BR/EDR ----------------------------- */
96*8f3e7eeaSChristopher Kilgour 
97*8f3e7eeaSChristopher Kilgour static PCAPNG_RESULT
98*8f3e7eeaSChristopher Kilgour create_bredr_capture_file_single_interface( PCAPNG_HANDLE * handle,
99*8f3e7eeaSChristopher Kilgour 					    const char * filename,
100*8f3e7eeaSChristopher Kilgour 					    const option_header * interface_options )
101*8f3e7eeaSChristopher Kilgour {
102*8f3e7eeaSChristopher Kilgour 	PCAPNG_RESULT retval = PCAPNG_OK;
103*8f3e7eeaSChristopher Kilgour 
104*8f3e7eeaSChristopher Kilgour 	retval = pcapng_create( handle,
105*8f3e7eeaSChristopher Kilgour 				filename,
106*8f3e7eeaSChristopher Kilgour 				(const option_header *) &libbtbb_section_options,
107*8f3e7eeaSChristopher Kilgour 				(size_t) getpagesize( ),
108*8f3e7eeaSChristopher Kilgour 				DLT_BLUETOOTH_BREDR_BB,
109*8f3e7eeaSChristopher Kilgour 				400,
110*8f3e7eeaSChristopher Kilgour 				interface_options,
111*8f3e7eeaSChristopher Kilgour 				(size_t) getpagesize( ) );
112*8f3e7eeaSChristopher Kilgour 
113*8f3e7eeaSChristopher Kilgour 	if (retval == PCAPNG_OK) {
114*8f3e7eeaSChristopher Kilgour 		/* if there is no timestamp resolution alread in the
115*8f3e7eeaSChristopher Kilgour 		   interface options, record nanosecond resolution */
116*8f3e7eeaSChristopher Kilgour 		retval = check_and_fix_tsresol( handle, interface_options );
117*8f3e7eeaSChristopher Kilgour 
118*8f3e7eeaSChristopher Kilgour 		if (retval != PCAPNG_OK) {
119*8f3e7eeaSChristopher Kilgour 			(void) pcapng_close( handle );
120*8f3e7eeaSChristopher Kilgour 		}
121*8f3e7eeaSChristopher Kilgour 	}
122*8f3e7eeaSChristopher Kilgour 
123*8f3e7eeaSChristopher Kilgour 	return retval;
124*8f3e7eeaSChristopher Kilgour }
125*8f3e7eeaSChristopher Kilgour 
126*8f3e7eeaSChristopher Kilgour int btbb_pcapng_create_file( const char *filename,
127*8f3e7eeaSChristopher Kilgour 			     const char *interface_desc,
128*8f3e7eeaSChristopher Kilgour 			     btbb_pcapng_handle ** ph )
129*8f3e7eeaSChristopher Kilgour {
130*8f3e7eeaSChristopher Kilgour 	int retval = PCAPNG_OK;
131*8f3e7eeaSChristopher Kilgour 	PCAPNG_HANDLE * handle = malloc( sizeof(PCAPNG_HANDLE) );
132*8f3e7eeaSChristopher Kilgour 	if (handle) {
133*8f3e7eeaSChristopher Kilgour 		const option_header * popt = NULL;
134*8f3e7eeaSChristopher Kilgour 		struct {
135*8f3e7eeaSChristopher Kilgour 			option_header header;
136*8f3e7eeaSChristopher Kilgour 			char desc[256];
137*8f3e7eeaSChristopher Kilgour 		} ifopt = {
138*8f3e7eeaSChristopher Kilgour 			.header = {
139*8f3e7eeaSChristopher Kilgour 				.option_code = IF_DESCRIPTION,
140*8f3e7eeaSChristopher Kilgour 			}
141*8f3e7eeaSChristopher Kilgour 		};
142*8f3e7eeaSChristopher Kilgour 		if (interface_desc) {
143*8f3e7eeaSChristopher Kilgour 			(void) strncpy( &ifopt.desc[0], interface_desc, 256 );
144*8f3e7eeaSChristopher Kilgour 			ifopt.desc[255] = '\0';
145*8f3e7eeaSChristopher Kilgour 			ifopt.header.option_length = strlen( ifopt.desc );
146*8f3e7eeaSChristopher Kilgour 			popt = (const option_header *) &ifopt;
147*8f3e7eeaSChristopher Kilgour 		}
148*8f3e7eeaSChristopher Kilgour 
149*8f3e7eeaSChristopher Kilgour 		retval = -create_bredr_capture_file_single_interface( handle,
150*8f3e7eeaSChristopher Kilgour 								      filename,
151*8f3e7eeaSChristopher Kilgour 								      popt );
152*8f3e7eeaSChristopher Kilgour 		if (retval == PCAPNG_OK) {
153*8f3e7eeaSChristopher Kilgour 			*ph = (btbb_pcapng_handle *) handle;
154*8f3e7eeaSChristopher Kilgour 		}
155*8f3e7eeaSChristopher Kilgour 		else {
156*8f3e7eeaSChristopher Kilgour 			free( handle );
157*8f3e7eeaSChristopher Kilgour 		}
158*8f3e7eeaSChristopher Kilgour 	}
159*8f3e7eeaSChristopher Kilgour 	else {
160*8f3e7eeaSChristopher Kilgour 		retval = -PCAPNG_NO_MEMORY;
161*8f3e7eeaSChristopher Kilgour 	}
162*8f3e7eeaSChristopher Kilgour 	return retval;
163*8f3e7eeaSChristopher Kilgour }
164*8f3e7eeaSChristopher Kilgour 
165*8f3e7eeaSChristopher Kilgour static PCAPNG_RESULT
166*8f3e7eeaSChristopher Kilgour append_bredr_packet( PCAPNG_HANDLE * handle,
167*8f3e7eeaSChristopher Kilgour 		     pcapng_bredr_packet * pkt )
168*8f3e7eeaSChristopher Kilgour {
169*8f3e7eeaSChristopher Kilgour 	return pcapng_append_packet( handle, ( const enhanced_packet_block *) pkt );
170*8f3e7eeaSChristopher Kilgour }
171*8f3e7eeaSChristopher Kilgour 
172*8f3e7eeaSChristopher Kilgour static void
173*8f3e7eeaSChristopher Kilgour assemble_pcapng_bredr_packet( pcapng_bredr_packet * pkt,
174*8f3e7eeaSChristopher Kilgour 			      const uint32_t interface_id,
175*8f3e7eeaSChristopher Kilgour 			      const uint64_t ns,
176*8f3e7eeaSChristopher Kilgour 			      const uint32_t caplen,
177*8f3e7eeaSChristopher Kilgour 			      const uint8_t rf_channel,
178*8f3e7eeaSChristopher Kilgour 			      const int8_t signal_power,
179*8f3e7eeaSChristopher Kilgour 			      const int8_t noise_power,
180*8f3e7eeaSChristopher Kilgour 			      const uint8_t access_code_offenses,
181*8f3e7eeaSChristopher Kilgour 			      const uint8_t payload_transport,
182*8f3e7eeaSChristopher Kilgour 			      const uint8_t payload_rate,
183*8f3e7eeaSChristopher Kilgour 			      const uint8_t corrected_header_bits,
184*8f3e7eeaSChristopher Kilgour 			      const int16_t corrected_payload_bits,
185*8f3e7eeaSChristopher Kilgour 			      const uint32_t lap,
186*8f3e7eeaSChristopher Kilgour 			      const uint32_t ref_lap,
187*8f3e7eeaSChristopher Kilgour                               const uint8_t ref_uap,
188*8f3e7eeaSChristopher Kilgour 			      const uint32_t bt_header,
189*8f3e7eeaSChristopher Kilgour 			      const uint16_t flags,
190*8f3e7eeaSChristopher Kilgour 			      const uint8_t * payload )
191*8f3e7eeaSChristopher Kilgour {
192*8f3e7eeaSChristopher Kilgour 	uint32_t pcapng_caplen = sizeof(pcap_bluetooth_bredr_bb_header)+caplen;
193*8f3e7eeaSChristopher Kilgour 	uint32_t block_length  = 4*((36+pcapng_caplen+3)/4);
194*8f3e7eeaSChristopher Kilgour 	uint32_t reflapuap = (ref_lap&0xffffff) | (ref_uap<<24);
195*8f3e7eeaSChristopher Kilgour 
196*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.block_type = BLOCK_TYPE_ENHANCED_PACKET;
197*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.block_total_length = block_length;
198*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.interface_id = interface_id;
199*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.timestamp_high = (uint32_t) (ns >> 32);
200*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.timestamp_low = (uint32_t) (ns & 0x0ffffffffull);
201*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.captured_len = pcapng_caplen;
202*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.packet_len = pcapng_caplen;
203*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.rf_channel = rf_channel;
204*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.signal_power = signal_power;
205*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.noise_power = noise_power;
206*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.access_code_offenses = access_code_offenses;
207*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.payload_transport_rate =
208*8f3e7eeaSChristopher Kilgour 		(payload_transport << 4) | payload_rate;
209*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.corrected_header_bits = corrected_header_bits;
210*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.corrected_payload_bits = htole16( corrected_payload_bits );
211*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.lap = htole32( lap );
212*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.ref_lap_uap = htole32( reflapuap );
213*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.bt_header = htole16( bt_header );
214*8f3e7eeaSChristopher Kilgour 	pkt->bredr_bb_header.flags = htole16( flags );
215*8f3e7eeaSChristopher Kilgour 	if (caplen) {
216*8f3e7eeaSChristopher Kilgour 		(void) memcpy( &pkt->bredr_payload[0], payload, caplen );
217*8f3e7eeaSChristopher Kilgour 	}
218*8f3e7eeaSChristopher Kilgour 	else {
219*8f3e7eeaSChristopher Kilgour 		pkt->bredr_bb_header.flags &= htole16( ~BREDR_PAYLOAD_PRESENT );
220*8f3e7eeaSChristopher Kilgour 	}
221*8f3e7eeaSChristopher Kilgour 	((uint32_t *)pkt)[block_length/4-2] = 0x00000000; /* no-options */
222*8f3e7eeaSChristopher Kilgour 	((uint32_t *)pkt)[block_length/4-1] = block_length;
223*8f3e7eeaSChristopher Kilgour }
224*8f3e7eeaSChristopher Kilgour 
225*8f3e7eeaSChristopher Kilgour int btbb_pcapng_append_packet(btbb_pcapng_handle * h, const uint64_t ns,
226*8f3e7eeaSChristopher Kilgour 			      const int8_t sigdbm, const int8_t noisedbm,
227*8f3e7eeaSChristopher Kilgour 			      const uint32_t reflap, const uint8_t refuap,
228*8f3e7eeaSChristopher Kilgour 			      const btbb_packet *pkt)
229*8f3e7eeaSChristopher Kilgour {
230*8f3e7eeaSChristopher Kilgour 	uint16_t flags = BREDR_DEWHITENED | BREDR_SIGPOWER_VALID |
231*8f3e7eeaSChristopher Kilgour 		((noisedbm < sigdbm) ? BREDR_NOISEPOWER_VALID : 0) |
232*8f3e7eeaSChristopher Kilgour 		((reflap != LAP_ANY) ? BREDR_REFLAP_VALID : 0) |
233*8f3e7eeaSChristopher Kilgour 		((refuap != UAP_ANY) ? BREDR_REFUAP_VALID : 0);
234*8f3e7eeaSChristopher Kilgour 	uint8_t payload_bytes[400];
235*8f3e7eeaSChristopher Kilgour 	uint32_t caplen = (uint32_t) btbb_get_payload_packed( pkt, (char *) &payload_bytes[0] );
236*8f3e7eeaSChristopher Kilgour 	pcapng_bredr_packet pcapng_pkt;
237*8f3e7eeaSChristopher Kilgour 	assemble_pcapng_bredr_packet( &pcapng_pkt,
238*8f3e7eeaSChristopher Kilgour 				      0,
239*8f3e7eeaSChristopher Kilgour 				      ns,
240*8f3e7eeaSChristopher Kilgour 				      caplen,
241*8f3e7eeaSChristopher Kilgour 				      btbb_packet_get_channel(pkt),
242*8f3e7eeaSChristopher Kilgour 				      sigdbm,
243*8f3e7eeaSChristopher Kilgour 				      noisedbm,
244*8f3e7eeaSChristopher Kilgour 				      btbb_packet_get_ac_errors(pkt),
245*8f3e7eeaSChristopher Kilgour 				      BREDR_TRANSPORT_ANY,
246*8f3e7eeaSChristopher Kilgour 				      BREDR_GFSK, /* currently only supported */
247*8f3e7eeaSChristopher Kilgour 				      0, /* TODO: corrected header bits */
248*8f3e7eeaSChristopher Kilgour 				      0, /* TODO: corrected payload bits */
249*8f3e7eeaSChristopher Kilgour 				      btbb_packet_get_lap(pkt),
250*8f3e7eeaSChristopher Kilgour 				      reflap,
251*8f3e7eeaSChristopher Kilgour 				      refuap,
252*8f3e7eeaSChristopher Kilgour 				      btbb_packet_get_header_packed(pkt),
253*8f3e7eeaSChristopher Kilgour 				      flags,
254*8f3e7eeaSChristopher Kilgour 				      payload_bytes );
255*8f3e7eeaSChristopher Kilgour 	return -append_bredr_packet( (PCAPNG_HANDLE *)h, &pcapng_pkt );
256*8f3e7eeaSChristopher Kilgour }
257*8f3e7eeaSChristopher Kilgour 
258*8f3e7eeaSChristopher Kilgour static PCAPNG_RESULT
259*8f3e7eeaSChristopher Kilgour record_bd_addr_info( PCAPNG_HANDLE * handle,
260*8f3e7eeaSChristopher Kilgour 		     const uint64_t bd_addr,
261*8f3e7eeaSChristopher Kilgour 		     const uint8_t  uap_mask,
262*8f3e7eeaSChristopher Kilgour                      const uint8_t  nap_valid )
263*8f3e7eeaSChristopher Kilgour {
264*8f3e7eeaSChristopher Kilgour 	const bredr_br_addr_option bdopt = {
265*8f3e7eeaSChristopher Kilgour 		.header = {
266*8f3e7eeaSChristopher Kilgour 			.option_code = PCAPNG_BREDR_OPTION_BD_ADDR,
267*8f3e7eeaSChristopher Kilgour 			.option_length = sizeof(bredr_br_addr_option),
268*8f3e7eeaSChristopher Kilgour 		},
269*8f3e7eeaSChristopher Kilgour 		.bd_addr_info = {
270*8f3e7eeaSChristopher Kilgour 			.bd_addr = {
271*8f3e7eeaSChristopher Kilgour 				((bd_addr>>0)  & 0xff),
272*8f3e7eeaSChristopher Kilgour 				((bd_addr>>8)  & 0xff),
273*8f3e7eeaSChristopher Kilgour 				((bd_addr>>16) & 0xff),
274*8f3e7eeaSChristopher Kilgour 				((bd_addr>>24) & 0xff),
275*8f3e7eeaSChristopher Kilgour 				((bd_addr>>32) & 0xff),
276*8f3e7eeaSChristopher Kilgour 				((bd_addr>>40) & 0xff)
277*8f3e7eeaSChristopher Kilgour 			},
278*8f3e7eeaSChristopher Kilgour 			.uap_mask = uap_mask,
279*8f3e7eeaSChristopher Kilgour 			.nap_valid = nap_valid,
280*8f3e7eeaSChristopher Kilgour 		}
281*8f3e7eeaSChristopher Kilgour 	};
282*8f3e7eeaSChristopher Kilgour 	return pcapng_append_interface_option( handle,
283*8f3e7eeaSChristopher Kilgour 					       (const option_header *) &bdopt );
284*8f3e7eeaSChristopher Kilgour }
285*8f3e7eeaSChristopher Kilgour 
286*8f3e7eeaSChristopher Kilgour int btbb_pcapng_record_bdaddr(btbb_pcapng_handle * h, const uint64_t bdaddr,
287*8f3e7eeaSChristopher Kilgour                               const uint8_t uapmask, const uint8_t napvalid)
288*8f3e7eeaSChristopher Kilgour {
289*8f3e7eeaSChristopher Kilgour 	return -record_bd_addr_info( (PCAPNG_HANDLE *) h,
290*8f3e7eeaSChristopher Kilgour 				     bdaddr, uapmask, napvalid );
291*8f3e7eeaSChristopher Kilgour }
292*8f3e7eeaSChristopher Kilgour 
293*8f3e7eeaSChristopher Kilgour static PCAPNG_RESULT
294*8f3e7eeaSChristopher Kilgour record_bredr_master_clock_info( PCAPNG_HANDLE * handle,
295*8f3e7eeaSChristopher Kilgour 				const uint64_t bd_addr,
296*8f3e7eeaSChristopher Kilgour 				const uint64_t ns,
297*8f3e7eeaSChristopher Kilgour 				const uint32_t clk,
298*8f3e7eeaSChristopher Kilgour 	                        const uint32_t clk_mask)
299*8f3e7eeaSChristopher Kilgour {
300*8f3e7eeaSChristopher Kilgour 	const bredr_clk_option mcopt = {
301*8f3e7eeaSChristopher Kilgour 		.header = {
302*8f3e7eeaSChristopher Kilgour 			.option_code = PCAPNG_BREDR_OPTION_MASTER_CLOCK_INFO,
303*8f3e7eeaSChristopher Kilgour 			.option_length = sizeof(bredr_clk_option)
304*8f3e7eeaSChristopher Kilgour 		},
305*8f3e7eeaSChristopher Kilgour 		.clock_info = {
306*8f3e7eeaSChristopher Kilgour 			.ts = ns,
307*8f3e7eeaSChristopher Kilgour 			.lap_uap = htole32(bd_addr & 0xffffffff),
308*8f3e7eeaSChristopher Kilgour 			.clk = clk,
309*8f3e7eeaSChristopher Kilgour 			.clk_mask = clk_mask
310*8f3e7eeaSChristopher Kilgour 		}
311*8f3e7eeaSChristopher Kilgour 	};
312*8f3e7eeaSChristopher Kilgour 	return pcapng_append_interface_option( handle,
313*8f3e7eeaSChristopher Kilgour 					       (const option_header *) &mcopt );
314*8f3e7eeaSChristopher Kilgour }
315*8f3e7eeaSChristopher Kilgour 
316*8f3e7eeaSChristopher Kilgour int btbb_pcapng_record_btclock(btbb_pcapng_handle * h, const uint64_t bdaddr,
317*8f3e7eeaSChristopher Kilgour                                const uint64_t ns, const uint32_t clk,
318*8f3e7eeaSChristopher Kilgour 			       const uint32_t clkmask)
319*8f3e7eeaSChristopher Kilgour {
320*8f3e7eeaSChristopher Kilgour 	return -record_bredr_master_clock_info( (PCAPNG_HANDLE *) h,
321*8f3e7eeaSChristopher Kilgour 						bdaddr, ns, clk, clkmask );
322*8f3e7eeaSChristopher Kilgour }
323*8f3e7eeaSChristopher Kilgour 
324*8f3e7eeaSChristopher Kilgour int btbb_pcapng_close(btbb_pcapng_handle * h)
325*8f3e7eeaSChristopher Kilgour {
326*8f3e7eeaSChristopher Kilgour 	pcapng_close( (PCAPNG_HANDLE *) h );
327*8f3e7eeaSChristopher Kilgour 	if (h) {
328*8f3e7eeaSChristopher Kilgour 		free( h );
329*8f3e7eeaSChristopher Kilgour 	}
330*8f3e7eeaSChristopher Kilgour 	return -PCAPNG_INVALID_HANDLE;
331*8f3e7eeaSChristopher Kilgour }
332*8f3e7eeaSChristopher Kilgour 
333*8f3e7eeaSChristopher Kilgour /* --------------------------------- Low Energy ---------------------------- */
334*8f3e7eeaSChristopher Kilgour 
335*8f3e7eeaSChristopher Kilgour static PCAPNG_RESULT
336*8f3e7eeaSChristopher Kilgour create_le_capture_file_single_interface( PCAPNG_HANDLE * handle,
337*8f3e7eeaSChristopher Kilgour 					 const char * filename,
338*8f3e7eeaSChristopher Kilgour 					 const option_header * interface_options )
339*8f3e7eeaSChristopher Kilgour {
340*8f3e7eeaSChristopher Kilgour 	PCAPNG_RESULT retval = PCAPNG_OK;
341*8f3e7eeaSChristopher Kilgour 
342*8f3e7eeaSChristopher Kilgour 	retval = pcapng_create( handle,
343*8f3e7eeaSChristopher Kilgour 				filename,
344*8f3e7eeaSChristopher Kilgour 				(const option_header *) &libbtbb_section_options,
345*8f3e7eeaSChristopher Kilgour 				(size_t) getpagesize( ),
346*8f3e7eeaSChristopher Kilgour 				DLT_BLUETOOTH_LE_LL_WITH_PHDR,
347*8f3e7eeaSChristopher Kilgour 				64,
348*8f3e7eeaSChristopher Kilgour 				interface_options,
349*8f3e7eeaSChristopher Kilgour 				(size_t) getpagesize( ) );
350*8f3e7eeaSChristopher Kilgour 
351*8f3e7eeaSChristopher Kilgour 	if (retval == PCAPNG_OK) {
352*8f3e7eeaSChristopher Kilgour 		/* if there is no timestamp resolution alread in the
353*8f3e7eeaSChristopher Kilgour 		   interface options, record nanosecond resolution */
354*8f3e7eeaSChristopher Kilgour 		retval = check_and_fix_tsresol( handle, interface_options );
355*8f3e7eeaSChristopher Kilgour 
356*8f3e7eeaSChristopher Kilgour 		if (retval != PCAPNG_OK) {
357*8f3e7eeaSChristopher Kilgour 			(void) pcapng_close( handle );
358*8f3e7eeaSChristopher Kilgour 		}
359*8f3e7eeaSChristopher Kilgour 	}
360*8f3e7eeaSChristopher Kilgour 
361*8f3e7eeaSChristopher Kilgour 	return retval;
362*8f3e7eeaSChristopher Kilgour }
363*8f3e7eeaSChristopher Kilgour 
364*8f3e7eeaSChristopher Kilgour int
365*8f3e7eeaSChristopher Kilgour lell_pcapng_create_file(const char *filename, const char *interface_desc,
366*8f3e7eeaSChristopher Kilgour 			lell_pcapng_handle ** ph)
367*8f3e7eeaSChristopher Kilgour {
368*8f3e7eeaSChristopher Kilgour 	int retval = PCAPNG_OK;
369*8f3e7eeaSChristopher Kilgour 	PCAPNG_HANDLE * handle = malloc( sizeof(PCAPNG_HANDLE) );
370*8f3e7eeaSChristopher Kilgour 	if (handle) {
371*8f3e7eeaSChristopher Kilgour 		const option_header * popt = NULL;
372*8f3e7eeaSChristopher Kilgour 		struct {
373*8f3e7eeaSChristopher Kilgour 			option_header header;
374*8f3e7eeaSChristopher Kilgour 			char desc[256];
375*8f3e7eeaSChristopher Kilgour 		} ifopt = {
376*8f3e7eeaSChristopher Kilgour 			.header = {
377*8f3e7eeaSChristopher Kilgour 				.option_code = IF_DESCRIPTION,
378*8f3e7eeaSChristopher Kilgour 			}
379*8f3e7eeaSChristopher Kilgour 		};
380*8f3e7eeaSChristopher Kilgour 		if (interface_desc) {
381*8f3e7eeaSChristopher Kilgour 			(void) strncpy( &ifopt.desc[0], interface_desc, 256 );
382*8f3e7eeaSChristopher Kilgour 			ifopt.desc[255] = '\0';
383*8f3e7eeaSChristopher Kilgour 			ifopt.header.option_length = strlen( ifopt.desc );
384*8f3e7eeaSChristopher Kilgour 			popt = (const option_header *) &ifopt;
385*8f3e7eeaSChristopher Kilgour 		}
386*8f3e7eeaSChristopher Kilgour 
387*8f3e7eeaSChristopher Kilgour 		retval = -create_le_capture_file_single_interface( handle,
388*8f3e7eeaSChristopher Kilgour 								   filename,
389*8f3e7eeaSChristopher Kilgour 								   popt );
390*8f3e7eeaSChristopher Kilgour 		if (retval == PCAPNG_OK) {
391*8f3e7eeaSChristopher Kilgour 			*ph = (lell_pcapng_handle *) handle;
392*8f3e7eeaSChristopher Kilgour 		}
393*8f3e7eeaSChristopher Kilgour 		else {
394*8f3e7eeaSChristopher Kilgour 			free( handle );
395*8f3e7eeaSChristopher Kilgour 		}
396*8f3e7eeaSChristopher Kilgour 	}
397*8f3e7eeaSChristopher Kilgour 	else {
398*8f3e7eeaSChristopher Kilgour 		retval = -PCAPNG_NO_MEMORY;
399*8f3e7eeaSChristopher Kilgour 	}
400*8f3e7eeaSChristopher Kilgour 	return retval;
401*8f3e7eeaSChristopher Kilgour }
402*8f3e7eeaSChristopher Kilgour 
403*8f3e7eeaSChristopher Kilgour static PCAPNG_RESULT
404*8f3e7eeaSChristopher Kilgour append_le_packet( PCAPNG_HANDLE * handle,
405*8f3e7eeaSChristopher Kilgour 		  pcapng_le_packet * pkt )
406*8f3e7eeaSChristopher Kilgour {
407*8f3e7eeaSChristopher Kilgour 	return pcapng_append_packet( handle, ( const enhanced_packet_block *) pkt );
408*8f3e7eeaSChristopher Kilgour }
409*8f3e7eeaSChristopher Kilgour 
410*8f3e7eeaSChristopher Kilgour static void
411*8f3e7eeaSChristopher Kilgour assemble_pcapng_le_packet( pcapng_le_packet * pkt,
412*8f3e7eeaSChristopher Kilgour 			   const uint32_t interface_id,
413*8f3e7eeaSChristopher Kilgour 			   const uint64_t ns,
414*8f3e7eeaSChristopher Kilgour 			   const uint32_t caplen,
415*8f3e7eeaSChristopher Kilgour 			   const uint8_t rf_channel,
416*8f3e7eeaSChristopher Kilgour 			   const int8_t signal_power,
417*8f3e7eeaSChristopher Kilgour 			   const int8_t noise_power,
418*8f3e7eeaSChristopher Kilgour 			   const uint8_t access_address_offenses,
419*8f3e7eeaSChristopher Kilgour 			   const uint32_t ref_access_address,
420*8f3e7eeaSChristopher Kilgour 			   const uint16_t flags,
421*8f3e7eeaSChristopher Kilgour 			   const uint8_t * lepkt )
422*8f3e7eeaSChristopher Kilgour {
423*8f3e7eeaSChristopher Kilgour 	uint32_t pcapng_caplen = sizeof(pcap_bluetooth_le_ll_header)+caplen;
424*8f3e7eeaSChristopher Kilgour 	uint32_t block_length  = 4*((36+pcapng_caplen+3)/4);
425*8f3e7eeaSChristopher Kilgour 
426*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.block_type = BLOCK_TYPE_ENHANCED_PACKET;
427*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.block_total_length = block_length;
428*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.interface_id = interface_id;
429*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.timestamp_high = (uint32_t) (ns >> 32);
430*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.timestamp_low = (uint32_t) (ns & 0x0ffffffffull);
431*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.captured_len = pcapng_caplen;
432*8f3e7eeaSChristopher Kilgour 	pkt->blk_header.packet_len = pcapng_caplen;
433*8f3e7eeaSChristopher Kilgour 	pkt->le_ll_header.rf_channel = rf_channel;
434*8f3e7eeaSChristopher Kilgour 	pkt->le_ll_header.signal_power = signal_power;
435*8f3e7eeaSChristopher Kilgour 	pkt->le_ll_header.noise_power = noise_power;
436*8f3e7eeaSChristopher Kilgour 	pkt->le_ll_header.access_address_offenses = access_address_offenses;
437*8f3e7eeaSChristopher Kilgour 	pkt->le_ll_header.ref_access_address = htole32( ref_access_address );
438*8f3e7eeaSChristopher Kilgour 	pkt->le_ll_header.flags = htole16( flags );
439*8f3e7eeaSChristopher Kilgour 	(void) memcpy( &pkt->le_packet[0], lepkt, caplen );
440*8f3e7eeaSChristopher Kilgour 	((uint32_t *)pkt)[block_length/4-2] = 0x00000000; /* no-options */
441*8f3e7eeaSChristopher Kilgour 	((uint32_t *)pkt)[block_length/4-1] = block_length;
442*8f3e7eeaSChristopher Kilgour }
443*8f3e7eeaSChristopher Kilgour 
444*8f3e7eeaSChristopher Kilgour int
445*8f3e7eeaSChristopher Kilgour lell_pcapng_append_packet(lell_pcapng_handle * h, const uint64_t ns,
446*8f3e7eeaSChristopher Kilgour 			  const int8_t sigdbm, const int8_t noisedbm,
447*8f3e7eeaSChristopher Kilgour 			  const uint32_t refAA, const lell_packet *pkt)
448*8f3e7eeaSChristopher Kilgour {
449*8f3e7eeaSChristopher Kilgour 	uint16_t flags = LE_DEWHITENED | LE_AA_OFFENSES_VALID |
450*8f3e7eeaSChristopher Kilgour 		LE_SIGPOWER_VALID |
451*8f3e7eeaSChristopher Kilgour 		((noisedbm < sigdbm) ? LE_NOISEPOWER_VALID : 0) |
452*8f3e7eeaSChristopher Kilgour 		(lell_packet_is_data(pkt) ? 0 : LE_REF_AA_VALID);
453*8f3e7eeaSChristopher Kilgour 	pcapng_le_packet pcapng_pkt;
454*8f3e7eeaSChristopher Kilgour 	assemble_pcapng_le_packet( &pcapng_pkt,
455*8f3e7eeaSChristopher Kilgour 				   0,
456*8f3e7eeaSChristopher Kilgour 				   ns,
457*8f3e7eeaSChristopher Kilgour 				   9+pkt->length,
458*8f3e7eeaSChristopher Kilgour 				   pkt->channel_k,
459*8f3e7eeaSChristopher Kilgour 				   sigdbm,
460*8f3e7eeaSChristopher Kilgour 				   noisedbm,
461*8f3e7eeaSChristopher Kilgour 				   pkt->access_address_offenses,
462*8f3e7eeaSChristopher Kilgour 				   refAA,
463*8f3e7eeaSChristopher Kilgour 				   flags,
464*8f3e7eeaSChristopher Kilgour 				   &pkt->symbols[0] );
465*8f3e7eeaSChristopher Kilgour 	int retval = -append_le_packet( (PCAPNG_HANDLE *) h, &pcapng_pkt );
466*8f3e7eeaSChristopher Kilgour 	if ((retval == 0) && !lell_packet_is_data(pkt) && (pkt->adv_type == CONNECT_REQ)) {
467*8f3e7eeaSChristopher Kilgour 		(void) lell_pcapng_record_connect_req(h, ns, &pkt->symbols[0]);
468*8f3e7eeaSChristopher Kilgour 	}
469*8f3e7eeaSChristopher Kilgour 	return retval;
470*8f3e7eeaSChristopher Kilgour }
471*8f3e7eeaSChristopher Kilgour 
472*8f3e7eeaSChristopher Kilgour static PCAPNG_RESULT
473*8f3e7eeaSChristopher Kilgour record_le_connect_req_info( PCAPNG_HANDLE * handle,
474*8f3e7eeaSChristopher Kilgour 			    const uint64_t ns,
475*8f3e7eeaSChristopher Kilgour 			    const uint8_t * pdu )
476*8f3e7eeaSChristopher Kilgour {
477*8f3e7eeaSChristopher Kilgour 	le_ll_connection_info_option cropt = {
478*8f3e7eeaSChristopher Kilgour 		.header = {
479*8f3e7eeaSChristopher Kilgour 			.option_code = PCAPNG_LE_LL_CONNECTION_INFO,
480*8f3e7eeaSChristopher Kilgour 			.option_length = sizeof(le_ll_connection_info_option)
481*8f3e7eeaSChristopher Kilgour 		},
482*8f3e7eeaSChristopher Kilgour 		.connection_info = {
483*8f3e7eeaSChristopher Kilgour 			.ns = ns
484*8f3e7eeaSChristopher Kilgour 		}
485*8f3e7eeaSChristopher Kilgour 	};
486*8f3e7eeaSChristopher Kilgour 	(void) memcpy( &cropt.connection_info.pdu.bytes[0], pdu, 34 );
487*8f3e7eeaSChristopher Kilgour 	return pcapng_append_interface_option( handle,
488*8f3e7eeaSChristopher Kilgour 					       (const option_header *) &cropt );
489*8f3e7eeaSChristopher Kilgour }
490*8f3e7eeaSChristopher Kilgour 
491*8f3e7eeaSChristopher Kilgour int
492*8f3e7eeaSChristopher Kilgour lell_pcapng_record_connect_req(lell_pcapng_handle * h, const uint64_t ns,
493*8f3e7eeaSChristopher Kilgour 			       const uint8_t * pdu)
494*8f3e7eeaSChristopher Kilgour {
495*8f3e7eeaSChristopher Kilgour 	return -record_le_connect_req_info( (PCAPNG_HANDLE *) h, ns, pdu );
496*8f3e7eeaSChristopher Kilgour }
497*8f3e7eeaSChristopher Kilgour 
498*8f3e7eeaSChristopher Kilgour int lell_pcapng_close(lell_pcapng_handle *h)
499*8f3e7eeaSChristopher Kilgour {
500*8f3e7eeaSChristopher Kilgour 	pcapng_close( (PCAPNG_HANDLE *) h );
501*8f3e7eeaSChristopher Kilgour 	if (h) {
502*8f3e7eeaSChristopher Kilgour 		free( h );
503*8f3e7eeaSChristopher Kilgour 	}
504*8f3e7eeaSChristopher Kilgour 	return -PCAPNG_INVALID_HANDLE;
505*8f3e7eeaSChristopher Kilgour }
506