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 #include "bluetooth_le_packet.h" 23f83b85cfSDominic Spill #include "bluetooth_packet.h" 248f3e7eeaSChristopher Kilgour #include "btbb.h" 258f3e7eeaSChristopher Kilgour #include "pcap-common.h" 268f3e7eeaSChristopher Kilgour 278f3e7eeaSChristopher Kilgour #include <stdlib.h> 288f3e7eeaSChristopher Kilgour #include <string.h> 298f3e7eeaSChristopher Kilgour 308f3e7eeaSChristopher Kilgour typedef enum { 318f3e7eeaSChristopher Kilgour PCAP_OK = 0, 328f3e7eeaSChristopher Kilgour PCAP_INVALID_HANDLE, 338f3e7eeaSChristopher Kilgour PCAP_FILE_NOT_ALLOWED, 348f3e7eeaSChristopher Kilgour PCAP_NO_MEMORY, 358f3e7eeaSChristopher Kilgour } PCAP_RESULT; 368f3e7eeaSChristopher Kilgour 37*a3df4d72SDominic Spill #if defined(ENABLE_PCAP) 388f3e7eeaSChristopher Kilgour 398f3e7eeaSChristopher Kilgour /* BT BR/EDR support */ 408f3e7eeaSChristopher Kilgour 418f3e7eeaSChristopher Kilgour typedef struct btbb_pcap_handle { 428f3e7eeaSChristopher Kilgour pcap_t * pcap; 438f3e7eeaSChristopher Kilgour pcap_dumper_t * dumper; 448f3e7eeaSChristopher Kilgour } btbb_pcap_handle; 458f3e7eeaSChristopher Kilgour 468f3e7eeaSChristopher Kilgour int 478f3e7eeaSChristopher Kilgour btbb_pcap_create_file(const char *filename, btbb_pcap_handle ** ph) 488f3e7eeaSChristopher Kilgour { 498f3e7eeaSChristopher Kilgour int retval = 0; 508f3e7eeaSChristopher Kilgour btbb_pcap_handle * handle = malloc( sizeof(btbb_pcap_handle) ); 518f3e7eeaSChristopher Kilgour if (handle) { 528f3e7eeaSChristopher Kilgour memset(handle, 0, sizeof(*handle)); 5345809783SMike Ryan #ifdef PCAP_TSTAMP_PRECISION_NANO 548f3e7eeaSChristopher Kilgour handle->pcap = pcap_open_dead_with_tstamp_precision(DLT_BLUETOOTH_BREDR_BB, 550e05cc66SDominic Spill BREDR_MAX_PAYLOAD, 568f3e7eeaSChristopher Kilgour PCAP_TSTAMP_PRECISION_NANO); 5745809783SMike Ryan #else 580e05cc66SDominic Spill handle->pcap = pcap_open_dead(DLT_BLUETOOTH_BREDR_BB, BREDR_MAX_PAYLOAD); 5945809783SMike Ryan #endif 608f3e7eeaSChristopher Kilgour if (handle->pcap) { 618f3e7eeaSChristopher Kilgour handle->dumper = pcap_dump_open(handle->pcap, filename); 628f3e7eeaSChristopher Kilgour if (handle->dumper) { 638f3e7eeaSChristopher Kilgour *ph = handle; 648f3e7eeaSChristopher Kilgour } 658f3e7eeaSChristopher Kilgour else { 66fa150dd3SDominic Spill pcap_perror(handle->pcap, "PCAP error:"); 678f3e7eeaSChristopher Kilgour retval = -PCAP_FILE_NOT_ALLOWED; 688f3e7eeaSChristopher Kilgour goto fail; 698f3e7eeaSChristopher Kilgour } 708f3e7eeaSChristopher Kilgour } 718f3e7eeaSChristopher Kilgour else { 728f3e7eeaSChristopher Kilgour retval = -PCAP_INVALID_HANDLE; 738f3e7eeaSChristopher Kilgour goto fail; 748f3e7eeaSChristopher Kilgour } 758f3e7eeaSChristopher Kilgour } 768f3e7eeaSChristopher Kilgour else { 778f3e7eeaSChristopher Kilgour retval = -PCAP_NO_MEMORY; 788f3e7eeaSChristopher Kilgour goto fail; 798f3e7eeaSChristopher Kilgour } 808f3e7eeaSChristopher Kilgour return retval; 818f3e7eeaSChristopher Kilgour fail: 828f3e7eeaSChristopher Kilgour (void) btbb_pcap_close( handle ); 838f3e7eeaSChristopher Kilgour return retval; 848f3e7eeaSChristopher Kilgour } 858f3e7eeaSChristopher Kilgour 868f3e7eeaSChristopher Kilgour typedef struct { 878f3e7eeaSChristopher Kilgour struct pcap_pkthdr pcap_header; 888f3e7eeaSChristopher Kilgour pcap_bluetooth_bredr_bb_header bredr_bb_header; 890e05cc66SDominic Spill uint8_t bredr_payload[BREDR_MAX_PAYLOAD]; 908f3e7eeaSChristopher Kilgour } pcap_bredr_packet; 918f3e7eeaSChristopher Kilgour 928f3e7eeaSChristopher Kilgour static void 938f3e7eeaSChristopher Kilgour assemble_pcapng_bredr_packet( pcap_bredr_packet * pkt, 948f3e7eeaSChristopher Kilgour const uint32_t interface_id, 958f3e7eeaSChristopher Kilgour const uint64_t ns, 968f3e7eeaSChristopher Kilgour const uint32_t caplen, 978f3e7eeaSChristopher Kilgour const uint8_t rf_channel, 988f3e7eeaSChristopher Kilgour const int8_t signal_power, 998f3e7eeaSChristopher Kilgour const int8_t noise_power, 1008f3e7eeaSChristopher Kilgour const uint8_t access_code_offenses, 1018f3e7eeaSChristopher Kilgour const uint8_t payload_transport, 1028f3e7eeaSChristopher Kilgour const uint8_t payload_rate, 1038f3e7eeaSChristopher Kilgour const uint8_t corrected_header_bits, 1048f3e7eeaSChristopher Kilgour const int16_t corrected_payload_bits, 1058f3e7eeaSChristopher Kilgour const uint32_t lap, 1068f3e7eeaSChristopher Kilgour const uint32_t ref_lap, 1078f3e7eeaSChristopher Kilgour const uint8_t ref_uap, 1088f3e7eeaSChristopher Kilgour const uint32_t bt_header, 1098f3e7eeaSChristopher Kilgour const uint16_t flags, 1108f3e7eeaSChristopher Kilgour const uint8_t * payload ) 1118f3e7eeaSChristopher Kilgour { 1128f3e7eeaSChristopher Kilgour uint32_t pcap_caplen = sizeof(pcap_bluetooth_bredr_bb_header)+caplen; 1138f3e7eeaSChristopher Kilgour uint32_t reflapuap = (ref_lap&0xffffff) | (ref_uap<<24); 1148f3e7eeaSChristopher Kilgour 1158f3e7eeaSChristopher Kilgour pkt->pcap_header.ts.tv_sec = ns / 1000000000ull; 1168f3e7eeaSChristopher Kilgour pkt->pcap_header.ts.tv_usec = ns % 1000000000ull; 1178f3e7eeaSChristopher Kilgour pkt->pcap_header.caplen = pcap_caplen; 1188f3e7eeaSChristopher Kilgour pkt->pcap_header.len = pcap_caplen; 1198f3e7eeaSChristopher Kilgour 1208f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.rf_channel = rf_channel; 1218f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.signal_power = signal_power; 1228f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.noise_power = noise_power; 1238f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.access_code_offenses = access_code_offenses; 1248f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.payload_transport_rate = 1258f3e7eeaSChristopher Kilgour (payload_transport << 4) | payload_rate; 1268f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.corrected_header_bits = corrected_header_bits; 1278f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.corrected_payload_bits = htole16( corrected_payload_bits ); 1288f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.lap = htole32( lap ); 1298f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.ref_lap_uap = htole32( reflapuap ); 1308f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.bt_header = htole16( bt_header ); 1318f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.flags = htole16( flags ); 1328f3e7eeaSChristopher Kilgour if (caplen) { 1338f3e7eeaSChristopher Kilgour (void) memcpy( &pkt->bredr_payload[0], payload, caplen ); 1348f3e7eeaSChristopher Kilgour } 1358f3e7eeaSChristopher Kilgour else { 1368f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.flags &= htole16( ~BREDR_PAYLOAD_PRESENT ); 1378f3e7eeaSChristopher Kilgour } 1388f3e7eeaSChristopher Kilgour } 1398f3e7eeaSChristopher Kilgour 1408f3e7eeaSChristopher Kilgour int 1418f3e7eeaSChristopher Kilgour btbb_pcap_append_packet(btbb_pcap_handle * h, const uint64_t ns, 1428f3e7eeaSChristopher Kilgour const int8_t sigdbm, const int8_t noisedbm, 1438f3e7eeaSChristopher Kilgour const uint32_t reflap, const uint8_t refuap, 1448f3e7eeaSChristopher Kilgour const btbb_packet *pkt) 1458f3e7eeaSChristopher Kilgour { 1468f3e7eeaSChristopher Kilgour if (h && h->dumper) { 1478f3e7eeaSChristopher Kilgour uint16_t flags = BREDR_DEWHITENED | BREDR_SIGPOWER_VALID | 1488f3e7eeaSChristopher Kilgour ((noisedbm < sigdbm) ? BREDR_NOISEPOWER_VALID : 0) | 1498f3e7eeaSChristopher Kilgour ((reflap != LAP_ANY) ? BREDR_REFLAP_VALID : 0) | 1508f3e7eeaSChristopher Kilgour ((refuap != UAP_ANY) ? BREDR_REFUAP_VALID : 0); 1510e05cc66SDominic Spill uint32_t caplen = (uint32_t) btbb_packet_get_payload_length(pkt); 1520e05cc66SDominic Spill uint8_t payload_bytes[caplen]; 1530e05cc66SDominic Spill btbb_get_payload_packed( pkt, (char *) &payload_bytes[0] ); 1540e05cc66SDominic Spill caplen = MIN(BREDR_MAX_PAYLOAD, caplen); 1558f3e7eeaSChristopher Kilgour pcap_bredr_packet pcap_pkt; 1568f3e7eeaSChristopher Kilgour assemble_pcapng_bredr_packet( &pcap_pkt, 1578f3e7eeaSChristopher Kilgour 0, 1588f3e7eeaSChristopher Kilgour ns, 1598f3e7eeaSChristopher Kilgour caplen, 1608f3e7eeaSChristopher Kilgour btbb_packet_get_channel(pkt), 1618f3e7eeaSChristopher Kilgour sigdbm, 1628f3e7eeaSChristopher Kilgour noisedbm, 1638f3e7eeaSChristopher Kilgour btbb_packet_get_ac_errors(pkt), 164f83b85cfSDominic Spill btbb_packet_get_transport(pkt), 165f83b85cfSDominic Spill btbb_packet_get_modulation(pkt), 1668f3e7eeaSChristopher Kilgour 0, /* TODO: corrected header bits */ 1678f3e7eeaSChristopher Kilgour 0, /* TODO: corrected payload bits */ 1688f3e7eeaSChristopher Kilgour btbb_packet_get_lap(pkt), 1698f3e7eeaSChristopher Kilgour reflap, 1708f3e7eeaSChristopher Kilgour refuap, 1718f3e7eeaSChristopher Kilgour btbb_packet_get_header_packed(pkt), 1728f3e7eeaSChristopher Kilgour flags, 1738f3e7eeaSChristopher Kilgour payload_bytes ); 1748f3e7eeaSChristopher Kilgour pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.bredr_bb_header); 1758f3e7eeaSChristopher Kilgour return 0; 1768f3e7eeaSChristopher Kilgour } 1778f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 1788f3e7eeaSChristopher Kilgour } 1798f3e7eeaSChristopher Kilgour 1808f3e7eeaSChristopher Kilgour int 1818f3e7eeaSChristopher Kilgour btbb_pcap_close(btbb_pcap_handle * h) 1828f3e7eeaSChristopher Kilgour { 1838f3e7eeaSChristopher Kilgour if (h && h->dumper) { 1848f3e7eeaSChristopher Kilgour pcap_dump_close(h->dumper); 1858f3e7eeaSChristopher Kilgour } 1868f3e7eeaSChristopher Kilgour if (h && h->pcap) { 1878f3e7eeaSChristopher Kilgour pcap_close(h->pcap); 1888f3e7eeaSChristopher Kilgour } 1898f3e7eeaSChristopher Kilgour if (h) { 1908f3e7eeaSChristopher Kilgour free(h); 1918f3e7eeaSChristopher Kilgour return 0; 1928f3e7eeaSChristopher Kilgour } 1938f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 1948f3e7eeaSChristopher Kilgour } 1958f3e7eeaSChristopher Kilgour 1968f3e7eeaSChristopher Kilgour /* BTLE support */ 1978f3e7eeaSChristopher Kilgour 1988f3e7eeaSChristopher Kilgour typedef struct lell_pcap_handle { 1998f3e7eeaSChristopher Kilgour pcap_t * pcap; 2008f3e7eeaSChristopher Kilgour pcap_dumper_t * dumper; 2018f3e7eeaSChristopher Kilgour int dlt; 2028f3e7eeaSChristopher Kilgour uint8_t btle_ppi_version; 2038f3e7eeaSChristopher Kilgour } lell_pcap_handle; 2048f3e7eeaSChristopher Kilgour 2058f3e7eeaSChristopher Kilgour static int 2068f3e7eeaSChristopher Kilgour lell_pcap_create_file_dlt(const char *filename, int dlt, lell_pcap_handle ** ph) 2078f3e7eeaSChristopher Kilgour { 2088f3e7eeaSChristopher Kilgour int retval = 0; 2098f3e7eeaSChristopher Kilgour lell_pcap_handle * handle = malloc( sizeof(lell_pcap_handle) ); 2108f3e7eeaSChristopher Kilgour if (handle) { 2118f3e7eeaSChristopher Kilgour memset(handle, 0, sizeof(*handle)); 21245809783SMike Ryan #ifdef PCAP_TSTAMP_PRECISION_NANO 2138f3e7eeaSChristopher Kilgour handle->pcap = pcap_open_dead_with_tstamp_precision(dlt, 2140e05cc66SDominic Spill BREDR_MAX_PAYLOAD, 2158f3e7eeaSChristopher Kilgour PCAP_TSTAMP_PRECISION_NANO); 21645809783SMike Ryan #else 2170e05cc66SDominic Spill handle->pcap = pcap_open_dead(dlt, BREDR_MAX_PAYLOAD); 21845809783SMike Ryan #endif 2198f3e7eeaSChristopher Kilgour if (handle->pcap) { 2208f3e7eeaSChristopher Kilgour handle->dumper = pcap_dump_open(handle->pcap, filename); 2218f3e7eeaSChristopher Kilgour if (handle->dumper) { 2228f3e7eeaSChristopher Kilgour handle->dlt = dlt; 2238f3e7eeaSChristopher Kilgour *ph = handle; 2248f3e7eeaSChristopher Kilgour } 2258f3e7eeaSChristopher Kilgour else { 2268f3e7eeaSChristopher Kilgour retval = -PCAP_FILE_NOT_ALLOWED; 2278f3e7eeaSChristopher Kilgour goto fail; 2288f3e7eeaSChristopher Kilgour } 2298f3e7eeaSChristopher Kilgour } 2308f3e7eeaSChristopher Kilgour else { 2318f3e7eeaSChristopher Kilgour retval = -PCAP_INVALID_HANDLE; 2328f3e7eeaSChristopher Kilgour goto fail; 2338f3e7eeaSChristopher Kilgour } 2348f3e7eeaSChristopher Kilgour } 2358f3e7eeaSChristopher Kilgour else { 2368f3e7eeaSChristopher Kilgour retval = -PCAP_NO_MEMORY; 2378f3e7eeaSChristopher Kilgour goto fail; 2388f3e7eeaSChristopher Kilgour } 2398f3e7eeaSChristopher Kilgour return retval; 2408f3e7eeaSChristopher Kilgour fail: 2418f3e7eeaSChristopher Kilgour (void) lell_pcap_close( handle ); 2428f3e7eeaSChristopher Kilgour return retval; 2438f3e7eeaSChristopher Kilgour } 2448f3e7eeaSChristopher Kilgour 2458f3e7eeaSChristopher Kilgour int 2468f3e7eeaSChristopher Kilgour lell_pcap_create_file(const char *filename, lell_pcap_handle ** ph) 2478f3e7eeaSChristopher Kilgour { 2488f3e7eeaSChristopher Kilgour return lell_pcap_create_file_dlt(filename, DLT_BLUETOOTH_LE_LL_WITH_PHDR, ph); 2498f3e7eeaSChristopher Kilgour } 2508f3e7eeaSChristopher Kilgour 2518f3e7eeaSChristopher Kilgour int 2528f3e7eeaSChristopher Kilgour lell_pcap_ppi_create_file(const char *filename, int btle_ppi_version, 2538f3e7eeaSChristopher Kilgour lell_pcap_handle ** ph) 2548f3e7eeaSChristopher Kilgour { 2558f3e7eeaSChristopher Kilgour int retval = lell_pcap_create_file_dlt(filename, DLT_PPI, ph); 2568f3e7eeaSChristopher Kilgour if (!retval) { 2578f3e7eeaSChristopher Kilgour (*ph)->btle_ppi_version = btle_ppi_version; 2588f3e7eeaSChristopher Kilgour } 2598f3e7eeaSChristopher Kilgour return retval; 2608f3e7eeaSChristopher Kilgour } 2618f3e7eeaSChristopher Kilgour 2628f3e7eeaSChristopher Kilgour typedef struct { 2638f3e7eeaSChristopher Kilgour struct pcap_pkthdr pcap_header; 2648f3e7eeaSChristopher Kilgour pcap_bluetooth_le_ll_header le_ll_header; 2650e05cc66SDominic Spill uint8_t le_packet[LE_MAX_PAYLOAD]; 2668f3e7eeaSChristopher Kilgour } pcap_le_packet; 2678f3e7eeaSChristopher Kilgour 2688f3e7eeaSChristopher Kilgour static void 2698f3e7eeaSChristopher Kilgour assemble_pcapng_le_packet( pcap_le_packet * pkt, 2708f3e7eeaSChristopher Kilgour const uint32_t interface_id, 2718f3e7eeaSChristopher Kilgour const uint64_t ns, 2728f3e7eeaSChristopher Kilgour const uint32_t caplen, 2738f3e7eeaSChristopher Kilgour const uint8_t rf_channel, 2748f3e7eeaSChristopher Kilgour const int8_t signal_power, 2758f3e7eeaSChristopher Kilgour const int8_t noise_power, 2768f3e7eeaSChristopher Kilgour const uint8_t access_address_offenses, 2778f3e7eeaSChristopher Kilgour const uint32_t ref_access_address, 2788f3e7eeaSChristopher Kilgour const uint16_t flags, 2798f3e7eeaSChristopher Kilgour const uint8_t * lepkt ) 2808f3e7eeaSChristopher Kilgour { 2818f3e7eeaSChristopher Kilgour uint32_t pcap_caplen = sizeof(pcap_bluetooth_le_ll_header)+caplen; 2828f3e7eeaSChristopher Kilgour 2838f3e7eeaSChristopher Kilgour pkt->pcap_header.ts.tv_sec = ns / 1000000000ull; 2848f3e7eeaSChristopher Kilgour pkt->pcap_header.ts.tv_usec = ns % 1000000000ull; 2858f3e7eeaSChristopher Kilgour pkt->pcap_header.caplen = pcap_caplen; 2868f3e7eeaSChristopher Kilgour pkt->pcap_header.len = pcap_caplen; 2878f3e7eeaSChristopher Kilgour 2888f3e7eeaSChristopher Kilgour pkt->le_ll_header.rf_channel = rf_channel; 2898f3e7eeaSChristopher Kilgour pkt->le_ll_header.signal_power = signal_power; 2908f3e7eeaSChristopher Kilgour pkt->le_ll_header.noise_power = noise_power; 2918f3e7eeaSChristopher Kilgour pkt->le_ll_header.access_address_offenses = access_address_offenses; 2928f3e7eeaSChristopher Kilgour pkt->le_ll_header.ref_access_address = htole32( ref_access_address ); 2938f3e7eeaSChristopher Kilgour pkt->le_ll_header.flags = htole16( flags ); 2948f3e7eeaSChristopher Kilgour (void) memcpy( &pkt->le_packet[0], lepkt, caplen ); 2958f3e7eeaSChristopher Kilgour } 2968f3e7eeaSChristopher Kilgour 2978f3e7eeaSChristopher Kilgour int 2988f3e7eeaSChristopher Kilgour lell_pcap_append_packet(lell_pcap_handle * h, const uint64_t ns, 2998f3e7eeaSChristopher Kilgour const int8_t sigdbm, const int8_t noisedbm, 3008f3e7eeaSChristopher Kilgour const uint32_t refAA, const lell_packet *pkt) 3018f3e7eeaSChristopher Kilgour { 3028f3e7eeaSChristopher Kilgour if (h && h->dumper && 3038f3e7eeaSChristopher Kilgour (h->dlt == DLT_BLUETOOTH_LE_LL_WITH_PHDR)) { 3048f3e7eeaSChristopher Kilgour uint16_t flags = LE_DEWHITENED | LE_AA_OFFENSES_VALID | 3058f3e7eeaSChristopher Kilgour LE_SIGPOWER_VALID | 3068f3e7eeaSChristopher Kilgour ((noisedbm < sigdbm) ? LE_NOISEPOWER_VALID : 0) | 3078f3e7eeaSChristopher Kilgour (lell_packet_is_data(pkt) ? 0 : LE_REF_AA_VALID); 3088f3e7eeaSChristopher Kilgour pcap_le_packet pcap_pkt; 3098f3e7eeaSChristopher Kilgour assemble_pcapng_le_packet( &pcap_pkt, 3108f3e7eeaSChristopher Kilgour 0, 3118f3e7eeaSChristopher Kilgour ns, 3128f3e7eeaSChristopher Kilgour 9+pkt->length, 3138f3e7eeaSChristopher Kilgour pkt->channel_k, 3148f3e7eeaSChristopher Kilgour sigdbm, 3158f3e7eeaSChristopher Kilgour noisedbm, 3168f3e7eeaSChristopher Kilgour pkt->access_address_offenses, 3178f3e7eeaSChristopher Kilgour refAA, 3188f3e7eeaSChristopher Kilgour flags, 3198f3e7eeaSChristopher Kilgour &pkt->symbols[0] ); 3208f3e7eeaSChristopher Kilgour pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.le_ll_header); 3218f3e7eeaSChristopher Kilgour return 0; 3228f3e7eeaSChristopher Kilgour } 3238f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 3248f3e7eeaSChristopher Kilgour } 3258f3e7eeaSChristopher Kilgour 3268f3e7eeaSChristopher Kilgour #define PPI_BTLE 30006 3278f3e7eeaSChristopher Kilgour 3288f3e7eeaSChristopher Kilgour typedef struct __attribute__((packed)) { 3298f3e7eeaSChristopher Kilgour uint8_t pph_version; 3308f3e7eeaSChristopher Kilgour uint8_t pph_flags; 3318f3e7eeaSChristopher Kilgour uint16_t pph_len; 3328f3e7eeaSChristopher Kilgour uint32_t pph_dlt; 3338f3e7eeaSChristopher Kilgour } ppi_packet_header_t; 3348f3e7eeaSChristopher Kilgour 3358f3e7eeaSChristopher Kilgour typedef struct __attribute__((packed)) { 3368f3e7eeaSChristopher Kilgour uint16_t pfh_type; 3378f3e7eeaSChristopher Kilgour uint16_t pfh_datalen; 3388f3e7eeaSChristopher Kilgour } ppi_fieldheader_t; 3398f3e7eeaSChristopher Kilgour 3408f3e7eeaSChristopher Kilgour typedef struct __attribute__((packed)) { 3418f3e7eeaSChristopher Kilgour uint8_t btle_version; 3428f3e7eeaSChristopher Kilgour uint16_t btle_channel; 3438f3e7eeaSChristopher Kilgour uint8_t btle_clkn_high; 3448f3e7eeaSChristopher Kilgour uint32_t btle_clk100ns; 3458f3e7eeaSChristopher Kilgour int8_t rssi_max; 3468f3e7eeaSChristopher Kilgour int8_t rssi_min; 3478f3e7eeaSChristopher Kilgour int8_t rssi_avg; 3488f3e7eeaSChristopher Kilgour uint8_t rssi_count; 3498f3e7eeaSChristopher Kilgour } ppi_btle_t; 3508f3e7eeaSChristopher Kilgour 3518f3e7eeaSChristopher Kilgour typedef struct __attribute__((packed)) { 3528f3e7eeaSChristopher Kilgour struct pcap_pkthdr pcap_header; 3538f3e7eeaSChristopher Kilgour ppi_packet_header_t ppi_packet_header; 3548f3e7eeaSChristopher Kilgour ppi_fieldheader_t ppi_fieldheader; 3558f3e7eeaSChristopher Kilgour ppi_btle_t le_ll_ppi_header; 3560e05cc66SDominic Spill uint8_t le_packet[LE_MAX_PAYLOAD]; 3578f3e7eeaSChristopher Kilgour } pcap_ppi_le_packet; 3588f3e7eeaSChristopher Kilgour 3598f3e7eeaSChristopher Kilgour int 3608f3e7eeaSChristopher Kilgour lell_pcap_append_ppi_packet(lell_pcap_handle * h, const uint64_t ns, 3618f3e7eeaSChristopher Kilgour const uint8_t clkn_high, 3628f3e7eeaSChristopher Kilgour const int8_t rssi_min, const int8_t rssi_max, 3638f3e7eeaSChristopher Kilgour const int8_t rssi_avg, const uint8_t rssi_count, 3648f3e7eeaSChristopher Kilgour const lell_packet *pkt) 3658f3e7eeaSChristopher Kilgour { 3668f3e7eeaSChristopher Kilgour const ppi_packet_header_sz = sizeof(ppi_packet_header_t); 3678f3e7eeaSChristopher Kilgour const ppi_fieldheader_sz = sizeof(ppi_fieldheader_t); 3688f3e7eeaSChristopher Kilgour const le_ll_ppi_header_sz = sizeof(ppi_btle_t); 3698f3e7eeaSChristopher Kilgour 3708f3e7eeaSChristopher Kilgour if (h && h->dumper && 3718f3e7eeaSChristopher Kilgour (h->dlt == DLT_PPI)) { 3728f3e7eeaSChristopher Kilgour pcap_ppi_le_packet pcap_pkt; 3738f3e7eeaSChristopher Kilgour uint32_t pcap_caplen = 374b53c3fb7SMike Ryan ppi_packet_header_sz+ppi_fieldheader_sz+le_ll_ppi_header_sz+pkt->length+9; 3758f3e7eeaSChristopher Kilgour uint16_t MHz = 2402 + 2*lell_get_channel_k(pkt); 3768f3e7eeaSChristopher Kilgour 3778f3e7eeaSChristopher Kilgour pcap_pkt.pcap_header.ts.tv_sec = ns / 1000000000ull; 3788f3e7eeaSChristopher Kilgour pcap_pkt.pcap_header.ts.tv_usec = ns % 1000000000ull; 3798f3e7eeaSChristopher Kilgour pcap_pkt.pcap_header.caplen = pcap_caplen; 3808f3e7eeaSChristopher Kilgour pcap_pkt.pcap_header.len = pcap_caplen; 3818f3e7eeaSChristopher Kilgour 3828f3e7eeaSChristopher Kilgour pcap_pkt.ppi_packet_header.pph_version = 0; 3838f3e7eeaSChristopher Kilgour pcap_pkt.ppi_packet_header.pph_flags = 0; 3848f3e7eeaSChristopher Kilgour pcap_pkt.ppi_packet_header.pph_len = htole16(ppi_packet_header_sz+ppi_fieldheader_sz+le_ll_ppi_header_sz); 3858f3e7eeaSChristopher Kilgour pcap_pkt.ppi_packet_header.pph_dlt = htole32(DLT_USER0); 3868f3e7eeaSChristopher Kilgour 3878f3e7eeaSChristopher Kilgour pcap_pkt.ppi_fieldheader.pfh_type = htole16(PPI_BTLE); 3888f3e7eeaSChristopher Kilgour pcap_pkt.ppi_fieldheader.pfh_datalen = htole16(le_ll_ppi_header_sz); 3898f3e7eeaSChristopher Kilgour 3908f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.btle_version = h->btle_ppi_version; 3918f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.btle_channel = htole16(MHz); 3928f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.btle_clkn_high = clkn_high; 3938f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.btle_clk100ns = htole32(pkt->clk100ns); 3948f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.rssi_max = rssi_max; 3958f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.rssi_min = rssi_min; 3968f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.rssi_avg = rssi_avg; 3978f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.rssi_count = rssi_count; 398a7fccc50SMike Ryan (void) memcpy( &pcap_pkt.le_packet[0], &pkt->symbols[0], pkt->length + 9 ); // FIXME where does the 9 come from? 399b53c3fb7SMike Ryan pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.ppi_packet_header); 400cf8c0e31SMike Ryan pcap_dump_flush(h->dumper); 4018f3e7eeaSChristopher Kilgour return 0; 4028f3e7eeaSChristopher Kilgour } 4038f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 4048f3e7eeaSChristopher Kilgour } 4058f3e7eeaSChristopher Kilgour 4068f3e7eeaSChristopher Kilgour int 4078f3e7eeaSChristopher Kilgour lell_pcap_close(lell_pcap_handle *h) 4088f3e7eeaSChristopher Kilgour { 4098f3e7eeaSChristopher Kilgour if (h && h->dumper) { 4108f3e7eeaSChristopher Kilgour pcap_dump_close(h->dumper); 4118f3e7eeaSChristopher Kilgour } 4128f3e7eeaSChristopher Kilgour if (h && h->pcap) { 4138f3e7eeaSChristopher Kilgour pcap_close(h->pcap); 4148f3e7eeaSChristopher Kilgour } 4158f3e7eeaSChristopher Kilgour if (h) { 4168f3e7eeaSChristopher Kilgour free(h); 4178f3e7eeaSChristopher Kilgour return 0; 4188f3e7eeaSChristopher Kilgour } 4198f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 4208f3e7eeaSChristopher Kilgour } 4218f3e7eeaSChristopher Kilgour 422*a3df4d72SDominic Spill #endif /* ENABLE_PCAP */ 423