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 28e25b118aSDominic Spill #include <string.h> 29e25b118aSDominic Spill #include "bluetooth_le_packet.h" 30e25b118aSDominic Spill #include <ctype.h> 31e25b118aSDominic Spill 32e25b118aSDominic Spill /* string representations of advertising packet type */ 33e25b118aSDominic Spill static const char *ADV_TYPE_NAMES[] = { 34e25b118aSDominic Spill "ADV_IND", "ADV_DIRECT_IND", "ADV_NONCONN_IND", "SCAN_REQ", 35e25b118aSDominic Spill "SCAN_RSP", "CONNECT_REQ", "ADV_SCAN_IND", 36e25b118aSDominic Spill }; 37e25b118aSDominic Spill 38e25b118aSDominic Spill /* source clock accuracy in a connect packet */ 39e25b118aSDominic Spill static const char *CONNECT_SCA[] = { 40e25b118aSDominic Spill "251 ppm to 500 ppm", "151 ppm to 250 ppm", "101 ppm to 150 ppm", 41e25b118aSDominic Spill "76 ppm to 100 ppm", "51 ppm to 75 ppm", "31 ppm to 50 ppm", 42e25b118aSDominic Spill "21 ppm to 30 ppm", "0 ppm to 20 ppm", 43e25b118aSDominic Spill }; 44e25b118aSDominic Spill 45e25b118aSDominic Spill // count of objects in an array, shamelessly stolen from Chrome 46e25b118aSDominic Spill #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 47e25b118aSDominic Spill 48e25b118aSDominic Spill void decode_le(uint8_t *stream, uint16_t phys_channel, uint32_t clk100ns, le_packet_t *p) { 49e25b118aSDominic Spill memcpy(p->symbols, stream, MAX_LE_SYMBOLS); 50e25b118aSDominic Spill 51e25b118aSDominic Spill p->channel_idx = le_channel_index(phys_channel); 52e25b118aSDominic Spill p->clk100ns = clk100ns; 53e25b118aSDominic Spill 54e25b118aSDominic Spill p->access_address = 0; 55e25b118aSDominic Spill p->access_address |= p->symbols[0]; 56e25b118aSDominic Spill p->access_address |= p->symbols[1] << 8; 57e25b118aSDominic Spill p->access_address |= p->symbols[2] << 16; 58e25b118aSDominic Spill p->access_address |= p->symbols[3] << 24; 59e25b118aSDominic Spill 60e25b118aSDominic Spill if (le_packet_is_data(p)) { 61e25b118aSDominic Spill // data PDU 62e25b118aSDominic Spill p->length = p->symbols[5] & 0x1f; 63e25b118aSDominic Spill } else { 64e25b118aSDominic Spill // advertising PDU 65e25b118aSDominic Spill p->length = p->symbols[5] & 0x3f; 66e25b118aSDominic Spill p->adv_type = p->symbols[4] & 0xf; 67e25b118aSDominic Spill p->adv_tx_add = p->symbols[4] & 0x40 ? 1 : 0; 68e25b118aSDominic Spill p->adv_rx_add = p->symbols[4] & 0x80 ? 1 : 0; 69e25b118aSDominic Spill } 70e25b118aSDominic Spill } 71e25b118aSDominic Spill 72e25b118aSDominic Spill int le_packet_is_data(le_packet_t *p) { 73e25b118aSDominic Spill return p->channel_idx < 37; 74e25b118aSDominic Spill } 75e25b118aSDominic Spill 76e25b118aSDominic Spill uint8_t le_channel_index(uint16_t phys_channel) { 77e25b118aSDominic Spill uint8_t ret; 78e25b118aSDominic Spill if (phys_channel == 2402) { 79e25b118aSDominic Spill ret = 37; 80e25b118aSDominic Spill } else if (phys_channel < 2426) { // 0 - 10 81e25b118aSDominic Spill ret = (phys_channel - 2404) / 2; 82e25b118aSDominic Spill } else if (phys_channel == 2426) { 83e25b118aSDominic Spill ret = 38; 84e25b118aSDominic Spill } else if (phys_channel < 2480) { // 11 - 36 85e25b118aSDominic Spill ret = 11 + (phys_channel - 2428) / 2; 86e25b118aSDominic Spill } else { 87e25b118aSDominic Spill ret = 39; 88e25b118aSDominic Spill } 89e25b118aSDominic Spill return ret; 90e25b118aSDominic Spill } 91e25b118aSDominic Spill 92e25b118aSDominic Spill const char *le_adv_type(le_packet_t *p) { 93e25b118aSDominic Spill if (le_packet_is_data(p)) 94e25b118aSDominic Spill return NULL; 95e25b118aSDominic Spill if (p->adv_type < COUNT_OF(ADV_TYPE_NAMES)) 96e25b118aSDominic Spill return ADV_TYPE_NAMES[p->adv_type]; 97e25b118aSDominic Spill return "UNKNOWN"; 98e25b118aSDominic Spill } 99e25b118aSDominic Spill 100e25b118aSDominic Spill static void _dump_addr(char *name, uint8_t *buf, int offset, int random) { 101e25b118aSDominic Spill int i; 102e25b118aSDominic Spill printf(" %s%02x", name, buf[offset+5]); 103e25b118aSDominic Spill for (i = 4; i >= 0; --i) 104e25b118aSDominic Spill printf(":%02x", buf[offset+i]); 105e25b118aSDominic Spill printf(" (%s)\n", random ? "random" : "public"); 106e25b118aSDominic Spill } 107e25b118aSDominic Spill 108e25b118aSDominic Spill static void _dump_8(char *name, uint8_t *buf, int offset) { 109e25b118aSDominic Spill printf(" %s%02x (%d)\n", name, buf[offset], buf[offset]); 110e25b118aSDominic Spill } 111e25b118aSDominic Spill 112e25b118aSDominic Spill static void _dump_16(char *name, uint8_t *buf, int offset) { 113e25b118aSDominic Spill uint16_t val = buf[offset+1] << 8 | buf[offset]; 114e25b118aSDominic Spill printf(" %s%04x (%d)\n", name, val, val); 115e25b118aSDominic Spill } 116e25b118aSDominic Spill 117e25b118aSDominic Spill static void _dump_24(char *name, uint8_t *buf, int offset) { 118e25b118aSDominic Spill uint16_t val = buf[offset+2] << 16 | buf[offset+1] << 8 | buf[offset]; 119e25b118aSDominic Spill printf(" %s%06x\n", name, val); 120e25b118aSDominic Spill } 121e25b118aSDominic Spill 122e25b118aSDominic Spill static void _dump_32(char *name, uint8_t *buf, int offset) { 123e25b118aSDominic Spill uint32_t val = buf[offset+3] << 24 | 124e25b118aSDominic Spill buf[offset+2] << 16 | 125e25b118aSDominic Spill buf[offset+1] << 8 | 126e25b118aSDominic Spill buf[offset+0]; 127e25b118aSDominic Spill printf(" %s%08x\n", name, val); 128e25b118aSDominic Spill } 129e25b118aSDominic Spill 130e25b118aSDominic Spill static void _dump_uuid(uint8_t *uuid) { 131e25b118aSDominic Spill int i; 132e25b118aSDominic Spill for (i = 0; i < 4; ++i) 133e25b118aSDominic Spill printf("%02x", uuid[i]); 134e25b118aSDominic Spill printf("-"); 135e25b118aSDominic Spill for (i = 4; i < 6; ++i) 136e25b118aSDominic Spill printf("%02x", uuid[i]); 137e25b118aSDominic Spill printf("-"); 138e25b118aSDominic Spill for (i = 6; i < 8; ++i) 139e25b118aSDominic Spill printf("%02x", uuid[i]); 140e25b118aSDominic Spill printf("-"); 141e25b118aSDominic Spill for (i = 8; i < 10; ++i) 142e25b118aSDominic Spill printf("%02x", uuid[i]); 143e25b118aSDominic Spill printf("-"); 144e25b118aSDominic Spill for (i = 10; i < 16; ++i) 145e25b118aSDominic Spill printf("%02x", uuid[i]); 146e25b118aSDominic Spill } 147e25b118aSDominic Spill 148e25b118aSDominic Spill // Refer to pg 1735 of Bluetooth Core Spec 4.0 149e25b118aSDominic Spill static void _dump_scan_rsp_data(uint8_t *buf, int len) { 150e25b118aSDominic Spill int pos = 0; 151e25b118aSDominic Spill int sublen, i; 152e25b118aSDominic Spill uint8_t type; 153e25b118aSDominic Spill uint16_t val; 154e25b118aSDominic Spill char *cval; 155e25b118aSDominic Spill 156e25b118aSDominic Spill while (pos < len) { 157e25b118aSDominic Spill sublen = buf[pos]; 158e25b118aSDominic Spill ++pos; 159e25b118aSDominic Spill if (pos + sublen > len) { 160e25b118aSDominic Spill printf("Error: attempt to read past end of buffer (%d + %d > %d)\n", pos, sublen, len); 161e25b118aSDominic Spill return; 162e25b118aSDominic Spill } 163e25b118aSDominic Spill if (sublen == 0) { 164e25b118aSDominic Spill printf("Early return due to 0 length\n"); 165e25b118aSDominic Spill return; 166e25b118aSDominic Spill } 167e25b118aSDominic Spill type = buf[pos]; 168e25b118aSDominic Spill printf(" Type %02x", type); 169e25b118aSDominic Spill switch (type) { 170e25b118aSDominic Spill case 0x01: 171e25b118aSDominic Spill printf(" (Flags)\n"); 172e25b118aSDominic Spill printf(" "); 173e25b118aSDominic Spill for (i = 0; i < 8; ++i) 174e25b118aSDominic Spill printf("%d", buf[pos+1] & (1 << (7-i)) ? 1 : 0); 175e25b118aSDominic Spill printf("\n"); 176e25b118aSDominic Spill break; 17745000095SMike Ryan case 0x06: 17845000095SMike Ryan printf(" (128-bit Service UUIDs, more available)\n"); 17945000095SMike Ryan goto print128; 180e25b118aSDominic Spill case 0x07: 181e25b118aSDominic Spill printf(" (128-bit Service UUIDs)\n"); 18245000095SMike Ryan print128: 183e25b118aSDominic Spill if ((sublen - 1) % 16 == 0) { 184e25b118aSDominic Spill uint8_t uuid[16]; 185e25b118aSDominic Spill for (i = 0; i < sublen - 1; ++i) { 186e25b118aSDominic Spill uuid[15 - (i % 16)] = buf[pos+1+i]; 187e25b118aSDominic Spill if ((i & 15) == 15) { 188e25b118aSDominic Spill printf(" "); 189e25b118aSDominic Spill _dump_uuid(uuid); 190e25b118aSDominic Spill printf("\n"); 191e25b118aSDominic Spill } 192e25b118aSDominic Spill } 193e25b118aSDominic Spill } 194e25b118aSDominic Spill else { 195e25b118aSDominic Spill printf("Wrong length (%d, must be divisible by 16)\n", sublen-1); 196e25b118aSDominic Spill } 197e25b118aSDominic Spill break; 198e25b118aSDominic Spill case 0x09: 199e25b118aSDominic Spill printf(" (Complete Local Name)\n"); 200e25b118aSDominic Spill printf(" "); 201e25b118aSDominic Spill for (i = 1; i < sublen; ++i) 202e25b118aSDominic Spill printf("%c", isprint(buf[pos+i]) ? buf[pos+i] : '.'); 203e25b118aSDominic Spill printf("\n"); 204e25b118aSDominic Spill break; 205e25b118aSDominic Spill case 0x0a: 206e25b118aSDominic Spill printf(" (Tx Power Level)\n"); 207e25b118aSDominic Spill printf(" "); 208e25b118aSDominic Spill if (sublen-1 == 1) { 209e25b118aSDominic Spill cval = (char *)&buf[pos+1]; 210e25b118aSDominic Spill printf("%d dBm\n", *cval); 211e25b118aSDominic Spill } else { 212e25b118aSDominic Spill printf("Wrong length (%d, should be 1)\n", sublen-1); 213e25b118aSDominic Spill } 214e25b118aSDominic Spill break; 215e25b118aSDominic Spill case 0x12: 216e25b118aSDominic Spill printf(" (Slave Connection Interval Range)\n"); 217e25b118aSDominic Spill printf(" "); 218e25b118aSDominic Spill if (sublen-1 == 4) { 219e25b118aSDominic Spill val = (buf[pos+2] << 8) | buf[pos+1]; 220e25b118aSDominic Spill printf("(%0.2f, ", val * 1.25); 221e25b118aSDominic Spill val = (buf[pos+4] << 8) | buf[pos+3]; 222e25b118aSDominic Spill printf("%0.2f) ms\n", val * 1.25); 223e25b118aSDominic Spill } 224e25b118aSDominic Spill else { 225e25b118aSDominic Spill printf("Wrong length (%d, should be 4)\n", sublen-1); 226e25b118aSDominic Spill } 227e25b118aSDominic Spill break; 228e25b118aSDominic Spill case 0x16: 229e25b118aSDominic Spill printf(" (Service Data)\n"); 230e25b118aSDominic Spill printf(" "); 231e25b118aSDominic Spill if (sublen-1 >= 2) { 232e25b118aSDominic Spill val = (buf[pos+2] << 8) | buf[pos+1]; 233e25b118aSDominic Spill printf("UUID: %02x", val); 234e25b118aSDominic Spill if (sublen-1 > 2) { 235e25b118aSDominic Spill printf(", Additional:"); 236e25b118aSDominic Spill for (i = 3; i < sublen; ++i) 237e25b118aSDominic Spill printf(" %02x", buf[pos+i]); 238e25b118aSDominic Spill } 239e25b118aSDominic Spill printf("\n"); 240e25b118aSDominic Spill } 241e25b118aSDominic Spill else { 242e25b118aSDominic Spill printf("Wrong length (%d, should be >= 2)\n", sublen-1); 243e25b118aSDominic Spill } 244e25b118aSDominic Spill break; 245e25b118aSDominic Spill default: 246e25b118aSDominic Spill printf("\n"); 247e25b118aSDominic Spill printf(" "); 248e25b118aSDominic Spill for (i = 1; i < sublen; ++i) 249e25b118aSDominic Spill printf(" %02x", buf[pos+i]); 250e25b118aSDominic Spill printf("\n"); 251e25b118aSDominic Spill } 252e25b118aSDominic Spill pos += sublen; 253e25b118aSDominic Spill } 254e25b118aSDominic Spill } 255e25b118aSDominic Spill 256e25b118aSDominic Spill void le_print(le_packet_t *p) { 257387b6603SIvan Krasin int i, opcode; 258e25b118aSDominic Spill if (le_packet_is_data(p)) { 259e25b118aSDominic Spill int llid = p->symbols[4] & 0x3; 260e25b118aSDominic Spill static const char *llid_str[] = { 261e25b118aSDominic Spill "Reserved", 262e25b118aSDominic Spill "LL Data PDU / empty or L2CAP continuation", 263e25b118aSDominic Spill "LL Data PDU / L2CAP start", 264e25b118aSDominic Spill "LL Control PDU", 265e25b118aSDominic Spill }; 266e25b118aSDominic Spill 267e25b118aSDominic Spill printf("Data / AA %08x / %2d bytes\n", p->access_address, p->length); 268e25b118aSDominic Spill printf(" Channel Index: %d\n", p->channel_idx); 269e25b118aSDominic Spill printf(" LLID: %d / %s\n", llid, llid_str[llid]); 270e25b118aSDominic Spill printf(" NESN: %d SN: %d MD: %d\n", (p->symbols[4] >> 2) & 1, 271e25b118aSDominic Spill (p->symbols[4] >> 3) & 1, 272e25b118aSDominic Spill (p->symbols[4] >> 4) & 1); 273387b6603SIvan Krasin switch (llid) { 274387b6603SIvan Krasin case 3: // LL Control PDU 275387b6603SIvan Krasin opcode = p->symbols[6]; 276387b6603SIvan Krasin static const char *opcode_str[] = { 277387b6603SIvan Krasin "LL_CONNECTION_UPDATE_REQ", 278387b6603SIvan Krasin "LL_CHANNEL_MAP_REQ", 279387b6603SIvan Krasin "LL_TERMINATE_IND", 280387b6603SIvan Krasin "LL_ENC_REQ", 281387b6603SIvan Krasin "LL_ENC_RSP", 282387b6603SIvan Krasin "LL_START_ENC_REQ", 283387b6603SIvan Krasin "LL_START_ENC_RSP", 284387b6603SIvan Krasin "LL_UNKNOWN_RSP", 285387b6603SIvan Krasin "LL_FEATURE_REQ", 286387b6603SIvan Krasin "LL_FEATURE_RSP", 287387b6603SIvan Krasin "LL_PAUSE_ENC_REQ", 288387b6603SIvan Krasin "LL_PAUSE_ENC_RSP", 289387b6603SIvan Krasin "LL_VERSION_IND", 290387b6603SIvan Krasin "LL_REJECT_IND", 291*b3394904SMike Ryan "LL_SLAVE_FEATURE_REQ", 292*b3394904SMike Ryan "LL_CONNECTION_PARAM_REQ", 293*b3394904SMike Ryan "LL_CONNECTION_PARAM_RSP", 294*b3394904SMike Ryan "LL_REJECT_IND_EXT", 295*b3394904SMike Ryan "LL_PING_REQ", 296*b3394904SMike Ryan "LL_PING_RSP", 297387b6603SIvan Krasin "Reserved for Future Use", 298387b6603SIvan Krasin }; 299387b6603SIvan Krasin printf(" Opcode: %d / %s\n", opcode, opcode_str[(opcode<0x0E)?opcode:0x0E]); 300387b6603SIvan Krasin break; 301387b6603SIvan Krasin default: 302387b6603SIvan Krasin break; 303387b6603SIvan Krasin } 304e25b118aSDominic Spill } else { 305e25b118aSDominic Spill printf("Advertising / AA %08x / %2d bytes\n", p->access_address, p->length); 306e25b118aSDominic Spill printf(" Channel Index: %d\n", p->channel_idx); 307e25b118aSDominic Spill printf(" Type: %s\n", le_adv_type(p)); 308e25b118aSDominic Spill 309e25b118aSDominic Spill switch(p->adv_type) { 310e25b118aSDominic Spill case ADV_IND: 311e25b118aSDominic Spill _dump_addr("AdvA: ", p->symbols, 6, p->adv_tx_add); 312e25b118aSDominic Spill if (p->length-6 > 0) { 313e25b118aSDominic Spill printf(" AdvData:"); 314e25b118aSDominic Spill for (i = 0; i < p->length - 6; ++i) 315e25b118aSDominic Spill printf(" %02x", p->symbols[12+i]); 316e25b118aSDominic Spill printf("\n"); 317e25b118aSDominic Spill _dump_scan_rsp_data(&p->symbols[12], p->length-6); 318e25b118aSDominic Spill } 319e25b118aSDominic Spill break; 320e25b118aSDominic Spill case SCAN_REQ: 321e25b118aSDominic Spill _dump_addr("ScanA: ", p->symbols, 6, p->adv_tx_add); 322e25b118aSDominic Spill _dump_addr("AdvA: ", p->symbols, 12, p->adv_rx_add); 323e25b118aSDominic Spill break; 324e25b118aSDominic Spill case SCAN_RSP: 325e25b118aSDominic Spill _dump_addr("AdvA: ", p->symbols, 6, p->adv_tx_add); 326e25b118aSDominic Spill printf(" ScanRspData:"); 327e25b118aSDominic Spill for (i = 0; i < p->length - 6; ++i) 328e25b118aSDominic Spill printf(" %02x", p->symbols[12+i]); 329e25b118aSDominic Spill printf("\n"); 330e25b118aSDominic Spill _dump_scan_rsp_data(&p->symbols[12], p->length-6); 331e25b118aSDominic Spill break; 332e25b118aSDominic Spill case CONNECT_REQ: 333e25b118aSDominic Spill _dump_addr("InitA: ", p->symbols, 6, p->adv_tx_add); 334e25b118aSDominic Spill _dump_addr("AdvA: ", p->symbols, 12, p->adv_rx_add); 335e25b118aSDominic Spill _dump_32("AA: ", p->symbols, 18); 336e25b118aSDominic Spill _dump_24("CRCInit: ", p->symbols, 22); 337e25b118aSDominic Spill _dump_8("WinSize: ", p->symbols, 25); 338e25b118aSDominic Spill _dump_16("WinOffset: ", p->symbols, 26); 339e25b118aSDominic Spill _dump_16("Interval: ", p->symbols, 28); 340e25b118aSDominic Spill _dump_16("Latency: ", p->symbols, 30); 341e25b118aSDominic Spill _dump_16("Timeout: ", p->symbols, 32); 342e25b118aSDominic Spill 343e25b118aSDominic Spill printf(" ChM:"); 344e25b118aSDominic Spill for (i = 0; i < 5; ++i) 345e25b118aSDominic Spill printf(" %02x", p->symbols[34+i]); 346e25b118aSDominic Spill printf("\n"); 347e25b118aSDominic Spill 3485d00a97fSIvan Krasin printf(" Hop: %d\n", p->symbols[39] & 0x1f); 349e25b118aSDominic Spill printf(" SCA: %d, %s\n", 3505d00a97fSIvan Krasin p->symbols[39] >> 5, 3515d00a97fSIvan Krasin CONNECT_SCA[p->symbols[39] >> 5]); 352e25b118aSDominic Spill break; 353e25b118aSDominic Spill } 354e25b118aSDominic Spill } 355e25b118aSDominic Spill 356e25b118aSDominic Spill printf("\n"); 357e25b118aSDominic Spill printf(" Data: "); 358e25b118aSDominic Spill for (i = 6; i < 6 + p->length; ++i) 359e25b118aSDominic Spill printf(" %02x", p->symbols[i]); 360e25b118aSDominic Spill printf("\n"); 361e25b118aSDominic Spill 362e25b118aSDominic Spill printf(" CRC: "); 363e25b118aSDominic Spill for (i = 0; i < 3; ++i) 364e25b118aSDominic Spill printf(" %02x", p->symbols[6 + p->length + i]); 365e25b118aSDominic Spill printf("\n"); 366e25b118aSDominic Spill } 367