1*e25b118aSDominic Spill /* -*- c -*- */ 2*e25b118aSDominic Spill /* 3*e25b118aSDominic Spill * Copyright 2007 - 2012 Mike Ryan, Dominic Spill, Michael Ossmann 4*e25b118aSDominic Spill * Copyright 2005, 2006 Free Software Foundation, Inc. 5*e25b118aSDominic Spill * 6*e25b118aSDominic Spill * This file is part of libbtbb 7*e25b118aSDominic Spill * 8*e25b118aSDominic Spill * This program is free software; you can redistribute it and/or modify 9*e25b118aSDominic Spill * it under the terms of the GNU General Public License as published by 10*e25b118aSDominic Spill * the Free Software Foundation; either version 2, or (at your option) 11*e25b118aSDominic Spill * any later version. 12*e25b118aSDominic Spill * 13*e25b118aSDominic Spill * This program is distributed in the hope that it will be useful, 14*e25b118aSDominic Spill * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*e25b118aSDominic Spill * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*e25b118aSDominic Spill * GNU General Public License for more details. 17*e25b118aSDominic Spill * 18*e25b118aSDominic Spill * You should have received a copy of the GNU General Public License 19*e25b118aSDominic Spill * along with libbtbb; see the file COPYING. If not, write to 20*e25b118aSDominic Spill * the Free Software Foundation, Inc., 51 Franklin Street, 21*e25b118aSDominic Spill * Boston, MA 02110-1301, USA. 22*e25b118aSDominic Spill */ 23*e25b118aSDominic Spill 24*e25b118aSDominic Spill #ifdef HAVE_CONFIG_H 25*e25b118aSDominic Spill #include "config.h" 26*e25b118aSDominic Spill #endif 27*e25b118aSDominic Spill 28*e25b118aSDominic Spill #include <string.h> 29*e25b118aSDominic Spill #include "bluetooth_le_packet.h" 30*e25b118aSDominic Spill #include <ctype.h> 31*e25b118aSDominic Spill 32*e25b118aSDominic Spill /* string representations of advertising packet type */ 33*e25b118aSDominic Spill static const char *ADV_TYPE_NAMES[] = { 34*e25b118aSDominic Spill "ADV_IND", "ADV_DIRECT_IND", "ADV_NONCONN_IND", "SCAN_REQ", 35*e25b118aSDominic Spill "SCAN_RSP", "CONNECT_REQ", "ADV_SCAN_IND", 36*e25b118aSDominic Spill }; 37*e25b118aSDominic Spill 38*e25b118aSDominic Spill /* source clock accuracy in a connect packet */ 39*e25b118aSDominic Spill static const char *CONNECT_SCA[] = { 40*e25b118aSDominic Spill "251 ppm to 500 ppm", "151 ppm to 250 ppm", "101 ppm to 150 ppm", 41*e25b118aSDominic Spill "76 ppm to 100 ppm", "51 ppm to 75 ppm", "31 ppm to 50 ppm", 42*e25b118aSDominic Spill "21 ppm to 30 ppm", "0 ppm to 20 ppm", 43*e25b118aSDominic Spill }; 44*e25b118aSDominic Spill 45*e25b118aSDominic Spill // count of objects in an array, shamelessly stolen from Chrome 46*e25b118aSDominic Spill #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 47*e25b118aSDominic Spill 48*e25b118aSDominic Spill void decode_le(uint8_t *stream, uint16_t phys_channel, uint32_t clk100ns, le_packet_t *p) { 49*e25b118aSDominic Spill memcpy(p->symbols, stream, MAX_LE_SYMBOLS); 50*e25b118aSDominic Spill 51*e25b118aSDominic Spill p->channel_idx = le_channel_index(phys_channel); 52*e25b118aSDominic Spill p->clk100ns = clk100ns; 53*e25b118aSDominic Spill 54*e25b118aSDominic Spill p->access_address = 0; 55*e25b118aSDominic Spill p->access_address |= p->symbols[0]; 56*e25b118aSDominic Spill p->access_address |= p->symbols[1] << 8; 57*e25b118aSDominic Spill p->access_address |= p->symbols[2] << 16; 58*e25b118aSDominic Spill p->access_address |= p->symbols[3] << 24; 59*e25b118aSDominic Spill 60*e25b118aSDominic Spill if (le_packet_is_data(p)) { 61*e25b118aSDominic Spill // data PDU 62*e25b118aSDominic Spill p->length = p->symbols[5] & 0x1f; 63*e25b118aSDominic Spill } else { 64*e25b118aSDominic Spill // advertising PDU 65*e25b118aSDominic Spill p->length = p->symbols[5] & 0x3f; 66*e25b118aSDominic Spill p->adv_type = p->symbols[4] & 0xf; 67*e25b118aSDominic Spill p->adv_tx_add = p->symbols[4] & 0x40 ? 1 : 0; 68*e25b118aSDominic Spill p->adv_rx_add = p->symbols[4] & 0x80 ? 1 : 0; 69*e25b118aSDominic Spill } 70*e25b118aSDominic Spill } 71*e25b118aSDominic Spill 72*e25b118aSDominic Spill int le_packet_is_data(le_packet_t *p) { 73*e25b118aSDominic Spill return p->channel_idx < 37; 74*e25b118aSDominic Spill } 75*e25b118aSDominic Spill 76*e25b118aSDominic Spill uint8_t le_channel_index(uint16_t phys_channel) { 77*e25b118aSDominic Spill uint8_t ret; 78*e25b118aSDominic Spill if (phys_channel == 2402) { 79*e25b118aSDominic Spill ret = 37; 80*e25b118aSDominic Spill } else if (phys_channel < 2426) { // 0 - 10 81*e25b118aSDominic Spill ret = (phys_channel - 2404) / 2; 82*e25b118aSDominic Spill } else if (phys_channel == 2426) { 83*e25b118aSDominic Spill ret = 38; 84*e25b118aSDominic Spill } else if (phys_channel < 2480) { // 11 - 36 85*e25b118aSDominic Spill ret = 11 + (phys_channel - 2428) / 2; 86*e25b118aSDominic Spill } else { 87*e25b118aSDominic Spill ret = 39; 88*e25b118aSDominic Spill } 89*e25b118aSDominic Spill return ret; 90*e25b118aSDominic Spill } 91*e25b118aSDominic Spill 92*e25b118aSDominic Spill const char *le_adv_type(le_packet_t *p) { 93*e25b118aSDominic Spill if (le_packet_is_data(p)) 94*e25b118aSDominic Spill return NULL; 95*e25b118aSDominic Spill if (p->adv_type < COUNT_OF(ADV_TYPE_NAMES)) 96*e25b118aSDominic Spill return ADV_TYPE_NAMES[p->adv_type]; 97*e25b118aSDominic Spill return "UNKNOWN"; 98*e25b118aSDominic Spill } 99*e25b118aSDominic Spill 100*e25b118aSDominic Spill static void _dump_addr(char *name, uint8_t *buf, int offset, int random) { 101*e25b118aSDominic Spill int i; 102*e25b118aSDominic Spill printf(" %s%02x", name, buf[offset+5]); 103*e25b118aSDominic Spill for (i = 4; i >= 0; --i) 104*e25b118aSDominic Spill printf(":%02x", buf[offset+i]); 105*e25b118aSDominic Spill printf(" (%s)\n", random ? "random" : "public"); 106*e25b118aSDominic Spill } 107*e25b118aSDominic Spill 108*e25b118aSDominic Spill static void _dump_8(char *name, uint8_t *buf, int offset) { 109*e25b118aSDominic Spill printf(" %s%02x (%d)\n", name, buf[offset], buf[offset]); 110*e25b118aSDominic Spill } 111*e25b118aSDominic Spill 112*e25b118aSDominic Spill static void _dump_16(char *name, uint8_t *buf, int offset) { 113*e25b118aSDominic Spill uint16_t val = buf[offset+1] << 8 | buf[offset]; 114*e25b118aSDominic Spill printf(" %s%04x (%d)\n", name, val, val); 115*e25b118aSDominic Spill } 116*e25b118aSDominic Spill 117*e25b118aSDominic Spill static void _dump_24(char *name, uint8_t *buf, int offset) { 118*e25b118aSDominic Spill uint16_t val = buf[offset+2] << 16 | buf[offset+1] << 8 | buf[offset]; 119*e25b118aSDominic Spill printf(" %s%06x\n", name, val); 120*e25b118aSDominic Spill } 121*e25b118aSDominic Spill 122*e25b118aSDominic Spill static void _dump_32(char *name, uint8_t *buf, int offset) { 123*e25b118aSDominic Spill uint32_t val = buf[offset+3] << 24 | 124*e25b118aSDominic Spill buf[offset+2] << 16 | 125*e25b118aSDominic Spill buf[offset+1] << 8 | 126*e25b118aSDominic Spill buf[offset+0]; 127*e25b118aSDominic Spill printf(" %s%08x\n", name, val); 128*e25b118aSDominic Spill } 129*e25b118aSDominic Spill 130*e25b118aSDominic Spill static void _dump_uuid(uint8_t *uuid) { 131*e25b118aSDominic Spill int i; 132*e25b118aSDominic Spill for (i = 0; i < 4; ++i) 133*e25b118aSDominic Spill printf("%02x", uuid[i]); 134*e25b118aSDominic Spill printf("-"); 135*e25b118aSDominic Spill for (i = 4; i < 6; ++i) 136*e25b118aSDominic Spill printf("%02x", uuid[i]); 137*e25b118aSDominic Spill printf("-"); 138*e25b118aSDominic Spill for (i = 6; i < 8; ++i) 139*e25b118aSDominic Spill printf("%02x", uuid[i]); 140*e25b118aSDominic Spill printf("-"); 141*e25b118aSDominic Spill for (i = 8; i < 10; ++i) 142*e25b118aSDominic Spill printf("%02x", uuid[i]); 143*e25b118aSDominic Spill printf("-"); 144*e25b118aSDominic Spill for (i = 10; i < 16; ++i) 145*e25b118aSDominic Spill printf("%02x", uuid[i]); 146*e25b118aSDominic Spill } 147*e25b118aSDominic Spill 148*e25b118aSDominic Spill // Refer to pg 1735 of Bluetooth Core Spec 4.0 149*e25b118aSDominic Spill static void _dump_scan_rsp_data(uint8_t *buf, int len) { 150*e25b118aSDominic Spill int pos = 0; 151*e25b118aSDominic Spill int sublen, i; 152*e25b118aSDominic Spill uint8_t type; 153*e25b118aSDominic Spill uint16_t val; 154*e25b118aSDominic Spill char *cval; 155*e25b118aSDominic Spill 156*e25b118aSDominic Spill while (pos < len) { 157*e25b118aSDominic Spill sublen = buf[pos]; 158*e25b118aSDominic Spill ++pos; 159*e25b118aSDominic Spill if (pos + sublen > len) { 160*e25b118aSDominic Spill printf("Error: attempt to read past end of buffer (%d + %d > %d)\n", pos, sublen, len); 161*e25b118aSDominic Spill return; 162*e25b118aSDominic Spill } 163*e25b118aSDominic Spill if (sublen == 0) { 164*e25b118aSDominic Spill printf("Early return due to 0 length\n"); 165*e25b118aSDominic Spill return; 166*e25b118aSDominic Spill } 167*e25b118aSDominic Spill type = buf[pos]; 168*e25b118aSDominic Spill printf(" Type %02x", type); 169*e25b118aSDominic Spill switch (type) { 170*e25b118aSDominic Spill case 0x01: 171*e25b118aSDominic Spill printf(" (Flags)\n"); 172*e25b118aSDominic Spill printf(" "); 173*e25b118aSDominic Spill for (i = 0; i < 8; ++i) 174*e25b118aSDominic Spill printf("%d", buf[pos+1] & (1 << (7-i)) ? 1 : 0); 175*e25b118aSDominic Spill printf("\n"); 176*e25b118aSDominic Spill break; 177*e25b118aSDominic Spill case 0x07: 178*e25b118aSDominic Spill printf(" (128-bit Service UUIDs)\n"); 179*e25b118aSDominic Spill if ((sublen - 1) % 16 == 0) { 180*e25b118aSDominic Spill uint8_t uuid[16]; 181*e25b118aSDominic Spill for (i = 0; i < sublen - 1; ++i) { 182*e25b118aSDominic Spill uuid[15 - (i % 16)] = buf[pos+1+i]; 183*e25b118aSDominic Spill if ((i & 15) == 15) { 184*e25b118aSDominic Spill printf(" "); 185*e25b118aSDominic Spill _dump_uuid(uuid); 186*e25b118aSDominic Spill printf("\n"); 187*e25b118aSDominic Spill } 188*e25b118aSDominic Spill } 189*e25b118aSDominic Spill } 190*e25b118aSDominic Spill else { 191*e25b118aSDominic Spill printf("Wrong length (%d, must be divisible by 16)\n", sublen-1); 192*e25b118aSDominic Spill } 193*e25b118aSDominic Spill break; 194*e25b118aSDominic Spill case 0x09: 195*e25b118aSDominic Spill printf(" (Complete Local Name)\n"); 196*e25b118aSDominic Spill printf(" "); 197*e25b118aSDominic Spill for (i = 1; i < sublen; ++i) 198*e25b118aSDominic Spill printf("%c", isprint(buf[pos+i]) ? buf[pos+i] : '.'); 199*e25b118aSDominic Spill printf("\n"); 200*e25b118aSDominic Spill break; 201*e25b118aSDominic Spill case 0x0a: 202*e25b118aSDominic Spill printf(" (Tx Power Level)\n"); 203*e25b118aSDominic Spill printf(" "); 204*e25b118aSDominic Spill if (sublen-1 == 1) { 205*e25b118aSDominic Spill cval = (char *)&buf[pos+1]; 206*e25b118aSDominic Spill printf("%d dBm\n", *cval); 207*e25b118aSDominic Spill } else { 208*e25b118aSDominic Spill printf("Wrong length (%d, should be 1)\n", sublen-1); 209*e25b118aSDominic Spill } 210*e25b118aSDominic Spill break; 211*e25b118aSDominic Spill case 0x12: 212*e25b118aSDominic Spill printf(" (Slave Connection Interval Range)\n"); 213*e25b118aSDominic Spill printf(" "); 214*e25b118aSDominic Spill if (sublen-1 == 4) { 215*e25b118aSDominic Spill val = (buf[pos+2] << 8) | buf[pos+1]; 216*e25b118aSDominic Spill printf("(%0.2f, ", val * 1.25); 217*e25b118aSDominic Spill val = (buf[pos+4] << 8) | buf[pos+3]; 218*e25b118aSDominic Spill printf("%0.2f) ms\n", val * 1.25); 219*e25b118aSDominic Spill } 220*e25b118aSDominic Spill else { 221*e25b118aSDominic Spill printf("Wrong length (%d, should be 4)\n", sublen-1); 222*e25b118aSDominic Spill } 223*e25b118aSDominic Spill break; 224*e25b118aSDominic Spill case 0x16: 225*e25b118aSDominic Spill printf(" (Service Data)\n"); 226*e25b118aSDominic Spill printf(" "); 227*e25b118aSDominic Spill if (sublen-1 >= 2) { 228*e25b118aSDominic Spill val = (buf[pos+2] << 8) | buf[pos+1]; 229*e25b118aSDominic Spill printf("UUID: %02x", val); 230*e25b118aSDominic Spill if (sublen-1 > 2) { 231*e25b118aSDominic Spill printf(", Additional:"); 232*e25b118aSDominic Spill for (i = 3; i < sublen; ++i) 233*e25b118aSDominic Spill printf(" %02x", buf[pos+i]); 234*e25b118aSDominic Spill } 235*e25b118aSDominic Spill printf("\n"); 236*e25b118aSDominic Spill } 237*e25b118aSDominic Spill else { 238*e25b118aSDominic Spill printf("Wrong length (%d, should be >= 2)\n", sublen-1); 239*e25b118aSDominic Spill } 240*e25b118aSDominic Spill break; 241*e25b118aSDominic Spill default: 242*e25b118aSDominic Spill printf("\n"); 243*e25b118aSDominic Spill printf(" "); 244*e25b118aSDominic Spill for (i = 1; i < sublen; ++i) 245*e25b118aSDominic Spill printf(" %02x", buf[pos+i]); 246*e25b118aSDominic Spill printf("\n"); 247*e25b118aSDominic Spill } 248*e25b118aSDominic Spill pos += sublen; 249*e25b118aSDominic Spill } 250*e25b118aSDominic Spill } 251*e25b118aSDominic Spill 252*e25b118aSDominic Spill void le_print(le_packet_t *p) { 253*e25b118aSDominic Spill int i; 254*e25b118aSDominic Spill if (le_packet_is_data(p)) { 255*e25b118aSDominic Spill int llid = p->symbols[4] & 0x3; 256*e25b118aSDominic Spill static const char *llid_str[] = { 257*e25b118aSDominic Spill "Reserved", 258*e25b118aSDominic Spill "LL Data PDU / empty or L2CAP continuation", 259*e25b118aSDominic Spill "LL Data PDU / L2CAP start", 260*e25b118aSDominic Spill "LL Control PDU", 261*e25b118aSDominic Spill }; 262*e25b118aSDominic Spill 263*e25b118aSDominic Spill printf("Data / AA %08x / %2d bytes\n", p->access_address, p->length); 264*e25b118aSDominic Spill printf(" Channel Index: %d\n", p->channel_idx); 265*e25b118aSDominic Spill printf(" LLID: %d / %s\n", llid, llid_str[llid]); 266*e25b118aSDominic Spill printf(" NESN: %d SN: %d MD: %d\n", (p->symbols[4] >> 2) & 1, 267*e25b118aSDominic Spill (p->symbols[4] >> 3) & 1, 268*e25b118aSDominic Spill (p->symbols[4] >> 4) & 1); 269*e25b118aSDominic Spill } else { 270*e25b118aSDominic Spill printf("Advertising / AA %08x / %2d bytes\n", p->access_address, p->length); 271*e25b118aSDominic Spill printf(" Channel Index: %d\n", p->channel_idx); 272*e25b118aSDominic Spill printf(" Type: %s\n", le_adv_type(p)); 273*e25b118aSDominic Spill 274*e25b118aSDominic Spill switch(p->adv_type) { 275*e25b118aSDominic Spill case ADV_IND: 276*e25b118aSDominic Spill _dump_addr("AdvA: ", p->symbols, 6, p->adv_tx_add); 277*e25b118aSDominic Spill if (p->length-6 > 0) { 278*e25b118aSDominic Spill printf(" AdvData:"); 279*e25b118aSDominic Spill for (i = 0; i < p->length - 6; ++i) 280*e25b118aSDominic Spill printf(" %02x", p->symbols[12+i]); 281*e25b118aSDominic Spill printf("\n"); 282*e25b118aSDominic Spill _dump_scan_rsp_data(&p->symbols[12], p->length-6); 283*e25b118aSDominic Spill } 284*e25b118aSDominic Spill break; 285*e25b118aSDominic Spill case SCAN_REQ: 286*e25b118aSDominic Spill _dump_addr("ScanA: ", p->symbols, 6, p->adv_tx_add); 287*e25b118aSDominic Spill _dump_addr("AdvA: ", p->symbols, 12, p->adv_rx_add); 288*e25b118aSDominic Spill break; 289*e25b118aSDominic Spill case SCAN_RSP: 290*e25b118aSDominic Spill _dump_addr("AdvA: ", p->symbols, 6, p->adv_tx_add); 291*e25b118aSDominic Spill printf(" ScanRspData:"); 292*e25b118aSDominic Spill for (i = 0; i < p->length - 6; ++i) 293*e25b118aSDominic Spill printf(" %02x", p->symbols[12+i]); 294*e25b118aSDominic Spill printf("\n"); 295*e25b118aSDominic Spill _dump_scan_rsp_data(&p->symbols[12], p->length-6); 296*e25b118aSDominic Spill break; 297*e25b118aSDominic Spill case CONNECT_REQ: 298*e25b118aSDominic Spill _dump_addr("InitA: ", p->symbols, 6, p->adv_tx_add); 299*e25b118aSDominic Spill _dump_addr("AdvA: ", p->symbols, 12, p->adv_rx_add); 300*e25b118aSDominic Spill _dump_32("AA: ", p->symbols, 18); 301*e25b118aSDominic Spill _dump_24("CRCInit: ", p->symbols, 22); 302*e25b118aSDominic Spill _dump_8("WinSize: ", p->symbols, 25); 303*e25b118aSDominic Spill _dump_16("WinOffset: ", p->symbols, 26); 304*e25b118aSDominic Spill _dump_16("Interval: ", p->symbols, 28); 305*e25b118aSDominic Spill _dump_16("Latency: ", p->symbols, 30); 306*e25b118aSDominic Spill _dump_16("Timeout: ", p->symbols, 32); 307*e25b118aSDominic Spill 308*e25b118aSDominic Spill printf(" ChM:"); 309*e25b118aSDominic Spill for (i = 0; i < 5; ++i) 310*e25b118aSDominic Spill printf(" %02x", p->symbols[34+i]); 311*e25b118aSDominic Spill printf("\n"); 312*e25b118aSDominic Spill 313*e25b118aSDominic Spill printf(" Hop: %d\n", p->symbols[37] & 0x1f); 314*e25b118aSDominic Spill printf(" SCA: %d, %s\n", 315*e25b118aSDominic Spill p->symbols[37] >> 5, 316*e25b118aSDominic Spill CONNECT_SCA[p->symbols[37] >> 5]); 317*e25b118aSDominic Spill break; 318*e25b118aSDominic Spill } 319*e25b118aSDominic Spill } 320*e25b118aSDominic Spill 321*e25b118aSDominic Spill printf("\n"); 322*e25b118aSDominic Spill printf(" Data: "); 323*e25b118aSDominic Spill for (i = 6; i < 6 + p->length; ++i) 324*e25b118aSDominic Spill printf(" %02x", p->symbols[i]); 325*e25b118aSDominic Spill printf("\n"); 326*e25b118aSDominic Spill 327*e25b118aSDominic Spill printf(" CRC: "); 328*e25b118aSDominic Spill for (i = 0; i < 3; ++i) 329*e25b118aSDominic Spill printf(" %02x", p->symbols[6 + p->length + i]); 330*e25b118aSDominic Spill printf("\n"); 331*e25b118aSDominic Spill } 332