1e25b118aSDominic Spill /* -*- c -*- */ 2e25b118aSDominic Spill /* 3e25b118aSDominic Spill * Copyright 2007 - 2012 Mike Ryan, Dominic Spill, Michael Ossmann 4e25b118aSDominic Spill * Copyright 2005, 2006 Free Software Foundation, Inc. 5e25b118aSDominic Spill * 6e25b118aSDominic Spill * This file is part of libbtbb 7e25b118aSDominic Spill * 8e25b118aSDominic Spill * This program is free software; you can redistribute it and/or modify 9e25b118aSDominic Spill * it under the terms of the GNU General Public License as published by 10e25b118aSDominic Spill * the Free Software Foundation; either version 2, or (at your option) 11e25b118aSDominic Spill * any later version. 12e25b118aSDominic Spill * 13e25b118aSDominic Spill * This program is distributed in the hope that it will be useful, 14e25b118aSDominic Spill * but WITHOUT ANY WARRANTY; without even the implied warranty of 15e25b118aSDominic Spill * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16e25b118aSDominic Spill * GNU General Public License for more details. 17e25b118aSDominic Spill * 18e25b118aSDominic Spill * You should have received a copy of the GNU General Public License 19e25b118aSDominic Spill * along with libbtbb; see the file COPYING. If not, write to 20e25b118aSDominic Spill * the Free Software Foundation, Inc., 51 Franklin Street, 21e25b118aSDominic Spill * Boston, MA 02110-1301, USA. 22e25b118aSDominic Spill */ 23e25b118aSDominic Spill 24e25b118aSDominic Spill #ifdef HAVE_CONFIG_H 25e25b118aSDominic Spill #include "config.h" 26e25b118aSDominic Spill #endif 27e25b118aSDominic Spill 28*8f3e7eeaSChristopher Kilgour #include "btbb.h" 29e25b118aSDominic Spill #include "bluetooth_le_packet.h" 30e25b118aSDominic Spill #include <ctype.h> 31*8f3e7eeaSChristopher Kilgour #include <string.h> 32e25b118aSDominic Spill 33e25b118aSDominic Spill /* string representations of advertising packet type */ 34e25b118aSDominic Spill static const char *ADV_TYPE_NAMES[] = { 35e25b118aSDominic Spill "ADV_IND", "ADV_DIRECT_IND", "ADV_NONCONN_IND", "SCAN_REQ", 36e25b118aSDominic Spill "SCAN_RSP", "CONNECT_REQ", "ADV_SCAN_IND", 37e25b118aSDominic Spill }; 38e25b118aSDominic Spill 39e25b118aSDominic Spill /* source clock accuracy in a connect packet */ 40e25b118aSDominic Spill static const char *CONNECT_SCA[] = { 41e25b118aSDominic Spill "251 ppm to 500 ppm", "151 ppm to 250 ppm", "101 ppm to 150 ppm", 42e25b118aSDominic Spill "76 ppm to 100 ppm", "51 ppm to 75 ppm", "31 ppm to 50 ppm", 43e25b118aSDominic Spill "21 ppm to 30 ppm", "0 ppm to 20 ppm", 44e25b118aSDominic Spill }; 45e25b118aSDominic Spill 46e25b118aSDominic Spill // count of objects in an array, shamelessly stolen from Chrome 47e25b118aSDominic Spill #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 48e25b118aSDominic Spill 49*8f3e7eeaSChristopher Kilgour static int aa_access_channel_off_by_one(const uint32_t aa) { 50*8f3e7eeaSChristopher Kilgour int retval = 0; 51*8f3e7eeaSChristopher Kilgour switch(aa) { 52*8f3e7eeaSChristopher Kilgour /* single zero->one flips */ 53*8f3e7eeaSChristopher Kilgour case 0x8e89bed7: 54*8f3e7eeaSChristopher Kilgour case 0x8e89bede: 55*8f3e7eeaSChristopher Kilgour case 0x8e89bef6: 56*8f3e7eeaSChristopher Kilgour case 0x8e89bfd6: 57*8f3e7eeaSChristopher Kilgour case 0x8e89fed6: 58*8f3e7eeaSChristopher Kilgour case 0x8e8bbed6: 59*8f3e7eeaSChristopher Kilgour case 0x8e8dbed6: 60*8f3e7eeaSChristopher Kilgour case 0x8e99bed6: 61*8f3e7eeaSChristopher Kilgour case 0x8ea9bed6: 62*8f3e7eeaSChristopher Kilgour case 0x8ec9bed6: 63*8f3e7eeaSChristopher Kilgour case 0x8f89bed6: 64*8f3e7eeaSChristopher Kilgour case 0x9e89bed6: 65*8f3e7eeaSChristopher Kilgour case 0xae89bed6: 66*8f3e7eeaSChristopher Kilgour case 0xce89bed6: 67*8f3e7eeaSChristopher Kilgour /* single one->zero flips */ 68*8f3e7eeaSChristopher Kilgour case 0x8e89bed4: 69*8f3e7eeaSChristopher Kilgour case 0x8e89bed2: 70*8f3e7eeaSChristopher Kilgour case 0x8e89bec6: 71*8f3e7eeaSChristopher Kilgour case 0x8e89be96: 72*8f3e7eeaSChristopher Kilgour case 0x8e89be56: 73*8f3e7eeaSChristopher Kilgour case 0x8e89bcd6: 74*8f3e7eeaSChristopher Kilgour case 0x8e89bad6: 75*8f3e7eeaSChristopher Kilgour case 0x8e89b6d6: 76*8f3e7eeaSChristopher Kilgour case 0x8e89aed6: 77*8f3e7eeaSChristopher Kilgour case 0x8e899ed6: 78*8f3e7eeaSChristopher Kilgour case 0x8e893ed6: 79*8f3e7eeaSChristopher Kilgour case 0x8e88bed6: 80*8f3e7eeaSChristopher Kilgour case 0x8e81bed6: 81*8f3e7eeaSChristopher Kilgour case 0x8e09bed6: 82*8f3e7eeaSChristopher Kilgour case 0x8c89bed6: 83*8f3e7eeaSChristopher Kilgour case 0x8a89bed6: 84*8f3e7eeaSChristopher Kilgour case 0x8689bed6: 85*8f3e7eeaSChristopher Kilgour case 0x0e89bed6: 86*8f3e7eeaSChristopher Kilgour retval = 1; 87*8f3e7eeaSChristopher Kilgour break; 88*8f3e7eeaSChristopher Kilgour } 89*8f3e7eeaSChristopher Kilgour return retval; 90*8f3e7eeaSChristopher Kilgour } 91e25b118aSDominic Spill 92*8f3e7eeaSChristopher Kilgour /* 93*8f3e7eeaSChristopher Kilgour * A helper function for filtering bogus packets on data channels. 94*8f3e7eeaSChristopher Kilgour * 95*8f3e7eeaSChristopher Kilgour * If a candidate capture packet is random noise we would expect its 96*8f3e7eeaSChristopher Kilgour * Access Address to be a randomly distributed 32-bit number. An 97*8f3e7eeaSChristopher Kilgour * exhaustive software analysis reveals that of 4294967296 possible 98*8f3e7eeaSChristopher Kilgour * 32-bit Access Address values, 2900629660 (67.5%) are acceptable and 99*8f3e7eeaSChristopher Kilgour * 1394337636 (32.5%) are invalid. This function will identify which 100*8f3e7eeaSChristopher Kilgour * category a candidate Access Address falls into by returning the 101*8f3e7eeaSChristopher Kilgour * number of offenses contained. 102*8f3e7eeaSChristopher Kilgour * 103*8f3e7eeaSChristopher Kilgour * Refer to BT 4.x, Vol 6, Par B, Section 2.1.2. 104*8f3e7eeaSChristopher Kilgour * 105*8f3e7eeaSChristopher Kilgour * The Access Address in data channel packets meet the 106*8f3e7eeaSChristopher Kilgour * following requirements: 107*8f3e7eeaSChristopher Kilgour * - It shall have no more than six consecutive zeros or ones. 108*8f3e7eeaSChristopher Kilgour * - It shall not be the advertising channel packets’ Access Address. 109*8f3e7eeaSChristopher Kilgour * - It shall not be a sequence that differs from the advertising channel packets’ 110*8f3e7eeaSChristopher Kilgour * Access Address by only one bit. 111*8f3e7eeaSChristopher Kilgour * - It shall not have all four octets equal. 112*8f3e7eeaSChristopher Kilgour * - It shall have no more than 24 transitions. 113*8f3e7eeaSChristopher Kilgour * - It shall have a minimum of two transitions in the most significant six bits. 114*8f3e7eeaSChristopher Kilgour */ 115*8f3e7eeaSChristopher Kilgour static int aa_data_channel_offenses(const uint32_t aa) { 116*8f3e7eeaSChristopher Kilgour int retval = 0, transitions = 0; 117*8f3e7eeaSChristopher Kilgour unsigned shift, odd = (unsigned) (aa & 1); 118*8f3e7eeaSChristopher Kilgour uint8_t aab3, aab2, aab1, aab0 = (uint8_t) (aa & 0xff); 119e25b118aSDominic Spill 120*8f3e7eeaSChristopher Kilgour const uint8_t EIGHT_BIT_TRANSITIONS_EVEN[256] = { 121*8f3e7eeaSChristopher Kilgour 0, 2, 2, 2, 2, 4, 2, 2, 2, 4, 4, 4, 2, 4, 2, 2, 122*8f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2, 123*8f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4, 124*8f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2, 125*8f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4, 126*8f3e7eeaSChristopher Kilgour 4, 6, 6, 6, 6, 8, 6, 6, 4, 6, 6, 6, 4, 6, 4, 4, 127*8f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4, 128*8f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2, 129*8f3e7eeaSChristopher Kilgour 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3, 130*8f3e7eeaSChristopher Kilgour 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3, 131*8f3e7eeaSChristopher Kilgour 3, 5, 5, 5, 5, 7, 5, 5, 5, 7, 7, 7, 5, 7, 5, 5, 132*8f3e7eeaSChristopher Kilgour 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3, 133*8f3e7eeaSChristopher Kilgour 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3, 134*8f3e7eeaSChristopher Kilgour 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3, 135*8f3e7eeaSChristopher Kilgour 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3, 136*8f3e7eeaSChristopher Kilgour 1, 3, 3, 3, 3, 5, 3, 3, 1, 3, 3, 3, 1, 3, 1, 1 137*8f3e7eeaSChristopher Kilgour }; 138e25b118aSDominic Spill 139*8f3e7eeaSChristopher Kilgour const uint8_t EIGHT_BIT_TRANSITIONS_ODD[256] = { 140*8f3e7eeaSChristopher Kilgour 1, 1, 3, 1, 3, 3, 3, 1, 3, 3, 5, 3, 3, 3, 3, 1, 141*8f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1, 142*8f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3, 143*8f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1, 144*8f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3, 145*8f3e7eeaSChristopher Kilgour 5, 5, 7, 5, 7, 7, 7, 5, 5, 5, 7, 5, 5, 5, 5, 3, 146*8f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3, 147*8f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1, 148*8f3e7eeaSChristopher Kilgour 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2, 149*8f3e7eeaSChristopher Kilgour 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2, 150*8f3e7eeaSChristopher Kilgour 4, 4, 6, 4, 6, 6, 6, 4, 6, 6, 8, 6, 6, 6, 6, 4, 151*8f3e7eeaSChristopher Kilgour 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2, 152*8f3e7eeaSChristopher Kilgour 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2, 153*8f3e7eeaSChristopher Kilgour 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2, 154*8f3e7eeaSChristopher Kilgour 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2, 155*8f3e7eeaSChristopher Kilgour 2, 2, 4, 2, 4, 4, 4, 2, 2, 2, 4, 2, 2, 2, 2, 0 156*8f3e7eeaSChristopher Kilgour }; 157*8f3e7eeaSChristopher Kilgour 158*8f3e7eeaSChristopher Kilgour transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab0] : EIGHT_BIT_TRANSITIONS_EVEN[aab0] ); 159*8f3e7eeaSChristopher Kilgour odd = (unsigned) (aab0 & 0x80); 160*8f3e7eeaSChristopher Kilgour aab1 = (uint8_t) (aa >> 8); 161*8f3e7eeaSChristopher Kilgour transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab1] : EIGHT_BIT_TRANSITIONS_EVEN[aab1] ); 162*8f3e7eeaSChristopher Kilgour odd = (unsigned) (aab1 & 0x80); 163*8f3e7eeaSChristopher Kilgour aab2 = (uint8_t) (aa >> 16); 164*8f3e7eeaSChristopher Kilgour transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab2] : EIGHT_BIT_TRANSITIONS_EVEN[aab2] ); 165*8f3e7eeaSChristopher Kilgour odd = (unsigned) (aab2 & 0x80); 166*8f3e7eeaSChristopher Kilgour aab3 = (uint8_t) (aa >> 24); 167*8f3e7eeaSChristopher Kilgour transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab3] : EIGHT_BIT_TRANSITIONS_EVEN[aab3] ); 168*8f3e7eeaSChristopher Kilgour 169*8f3e7eeaSChristopher Kilgour /* consider excessive transitions as offenses */ 170*8f3e7eeaSChristopher Kilgour if (transitions > 24) { 171*8f3e7eeaSChristopher Kilgour retval += (transitions - 24); 172*8f3e7eeaSChristopher Kilgour } 173*8f3e7eeaSChristopher Kilgour 174*8f3e7eeaSChristopher Kilgour const uint8_t AA_MSB6_ALLOWED[64] = { 175*8f3e7eeaSChristopher Kilgour 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 176*8f3e7eeaSChristopher Kilgour 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 177*8f3e7eeaSChristopher Kilgour 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 178*8f3e7eeaSChristopher Kilgour 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0 179*8f3e7eeaSChristopher Kilgour }; 180*8f3e7eeaSChristopher Kilgour 181*8f3e7eeaSChristopher Kilgour /* consider excessive transitions in the 6 MSBs as an offense */ 182*8f3e7eeaSChristopher Kilgour retval += (1 - AA_MSB6_ALLOWED[aab3>>2]); 183*8f3e7eeaSChristopher Kilgour 184*8f3e7eeaSChristopher Kilgour /* consider all bytes as being equal an offense */ 185*8f3e7eeaSChristopher Kilgour retval += (((aab0 == aab1) && (aab0 == aab2) && (aab0 == aab3)) ? 1 : 0); 186*8f3e7eeaSChristopher Kilgour 187*8f3e7eeaSChristopher Kilgour /* access-channel address and off-by-ones are illegal */ 188*8f3e7eeaSChristopher Kilgour retval += ((aa == 0x8e89bed6) ? 1 : 0); 189*8f3e7eeaSChristopher Kilgour retval += aa_access_channel_off_by_one(aa); 190*8f3e7eeaSChristopher Kilgour 191*8f3e7eeaSChristopher Kilgour /* inspect nibble triples for insufficient bit transitions */ 192*8f3e7eeaSChristopher Kilgour for(shift=0; shift<=20; shift+=4) { 193*8f3e7eeaSChristopher Kilgour uint16_t twelvebits = (uint16_t) ((aa >> shift) & 0xfff); 194*8f3e7eeaSChristopher Kilgour switch( twelvebits ) { 195*8f3e7eeaSChristopher Kilgour /* seven consecutive zeroes */ 196*8f3e7eeaSChristopher Kilgour case 0x080: case 0x180: case 0x280: case 0x380: case 0x480: 197*8f3e7eeaSChristopher Kilgour case 0x580: case 0x680: case 0x780: case 0x880: case 0x980: 198*8f3e7eeaSChristopher Kilgour case 0xa80: case 0xb80: case 0xc80: case 0xd80: case 0xe80: 199*8f3e7eeaSChristopher Kilgour case 0xf80: case 0x101: case 0x301: case 0x501: case 0x701: 200*8f3e7eeaSChristopher Kilgour case 0x901: case 0xb01: case 0xd01: case 0xf01: case 0x202: 201*8f3e7eeaSChristopher Kilgour case 0x602: case 0xa02: case 0xe02: case 0x203: case 0x603: 202*8f3e7eeaSChristopher Kilgour case 0xa03: case 0xe03: case 0x404: case 0xc04: case 0x405: 203*8f3e7eeaSChristopher Kilgour case 0xc05: case 0x406: case 0xc06: case 0x407: case 0xc07: 204*8f3e7eeaSChristopher Kilgour case 0x808: case 0x809: case 0x80a: case 0x80b: case 0x80c: 205*8f3e7eeaSChristopher Kilgour case 0x80d: case 0x80e: case 0x80f: case 0x010: case 0x011: 206*8f3e7eeaSChristopher Kilgour case 0x012: case 0x013: case 0x014: case 0x015: case 0x016: 207*8f3e7eeaSChristopher Kilgour case 0x017: case 0x018: case 0x019: case 0x01a: case 0x01b: 208*8f3e7eeaSChristopher Kilgour case 0x01c: case 0x01d: case 0x01e: case 0x01f: 209*8f3e7eeaSChristopher Kilgour /* eight consecutive zeroes */ 210*8f3e7eeaSChristopher Kilgour case 0x100: case 0x300: case 0x500: case 0x700: case 0x900: 211*8f3e7eeaSChristopher Kilgour case 0xb00: case 0xd00: case 0xf00: case 0x201: case 0x601: 212*8f3e7eeaSChristopher Kilgour case 0xa01: case 0xe01: case 0x402: case 0xc02: case 0x403: 213*8f3e7eeaSChristopher Kilgour case 0xc03: case 0x804: case 0x805: case 0x806: case 0x807: 214*8f3e7eeaSChristopher Kilgour case 0x008: case 0x009: case 0x00a: case 0x00b: case 0x00c: 215*8f3e7eeaSChristopher Kilgour case 0x00d: case 0x00e: case 0x00f: 216*8f3e7eeaSChristopher Kilgour /* nine consecutive zeroes */ 217*8f3e7eeaSChristopher Kilgour case 0xe00: case 0xc01: case 0x802: case 0x803: case 0x004: 218*8f3e7eeaSChristopher Kilgour case 0x005: case 0x006: case 0x007: 219*8f3e7eeaSChristopher Kilgour /* ten consecutive zeroes */ 220*8f3e7eeaSChristopher Kilgour case 0x400: case 0xc00: case 0x801: case 0x002: case 0x003: 221*8f3e7eeaSChristopher Kilgour /* eleven consecutive zeroes */ 222*8f3e7eeaSChristopher Kilgour case 0x800: case 0x001: 223*8f3e7eeaSChristopher Kilgour /* twelve consecutive zeroes */ 224*8f3e7eeaSChristopher Kilgour case 0x000: 225*8f3e7eeaSChristopher Kilgour /* seven consecutive ones */ 226*8f3e7eeaSChristopher Kilgour case 0x07f: case 0x0fe: case 0x2fe: case 0x4fe: case 0x6fe: 227*8f3e7eeaSChristopher Kilgour case 0x8fe: case 0xafe: case 0xcfe: case 0xefe: case 0x1fc: 228*8f3e7eeaSChristopher Kilgour case 0x5fc: case 0x9fc: case 0xdfc: case 0x1fd: case 0x5fd: 229*8f3e7eeaSChristopher Kilgour case 0x9fd: case 0xdfd: case 0x3f8: case 0xbf8: case 0x3f9: 230*8f3e7eeaSChristopher Kilgour case 0xbf9: case 0x3fa: case 0xbfa: case 0x3fb: case 0xbfb: 231*8f3e7eeaSChristopher Kilgour case 0x7f4: case 0x7f5: case 0x7f6: case 0x7f7: case 0xfe0: 232*8f3e7eeaSChristopher Kilgour /* eight consecutive ones */ 233*8f3e7eeaSChristopher Kilgour case 0x0ff: case 0x2ff: case 0x4ff: case 0x6ff: case 0x8ff: 234*8f3e7eeaSChristopher Kilgour case 0xaff: case 0xcff: case 0xeff: case 0x1fe: case 0x5fe: 235*8f3e7eeaSChristopher Kilgour case 0x9fe: case 0xdfe: case 0x3fc: case 0xbfc: case 0x3fd: 236*8f3e7eeaSChristopher Kilgour case 0xbfd: case 0x7f8: case 0x7f9: case 0x7fa: case 0x7fb: 237*8f3e7eeaSChristopher Kilgour case 0xff0: case 0xff1: case 0xff2: case 0xff3: case 0xff4: 238*8f3e7eeaSChristopher Kilgour case 0xff5: case 0xff6: case 0xff7: 239*8f3e7eeaSChristopher Kilgour /* nine consecutive ones */ 240*8f3e7eeaSChristopher Kilgour case 0x1ff: case 0x5ff: case 0x9ff: case 0xdff: case 0x3fe: 241*8f3e7eeaSChristopher Kilgour case 0xbfe: case 0x7fc: case 0x7fd: case 0xff8: case 0xff9: 242*8f3e7eeaSChristopher Kilgour case 0xffa: case 0xffb: 243*8f3e7eeaSChristopher Kilgour /* ten consecutive ones */ 244*8f3e7eeaSChristopher Kilgour case 0x3ff: case 0xbff: case 0x7fe: case 0xffc: case 0xffd: 245*8f3e7eeaSChristopher Kilgour /* eleven consecutive ones */ 246*8f3e7eeaSChristopher Kilgour case 0x7ff: case 0xffe: 247*8f3e7eeaSChristopher Kilgour /* all ones */ 248*8f3e7eeaSChristopher Kilgour case 0xfff: 249*8f3e7eeaSChristopher Kilgour retval++; 250*8f3e7eeaSChristopher Kilgour break; 251*8f3e7eeaSChristopher Kilgour default: 252*8f3e7eeaSChristopher Kilgour break; 253e25b118aSDominic Spill } 254e25b118aSDominic Spill } 255e25b118aSDominic Spill 256*8f3e7eeaSChristopher Kilgour return retval; 257e25b118aSDominic Spill } 258e25b118aSDominic Spill 259*8f3e7eeaSChristopher Kilgour lell_packet * 260*8f3e7eeaSChristopher Kilgour lell_packet_new(void) 261*8f3e7eeaSChristopher Kilgour { 262*8f3e7eeaSChristopher Kilgour lell_packet *pkt = (lell_packet *)calloc(1, sizeof(lell_packet)); 263*8f3e7eeaSChristopher Kilgour pkt->refcount = 1; 264*8f3e7eeaSChristopher Kilgour return pkt; 265*8f3e7eeaSChristopher Kilgour } 266*8f3e7eeaSChristopher Kilgour 267*8f3e7eeaSChristopher Kilgour void 268*8f3e7eeaSChristopher Kilgour lell_packet_ref(lell_packet *pkt) 269*8f3e7eeaSChristopher Kilgour { 270*8f3e7eeaSChristopher Kilgour pkt->refcount++; 271*8f3e7eeaSChristopher Kilgour } 272*8f3e7eeaSChristopher Kilgour 273*8f3e7eeaSChristopher Kilgour void 274*8f3e7eeaSChristopher Kilgour lell_packet_unref(lell_packet *pkt) 275*8f3e7eeaSChristopher Kilgour { 276*8f3e7eeaSChristopher Kilgour pkt->refcount--; 277*8f3e7eeaSChristopher Kilgour if (pkt->refcount == 0) 278*8f3e7eeaSChristopher Kilgour free(pkt); 279*8f3e7eeaSChristopher Kilgour } 280*8f3e7eeaSChristopher Kilgour 281*8f3e7eeaSChristopher Kilgour static uint8_t le_channel_index(uint16_t phys_channel) { 282e25b118aSDominic Spill uint8_t ret; 283e25b118aSDominic Spill if (phys_channel == 2402) { 284e25b118aSDominic Spill ret = 37; 285e25b118aSDominic Spill } else if (phys_channel < 2426) { // 0 - 10 286e25b118aSDominic Spill ret = (phys_channel - 2404) / 2; 287e25b118aSDominic Spill } else if (phys_channel == 2426) { 288e25b118aSDominic Spill ret = 38; 289e25b118aSDominic Spill } else if (phys_channel < 2480) { // 11 - 36 290e25b118aSDominic Spill ret = 11 + (phys_channel - 2428) / 2; 291e25b118aSDominic Spill } else { 292e25b118aSDominic Spill ret = 39; 293e25b118aSDominic Spill } 294e25b118aSDominic Spill return ret; 295e25b118aSDominic Spill } 296e25b118aSDominic Spill 297*8f3e7eeaSChristopher Kilgour void lell_allocate_and_decode(const uint8_t *stream, uint16_t phys_channel, uint32_t clk100ns, lell_packet **pkt) 298*8f3e7eeaSChristopher Kilgour { 299*8f3e7eeaSChristopher Kilgour *pkt = lell_packet_new( ); 300*8f3e7eeaSChristopher Kilgour memcpy((*pkt)->symbols, stream, MAX_LE_SYMBOLS); 301*8f3e7eeaSChristopher Kilgour 302*8f3e7eeaSChristopher Kilgour (*pkt)->channel_idx = le_channel_index(phys_channel); 303*8f3e7eeaSChristopher Kilgour (*pkt)->channel_k = (phys_channel-2402)/2; 304*8f3e7eeaSChristopher Kilgour (*pkt)->clk100ns = clk100ns; 305*8f3e7eeaSChristopher Kilgour 306*8f3e7eeaSChristopher Kilgour (*pkt)->access_address = 0; 307*8f3e7eeaSChristopher Kilgour (*pkt)->access_address |= (*pkt)->symbols[0]; 308*8f3e7eeaSChristopher Kilgour (*pkt)->access_address |= (*pkt)->symbols[1] << 8; 309*8f3e7eeaSChristopher Kilgour (*pkt)->access_address |= (*pkt)->symbols[2] << 16; 310*8f3e7eeaSChristopher Kilgour (*pkt)->access_address |= (*pkt)->symbols[3] << 24; 311*8f3e7eeaSChristopher Kilgour 312*8f3e7eeaSChristopher Kilgour if (lell_packet_is_data(*pkt)) { 313*8f3e7eeaSChristopher Kilgour // data PDU 314*8f3e7eeaSChristopher Kilgour (*pkt)->length = (*pkt)->symbols[5] & 0x1f; 315*8f3e7eeaSChristopher Kilgour (*pkt)->access_address_offenses = aa_data_channel_offenses((*pkt)->access_address); 316*8f3e7eeaSChristopher Kilgour (*pkt)->flags.as_bits.access_address_ok = (*pkt)->access_address_offenses ? 0 : 1; 317*8f3e7eeaSChristopher Kilgour } else { 318*8f3e7eeaSChristopher Kilgour // advertising PDU 319*8f3e7eeaSChristopher Kilgour (*pkt)->length = (*pkt)->symbols[5] & 0x3f; 320*8f3e7eeaSChristopher Kilgour (*pkt)->adv_type = (*pkt)->symbols[4] & 0xf; 321*8f3e7eeaSChristopher Kilgour (*pkt)->adv_tx_add = (*pkt)->symbols[4] & 0x40 ? 1 : 0; 322*8f3e7eeaSChristopher Kilgour (*pkt)->adv_rx_add = (*pkt)->symbols[4] & 0x80 ? 1 : 0; 323*8f3e7eeaSChristopher Kilgour (*pkt)->flags.as_bits.access_address_ok = ((*pkt)->access_address == 0x8e89bed6); 324*8f3e7eeaSChristopher Kilgour (*pkt)->access_address_offenses = (*pkt)->flags.as_bits.access_address_ok ? 0 : 325*8f3e7eeaSChristopher Kilgour (aa_access_channel_off_by_one((*pkt)->access_address) ? 1 : 32); 326*8f3e7eeaSChristopher Kilgour } 327*8f3e7eeaSChristopher Kilgour } 328*8f3e7eeaSChristopher Kilgour 329*8f3e7eeaSChristopher Kilgour unsigned lell_packet_is_data(const lell_packet *pkt) 330*8f3e7eeaSChristopher Kilgour { 331*8f3e7eeaSChristopher Kilgour return (unsigned) (pkt->channel_idx < 37); 332*8f3e7eeaSChristopher Kilgour } 333*8f3e7eeaSChristopher Kilgour 334*8f3e7eeaSChristopher Kilgour uint32_t lell_get_access_address(const lell_packet *pkt) 335*8f3e7eeaSChristopher Kilgour { 336*8f3e7eeaSChristopher Kilgour return pkt->access_address; 337*8f3e7eeaSChristopher Kilgour } 338*8f3e7eeaSChristopher Kilgour 339*8f3e7eeaSChristopher Kilgour unsigned lell_get_access_address_offenses(const lell_packet *pkt) 340*8f3e7eeaSChristopher Kilgour { 341*8f3e7eeaSChristopher Kilgour return pkt->access_address_offenses; 342*8f3e7eeaSChristopher Kilgour } 343*8f3e7eeaSChristopher Kilgour 344*8f3e7eeaSChristopher Kilgour unsigned lell_get_channel_index(const lell_packet *pkt) 345*8f3e7eeaSChristopher Kilgour { 346*8f3e7eeaSChristopher Kilgour return pkt->channel_idx; 347*8f3e7eeaSChristopher Kilgour } 348*8f3e7eeaSChristopher Kilgour 349*8f3e7eeaSChristopher Kilgour unsigned lell_get_channel_k(const lell_packet *pkt) 350*8f3e7eeaSChristopher Kilgour { 351*8f3e7eeaSChristopher Kilgour return pkt->channel_k; 352*8f3e7eeaSChristopher Kilgour } 353*8f3e7eeaSChristopher Kilgour 354*8f3e7eeaSChristopher Kilgour const char * lell_get_adv_type_str(const lell_packet *pkt) 355*8f3e7eeaSChristopher Kilgour { 356*8f3e7eeaSChristopher Kilgour if (lell_packet_is_data(pkt)) 357e25b118aSDominic Spill return NULL; 358*8f3e7eeaSChristopher Kilgour if (pkt->adv_type < COUNT_OF(ADV_TYPE_NAMES)) 359*8f3e7eeaSChristopher Kilgour return ADV_TYPE_NAMES[pkt->adv_type]; 360e25b118aSDominic Spill return "UNKNOWN"; 361e25b118aSDominic Spill } 362e25b118aSDominic Spill 363*8f3e7eeaSChristopher Kilgour static void _dump_addr(const char *name, const uint8_t *buf, int offset, int random) { 364e25b118aSDominic Spill int i; 365e25b118aSDominic Spill printf(" %s%02x", name, buf[offset+5]); 366e25b118aSDominic Spill for (i = 4; i >= 0; --i) 367e25b118aSDominic Spill printf(":%02x", buf[offset+i]); 368e25b118aSDominic Spill printf(" (%s)\n", random ? "random" : "public"); 369e25b118aSDominic Spill } 370e25b118aSDominic Spill 371*8f3e7eeaSChristopher Kilgour static void _dump_8(const char *name, const uint8_t *buf, int offset) { 372e25b118aSDominic Spill printf(" %s%02x (%d)\n", name, buf[offset], buf[offset]); 373e25b118aSDominic Spill } 374e25b118aSDominic Spill 375*8f3e7eeaSChristopher Kilgour static void _dump_16(const char *name, const uint8_t *buf, int offset) { 376e25b118aSDominic Spill uint16_t val = buf[offset+1] << 8 | buf[offset]; 377e25b118aSDominic Spill printf(" %s%04x (%d)\n", name, val, val); 378e25b118aSDominic Spill } 379e25b118aSDominic Spill 380*8f3e7eeaSChristopher Kilgour static void _dump_24(const char *name, const uint8_t *buf, int offset) { 381e25b118aSDominic Spill uint16_t val = buf[offset+2] << 16 | buf[offset+1] << 8 | buf[offset]; 382e25b118aSDominic Spill printf(" %s%06x\n", name, val); 383e25b118aSDominic Spill } 384e25b118aSDominic Spill 385*8f3e7eeaSChristopher Kilgour static void _dump_32(const char *name, const uint8_t *buf, int offset) { 386e25b118aSDominic Spill uint32_t val = buf[offset+3] << 24 | 387e25b118aSDominic Spill buf[offset+2] << 16 | 388e25b118aSDominic Spill buf[offset+1] << 8 | 389e25b118aSDominic Spill buf[offset+0]; 390e25b118aSDominic Spill printf(" %s%08x\n", name, val); 391e25b118aSDominic Spill } 392e25b118aSDominic Spill 393*8f3e7eeaSChristopher Kilgour static void _dump_uuid(const uint8_t *uuid) { 394e25b118aSDominic Spill int i; 395e25b118aSDominic Spill for (i = 0; i < 4; ++i) 396e25b118aSDominic Spill printf("%02x", uuid[i]); 397e25b118aSDominic Spill printf("-"); 398e25b118aSDominic Spill for (i = 4; i < 6; ++i) 399e25b118aSDominic Spill printf("%02x", uuid[i]); 400e25b118aSDominic Spill printf("-"); 401e25b118aSDominic Spill for (i = 6; i < 8; ++i) 402e25b118aSDominic Spill printf("%02x", uuid[i]); 403e25b118aSDominic Spill printf("-"); 404e25b118aSDominic Spill for (i = 8; i < 10; ++i) 405e25b118aSDominic Spill printf("%02x", uuid[i]); 406e25b118aSDominic Spill printf("-"); 407e25b118aSDominic Spill for (i = 10; i < 16; ++i) 408e25b118aSDominic Spill printf("%02x", uuid[i]); 409e25b118aSDominic Spill } 410e25b118aSDominic Spill 411e25b118aSDominic Spill // Refer to pg 1735 of Bluetooth Core Spec 4.0 412*8f3e7eeaSChristopher Kilgour static void _dump_scan_rsp_data(const uint8_t *buf, int len) { 413e25b118aSDominic Spill int pos = 0; 414e25b118aSDominic Spill int sublen, i; 415e25b118aSDominic Spill uint8_t type; 416e25b118aSDominic Spill uint16_t val; 417e25b118aSDominic Spill char *cval; 418e25b118aSDominic Spill 419e25b118aSDominic Spill while (pos < len) { 420e25b118aSDominic Spill sublen = buf[pos]; 421e25b118aSDominic Spill ++pos; 422e25b118aSDominic Spill if (pos + sublen > len) { 423e25b118aSDominic Spill printf("Error: attempt to read past end of buffer (%d + %d > %d)\n", pos, sublen, len); 424e25b118aSDominic Spill return; 425e25b118aSDominic Spill } 426e25b118aSDominic Spill if (sublen == 0) { 427e25b118aSDominic Spill printf("Early return due to 0 length\n"); 428e25b118aSDominic Spill return; 429e25b118aSDominic Spill } 430e25b118aSDominic Spill type = buf[pos]; 431e25b118aSDominic Spill printf(" Type %02x", type); 432e25b118aSDominic Spill switch (type) { 433e25b118aSDominic Spill case 0x01: 434e25b118aSDominic Spill printf(" (Flags)\n"); 435e25b118aSDominic Spill printf(" "); 436e25b118aSDominic Spill for (i = 0; i < 8; ++i) 437e25b118aSDominic Spill printf("%d", buf[pos+1] & (1 << (7-i)) ? 1 : 0); 438e25b118aSDominic Spill printf("\n"); 439e25b118aSDominic Spill break; 44045000095SMike Ryan case 0x06: 44145000095SMike Ryan printf(" (128-bit Service UUIDs, more available)\n"); 44245000095SMike Ryan goto print128; 443e25b118aSDominic Spill case 0x07: 444e25b118aSDominic Spill printf(" (128-bit Service UUIDs)\n"); 44545000095SMike Ryan print128: 446e25b118aSDominic Spill if ((sublen - 1) % 16 == 0) { 447e25b118aSDominic Spill uint8_t uuid[16]; 448e25b118aSDominic Spill for (i = 0; i < sublen - 1; ++i) { 449e25b118aSDominic Spill uuid[15 - (i % 16)] = buf[pos+1+i]; 450e25b118aSDominic Spill if ((i & 15) == 15) { 451e25b118aSDominic Spill printf(" "); 452e25b118aSDominic Spill _dump_uuid(uuid); 453e25b118aSDominic Spill printf("\n"); 454e25b118aSDominic Spill } 455e25b118aSDominic Spill } 456e25b118aSDominic Spill } 457e25b118aSDominic Spill else { 458e25b118aSDominic Spill printf("Wrong length (%d, must be divisible by 16)\n", sublen-1); 459e25b118aSDominic Spill } 460e25b118aSDominic Spill break; 461e25b118aSDominic Spill case 0x09: 462e25b118aSDominic Spill printf(" (Complete Local Name)\n"); 463e25b118aSDominic Spill printf(" "); 464e25b118aSDominic Spill for (i = 1; i < sublen; ++i) 465e25b118aSDominic Spill printf("%c", isprint(buf[pos+i]) ? buf[pos+i] : '.'); 466e25b118aSDominic Spill printf("\n"); 467e25b118aSDominic Spill break; 468e25b118aSDominic Spill case 0x0a: 469e25b118aSDominic Spill printf(" (Tx Power Level)\n"); 470e25b118aSDominic Spill printf(" "); 471e25b118aSDominic Spill if (sublen-1 == 1) { 472e25b118aSDominic Spill cval = (char *)&buf[pos+1]; 473e25b118aSDominic Spill printf("%d dBm\n", *cval); 474e25b118aSDominic Spill } else { 475e25b118aSDominic Spill printf("Wrong length (%d, should be 1)\n", sublen-1); 476e25b118aSDominic Spill } 477e25b118aSDominic Spill break; 478e25b118aSDominic Spill case 0x12: 479e25b118aSDominic Spill printf(" (Slave Connection Interval Range)\n"); 480e25b118aSDominic Spill printf(" "); 481e25b118aSDominic Spill if (sublen-1 == 4) { 482e25b118aSDominic Spill val = (buf[pos+2] << 8) | buf[pos+1]; 483e25b118aSDominic Spill printf("(%0.2f, ", val * 1.25); 484e25b118aSDominic Spill val = (buf[pos+4] << 8) | buf[pos+3]; 485e25b118aSDominic Spill printf("%0.2f) ms\n", val * 1.25); 486e25b118aSDominic Spill } 487e25b118aSDominic Spill else { 488e25b118aSDominic Spill printf("Wrong length (%d, should be 4)\n", sublen-1); 489e25b118aSDominic Spill } 490e25b118aSDominic Spill break; 491e25b118aSDominic Spill case 0x16: 492e25b118aSDominic Spill printf(" (Service Data)\n"); 493e25b118aSDominic Spill printf(" "); 494e25b118aSDominic Spill if (sublen-1 >= 2) { 495e25b118aSDominic Spill val = (buf[pos+2] << 8) | buf[pos+1]; 496e25b118aSDominic Spill printf("UUID: %02x", val); 497e25b118aSDominic Spill if (sublen-1 > 2) { 498e25b118aSDominic Spill printf(", Additional:"); 499e25b118aSDominic Spill for (i = 3; i < sublen; ++i) 500e25b118aSDominic Spill printf(" %02x", buf[pos+i]); 501e25b118aSDominic Spill } 502e25b118aSDominic Spill printf("\n"); 503e25b118aSDominic Spill } 504e25b118aSDominic Spill else { 505e25b118aSDominic Spill printf("Wrong length (%d, should be >= 2)\n", sublen-1); 506e25b118aSDominic Spill } 507e25b118aSDominic Spill break; 508e25b118aSDominic Spill default: 509e25b118aSDominic Spill printf("\n"); 510e25b118aSDominic Spill printf(" "); 511e25b118aSDominic Spill for (i = 1; i < sublen; ++i) 512e25b118aSDominic Spill printf(" %02x", buf[pos+i]); 513e25b118aSDominic Spill printf("\n"); 514e25b118aSDominic Spill } 515e25b118aSDominic Spill pos += sublen; 516e25b118aSDominic Spill } 517e25b118aSDominic Spill } 518e25b118aSDominic Spill 519*8f3e7eeaSChristopher Kilgour void lell_print(const lell_packet *pkt) 520*8f3e7eeaSChristopher Kilgour { 521387b6603SIvan Krasin int i, opcode; 522*8f3e7eeaSChristopher Kilgour if (lell_packet_is_data(pkt)) { 523*8f3e7eeaSChristopher Kilgour int llid = pkt->symbols[4] & 0x3; 524e25b118aSDominic Spill static const char *llid_str[] = { 525e25b118aSDominic Spill "Reserved", 526e25b118aSDominic Spill "LL Data PDU / empty or L2CAP continuation", 527e25b118aSDominic Spill "LL Data PDU / L2CAP start", 528e25b118aSDominic Spill "LL Control PDU", 529e25b118aSDominic Spill }; 530e25b118aSDominic Spill 531*8f3e7eeaSChristopher Kilgour printf("Data / AA %08x (%s) / %2d bytes\n", pkt->access_address, 532*8f3e7eeaSChristopher Kilgour pkt->flags.as_bits.access_address_ok ? "valid" : "invalid", 533*8f3e7eeaSChristopher Kilgour pkt->length); 534*8f3e7eeaSChristopher Kilgour printf(" Channel Index: %d\n", pkt->channel_idx); 535e25b118aSDominic Spill printf(" LLID: %d / %s\n", llid, llid_str[llid]); 536*8f3e7eeaSChristopher Kilgour printf(" NESN: %d SN: %d MD: %d\n", (pkt->symbols[4] >> 2) & 1, 537*8f3e7eeaSChristopher Kilgour (pkt->symbols[4] >> 3) & 1, 538*8f3e7eeaSChristopher Kilgour (pkt->symbols[4] >> 4) & 1); 539387b6603SIvan Krasin switch (llid) { 540387b6603SIvan Krasin case 3: // LL Control PDU 541*8f3e7eeaSChristopher Kilgour opcode = pkt->symbols[6]; 542387b6603SIvan Krasin static const char *opcode_str[] = { 543387b6603SIvan Krasin "LL_CONNECTION_UPDATE_REQ", 544387b6603SIvan Krasin "LL_CHANNEL_MAP_REQ", 545387b6603SIvan Krasin "LL_TERMINATE_IND", 546387b6603SIvan Krasin "LL_ENC_REQ", 547387b6603SIvan Krasin "LL_ENC_RSP", 548387b6603SIvan Krasin "LL_START_ENC_REQ", 549387b6603SIvan Krasin "LL_START_ENC_RSP", 550387b6603SIvan Krasin "LL_UNKNOWN_RSP", 551387b6603SIvan Krasin "LL_FEATURE_REQ", 552387b6603SIvan Krasin "LL_FEATURE_RSP", 553387b6603SIvan Krasin "LL_PAUSE_ENC_REQ", 554387b6603SIvan Krasin "LL_PAUSE_ENC_RSP", 555387b6603SIvan Krasin "LL_VERSION_IND", 556387b6603SIvan Krasin "LL_REJECT_IND", 557b3394904SMike Ryan "LL_SLAVE_FEATURE_REQ", 558b3394904SMike Ryan "LL_CONNECTION_PARAM_REQ", 559b3394904SMike Ryan "LL_CONNECTION_PARAM_RSP", 560b3394904SMike Ryan "LL_REJECT_IND_EXT", 561b3394904SMike Ryan "LL_PING_REQ", 562b3394904SMike Ryan "LL_PING_RSP", 563387b6603SIvan Krasin "Reserved for Future Use", 564387b6603SIvan Krasin }; 565ba100f3dSMike Ryan printf(" Opcode: %d / %s\n", opcode, opcode_str[(opcode<0x14)?opcode:0x14]); 566387b6603SIvan Krasin break; 567387b6603SIvan Krasin default: 568387b6603SIvan Krasin break; 569387b6603SIvan Krasin } 570e25b118aSDominic Spill } else { 571*8f3e7eeaSChristopher Kilgour printf("Advertising / AA %08x (%s)/ %2d bytes\n", pkt->access_address, 572*8f3e7eeaSChristopher Kilgour pkt->flags.as_bits.access_address_ok ? "valid" : "invalid", 573*8f3e7eeaSChristopher Kilgour pkt->length); 574*8f3e7eeaSChristopher Kilgour printf(" Channel Index: %d\n", pkt->channel_idx); 575*8f3e7eeaSChristopher Kilgour printf(" Type: %s\n", lell_get_adv_type_str(pkt)); 576e25b118aSDominic Spill 577*8f3e7eeaSChristopher Kilgour switch(pkt->adv_type) { 578e25b118aSDominic Spill case ADV_IND: 579*8f3e7eeaSChristopher Kilgour _dump_addr("AdvA: ", pkt->symbols, 6, pkt->adv_tx_add); 580*8f3e7eeaSChristopher Kilgour if (pkt->length-6 > 0) { 581e25b118aSDominic Spill printf(" AdvData:"); 582*8f3e7eeaSChristopher Kilgour for (i = 0; i < pkt->length - 6; ++i) 583*8f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[12+i]); 584e25b118aSDominic Spill printf("\n"); 585*8f3e7eeaSChristopher Kilgour _dump_scan_rsp_data(&pkt->symbols[12], pkt->length-6); 586e25b118aSDominic Spill } 587e25b118aSDominic Spill break; 588e25b118aSDominic Spill case SCAN_REQ: 589*8f3e7eeaSChristopher Kilgour _dump_addr("ScanA: ", pkt->symbols, 6, pkt->adv_tx_add); 590*8f3e7eeaSChristopher Kilgour _dump_addr("AdvA: ", pkt->symbols, 12, pkt->adv_rx_add); 591e25b118aSDominic Spill break; 592e25b118aSDominic Spill case SCAN_RSP: 593*8f3e7eeaSChristopher Kilgour _dump_addr("AdvA: ", pkt->symbols, 6, pkt->adv_tx_add); 594e25b118aSDominic Spill printf(" ScanRspData:"); 595*8f3e7eeaSChristopher Kilgour for (i = 0; i < pkt->length - 6; ++i) 596*8f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[12+i]); 597e25b118aSDominic Spill printf("\n"); 598*8f3e7eeaSChristopher Kilgour _dump_scan_rsp_data(&pkt->symbols[12], pkt->length-6); 599e25b118aSDominic Spill break; 600e25b118aSDominic Spill case CONNECT_REQ: 601*8f3e7eeaSChristopher Kilgour _dump_addr("InitA: ", pkt->symbols, 6, pkt->adv_tx_add); 602*8f3e7eeaSChristopher Kilgour _dump_addr("AdvA: ", pkt->symbols, 12, pkt->adv_rx_add); 603*8f3e7eeaSChristopher Kilgour _dump_32("AA: ", pkt->symbols, 18); 604*8f3e7eeaSChristopher Kilgour _dump_24("CRCInit: ", pkt->symbols, 22); 605*8f3e7eeaSChristopher Kilgour _dump_8("WinSize: ", pkt->symbols, 25); 606*8f3e7eeaSChristopher Kilgour _dump_16("WinOffset: ", pkt->symbols, 26); 607*8f3e7eeaSChristopher Kilgour _dump_16("Interval: ", pkt->symbols, 28); 608*8f3e7eeaSChristopher Kilgour _dump_16("Latency: ", pkt->symbols, 30); 609*8f3e7eeaSChristopher Kilgour _dump_16("Timeout: ", pkt->symbols, 32); 610e25b118aSDominic Spill 611e25b118aSDominic Spill printf(" ChM:"); 612e25b118aSDominic Spill for (i = 0; i < 5; ++i) 613*8f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[34+i]); 614e25b118aSDominic Spill printf("\n"); 615e25b118aSDominic Spill 616*8f3e7eeaSChristopher Kilgour printf(" Hop: %d\n", pkt->symbols[39] & 0x1f); 617e25b118aSDominic Spill printf(" SCA: %d, %s\n", 618*8f3e7eeaSChristopher Kilgour pkt->symbols[39] >> 5, 619*8f3e7eeaSChristopher Kilgour CONNECT_SCA[pkt->symbols[39] >> 5]); 620e25b118aSDominic Spill break; 621e25b118aSDominic Spill } 622e25b118aSDominic Spill } 623e25b118aSDominic Spill 624e25b118aSDominic Spill printf("\n"); 625e25b118aSDominic Spill printf(" Data: "); 626*8f3e7eeaSChristopher Kilgour for (i = 6; i < 6 + pkt->length; ++i) 627*8f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[i]); 628e25b118aSDominic Spill printf("\n"); 629e25b118aSDominic Spill 630e25b118aSDominic Spill printf(" CRC: "); 631e25b118aSDominic Spill for (i = 0; i < 3; ++i) 632*8f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[6 + pkt->length + i]); 633e25b118aSDominic Spill printf("\n"); 634e25b118aSDominic Spill } 635