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 #include "bluetooth_le_packet.h" 23*8f3e7eeaSChristopher Kilgour #include "btbb.h" 24*8f3e7eeaSChristopher Kilgour #include "pcap-common.h" 25*8f3e7eeaSChristopher Kilgour 26*8f3e7eeaSChristopher Kilgour #include <stdlib.h> 27*8f3e7eeaSChristopher Kilgour #include <string.h> 28*8f3e7eeaSChristopher Kilgour 29*8f3e7eeaSChristopher Kilgour typedef enum { 30*8f3e7eeaSChristopher Kilgour PCAP_OK = 0, 31*8f3e7eeaSChristopher Kilgour PCAP_INVALID_HANDLE, 32*8f3e7eeaSChristopher Kilgour PCAP_FILE_NOT_ALLOWED, 33*8f3e7eeaSChristopher Kilgour PCAP_NO_MEMORY, 34*8f3e7eeaSChristopher Kilgour } PCAP_RESULT; 35*8f3e7eeaSChristopher Kilgour 36*8f3e7eeaSChristopher Kilgour #if defined(USE_PCAP) 37*8f3e7eeaSChristopher Kilgour 38*8f3e7eeaSChristopher Kilgour /* BT BR/EDR support */ 39*8f3e7eeaSChristopher Kilgour 40*8f3e7eeaSChristopher Kilgour typedef struct btbb_pcap_handle { 41*8f3e7eeaSChristopher Kilgour pcap_t * pcap; 42*8f3e7eeaSChristopher Kilgour pcap_dumper_t * dumper; 43*8f3e7eeaSChristopher Kilgour } btbb_pcap_handle; 44*8f3e7eeaSChristopher Kilgour 45*8f3e7eeaSChristopher Kilgour int 46*8f3e7eeaSChristopher Kilgour btbb_pcap_create_file(const char *filename, btbb_pcap_handle ** ph) 47*8f3e7eeaSChristopher Kilgour { 48*8f3e7eeaSChristopher Kilgour int retval = 0; 49*8f3e7eeaSChristopher Kilgour btbb_pcap_handle * handle = malloc( sizeof(btbb_pcap_handle) ); 50*8f3e7eeaSChristopher Kilgour if (handle) { 51*8f3e7eeaSChristopher Kilgour memset(handle, 0, sizeof(*handle)); 52*8f3e7eeaSChristopher Kilgour handle->pcap = pcap_open_dead_with_tstamp_precision(DLT_BLUETOOTH_BREDR_BB, 53*8f3e7eeaSChristopher Kilgour 400, 54*8f3e7eeaSChristopher Kilgour PCAP_TSTAMP_PRECISION_NANO); 55*8f3e7eeaSChristopher Kilgour if (handle->pcap) { 56*8f3e7eeaSChristopher Kilgour handle->dumper = pcap_dump_open(handle->pcap, filename); 57*8f3e7eeaSChristopher Kilgour if (handle->dumper) { 58*8f3e7eeaSChristopher Kilgour *ph = handle; 59*8f3e7eeaSChristopher Kilgour } 60*8f3e7eeaSChristopher Kilgour else { 61*8f3e7eeaSChristopher Kilgour retval = -PCAP_FILE_NOT_ALLOWED; 62*8f3e7eeaSChristopher Kilgour goto fail; 63*8f3e7eeaSChristopher Kilgour } 64*8f3e7eeaSChristopher Kilgour } 65*8f3e7eeaSChristopher Kilgour else { 66*8f3e7eeaSChristopher Kilgour retval = -PCAP_INVALID_HANDLE; 67*8f3e7eeaSChristopher Kilgour goto fail; 68*8f3e7eeaSChristopher Kilgour } 69*8f3e7eeaSChristopher Kilgour } 70*8f3e7eeaSChristopher Kilgour else { 71*8f3e7eeaSChristopher Kilgour retval = -PCAP_NO_MEMORY; 72*8f3e7eeaSChristopher Kilgour goto fail; 73*8f3e7eeaSChristopher Kilgour } 74*8f3e7eeaSChristopher Kilgour return retval; 75*8f3e7eeaSChristopher Kilgour fail: 76*8f3e7eeaSChristopher Kilgour (void) btbb_pcap_close( handle ); 77*8f3e7eeaSChristopher Kilgour return retval; 78*8f3e7eeaSChristopher Kilgour } 79*8f3e7eeaSChristopher Kilgour 80*8f3e7eeaSChristopher Kilgour typedef struct { 81*8f3e7eeaSChristopher Kilgour struct pcap_pkthdr pcap_header; 82*8f3e7eeaSChristopher Kilgour pcap_bluetooth_bredr_bb_header bredr_bb_header; 83*8f3e7eeaSChristopher Kilgour uint8_t bredr_payload[400]; 84*8f3e7eeaSChristopher Kilgour } pcap_bredr_packet; 85*8f3e7eeaSChristopher Kilgour 86*8f3e7eeaSChristopher Kilgour static void 87*8f3e7eeaSChristopher Kilgour assemble_pcapng_bredr_packet( pcap_bredr_packet * pkt, 88*8f3e7eeaSChristopher Kilgour const uint32_t interface_id, 89*8f3e7eeaSChristopher Kilgour const uint64_t ns, 90*8f3e7eeaSChristopher Kilgour const uint32_t caplen, 91*8f3e7eeaSChristopher Kilgour const uint8_t rf_channel, 92*8f3e7eeaSChristopher Kilgour const int8_t signal_power, 93*8f3e7eeaSChristopher Kilgour const int8_t noise_power, 94*8f3e7eeaSChristopher Kilgour const uint8_t access_code_offenses, 95*8f3e7eeaSChristopher Kilgour const uint8_t payload_transport, 96*8f3e7eeaSChristopher Kilgour const uint8_t payload_rate, 97*8f3e7eeaSChristopher Kilgour const uint8_t corrected_header_bits, 98*8f3e7eeaSChristopher Kilgour const int16_t corrected_payload_bits, 99*8f3e7eeaSChristopher Kilgour const uint32_t lap, 100*8f3e7eeaSChristopher Kilgour const uint32_t ref_lap, 101*8f3e7eeaSChristopher Kilgour const uint8_t ref_uap, 102*8f3e7eeaSChristopher Kilgour const uint32_t bt_header, 103*8f3e7eeaSChristopher Kilgour const uint16_t flags, 104*8f3e7eeaSChristopher Kilgour const uint8_t * payload ) 105*8f3e7eeaSChristopher Kilgour { 106*8f3e7eeaSChristopher Kilgour uint32_t pcap_caplen = sizeof(pcap_bluetooth_bredr_bb_header)+caplen; 107*8f3e7eeaSChristopher Kilgour uint32_t reflapuap = (ref_lap&0xffffff) | (ref_uap<<24); 108*8f3e7eeaSChristopher Kilgour 109*8f3e7eeaSChristopher Kilgour pkt->pcap_header.ts.tv_sec = ns / 1000000000ull; 110*8f3e7eeaSChristopher Kilgour pkt->pcap_header.ts.tv_usec = ns % 1000000000ull; 111*8f3e7eeaSChristopher Kilgour pkt->pcap_header.caplen = pcap_caplen; 112*8f3e7eeaSChristopher Kilgour pkt->pcap_header.len = pcap_caplen; 113*8f3e7eeaSChristopher Kilgour 114*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.rf_channel = rf_channel; 115*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.signal_power = signal_power; 116*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.noise_power = noise_power; 117*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.access_code_offenses = access_code_offenses; 118*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.payload_transport_rate = 119*8f3e7eeaSChristopher Kilgour (payload_transport << 4) | payload_rate; 120*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.corrected_header_bits = corrected_header_bits; 121*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.corrected_payload_bits = htole16( corrected_payload_bits ); 122*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.lap = htole32( lap ); 123*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.ref_lap_uap = htole32( reflapuap ); 124*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.bt_header = htole16( bt_header ); 125*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.flags = htole16( flags ); 126*8f3e7eeaSChristopher Kilgour if (caplen) { 127*8f3e7eeaSChristopher Kilgour (void) memcpy( &pkt->bredr_payload[0], payload, caplen ); 128*8f3e7eeaSChristopher Kilgour } 129*8f3e7eeaSChristopher Kilgour else { 130*8f3e7eeaSChristopher Kilgour pkt->bredr_bb_header.flags &= htole16( ~BREDR_PAYLOAD_PRESENT ); 131*8f3e7eeaSChristopher Kilgour } 132*8f3e7eeaSChristopher Kilgour } 133*8f3e7eeaSChristopher Kilgour 134*8f3e7eeaSChristopher Kilgour int 135*8f3e7eeaSChristopher Kilgour btbb_pcap_append_packet(btbb_pcap_handle * h, const uint64_t ns, 136*8f3e7eeaSChristopher Kilgour const int8_t sigdbm, const int8_t noisedbm, 137*8f3e7eeaSChristopher Kilgour const uint32_t reflap, const uint8_t refuap, 138*8f3e7eeaSChristopher Kilgour const btbb_packet *pkt) 139*8f3e7eeaSChristopher Kilgour { 140*8f3e7eeaSChristopher Kilgour if (h && h->dumper) { 141*8f3e7eeaSChristopher Kilgour uint16_t flags = BREDR_DEWHITENED | BREDR_SIGPOWER_VALID | 142*8f3e7eeaSChristopher Kilgour ((noisedbm < sigdbm) ? BREDR_NOISEPOWER_VALID : 0) | 143*8f3e7eeaSChristopher Kilgour ((reflap != LAP_ANY) ? BREDR_REFLAP_VALID : 0) | 144*8f3e7eeaSChristopher Kilgour ((refuap != UAP_ANY) ? BREDR_REFUAP_VALID : 0); 145*8f3e7eeaSChristopher Kilgour uint8_t payload_bytes[400]; 146*8f3e7eeaSChristopher Kilgour uint32_t caplen = (uint32_t) btbb_get_payload_packed( pkt, (char *) &payload_bytes[0] ); 147*8f3e7eeaSChristopher Kilgour pcap_bredr_packet pcap_pkt; 148*8f3e7eeaSChristopher Kilgour assemble_pcapng_bredr_packet( &pcap_pkt, 149*8f3e7eeaSChristopher Kilgour 0, 150*8f3e7eeaSChristopher Kilgour ns, 151*8f3e7eeaSChristopher Kilgour caplen, 152*8f3e7eeaSChristopher Kilgour btbb_packet_get_channel(pkt), 153*8f3e7eeaSChristopher Kilgour sigdbm, 154*8f3e7eeaSChristopher Kilgour noisedbm, 155*8f3e7eeaSChristopher Kilgour btbb_packet_get_ac_errors(pkt), 156*8f3e7eeaSChristopher Kilgour BREDR_TRANSPORT_ANY, 157*8f3e7eeaSChristopher Kilgour BREDR_GFSK, /* currently only supported */ 158*8f3e7eeaSChristopher Kilgour 0, /* TODO: corrected header bits */ 159*8f3e7eeaSChristopher Kilgour 0, /* TODO: corrected payload bits */ 160*8f3e7eeaSChristopher Kilgour btbb_packet_get_lap(pkt), 161*8f3e7eeaSChristopher Kilgour reflap, 162*8f3e7eeaSChristopher Kilgour refuap, 163*8f3e7eeaSChristopher Kilgour btbb_packet_get_header_packed(pkt), 164*8f3e7eeaSChristopher Kilgour flags, 165*8f3e7eeaSChristopher Kilgour payload_bytes ); 166*8f3e7eeaSChristopher Kilgour pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.bredr_bb_header); 167*8f3e7eeaSChristopher Kilgour return 0; 168*8f3e7eeaSChristopher Kilgour } 169*8f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 170*8f3e7eeaSChristopher Kilgour } 171*8f3e7eeaSChristopher Kilgour 172*8f3e7eeaSChristopher Kilgour int 173*8f3e7eeaSChristopher Kilgour btbb_pcap_close(btbb_pcap_handle * h) 174*8f3e7eeaSChristopher Kilgour { 175*8f3e7eeaSChristopher Kilgour if (h && h->dumper) { 176*8f3e7eeaSChristopher Kilgour pcap_dump_close(h->dumper); 177*8f3e7eeaSChristopher Kilgour } 178*8f3e7eeaSChristopher Kilgour if (h && h->pcap) { 179*8f3e7eeaSChristopher Kilgour pcap_close(h->pcap); 180*8f3e7eeaSChristopher Kilgour } 181*8f3e7eeaSChristopher Kilgour if (h) { 182*8f3e7eeaSChristopher Kilgour free(h); 183*8f3e7eeaSChristopher Kilgour return 0; 184*8f3e7eeaSChristopher Kilgour } 185*8f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 186*8f3e7eeaSChristopher Kilgour } 187*8f3e7eeaSChristopher Kilgour 188*8f3e7eeaSChristopher Kilgour /* BTLE support */ 189*8f3e7eeaSChristopher Kilgour 190*8f3e7eeaSChristopher Kilgour typedef struct lell_pcap_handle { 191*8f3e7eeaSChristopher Kilgour pcap_t * pcap; 192*8f3e7eeaSChristopher Kilgour pcap_dumper_t * dumper; 193*8f3e7eeaSChristopher Kilgour int dlt; 194*8f3e7eeaSChristopher Kilgour uint8_t btle_ppi_version; 195*8f3e7eeaSChristopher Kilgour } lell_pcap_handle; 196*8f3e7eeaSChristopher Kilgour 197*8f3e7eeaSChristopher Kilgour static int 198*8f3e7eeaSChristopher Kilgour lell_pcap_create_file_dlt(const char *filename, int dlt, lell_pcap_handle ** ph) 199*8f3e7eeaSChristopher Kilgour { 200*8f3e7eeaSChristopher Kilgour int retval = 0; 201*8f3e7eeaSChristopher Kilgour lell_pcap_handle * handle = malloc( sizeof(lell_pcap_handle) ); 202*8f3e7eeaSChristopher Kilgour if (handle) { 203*8f3e7eeaSChristopher Kilgour memset(handle, 0, sizeof(*handle)); 204*8f3e7eeaSChristopher Kilgour handle->pcap = pcap_open_dead_with_tstamp_precision(dlt, 205*8f3e7eeaSChristopher Kilgour 400, 206*8f3e7eeaSChristopher Kilgour PCAP_TSTAMP_PRECISION_NANO); 207*8f3e7eeaSChristopher Kilgour if (handle->pcap) { 208*8f3e7eeaSChristopher Kilgour handle->dumper = pcap_dump_open(handle->pcap, filename); 209*8f3e7eeaSChristopher Kilgour if (handle->dumper) { 210*8f3e7eeaSChristopher Kilgour handle->dlt = dlt; 211*8f3e7eeaSChristopher Kilgour *ph = handle; 212*8f3e7eeaSChristopher Kilgour } 213*8f3e7eeaSChristopher Kilgour else { 214*8f3e7eeaSChristopher Kilgour retval = -PCAP_FILE_NOT_ALLOWED; 215*8f3e7eeaSChristopher Kilgour goto fail; 216*8f3e7eeaSChristopher Kilgour } 217*8f3e7eeaSChristopher Kilgour } 218*8f3e7eeaSChristopher Kilgour else { 219*8f3e7eeaSChristopher Kilgour retval = -PCAP_INVALID_HANDLE; 220*8f3e7eeaSChristopher Kilgour goto fail; 221*8f3e7eeaSChristopher Kilgour } 222*8f3e7eeaSChristopher Kilgour } 223*8f3e7eeaSChristopher Kilgour else { 224*8f3e7eeaSChristopher Kilgour retval = -PCAP_NO_MEMORY; 225*8f3e7eeaSChristopher Kilgour goto fail; 226*8f3e7eeaSChristopher Kilgour } 227*8f3e7eeaSChristopher Kilgour return retval; 228*8f3e7eeaSChristopher Kilgour fail: 229*8f3e7eeaSChristopher Kilgour (void) lell_pcap_close( handle ); 230*8f3e7eeaSChristopher Kilgour return retval; 231*8f3e7eeaSChristopher Kilgour } 232*8f3e7eeaSChristopher Kilgour 233*8f3e7eeaSChristopher Kilgour int 234*8f3e7eeaSChristopher Kilgour lell_pcap_create_file(const char *filename, lell_pcap_handle ** ph) 235*8f3e7eeaSChristopher Kilgour { 236*8f3e7eeaSChristopher Kilgour return lell_pcap_create_file_dlt(filename, DLT_BLUETOOTH_LE_LL_WITH_PHDR, ph); 237*8f3e7eeaSChristopher Kilgour } 238*8f3e7eeaSChristopher Kilgour 239*8f3e7eeaSChristopher Kilgour int 240*8f3e7eeaSChristopher Kilgour lell_pcap_ppi_create_file(const char *filename, int btle_ppi_version, 241*8f3e7eeaSChristopher Kilgour lell_pcap_handle ** ph) 242*8f3e7eeaSChristopher Kilgour { 243*8f3e7eeaSChristopher Kilgour int retval = lell_pcap_create_file_dlt(filename, DLT_PPI, ph); 244*8f3e7eeaSChristopher Kilgour if (!retval) { 245*8f3e7eeaSChristopher Kilgour (*ph)->btle_ppi_version = btle_ppi_version; 246*8f3e7eeaSChristopher Kilgour } 247*8f3e7eeaSChristopher Kilgour return retval; 248*8f3e7eeaSChristopher Kilgour } 249*8f3e7eeaSChristopher Kilgour 250*8f3e7eeaSChristopher Kilgour typedef struct { 251*8f3e7eeaSChristopher Kilgour struct pcap_pkthdr pcap_header; 252*8f3e7eeaSChristopher Kilgour pcap_bluetooth_le_ll_header le_ll_header; 253*8f3e7eeaSChristopher Kilgour uint8_t le_packet[48]; 254*8f3e7eeaSChristopher Kilgour } pcap_le_packet; 255*8f3e7eeaSChristopher Kilgour 256*8f3e7eeaSChristopher Kilgour static void 257*8f3e7eeaSChristopher Kilgour assemble_pcapng_le_packet( pcap_le_packet * pkt, 258*8f3e7eeaSChristopher Kilgour const uint32_t interface_id, 259*8f3e7eeaSChristopher Kilgour const uint64_t ns, 260*8f3e7eeaSChristopher Kilgour const uint32_t caplen, 261*8f3e7eeaSChristopher Kilgour const uint8_t rf_channel, 262*8f3e7eeaSChristopher Kilgour const int8_t signal_power, 263*8f3e7eeaSChristopher Kilgour const int8_t noise_power, 264*8f3e7eeaSChristopher Kilgour const uint8_t access_address_offenses, 265*8f3e7eeaSChristopher Kilgour const uint32_t ref_access_address, 266*8f3e7eeaSChristopher Kilgour const uint16_t flags, 267*8f3e7eeaSChristopher Kilgour const uint8_t * lepkt ) 268*8f3e7eeaSChristopher Kilgour { 269*8f3e7eeaSChristopher Kilgour uint32_t pcap_caplen = sizeof(pcap_bluetooth_le_ll_header)+caplen; 270*8f3e7eeaSChristopher Kilgour 271*8f3e7eeaSChristopher Kilgour pkt->pcap_header.ts.tv_sec = ns / 1000000000ull; 272*8f3e7eeaSChristopher Kilgour pkt->pcap_header.ts.tv_usec = ns % 1000000000ull; 273*8f3e7eeaSChristopher Kilgour pkt->pcap_header.caplen = pcap_caplen; 274*8f3e7eeaSChristopher Kilgour pkt->pcap_header.len = pcap_caplen; 275*8f3e7eeaSChristopher Kilgour 276*8f3e7eeaSChristopher Kilgour pkt->le_ll_header.rf_channel = rf_channel; 277*8f3e7eeaSChristopher Kilgour pkt->le_ll_header.signal_power = signal_power; 278*8f3e7eeaSChristopher Kilgour pkt->le_ll_header.noise_power = noise_power; 279*8f3e7eeaSChristopher Kilgour pkt->le_ll_header.access_address_offenses = access_address_offenses; 280*8f3e7eeaSChristopher Kilgour pkt->le_ll_header.ref_access_address = htole32( ref_access_address ); 281*8f3e7eeaSChristopher Kilgour pkt->le_ll_header.flags = htole16( flags ); 282*8f3e7eeaSChristopher Kilgour (void) memcpy( &pkt->le_packet[0], lepkt, caplen ); 283*8f3e7eeaSChristopher Kilgour } 284*8f3e7eeaSChristopher Kilgour 285*8f3e7eeaSChristopher Kilgour int 286*8f3e7eeaSChristopher Kilgour lell_pcap_append_packet(lell_pcap_handle * h, const uint64_t ns, 287*8f3e7eeaSChristopher Kilgour const int8_t sigdbm, const int8_t noisedbm, 288*8f3e7eeaSChristopher Kilgour const uint32_t refAA, const lell_packet *pkt) 289*8f3e7eeaSChristopher Kilgour { 290*8f3e7eeaSChristopher Kilgour if (h && h->dumper && 291*8f3e7eeaSChristopher Kilgour (h->dlt == DLT_BLUETOOTH_LE_LL_WITH_PHDR)) { 292*8f3e7eeaSChristopher Kilgour uint16_t flags = LE_DEWHITENED | LE_AA_OFFENSES_VALID | 293*8f3e7eeaSChristopher Kilgour LE_SIGPOWER_VALID | 294*8f3e7eeaSChristopher Kilgour ((noisedbm < sigdbm) ? LE_NOISEPOWER_VALID : 0) | 295*8f3e7eeaSChristopher Kilgour (lell_packet_is_data(pkt) ? 0 : LE_REF_AA_VALID); 296*8f3e7eeaSChristopher Kilgour pcap_le_packet pcap_pkt; 297*8f3e7eeaSChristopher Kilgour assemble_pcapng_le_packet( &pcap_pkt, 298*8f3e7eeaSChristopher Kilgour 0, 299*8f3e7eeaSChristopher Kilgour ns, 300*8f3e7eeaSChristopher Kilgour 9+pkt->length, 301*8f3e7eeaSChristopher Kilgour pkt->channel_k, 302*8f3e7eeaSChristopher Kilgour sigdbm, 303*8f3e7eeaSChristopher Kilgour noisedbm, 304*8f3e7eeaSChristopher Kilgour pkt->access_address_offenses, 305*8f3e7eeaSChristopher Kilgour refAA, 306*8f3e7eeaSChristopher Kilgour flags, 307*8f3e7eeaSChristopher Kilgour &pkt->symbols[0] ); 308*8f3e7eeaSChristopher Kilgour pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.le_ll_header); 309*8f3e7eeaSChristopher Kilgour return 0; 310*8f3e7eeaSChristopher Kilgour } 311*8f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 312*8f3e7eeaSChristopher Kilgour } 313*8f3e7eeaSChristopher Kilgour 314*8f3e7eeaSChristopher Kilgour #define PPI_BTLE 30006 315*8f3e7eeaSChristopher Kilgour 316*8f3e7eeaSChristopher Kilgour typedef struct __attribute__((packed)) { 317*8f3e7eeaSChristopher Kilgour uint8_t pph_version; 318*8f3e7eeaSChristopher Kilgour uint8_t pph_flags; 319*8f3e7eeaSChristopher Kilgour uint16_t pph_len; 320*8f3e7eeaSChristopher Kilgour uint32_t pph_dlt; 321*8f3e7eeaSChristopher Kilgour } ppi_packet_header_t; 322*8f3e7eeaSChristopher Kilgour 323*8f3e7eeaSChristopher Kilgour typedef struct __attribute__((packed)) { 324*8f3e7eeaSChristopher Kilgour uint16_t pfh_type; 325*8f3e7eeaSChristopher Kilgour uint16_t pfh_datalen; 326*8f3e7eeaSChristopher Kilgour } ppi_fieldheader_t; 327*8f3e7eeaSChristopher Kilgour 328*8f3e7eeaSChristopher Kilgour typedef struct __attribute__((packed)) { 329*8f3e7eeaSChristopher Kilgour uint8_t btle_version; 330*8f3e7eeaSChristopher Kilgour uint16_t btle_channel; 331*8f3e7eeaSChristopher Kilgour uint8_t btle_clkn_high; 332*8f3e7eeaSChristopher Kilgour uint32_t btle_clk100ns; 333*8f3e7eeaSChristopher Kilgour int8_t rssi_max; 334*8f3e7eeaSChristopher Kilgour int8_t rssi_min; 335*8f3e7eeaSChristopher Kilgour int8_t rssi_avg; 336*8f3e7eeaSChristopher Kilgour uint8_t rssi_count; 337*8f3e7eeaSChristopher Kilgour } ppi_btle_t; 338*8f3e7eeaSChristopher Kilgour 339*8f3e7eeaSChristopher Kilgour typedef struct __attribute__((packed)) { 340*8f3e7eeaSChristopher Kilgour struct pcap_pkthdr pcap_header; 341*8f3e7eeaSChristopher Kilgour ppi_packet_header_t ppi_packet_header; 342*8f3e7eeaSChristopher Kilgour ppi_fieldheader_t ppi_fieldheader; 343*8f3e7eeaSChristopher Kilgour ppi_btle_t le_ll_ppi_header; 344*8f3e7eeaSChristopher Kilgour uint8_t le_packet[48]; 345*8f3e7eeaSChristopher Kilgour } pcap_ppi_le_packet; 346*8f3e7eeaSChristopher Kilgour 347*8f3e7eeaSChristopher Kilgour int 348*8f3e7eeaSChristopher Kilgour lell_pcap_append_ppi_packet(lell_pcap_handle * h, const uint64_t ns, 349*8f3e7eeaSChristopher Kilgour const uint8_t clkn_high, 350*8f3e7eeaSChristopher Kilgour const int8_t rssi_min, const int8_t rssi_max, 351*8f3e7eeaSChristopher Kilgour const int8_t rssi_avg, const uint8_t rssi_count, 352*8f3e7eeaSChristopher Kilgour const lell_packet *pkt) 353*8f3e7eeaSChristopher Kilgour { 354*8f3e7eeaSChristopher Kilgour const ppi_packet_header_sz = sizeof(ppi_packet_header_t); 355*8f3e7eeaSChristopher Kilgour const ppi_fieldheader_sz = sizeof(ppi_fieldheader_t); 356*8f3e7eeaSChristopher Kilgour const le_ll_ppi_header_sz = sizeof(ppi_btle_t); 357*8f3e7eeaSChristopher Kilgour 358*8f3e7eeaSChristopher Kilgour if (h && h->dumper && 359*8f3e7eeaSChristopher Kilgour (h->dlt == DLT_PPI)) { 360*8f3e7eeaSChristopher Kilgour pcap_ppi_le_packet pcap_pkt; 361*8f3e7eeaSChristopher Kilgour uint32_t pcap_caplen = 362*8f3e7eeaSChristopher Kilgour ppi_packet_header_sz+ppi_fieldheader_sz+le_ll_ppi_header_sz+pkt->length; 363*8f3e7eeaSChristopher Kilgour uint16_t MHz = 2402 + 2*lell_get_channel_k(pkt); 364*8f3e7eeaSChristopher Kilgour 365*8f3e7eeaSChristopher Kilgour pcap_pkt.pcap_header.ts.tv_sec = ns / 1000000000ull; 366*8f3e7eeaSChristopher Kilgour pcap_pkt.pcap_header.ts.tv_usec = ns % 1000000000ull; 367*8f3e7eeaSChristopher Kilgour pcap_pkt.pcap_header.caplen = pcap_caplen; 368*8f3e7eeaSChristopher Kilgour pcap_pkt.pcap_header.len = pcap_caplen; 369*8f3e7eeaSChristopher Kilgour 370*8f3e7eeaSChristopher Kilgour pcap_pkt.ppi_packet_header.pph_version = 0; 371*8f3e7eeaSChristopher Kilgour pcap_pkt.ppi_packet_header.pph_flags = 0; 372*8f3e7eeaSChristopher Kilgour pcap_pkt.ppi_packet_header.pph_len = htole16(ppi_packet_header_sz+ppi_fieldheader_sz+le_ll_ppi_header_sz); 373*8f3e7eeaSChristopher Kilgour pcap_pkt.ppi_packet_header.pph_dlt = htole32(DLT_USER0); 374*8f3e7eeaSChristopher Kilgour 375*8f3e7eeaSChristopher Kilgour pcap_pkt.ppi_fieldheader.pfh_type = htole16(PPI_BTLE); 376*8f3e7eeaSChristopher Kilgour pcap_pkt.ppi_fieldheader.pfh_datalen = htole16(le_ll_ppi_header_sz); 377*8f3e7eeaSChristopher Kilgour 378*8f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.btle_version = h->btle_ppi_version; 379*8f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.btle_channel = htole16(MHz); 380*8f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.btle_clkn_high = clkn_high; 381*8f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.btle_clk100ns = htole32(pkt->clk100ns); 382*8f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.rssi_max = rssi_max; 383*8f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.rssi_min = rssi_min; 384*8f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.rssi_avg = rssi_avg; 385*8f3e7eeaSChristopher Kilgour pcap_pkt.le_ll_ppi_header.rssi_count = rssi_count; 386*8f3e7eeaSChristopher Kilgour (void) memcpy( &pcap_pkt.le_packet[0], &pkt->symbols[0], pcap_caplen ); 387*8f3e7eeaSChristopher Kilgour pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.le_ll_ppi_header); 388*8f3e7eeaSChristopher Kilgour return 0; 389*8f3e7eeaSChristopher Kilgour } 390*8f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 391*8f3e7eeaSChristopher Kilgour } 392*8f3e7eeaSChristopher Kilgour 393*8f3e7eeaSChristopher Kilgour int 394*8f3e7eeaSChristopher Kilgour lell_pcap_close(lell_pcap_handle *h) 395*8f3e7eeaSChristopher Kilgour { 396*8f3e7eeaSChristopher Kilgour if (h && h->dumper) { 397*8f3e7eeaSChristopher Kilgour pcap_dump_close(h->dumper); 398*8f3e7eeaSChristopher Kilgour } 399*8f3e7eeaSChristopher Kilgour if (h && h->pcap) { 400*8f3e7eeaSChristopher Kilgour pcap_close(h->pcap); 401*8f3e7eeaSChristopher Kilgour } 402*8f3e7eeaSChristopher Kilgour if (h) { 403*8f3e7eeaSChristopher Kilgour free(h); 404*8f3e7eeaSChristopher Kilgour return 0; 405*8f3e7eeaSChristopher Kilgour } 406*8f3e7eeaSChristopher Kilgour return -PCAP_INVALID_HANDLE; 407*8f3e7eeaSChristopher Kilgour } 408*8f3e7eeaSChristopher Kilgour 409*8f3e7eeaSChristopher Kilgour #endif /* USE_PCAP */ 410