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