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