18f3e7eeaSChristopher Kilgour /* -*- c -*- */ 28f3e7eeaSChristopher Kilgour /* 38f3e7eeaSChristopher Kilgour * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com 48f3e7eeaSChristopher Kilgour * 58f3e7eeaSChristopher Kilgour * This file is part of libbtbb 68f3e7eeaSChristopher Kilgour * 78f3e7eeaSChristopher Kilgour * This program is free software; you can redistribute it and/or modify 88f3e7eeaSChristopher Kilgour * it under the terms of the GNU General Public License as published by 98f3e7eeaSChristopher Kilgour * the Free Software Foundation; either version 2, or (at your option) 108f3e7eeaSChristopher Kilgour * any later version. 118f3e7eeaSChristopher Kilgour * 128f3e7eeaSChristopher Kilgour * This program is distributed in the hope that it will be useful, 138f3e7eeaSChristopher Kilgour * but WITHOUT ANY WARRANTY; without even the implied warranty of 148f3e7eeaSChristopher Kilgour * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 158f3e7eeaSChristopher Kilgour * GNU General Public License for more details. 168f3e7eeaSChristopher Kilgour * 178f3e7eeaSChristopher Kilgour * You should have received a copy of the GNU General Public License 188f3e7eeaSChristopher Kilgour * along with libbtbb; see the file COPYING. If not, write to 198f3e7eeaSChristopher Kilgour * the Free Software Foundation, Inc., 51 Franklin Street, 208f3e7eeaSChristopher Kilgour * Boston, MA 02110-1301, USA. 218f3e7eeaSChristopher Kilgour */ 228f3e7eeaSChristopher Kilgour 238f3e7eeaSChristopher Kilgour #include "btbb.h" 248f3e7eeaSChristopher Kilgour #include "bluetooth_le_packet.h" 25f83b85cfSDominic Spill #include "bluetooth_packet.h" 268f3e7eeaSChristopher Kilgour #include "pcapng-bt.h" 278f3e7eeaSChristopher Kilgour #include <stdlib.h> 288f3e7eeaSChristopher Kilgour #include <string.h> 298f3e7eeaSChristopher Kilgour #include <time.h> 308f3e7eeaSChristopher Kilgour #include <unistd.h> 310e05cc66SDominic Spill #include <stdio.h> 32*1ce7419bSTheodore A. Roth #include <assert.h> 338f3e7eeaSChristopher Kilgour 348f3e7eeaSChristopher Kilgour /* generic section options indicating libbtbb */ 358f3e7eeaSChristopher Kilgour const struct { 368f3e7eeaSChristopher Kilgour struct { 378f3e7eeaSChristopher Kilgour option_header hdr; 388f3e7eeaSChristopher Kilgour char libname[8]; 398f3e7eeaSChristopher Kilgour } libopt; 408f3e7eeaSChristopher Kilgour struct { 418f3e7eeaSChristopher Kilgour option_header hdr; 428f3e7eeaSChristopher Kilgour } termopt; 438f3e7eeaSChristopher Kilgour } libbtbb_section_options = { 448f3e7eeaSChristopher Kilgour .libopt = { 458f3e7eeaSChristopher Kilgour .hdr = { 468f3e7eeaSChristopher Kilgour .option_code = SHB_USERAPPL, 478f3e7eeaSChristopher Kilgour .option_length = 7 }, 488f3e7eeaSChristopher Kilgour .libname = "libbtbb" 498f3e7eeaSChristopher Kilgour }, 508f3e7eeaSChristopher Kilgour .termopt = { 518f3e7eeaSChristopher Kilgour .hdr = { 528f3e7eeaSChristopher Kilgour .option_code = OPT_ENDOFOPT, 538f3e7eeaSChristopher Kilgour .option_length = 0 548f3e7eeaSChristopher Kilgour } 558f3e7eeaSChristopher Kilgour } 568f3e7eeaSChristopher Kilgour }; 578f3e7eeaSChristopher Kilgour 588f3e7eeaSChristopher Kilgour static PCAPNG_RESULT 598f3e7eeaSChristopher Kilgour check_and_fix_tsresol( PCAPNG_HANDLE * handle, 608f3e7eeaSChristopher Kilgour const option_header * interface_options ) 618f3e7eeaSChristopher Kilgour { 628f3e7eeaSChristopher Kilgour PCAPNG_RESULT retval = PCAPNG_OK; 638f3e7eeaSChristopher Kilgour int got_tsresol = 0; 648f3e7eeaSChristopher Kilgour 658f3e7eeaSChristopher Kilgour while( !got_tsresol && 668f3e7eeaSChristopher Kilgour interface_options && 678f3e7eeaSChristopher Kilgour interface_options->option_code && 688f3e7eeaSChristopher Kilgour interface_options->option_length) { 698f3e7eeaSChristopher Kilgour if (interface_options->option_code == IF_TSRESOL) { 708f3e7eeaSChristopher Kilgour got_tsresol = 1; 718f3e7eeaSChristopher Kilgour } 728f3e7eeaSChristopher Kilgour else { 738f3e7eeaSChristopher Kilgour size_t step = 4+4*((interface_options->option_length+3)/4); 748f3e7eeaSChristopher Kilgour uint8_t * next = &((uint8_t *)interface_options)[step]; 758f3e7eeaSChristopher Kilgour interface_options = (const option_header *) next; 768f3e7eeaSChristopher Kilgour } 778f3e7eeaSChristopher Kilgour } 788f3e7eeaSChristopher Kilgour 798f3e7eeaSChristopher Kilgour if (!got_tsresol) { 808f3e7eeaSChristopher Kilgour const struct { 818f3e7eeaSChristopher Kilgour option_header hdr; 828f3e7eeaSChristopher Kilgour uint8_t resol; 838f3e7eeaSChristopher Kilgour } tsresol = { 848f3e7eeaSChristopher Kilgour .hdr = { 858f3e7eeaSChristopher Kilgour .option_code = IF_TSRESOL, 868f3e7eeaSChristopher Kilgour .option_length = 1, 878f3e7eeaSChristopher Kilgour }, 888f3e7eeaSChristopher Kilgour .resol = 9 /* 10^-9 is nanoseconds */ 898f3e7eeaSChristopher Kilgour }; 908f3e7eeaSChristopher Kilgour 918f3e7eeaSChristopher Kilgour retval = pcapng_append_interface_option( handle, 928f3e7eeaSChristopher Kilgour (const option_header *) &tsresol ); 938f3e7eeaSChristopher Kilgour } 948f3e7eeaSChristopher Kilgour 958f3e7eeaSChristopher Kilgour return retval; 968f3e7eeaSChristopher Kilgour } 978f3e7eeaSChristopher Kilgour 988f3e7eeaSChristopher Kilgour /* --------------------------------- BR/EDR ----------------------------- */ 998f3e7eeaSChristopher Kilgour 1008f3e7eeaSChristopher Kilgour static PCAPNG_RESULT 1018f3e7eeaSChristopher Kilgour create_bredr_capture_file_single_interface( PCAPNG_HANDLE * handle, 1028f3e7eeaSChristopher Kilgour const char * filename, 1038f3e7eeaSChristopher Kilgour const option_header * interface_options ) 1048f3e7eeaSChristopher Kilgour { 1058f3e7eeaSChristopher Kilgour PCAPNG_RESULT retval = PCAPNG_OK; 1068f3e7eeaSChristopher Kilgour 1078f3e7eeaSChristopher Kilgour retval = pcapng_create( handle, 1088f3e7eeaSChristopher Kilgour filename, 1098f3e7eeaSChristopher Kilgour (const option_header *) &libbtbb_section_options, 1108f3e7eeaSChristopher Kilgour (size_t) getpagesize( ), 1118f3e7eeaSChristopher Kilgour DLT_BLUETOOTH_BREDR_BB, 1120e05cc66SDominic Spill BREDR_MAX_PAYLOAD, 1138f3e7eeaSChristopher Kilgour interface_options, 1148f3e7eeaSChristopher Kilgour (size_t) getpagesize( ) ); 1158f3e7eeaSChristopher Kilgour 1168f3e7eeaSChristopher Kilgour if (retval == PCAPNG_OK) { 1178f3e7eeaSChristopher Kilgour /* if there is no timestamp resolution alread in the 1188f3e7eeaSChristopher Kilgour interface options, record nanosecond resolution */ 1198f3e7eeaSChristopher Kilgour retval = check_and_fix_tsresol( handle, interface_options ); 1208f3e7eeaSChristopher Kilgour 1218f3e7eeaSChristopher Kilgour if (retval != PCAPNG_OK) { 1228f3e7eeaSChristopher Kilgour (void) pcapng_close( handle ); 1238f3e7eeaSChristopher Kilgour } 1248f3e7eeaSChristopher Kilgour } 1258f3e7eeaSChristopher Kilgour 1268f3e7eeaSChristopher Kilgour return retval; 1278f3e7eeaSChristopher Kilgour } 1288f3e7eeaSChristopher Kilgour 1298f3e7eeaSChristopher Kilgour int btbb_pcapng_create_file( const char *filename, 1308f3e7eeaSChristopher Kilgour const char *interface_desc, 1318f3e7eeaSChristopher Kilgour btbb_pcapng_handle ** ph ) 1328f3e7eeaSChristopher Kilgour { 1338f3e7eeaSChristopher Kilgour int retval = PCAPNG_OK; 1348f3e7eeaSChristopher Kilgour PCAPNG_HANDLE * handle = malloc( sizeof(PCAPNG_HANDLE) ); 1358f3e7eeaSChristopher Kilgour if (handle) { 1368f3e7eeaSChristopher Kilgour const option_header * popt = NULL; 1378f3e7eeaSChristopher Kilgour struct { 1388f3e7eeaSChristopher Kilgour option_header header; 1398f3e7eeaSChristopher Kilgour char desc[256]; 1408f3e7eeaSChristopher Kilgour } ifopt = { 1418f3e7eeaSChristopher Kilgour .header = { 1428f3e7eeaSChristopher Kilgour .option_code = IF_DESCRIPTION, 1438f3e7eeaSChristopher Kilgour } 1448f3e7eeaSChristopher Kilgour }; 1458f3e7eeaSChristopher Kilgour if (interface_desc) { 1468f3e7eeaSChristopher Kilgour (void) strncpy( &ifopt.desc[0], interface_desc, 256 ); 1478f3e7eeaSChristopher Kilgour ifopt.desc[255] = '\0'; 1488f3e7eeaSChristopher Kilgour ifopt.header.option_length = strlen( ifopt.desc ); 1498f3e7eeaSChristopher Kilgour popt = (const option_header *) &ifopt; 1508f3e7eeaSChristopher Kilgour } 1518f3e7eeaSChristopher Kilgour 1528f3e7eeaSChristopher Kilgour retval = -create_bredr_capture_file_single_interface( handle, 1538f3e7eeaSChristopher Kilgour filename, 1548f3e7eeaSChristopher Kilgour popt ); 1558f3e7eeaSChristopher Kilgour if (retval == PCAPNG_OK) { 1568f3e7eeaSChristopher Kilgour *ph = (btbb_pcapng_handle *) handle; 1578f3e7eeaSChristopher Kilgour } 1588f3e7eeaSChristopher Kilgour else { 1598f3e7eeaSChristopher Kilgour free( handle ); 1608f3e7eeaSChristopher Kilgour } 1618f3e7eeaSChristopher Kilgour } 1628f3e7eeaSChristopher Kilgour else { 1638f3e7eeaSChristopher Kilgour retval = -PCAPNG_NO_MEMORY; 1648f3e7eeaSChristopher Kilgour } 1658f3e7eeaSChristopher Kilgour return retval; 1668f3e7eeaSChristopher Kilgour } 1678f3e7eeaSChristopher Kilgour 1688f3e7eeaSChristopher Kilgour static PCAPNG_RESULT 1698f3e7eeaSChristopher Kilgour append_bredr_packet( PCAPNG_HANDLE * handle, 1708f3e7eeaSChristopher Kilgour pcapng_bredr_packet * pkt ) 1718f3e7eeaSChristopher Kilgour { 1728f3e7eeaSChristopher Kilgour return pcapng_append_packet( handle, ( const enhanced_packet_block *) pkt ); 1738f3e7eeaSChristopher Kilgour } 1748f3e7eeaSChristopher Kilgour 1758f3e7eeaSChristopher Kilgour static void 1768f3e7eeaSChristopher Kilgour assemble_pcapng_bredr_packet( pcapng_bredr_packet * pkt, 1778f3e7eeaSChristopher Kilgour const uint32_t interface_id, 1788f3e7eeaSChristopher Kilgour const uint64_t ns, 1798f3e7eeaSChristopher Kilgour const uint32_t caplen, 1808f3e7eeaSChristopher Kilgour const uint8_t rf_channel, 1818f3e7eeaSChristopher Kilgour const int8_t signal_power, 1828f3e7eeaSChristopher Kilgour const int8_t noise_power, 1838f3e7eeaSChristopher Kilgour const uint8_t access_code_offenses, 1848f3e7eeaSChristopher Kilgour const uint8_t payload_transport, 1858f3e7eeaSChristopher Kilgour const uint8_t payload_rate, 1868f3e7eeaSChristopher Kilgour const uint8_t corrected_header_bits, 1878f3e7eeaSChristopher Kilgour const int16_t corrected_payload_bits, 1888f3e7eeaSChristopher Kilgour const uint32_t lap, 1898f3e7eeaSChristopher Kilgour const uint32_t ref_lap, 1908f3e7eeaSChristopher Kilgour const uint8_t ref_uap, 1918f3e7eeaSChristopher Kilgour const uint32_t bt_header, 1928f3e7eeaSChristopher Kilgour const uint16_t flags, 1930e05cc66SDominic Spill const char * payload ) 1948f3e7eeaSChristopher Kilgour { 1958f3e7eeaSChristopher Kilgour uint32_t pcapng_caplen = sizeof(pcap_bluetooth_bredr_bb_header)+caplen; 1968f3e7eeaSChristopher Kilgour uint32_t block_length = 4*((36+pcapng_caplen+3)/4); 1978f3e7eeaSChristopher Kilgour uint32_t reflapuap = (ref_lap&0xffffff) | (ref_uap<<24); 1988f3e7eeaSChristopher Kilgour 1998f3e7eeaSChristopher Kilgour pkt->blk_header.block_type = BLOCK_TYPE_ENHANCED_PACKET; 2008f3e7eeaSChristopher Kilgour pkt->blk_header.block_total_length = block_length; 2018f3e7eeaSChristopher Kilgour pkt->blk_header.interface_id = interface_id; 2028f3e7eeaSChristopher Kilgour pkt->blk_header.timestamp_high = (uint32_t) (ns >> 32); 2038f3e7eeaSChristopher Kilgour pkt->blk_header.timestamp_low = (uint32_t) (ns & 0x0ffffffffull); 2048f3e7eeaSChristopher Kilgour pkt->blk_header.captured_len = pcapng_caplen; 2058f3e7eeaSChristopher Kilgour pkt->blk_header.packet_len = pcapng_caplen; 2068f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.rf_channel = rf_channel; 2078f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.signal_power = signal_power; 2088f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.noise_power = noise_power; 2098f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.access_code_offenses = access_code_offenses; 2108f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.payload_transport_rate = 2118f3e7eeaSChristopher Kilgour (payload_transport << 4) | payload_rate; 2128f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.corrected_header_bits = corrected_header_bits; 2138f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.corrected_payload_bits = htole16( corrected_payload_bits ); 2148f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.lap = htole32( lap ); 2158f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.ref_lap_uap = htole32( reflapuap ); 2168f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.bt_header = htole16( bt_header ); 2178f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.flags = htole16( flags ); 2188f3e7eeaSChristopher Kilgour if (caplen) { 2198f3e7eeaSChristopher Kilgour (void) memcpy( &pkt->bredr_payload[0], payload, caplen ); 2208f3e7eeaSChristopher Kilgour } 2218f3e7eeaSChristopher Kilgour else { 2228f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.flags &= htole16( ~BREDR_PAYLOAD_PRESENT ); 2238f3e7eeaSChristopher Kilgour } 2248f3e7eeaSChristopher Kilgour ((uint32_t *)pkt)[block_length/4-2] = 0x00000000; /* no-options */ 2258f3e7eeaSChristopher Kilgour ((uint32_t *)pkt)[block_length/4-1] = block_length; 2268f3e7eeaSChristopher Kilgour } 2278f3e7eeaSChristopher Kilgour 2288f3e7eeaSChristopher Kilgour int btbb_pcapng_append_packet(btbb_pcapng_handle * h, const uint64_t ns, 2298f3e7eeaSChristopher Kilgour const int8_t sigdbm, const int8_t noisedbm, 2308f3e7eeaSChristopher Kilgour const uint32_t reflap, const uint8_t refuap, 2318f3e7eeaSChristopher Kilgour const btbb_packet *pkt) 2328f3e7eeaSChristopher Kilgour { 2338f3e7eeaSChristopher Kilgour uint16_t flags = BREDR_DEWHITENED | BREDR_SIGPOWER_VALID | 2348f3e7eeaSChristopher Kilgour ((noisedbm < sigdbm) ? BREDR_NOISEPOWER_VALID : 0) | 2358f3e7eeaSChristopher Kilgour ((reflap != LAP_ANY) ? BREDR_REFLAP_VALID : 0) | 2368f3e7eeaSChristopher Kilgour ((refuap != UAP_ANY) ? BREDR_REFUAP_VALID : 0); 2370e05cc66SDominic Spill int caplen = btbb_packet_get_payload_length(pkt); 2380e05cc66SDominic Spill char payload_bytes[caplen]; 2390e05cc66SDominic Spill btbb_get_payload_packed( pkt, &payload_bytes[0] ); 2400e05cc66SDominic Spill caplen = MIN(BREDR_MAX_PAYLOAD, caplen); 2418f3e7eeaSChristopher Kilgour pcapng_bredr_packet pcapng_pkt; 2428f3e7eeaSChristopher Kilgour assemble_pcapng_bredr_packet( &pcapng_pkt, 2438f3e7eeaSChristopher Kilgour 0, 2448f3e7eeaSChristopher Kilgour ns, 2458f3e7eeaSChristopher Kilgour caplen, 2468f3e7eeaSChristopher Kilgour btbb_packet_get_channel(pkt), 2478f3e7eeaSChristopher Kilgour sigdbm, 2488f3e7eeaSChristopher Kilgour noisedbm, 2498f3e7eeaSChristopher Kilgour btbb_packet_get_ac_errors(pkt), 250f83b85cfSDominic Spill btbb_packet_get_transport(pkt), 251f83b85cfSDominic Spill btbb_packet_get_modulation(pkt), 2528f3e7eeaSChristopher Kilgour 0, /* TODO: corrected header bits */ 2538f3e7eeaSChristopher Kilgour 0, /* TODO: corrected payload bits */ 2548f3e7eeaSChristopher Kilgour btbb_packet_get_lap(pkt), 2558f3e7eeaSChristopher Kilgour reflap, 2568f3e7eeaSChristopher Kilgour refuap, 2578f3e7eeaSChristopher Kilgour btbb_packet_get_header_packed(pkt), 2588f3e7eeaSChristopher Kilgour flags, 2598f3e7eeaSChristopher Kilgour payload_bytes ); 2608f3e7eeaSChristopher Kilgour return -append_bredr_packet( (PCAPNG_HANDLE *)h, &pcapng_pkt ); 2618f3e7eeaSChristopher Kilgour } 2628f3e7eeaSChristopher Kilgour 2638f3e7eeaSChristopher Kilgour static PCAPNG_RESULT 2648f3e7eeaSChristopher Kilgour record_bd_addr_info( PCAPNG_HANDLE * handle, 2658f3e7eeaSChristopher Kilgour const uint64_t bd_addr, 2668f3e7eeaSChristopher Kilgour const uint8_t uap_mask, 2678f3e7eeaSChristopher Kilgour const uint8_t nap_valid ) 2688f3e7eeaSChristopher Kilgour { 2698f3e7eeaSChristopher Kilgour const bredr_br_addr_option bdopt = { 2708f3e7eeaSChristopher Kilgour .header = { 2718f3e7eeaSChristopher Kilgour .option_code = PCAPNG_BREDR_OPTION_BD_ADDR, 2728f3e7eeaSChristopher Kilgour .option_length = sizeof(bredr_br_addr_option), 2738f3e7eeaSChristopher Kilgour }, 2748f3e7eeaSChristopher Kilgour .bd_addr_info = { 2758f3e7eeaSChristopher Kilgour .bd_addr = { 2768f3e7eeaSChristopher Kilgour ((bd_addr>>0) & 0xff), 2778f3e7eeaSChristopher Kilgour ((bd_addr>>8) & 0xff), 2788f3e7eeaSChristopher Kilgour ((bd_addr>>16) & 0xff), 2798f3e7eeaSChristopher Kilgour ((bd_addr>>24) & 0xff), 2808f3e7eeaSChristopher Kilgour ((bd_addr>>32) & 0xff), 2818f3e7eeaSChristopher Kilgour ((bd_addr>>40) & 0xff) 2828f3e7eeaSChristopher Kilgour }, 2838f3e7eeaSChristopher Kilgour .uap_mask = uap_mask, 2848f3e7eeaSChristopher Kilgour .nap_valid = nap_valid, 2858f3e7eeaSChristopher Kilgour } 2868f3e7eeaSChristopher Kilgour }; 2878f3e7eeaSChristopher Kilgour return pcapng_append_interface_option( handle, 2888f3e7eeaSChristopher Kilgour (const option_header *) &bdopt ); 2898f3e7eeaSChristopher Kilgour } 2908f3e7eeaSChristopher Kilgour 2918f3e7eeaSChristopher Kilgour int btbb_pcapng_record_bdaddr(btbb_pcapng_handle * h, const uint64_t bdaddr, 2928f3e7eeaSChristopher Kilgour const uint8_t uapmask, const uint8_t napvalid) 2938f3e7eeaSChristopher Kilgour { 2948f3e7eeaSChristopher Kilgour return -record_bd_addr_info( (PCAPNG_HANDLE *) h, 2958f3e7eeaSChristopher Kilgour bdaddr, uapmask, napvalid ); 2968f3e7eeaSChristopher Kilgour } 2978f3e7eeaSChristopher Kilgour 2988f3e7eeaSChristopher Kilgour static PCAPNG_RESULT 2998f3e7eeaSChristopher Kilgour record_bredr_master_clock_info( PCAPNG_HANDLE * handle, 3008f3e7eeaSChristopher Kilgour const uint64_t bd_addr, 3018f3e7eeaSChristopher Kilgour const uint64_t ns, 3028f3e7eeaSChristopher Kilgour const uint32_t clk, 3038f3e7eeaSChristopher Kilgour const uint32_t clk_mask) 3048f3e7eeaSChristopher Kilgour { 3058f3e7eeaSChristopher Kilgour const bredr_clk_option mcopt = { 3068f3e7eeaSChristopher Kilgour .header = { 3078f3e7eeaSChristopher Kilgour .option_code = PCAPNG_BREDR_OPTION_MASTER_CLOCK_INFO, 3088f3e7eeaSChristopher Kilgour .option_length = sizeof(bredr_clk_option) 3098f3e7eeaSChristopher Kilgour }, 3108f3e7eeaSChristopher Kilgour .clock_info = { 3118f3e7eeaSChristopher Kilgour .ts = ns, 3128f3e7eeaSChristopher Kilgour .lap_uap = htole32(bd_addr & 0xffffffff), 3138f3e7eeaSChristopher Kilgour .clk = clk, 3148f3e7eeaSChristopher Kilgour .clk_mask = clk_mask 3158f3e7eeaSChristopher Kilgour } 3168f3e7eeaSChristopher Kilgour }; 3178f3e7eeaSChristopher Kilgour return pcapng_append_interface_option( handle, 3188f3e7eeaSChristopher Kilgour (const option_header *) &mcopt ); 3198f3e7eeaSChristopher Kilgour } 3208f3e7eeaSChristopher Kilgour 3218f3e7eeaSChristopher Kilgour int btbb_pcapng_record_btclock(btbb_pcapng_handle * h, const uint64_t bdaddr, 3228f3e7eeaSChristopher Kilgour const uint64_t ns, const uint32_t clk, 3238f3e7eeaSChristopher Kilgour const uint32_t clkmask) 3248f3e7eeaSChristopher Kilgour { 3258f3e7eeaSChristopher Kilgour return -record_bredr_master_clock_info( (PCAPNG_HANDLE *) h, 3268f3e7eeaSChristopher Kilgour bdaddr, ns, clk, clkmask ); 3278f3e7eeaSChristopher Kilgour } 3288f3e7eeaSChristopher Kilgour 3298f3e7eeaSChristopher Kilgour int btbb_pcapng_close(btbb_pcapng_handle * h) 3308f3e7eeaSChristopher Kilgour { 3318f3e7eeaSChristopher Kilgour pcapng_close( (PCAPNG_HANDLE *) h ); 3328f3e7eeaSChristopher Kilgour if (h) { 3338f3e7eeaSChristopher Kilgour free( h ); 3348f3e7eeaSChristopher Kilgour } 3358f3e7eeaSChristopher Kilgour return -PCAPNG_INVALID_HANDLE; 3368f3e7eeaSChristopher Kilgour } 3378f3e7eeaSChristopher Kilgour 3388f3e7eeaSChristopher Kilgour /* --------------------------------- Low Energy ---------------------------- */ 3398f3e7eeaSChristopher Kilgour 3408f3e7eeaSChristopher Kilgour static PCAPNG_RESULT 3418f3e7eeaSChristopher Kilgour create_le_capture_file_single_interface( PCAPNG_HANDLE * handle, 3428f3e7eeaSChristopher Kilgour const char * filename, 3438f3e7eeaSChristopher Kilgour const option_header * interface_options ) 3448f3e7eeaSChristopher Kilgour { 3458f3e7eeaSChristopher Kilgour PCAPNG_RESULT retval = PCAPNG_OK; 3468f3e7eeaSChristopher Kilgour 3478f3e7eeaSChristopher Kilgour retval = pcapng_create( handle, 3488f3e7eeaSChristopher Kilgour filename, 3498f3e7eeaSChristopher Kilgour (const option_header *) &libbtbb_section_options, 3508f3e7eeaSChristopher Kilgour (size_t) getpagesize( ), 3518f3e7eeaSChristopher Kilgour DLT_BLUETOOTH_LE_LL_WITH_PHDR, 3528f3e7eeaSChristopher Kilgour 64, 3538f3e7eeaSChristopher Kilgour interface_options, 3548f3e7eeaSChristopher Kilgour (size_t) getpagesize( ) ); 3558f3e7eeaSChristopher Kilgour 3568f3e7eeaSChristopher Kilgour if (retval == PCAPNG_OK) { 3578f3e7eeaSChristopher Kilgour /* if there is no timestamp resolution alread in the 3588f3e7eeaSChristopher Kilgour interface options, record nanosecond resolution */ 3598f3e7eeaSChristopher Kilgour retval = check_and_fix_tsresol( handle, interface_options ); 3608f3e7eeaSChristopher Kilgour 3618f3e7eeaSChristopher Kilgour if (retval != PCAPNG_OK) { 3628f3e7eeaSChristopher Kilgour (void) pcapng_close( handle ); 3638f3e7eeaSChristopher Kilgour } 3648f3e7eeaSChristopher Kilgour } 3658f3e7eeaSChristopher Kilgour 3668f3e7eeaSChristopher Kilgour return retval; 3678f3e7eeaSChristopher Kilgour } 3688f3e7eeaSChristopher Kilgour 3698f3e7eeaSChristopher Kilgour int 3708f3e7eeaSChristopher Kilgour lell_pcapng_create_file(const char *filename, const char *interface_desc, 3718f3e7eeaSChristopher Kilgour lell_pcapng_handle ** ph) 3728f3e7eeaSChristopher Kilgour { 3738f3e7eeaSChristopher Kilgour int retval = PCAPNG_OK; 3748f3e7eeaSChristopher Kilgour PCAPNG_HANDLE * handle = malloc( sizeof(PCAPNG_HANDLE) ); 3758f3e7eeaSChristopher Kilgour if (handle) { 3768f3e7eeaSChristopher Kilgour const option_header * popt = NULL; 3778f3e7eeaSChristopher Kilgour struct { 3788f3e7eeaSChristopher Kilgour option_header header; 3798f3e7eeaSChristopher Kilgour char desc[256]; 3808f3e7eeaSChristopher Kilgour } ifopt = { 3818f3e7eeaSChristopher Kilgour .header = { 3828f3e7eeaSChristopher Kilgour .option_code = IF_DESCRIPTION, 3838f3e7eeaSChristopher Kilgour } 3848f3e7eeaSChristopher Kilgour }; 3858f3e7eeaSChristopher Kilgour if (interface_desc) { 3868f3e7eeaSChristopher Kilgour (void) strncpy( &ifopt.desc[0], interface_desc, 256 ); 3878f3e7eeaSChristopher Kilgour ifopt.desc[255] = '\0'; 3888f3e7eeaSChristopher Kilgour ifopt.header.option_length = strlen( ifopt.desc ); 3898f3e7eeaSChristopher Kilgour popt = (const option_header *) &ifopt; 3908f3e7eeaSChristopher Kilgour } 3918f3e7eeaSChristopher Kilgour 3928f3e7eeaSChristopher Kilgour retval = -create_le_capture_file_single_interface( handle, 3938f3e7eeaSChristopher Kilgour filename, 3948f3e7eeaSChristopher Kilgour popt ); 3958f3e7eeaSChristopher Kilgour if (retval == PCAPNG_OK) { 3968f3e7eeaSChristopher Kilgour *ph = (lell_pcapng_handle *) handle; 3978f3e7eeaSChristopher Kilgour } 3988f3e7eeaSChristopher Kilgour else { 3998f3e7eeaSChristopher Kilgour free( handle ); 4008f3e7eeaSChristopher Kilgour } 4018f3e7eeaSChristopher Kilgour } 4028f3e7eeaSChristopher Kilgour else { 4038f3e7eeaSChristopher Kilgour retval = -PCAPNG_NO_MEMORY; 4048f3e7eeaSChristopher Kilgour } 4058f3e7eeaSChristopher Kilgour return retval; 4068f3e7eeaSChristopher Kilgour } 4078f3e7eeaSChristopher Kilgour 4088f3e7eeaSChristopher Kilgour static PCAPNG_RESULT 4098f3e7eeaSChristopher Kilgour append_le_packet( PCAPNG_HANDLE * handle, 4108f3e7eeaSChristopher Kilgour pcapng_le_packet * pkt ) 4118f3e7eeaSChristopher Kilgour { 4128f3e7eeaSChristopher Kilgour return pcapng_append_packet( handle, ( const enhanced_packet_block *) pkt ); 4138f3e7eeaSChristopher Kilgour } 4148f3e7eeaSChristopher Kilgour 4158f3e7eeaSChristopher Kilgour static void 4168f3e7eeaSChristopher Kilgour assemble_pcapng_le_packet( pcapng_le_packet * pkt, 4178f3e7eeaSChristopher Kilgour const uint32_t interface_id, 4188f3e7eeaSChristopher Kilgour const uint64_t ns, 4198f3e7eeaSChristopher Kilgour const uint32_t caplen, 4208f3e7eeaSChristopher Kilgour const uint8_t rf_channel, 4218f3e7eeaSChristopher Kilgour const int8_t signal_power, 4228f3e7eeaSChristopher Kilgour const int8_t noise_power, 4238f3e7eeaSChristopher Kilgour const uint8_t access_address_offenses, 4248f3e7eeaSChristopher Kilgour const uint32_t ref_access_address, 4258f3e7eeaSChristopher Kilgour const uint16_t flags, 4268f3e7eeaSChristopher Kilgour const uint8_t * lepkt ) 4278f3e7eeaSChristopher Kilgour { 4288f3e7eeaSChristopher Kilgour uint32_t pcapng_caplen = sizeof(pcap_bluetooth_le_ll_header)+caplen; 4298f3e7eeaSChristopher Kilgour uint32_t block_length = 4*((36+pcapng_caplen+3)/4); 4308f3e7eeaSChristopher Kilgour 431*1ce7419bSTheodore A. Roth assert(caplen <= LE_MAX_PAYLOAD); 432*1ce7419bSTheodore A. Roth 4338f3e7eeaSChristopher Kilgour pkt->blk_header.block_type = BLOCK_TYPE_ENHANCED_PACKET; 4348f3e7eeaSChristopher Kilgour pkt->blk_header.block_total_length = block_length; 4358f3e7eeaSChristopher Kilgour pkt->blk_header.interface_id = interface_id; 4368f3e7eeaSChristopher Kilgour pkt->blk_header.timestamp_high = (uint32_t) (ns >> 32); 4378f3e7eeaSChristopher Kilgour pkt->blk_header.timestamp_low = (uint32_t) (ns & 0x0ffffffffull); 4388f3e7eeaSChristopher Kilgour pkt->blk_header.captured_len = pcapng_caplen; 4398f3e7eeaSChristopher Kilgour pkt->blk_header.packet_len = pcapng_caplen; 4408f3e7eeaSChristopher Kilgour pkt->le_ll_header.rf_channel = rf_channel; 4418f3e7eeaSChristopher Kilgour pkt->le_ll_header.signal_power = signal_power; 4428f3e7eeaSChristopher Kilgour pkt->le_ll_header.noise_power = noise_power; 4438f3e7eeaSChristopher Kilgour pkt->le_ll_header.access_address_offenses = access_address_offenses; 4448f3e7eeaSChristopher Kilgour pkt->le_ll_header.ref_access_address = htole32( ref_access_address ); 4458f3e7eeaSChristopher Kilgour pkt->le_ll_header.flags = htole16( flags ); 4468f3e7eeaSChristopher Kilgour (void) memcpy( &pkt->le_packet[0], lepkt, caplen ); 4478f3e7eeaSChristopher Kilgour ((uint32_t *)pkt)[block_length/4-2] = 0x00000000; /* no-options */ 4488f3e7eeaSChristopher Kilgour ((uint32_t *)pkt)[block_length/4-1] = block_length; 4498f3e7eeaSChristopher Kilgour } 4508f3e7eeaSChristopher Kilgour 4518f3e7eeaSChristopher Kilgour int 4528f3e7eeaSChristopher Kilgour lell_pcapng_append_packet(lell_pcapng_handle * h, const uint64_t ns, 4538f3e7eeaSChristopher Kilgour const int8_t sigdbm, const int8_t noisedbm, 4548f3e7eeaSChristopher Kilgour const uint32_t refAA, const lell_packet *pkt) 4558f3e7eeaSChristopher Kilgour { 4568f3e7eeaSChristopher Kilgour uint16_t flags = LE_DEWHITENED | LE_AA_OFFENSES_VALID | 4578f3e7eeaSChristopher Kilgour LE_SIGPOWER_VALID | 4588f3e7eeaSChristopher Kilgour ((noisedbm < sigdbm) ? LE_NOISEPOWER_VALID : 0) | 4598f3e7eeaSChristopher Kilgour (lell_packet_is_data(pkt) ? 0 : LE_REF_AA_VALID); 4608f3e7eeaSChristopher Kilgour pcapng_le_packet pcapng_pkt; 4618f3e7eeaSChristopher Kilgour assemble_pcapng_le_packet( &pcapng_pkt, 4628f3e7eeaSChristopher Kilgour 0, 4638f3e7eeaSChristopher Kilgour ns, 4648f3e7eeaSChristopher Kilgour 9+pkt->length, 4658f3e7eeaSChristopher Kilgour pkt->channel_k, 4668f3e7eeaSChristopher Kilgour sigdbm, 4678f3e7eeaSChristopher Kilgour noisedbm, 4688f3e7eeaSChristopher Kilgour pkt->access_address_offenses, 4698f3e7eeaSChristopher Kilgour refAA, 4708f3e7eeaSChristopher Kilgour flags, 4718f3e7eeaSChristopher Kilgour &pkt->symbols[0] ); 4728f3e7eeaSChristopher Kilgour int retval = -append_le_packet( (PCAPNG_HANDLE *) h, &pcapng_pkt ); 4738f3e7eeaSChristopher Kilgour if ((retval == 0) && !lell_packet_is_data(pkt) && (pkt->adv_type == CONNECT_REQ)) { 4748f3e7eeaSChristopher Kilgour (void) lell_pcapng_record_connect_req(h, ns, &pkt->symbols[0]); 4758f3e7eeaSChristopher Kilgour } 4768f3e7eeaSChristopher Kilgour return retval; 4778f3e7eeaSChristopher Kilgour } 4788f3e7eeaSChristopher Kilgour 4798f3e7eeaSChristopher Kilgour static PCAPNG_RESULT 4808f3e7eeaSChristopher Kilgour record_le_connect_req_info( PCAPNG_HANDLE * handle, 4818f3e7eeaSChristopher Kilgour const uint64_t ns, 4828f3e7eeaSChristopher Kilgour const uint8_t * pdu ) 4838f3e7eeaSChristopher Kilgour { 4848f3e7eeaSChristopher Kilgour le_ll_connection_info_option cropt = { 4858f3e7eeaSChristopher Kilgour .header = { 4868f3e7eeaSChristopher Kilgour .option_code = PCAPNG_LE_LL_CONNECTION_INFO, 4878f3e7eeaSChristopher Kilgour .option_length = sizeof(le_ll_connection_info_option) 4888f3e7eeaSChristopher Kilgour }, 4898f3e7eeaSChristopher Kilgour .connection_info = { 4908f3e7eeaSChristopher Kilgour .ns = ns 4918f3e7eeaSChristopher Kilgour } 4928f3e7eeaSChristopher Kilgour }; 4938f3e7eeaSChristopher Kilgour (void) memcpy( &cropt.connection_info.pdu.bytes[0], pdu, 34 ); 4948f3e7eeaSChristopher Kilgour return pcapng_append_interface_option( handle, 4958f3e7eeaSChristopher Kilgour (const option_header *) &cropt ); 4968f3e7eeaSChristopher Kilgour } 4978f3e7eeaSChristopher Kilgour 4988f3e7eeaSChristopher Kilgour int 4998f3e7eeaSChristopher Kilgour lell_pcapng_record_connect_req(lell_pcapng_handle * h, const uint64_t ns, 5008f3e7eeaSChristopher Kilgour const uint8_t * pdu) 5018f3e7eeaSChristopher Kilgour { 5028f3e7eeaSChristopher Kilgour return -record_le_connect_req_info( (PCAPNG_HANDLE *) h, ns, pdu ); 5038f3e7eeaSChristopher Kilgour } 5048f3e7eeaSChristopher Kilgour 5058f3e7eeaSChristopher Kilgour int lell_pcapng_close(lell_pcapng_handle *h) 5068f3e7eeaSChristopher Kilgour { 5078f3e7eeaSChristopher Kilgour pcapng_close( (PCAPNG_HANDLE *) h ); 5088f3e7eeaSChristopher Kilgour if (h) { 5098f3e7eeaSChristopher Kilgour free( h ); 5108f3e7eeaSChristopher Kilgour } 5118f3e7eeaSChristopher Kilgour return -PCAPNG_INVALID_HANDLE; 5128f3e7eeaSChristopher Kilgour } 513