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
288f3e7eeaSChristopher Kilgour #include "btbb.h"
29e25b118aSDominic Spill #include "bluetooth_le_packet.h"
30e25b118aSDominic Spill #include <ctype.h>
318f3e7eeaSChristopher Kilgour #include <string.h>
32e25b118aSDominic Spill
33f25ef1fbSMike Ryan /* company identifier lookup */
34f25ef1fbSMike Ryan const char *bt_compidtostr(uint16_t compid);
35f25ef1fbSMike Ryan
36e25b118aSDominic Spill /* string representations of advertising packet type */
37e25b118aSDominic Spill static const char *ADV_TYPE_NAMES[] = {
38e25b118aSDominic Spill "ADV_IND", "ADV_DIRECT_IND", "ADV_NONCONN_IND", "SCAN_REQ",
39e25b118aSDominic Spill "SCAN_RSP", "CONNECT_REQ", "ADV_SCAN_IND",
40e25b118aSDominic Spill };
41e25b118aSDominic Spill
42e25b118aSDominic Spill /* source clock accuracy in a connect packet */
43e25b118aSDominic Spill static const char *CONNECT_SCA[] = {
44e25b118aSDominic Spill "251 ppm to 500 ppm", "151 ppm to 250 ppm", "101 ppm to 150 ppm",
45e25b118aSDominic Spill "76 ppm to 100 ppm", "51 ppm to 75 ppm", "31 ppm to 50 ppm",
46e25b118aSDominic Spill "21 ppm to 30 ppm", "0 ppm to 20 ppm",
47e25b118aSDominic Spill };
48e25b118aSDominic Spill
49*ab0dd8d7SMike Ryan /* flags */
50*ab0dd8d7SMike Ryan static const char *FLAGS[] = {
51*ab0dd8d7SMike Ryan "LE Limited Discoverable Mode", "LE General Discoverable Mode",
52*ab0dd8d7SMike Ryan "BR/EDR Not Supported",
53*ab0dd8d7SMike Ryan "Simultaneous LE and BR/EDR to Same Device Capable (Controller)",
54*ab0dd8d7SMike Ryan "Simultaneous LE and BR/EDR to Same Device Capable (Host)",
55*ab0dd8d7SMike Ryan "Reserved", "Reserved", "Reserved",
56*ab0dd8d7SMike Ryan };
57*ab0dd8d7SMike Ryan
58e25b118aSDominic Spill // count of objects in an array, shamelessly stolen from Chrome
59e25b118aSDominic Spill #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
60e25b118aSDominic Spill
count_bits(uint32_t n)610a637dcaSDominic Spill static uint8_t count_bits(uint32_t n)
620a637dcaSDominic Spill {
630a637dcaSDominic Spill uint8_t i = 0;
640a637dcaSDominic Spill for (i = 0; n != 0; i++)
650a637dcaSDominic Spill n &= n - 1;
660a637dcaSDominic Spill return i;
670a637dcaSDominic Spill }
680a637dcaSDominic Spill
aa_access_channel_off_by_one(const uint32_t aa)698f3e7eeaSChristopher Kilgour static int aa_access_channel_off_by_one(const uint32_t aa) {
708f3e7eeaSChristopher Kilgour int retval = 0;
710a637dcaSDominic Spill if(count_bits(aa ^ LE_ADV_AA) == 1) {
728f3e7eeaSChristopher Kilgour retval = 1;
738f3e7eeaSChristopher Kilgour }
748f3e7eeaSChristopher Kilgour return retval;
758f3e7eeaSChristopher Kilgour }
76e25b118aSDominic Spill
778f3e7eeaSChristopher Kilgour /*
788f3e7eeaSChristopher Kilgour * A helper function for filtering bogus packets on data channels.
798f3e7eeaSChristopher Kilgour *
808f3e7eeaSChristopher Kilgour * If a candidate capture packet is random noise we would expect its
818f3e7eeaSChristopher Kilgour * Access Address to be a randomly distributed 32-bit number. An
828f3e7eeaSChristopher Kilgour * exhaustive software analysis reveals that of 4294967296 possible
838f3e7eeaSChristopher Kilgour * 32-bit Access Address values, 2900629660 (67.5%) are acceptable and
848f3e7eeaSChristopher Kilgour * 1394337636 (32.5%) are invalid. This function will identify which
858f3e7eeaSChristopher Kilgour * category a candidate Access Address falls into by returning the
868f3e7eeaSChristopher Kilgour * number of offenses contained.
878f3e7eeaSChristopher Kilgour *
888f3e7eeaSChristopher Kilgour * Refer to BT 4.x, Vol 6, Par B, Section 2.1.2.
898f3e7eeaSChristopher Kilgour *
908f3e7eeaSChristopher Kilgour * The Access Address in data channel packets meet the
918f3e7eeaSChristopher Kilgour * following requirements:
928f3e7eeaSChristopher Kilgour * - It shall have no more than six consecutive zeros or ones.
938f3e7eeaSChristopher Kilgour * - It shall not be the advertising channel packets’ Access Address.
948f3e7eeaSChristopher Kilgour * - It shall not be a sequence that differs from the advertising channel packets’
958f3e7eeaSChristopher Kilgour * Access Address by only one bit.
968f3e7eeaSChristopher Kilgour * - It shall not have all four octets equal.
978f3e7eeaSChristopher Kilgour * - It shall have no more than 24 transitions.
988f3e7eeaSChristopher Kilgour * - It shall have a minimum of two transitions in the most significant six bits.
998f3e7eeaSChristopher Kilgour */
aa_data_channel_offenses(const uint32_t aa)1008f3e7eeaSChristopher Kilgour static int aa_data_channel_offenses(const uint32_t aa) {
1018f3e7eeaSChristopher Kilgour int retval = 0, transitions = 0;
1028f3e7eeaSChristopher Kilgour unsigned shift, odd = (unsigned) (aa & 1);
1038f3e7eeaSChristopher Kilgour uint8_t aab3, aab2, aab1, aab0 = (uint8_t) (aa & 0xff);
104e25b118aSDominic Spill
1058f3e7eeaSChristopher Kilgour const uint8_t EIGHT_BIT_TRANSITIONS_EVEN[256] = {
1068f3e7eeaSChristopher Kilgour 0, 2, 2, 2, 2, 4, 2, 2, 2, 4, 4, 4, 2, 4, 2, 2,
1078f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2,
1088f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4,
1098f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2,
1108f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4,
1118f3e7eeaSChristopher Kilgour 4, 6, 6, 6, 6, 8, 6, 6, 4, 6, 6, 6, 4, 6, 4, 4,
1128f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4,
1138f3e7eeaSChristopher Kilgour 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2,
1148f3e7eeaSChristopher Kilgour 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3,
1158f3e7eeaSChristopher Kilgour 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3,
1168f3e7eeaSChristopher Kilgour 3, 5, 5, 5, 5, 7, 5, 5, 5, 7, 7, 7, 5, 7, 5, 5,
1178f3e7eeaSChristopher Kilgour 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3,
1188f3e7eeaSChristopher Kilgour 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3,
1198f3e7eeaSChristopher Kilgour 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3,
1208f3e7eeaSChristopher Kilgour 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3,
1218f3e7eeaSChristopher Kilgour 1, 3, 3, 3, 3, 5, 3, 3, 1, 3, 3, 3, 1, 3, 1, 1
1228f3e7eeaSChristopher Kilgour };
123e25b118aSDominic Spill
1248f3e7eeaSChristopher Kilgour const uint8_t EIGHT_BIT_TRANSITIONS_ODD[256] = {
1258f3e7eeaSChristopher Kilgour 1, 1, 3, 1, 3, 3, 3, 1, 3, 3, 5, 3, 3, 3, 3, 1,
1268f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1,
1278f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3,
1288f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1,
1298f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3,
1308f3e7eeaSChristopher Kilgour 5, 5, 7, 5, 7, 7, 7, 5, 5, 5, 7, 5, 5, 5, 5, 3,
1318f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3,
1328f3e7eeaSChristopher Kilgour 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1,
1338f3e7eeaSChristopher Kilgour 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2,
1348f3e7eeaSChristopher Kilgour 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2,
1358f3e7eeaSChristopher Kilgour 4, 4, 6, 4, 6, 6, 6, 4, 6, 6, 8, 6, 6, 6, 6, 4,
1368f3e7eeaSChristopher Kilgour 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2,
1378f3e7eeaSChristopher Kilgour 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2,
1388f3e7eeaSChristopher Kilgour 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2,
1398f3e7eeaSChristopher Kilgour 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2,
1408f3e7eeaSChristopher Kilgour 2, 2, 4, 2, 4, 4, 4, 2, 2, 2, 4, 2, 2, 2, 2, 0
1418f3e7eeaSChristopher Kilgour };
1428f3e7eeaSChristopher Kilgour
1438f3e7eeaSChristopher Kilgour transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab0] : EIGHT_BIT_TRANSITIONS_EVEN[aab0] );
1448f3e7eeaSChristopher Kilgour odd = (unsigned) (aab0 & 0x80);
1458f3e7eeaSChristopher Kilgour aab1 = (uint8_t) (aa >> 8);
1468f3e7eeaSChristopher Kilgour transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab1] : EIGHT_BIT_TRANSITIONS_EVEN[aab1] );
1478f3e7eeaSChristopher Kilgour odd = (unsigned) (aab1 & 0x80);
1488f3e7eeaSChristopher Kilgour aab2 = (uint8_t) (aa >> 16);
1498f3e7eeaSChristopher Kilgour transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab2] : EIGHT_BIT_TRANSITIONS_EVEN[aab2] );
1508f3e7eeaSChristopher Kilgour odd = (unsigned) (aab2 & 0x80);
1518f3e7eeaSChristopher Kilgour aab3 = (uint8_t) (aa >> 24);
1528f3e7eeaSChristopher Kilgour transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab3] : EIGHT_BIT_TRANSITIONS_EVEN[aab3] );
1538f3e7eeaSChristopher Kilgour
1548f3e7eeaSChristopher Kilgour /* consider excessive transitions as offenses */
1558f3e7eeaSChristopher Kilgour if (transitions > 24) {
1568f3e7eeaSChristopher Kilgour retval += (transitions - 24);
1578f3e7eeaSChristopher Kilgour }
1588f3e7eeaSChristopher Kilgour
1598f3e7eeaSChristopher Kilgour const uint8_t AA_MSB6_ALLOWED[64] = {
1608f3e7eeaSChristopher Kilgour 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
1618f3e7eeaSChristopher Kilgour 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
1628f3e7eeaSChristopher Kilgour 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1638f3e7eeaSChristopher Kilgour 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0
1648f3e7eeaSChristopher Kilgour };
1658f3e7eeaSChristopher Kilgour
1668f3e7eeaSChristopher Kilgour /* consider excessive transitions in the 6 MSBs as an offense */
1678f3e7eeaSChristopher Kilgour retval += (1 - AA_MSB6_ALLOWED[aab3>>2]);
1688f3e7eeaSChristopher Kilgour
1698f3e7eeaSChristopher Kilgour /* consider all bytes as being equal an offense */
1708f3e7eeaSChristopher Kilgour retval += (((aab0 == aab1) && (aab0 == aab2) && (aab0 == aab3)) ? 1 : 0);
1718f3e7eeaSChristopher Kilgour
1728f3e7eeaSChristopher Kilgour /* access-channel address and off-by-ones are illegal */
1730a637dcaSDominic Spill retval += ((aa == LE_ADV_AA) ? 1 : 0);
1748f3e7eeaSChristopher Kilgour retval += aa_access_channel_off_by_one(aa);
1758f3e7eeaSChristopher Kilgour
1768f3e7eeaSChristopher Kilgour /* inspect nibble triples for insufficient bit transitions */
1778f3e7eeaSChristopher Kilgour for(shift=0; shift<=20; shift+=4) {
1788f3e7eeaSChristopher Kilgour uint16_t twelvebits = (uint16_t) ((aa >> shift) & 0xfff);
1798f3e7eeaSChristopher Kilgour switch( twelvebits ) {
1808f3e7eeaSChristopher Kilgour /* seven consecutive zeroes */
1818f3e7eeaSChristopher Kilgour case 0x080: case 0x180: case 0x280: case 0x380: case 0x480:
1828f3e7eeaSChristopher Kilgour case 0x580: case 0x680: case 0x780: case 0x880: case 0x980:
1838f3e7eeaSChristopher Kilgour case 0xa80: case 0xb80: case 0xc80: case 0xd80: case 0xe80:
1848f3e7eeaSChristopher Kilgour case 0xf80: case 0x101: case 0x301: case 0x501: case 0x701:
1858f3e7eeaSChristopher Kilgour case 0x901: case 0xb01: case 0xd01: case 0xf01: case 0x202:
1868f3e7eeaSChristopher Kilgour case 0x602: case 0xa02: case 0xe02: case 0x203: case 0x603:
1878f3e7eeaSChristopher Kilgour case 0xa03: case 0xe03: case 0x404: case 0xc04: case 0x405:
1888f3e7eeaSChristopher Kilgour case 0xc05: case 0x406: case 0xc06: case 0x407: case 0xc07:
1898f3e7eeaSChristopher Kilgour case 0x808: case 0x809: case 0x80a: case 0x80b: case 0x80c:
1908f3e7eeaSChristopher Kilgour case 0x80d: case 0x80e: case 0x80f: case 0x010: case 0x011:
1918f3e7eeaSChristopher Kilgour case 0x012: case 0x013: case 0x014: case 0x015: case 0x016:
1928f3e7eeaSChristopher Kilgour case 0x017: case 0x018: case 0x019: case 0x01a: case 0x01b:
1938f3e7eeaSChristopher Kilgour case 0x01c: case 0x01d: case 0x01e: case 0x01f:
1948f3e7eeaSChristopher Kilgour /* eight consecutive zeroes */
1958f3e7eeaSChristopher Kilgour case 0x100: case 0x300: case 0x500: case 0x700: case 0x900:
1968f3e7eeaSChristopher Kilgour case 0xb00: case 0xd00: case 0xf00: case 0x201: case 0x601:
1978f3e7eeaSChristopher Kilgour case 0xa01: case 0xe01: case 0x402: case 0xc02: case 0x403:
1988f3e7eeaSChristopher Kilgour case 0xc03: case 0x804: case 0x805: case 0x806: case 0x807:
1998f3e7eeaSChristopher Kilgour case 0x008: case 0x009: case 0x00a: case 0x00b: case 0x00c:
2008f3e7eeaSChristopher Kilgour case 0x00d: case 0x00e: case 0x00f:
2018f3e7eeaSChristopher Kilgour /* nine consecutive zeroes */
2028f3e7eeaSChristopher Kilgour case 0xe00: case 0xc01: case 0x802: case 0x803: case 0x004:
2038f3e7eeaSChristopher Kilgour case 0x005: case 0x006: case 0x007:
2048f3e7eeaSChristopher Kilgour /* ten consecutive zeroes */
2058f3e7eeaSChristopher Kilgour case 0x400: case 0xc00: case 0x801: case 0x002: case 0x003:
2068f3e7eeaSChristopher Kilgour /* eleven consecutive zeroes */
2078f3e7eeaSChristopher Kilgour case 0x800: case 0x001:
2088f3e7eeaSChristopher Kilgour /* twelve consecutive zeroes */
2098f3e7eeaSChristopher Kilgour case 0x000:
2108f3e7eeaSChristopher Kilgour /* seven consecutive ones */
2118f3e7eeaSChristopher Kilgour case 0x07f: case 0x0fe: case 0x2fe: case 0x4fe: case 0x6fe:
2128f3e7eeaSChristopher Kilgour case 0x8fe: case 0xafe: case 0xcfe: case 0xefe: case 0x1fc:
2138f3e7eeaSChristopher Kilgour case 0x5fc: case 0x9fc: case 0xdfc: case 0x1fd: case 0x5fd:
2148f3e7eeaSChristopher Kilgour case 0x9fd: case 0xdfd: case 0x3f8: case 0xbf8: case 0x3f9:
2158f3e7eeaSChristopher Kilgour case 0xbf9: case 0x3fa: case 0xbfa: case 0x3fb: case 0xbfb:
2168f3e7eeaSChristopher Kilgour case 0x7f4: case 0x7f5: case 0x7f6: case 0x7f7: case 0xfe0:
2178f3e7eeaSChristopher Kilgour /* eight consecutive ones */
2188f3e7eeaSChristopher Kilgour case 0x0ff: case 0x2ff: case 0x4ff: case 0x6ff: case 0x8ff:
2198f3e7eeaSChristopher Kilgour case 0xaff: case 0xcff: case 0xeff: case 0x1fe: case 0x5fe:
2208f3e7eeaSChristopher Kilgour case 0x9fe: case 0xdfe: case 0x3fc: case 0xbfc: case 0x3fd:
2218f3e7eeaSChristopher Kilgour case 0xbfd: case 0x7f8: case 0x7f9: case 0x7fa: case 0x7fb:
2228f3e7eeaSChristopher Kilgour case 0xff0: case 0xff1: case 0xff2: case 0xff3: case 0xff4:
2238f3e7eeaSChristopher Kilgour case 0xff5: case 0xff6: case 0xff7:
2248f3e7eeaSChristopher Kilgour /* nine consecutive ones */
2258f3e7eeaSChristopher Kilgour case 0x1ff: case 0x5ff: case 0x9ff: case 0xdff: case 0x3fe:
2268f3e7eeaSChristopher Kilgour case 0xbfe: case 0x7fc: case 0x7fd: case 0xff8: case 0xff9:
2278f3e7eeaSChristopher Kilgour case 0xffa: case 0xffb:
2288f3e7eeaSChristopher Kilgour /* ten consecutive ones */
2298f3e7eeaSChristopher Kilgour case 0x3ff: case 0xbff: case 0x7fe: case 0xffc: case 0xffd:
2308f3e7eeaSChristopher Kilgour /* eleven consecutive ones */
2318f3e7eeaSChristopher Kilgour case 0x7ff: case 0xffe:
2328f3e7eeaSChristopher Kilgour /* all ones */
2338f3e7eeaSChristopher Kilgour case 0xfff:
2348f3e7eeaSChristopher Kilgour retval++;
2358f3e7eeaSChristopher Kilgour break;
2368f3e7eeaSChristopher Kilgour default:
2378f3e7eeaSChristopher Kilgour break;
238e25b118aSDominic Spill }
239e25b118aSDominic Spill }
240e25b118aSDominic Spill
2418f3e7eeaSChristopher Kilgour return retval;
242e25b118aSDominic Spill }
243e25b118aSDominic Spill
2448f3e7eeaSChristopher Kilgour lell_packet *
lell_packet_new(void)2458f3e7eeaSChristopher Kilgour lell_packet_new(void)
2468f3e7eeaSChristopher Kilgour {
2478f3e7eeaSChristopher Kilgour lell_packet *pkt = (lell_packet *)calloc(1, sizeof(lell_packet));
2488f3e7eeaSChristopher Kilgour pkt->refcount = 1;
2498f3e7eeaSChristopher Kilgour return pkt;
2508f3e7eeaSChristopher Kilgour }
2518f3e7eeaSChristopher Kilgour
2528f3e7eeaSChristopher Kilgour void
lell_packet_ref(lell_packet * pkt)2538f3e7eeaSChristopher Kilgour lell_packet_ref(lell_packet *pkt)
2548f3e7eeaSChristopher Kilgour {
2558f3e7eeaSChristopher Kilgour pkt->refcount++;
2568f3e7eeaSChristopher Kilgour }
2578f3e7eeaSChristopher Kilgour
2588f3e7eeaSChristopher Kilgour void
lell_packet_unref(lell_packet * pkt)2598f3e7eeaSChristopher Kilgour lell_packet_unref(lell_packet *pkt)
2608f3e7eeaSChristopher Kilgour {
2618f3e7eeaSChristopher Kilgour pkt->refcount--;
2628f3e7eeaSChristopher Kilgour if (pkt->refcount == 0)
2638f3e7eeaSChristopher Kilgour free(pkt);
2648f3e7eeaSChristopher Kilgour }
2658f3e7eeaSChristopher Kilgour
le_channel_index(uint16_t phys_channel)2668f3e7eeaSChristopher Kilgour static uint8_t le_channel_index(uint16_t phys_channel) {
267e25b118aSDominic Spill uint8_t ret;
268e25b118aSDominic Spill if (phys_channel == 2402) {
269e25b118aSDominic Spill ret = 37;
270e25b118aSDominic Spill } else if (phys_channel < 2426) { // 0 - 10
271e25b118aSDominic Spill ret = (phys_channel - 2404) / 2;
272e25b118aSDominic Spill } else if (phys_channel == 2426) {
273e25b118aSDominic Spill ret = 38;
274e25b118aSDominic Spill } else if (phys_channel < 2480) { // 11 - 36
275e25b118aSDominic Spill ret = 11 + (phys_channel - 2428) / 2;
276e25b118aSDominic Spill } else {
277e25b118aSDominic Spill ret = 39;
278e25b118aSDominic Spill }
279e25b118aSDominic Spill return ret;
280e25b118aSDominic Spill }
281e25b118aSDominic Spill
lell_allocate_and_decode(const uint8_t * stream,uint16_t phys_channel,uint32_t clk100ns,lell_packet ** pkt)2828f3e7eeaSChristopher Kilgour void lell_allocate_and_decode(const uint8_t *stream, uint16_t phys_channel, uint32_t clk100ns, lell_packet **pkt)
2838f3e7eeaSChristopher Kilgour {
2848f3e7eeaSChristopher Kilgour *pkt = lell_packet_new( );
2858f3e7eeaSChristopher Kilgour memcpy((*pkt)->symbols, stream, MAX_LE_SYMBOLS);
2868f3e7eeaSChristopher Kilgour
2878f3e7eeaSChristopher Kilgour (*pkt)->channel_idx = le_channel_index(phys_channel);
2888f3e7eeaSChristopher Kilgour (*pkt)->channel_k = (phys_channel-2402)/2;
2898f3e7eeaSChristopher Kilgour (*pkt)->clk100ns = clk100ns;
2908f3e7eeaSChristopher Kilgour
2918f3e7eeaSChristopher Kilgour (*pkt)->access_address = 0;
2928f3e7eeaSChristopher Kilgour (*pkt)->access_address |= (*pkt)->symbols[0];
2938f3e7eeaSChristopher Kilgour (*pkt)->access_address |= (*pkt)->symbols[1] << 8;
2948f3e7eeaSChristopher Kilgour (*pkt)->access_address |= (*pkt)->symbols[2] << 16;
2958f3e7eeaSChristopher Kilgour (*pkt)->access_address |= (*pkt)->symbols[3] << 24;
2968f3e7eeaSChristopher Kilgour
2978f3e7eeaSChristopher Kilgour if (lell_packet_is_data(*pkt)) {
2988f3e7eeaSChristopher Kilgour // data PDU
2998f3e7eeaSChristopher Kilgour (*pkt)->length = (*pkt)->symbols[5] & 0x1f;
3008f3e7eeaSChristopher Kilgour (*pkt)->access_address_offenses = aa_data_channel_offenses((*pkt)->access_address);
3018f3e7eeaSChristopher Kilgour (*pkt)->flags.as_bits.access_address_ok = (*pkt)->access_address_offenses ? 0 : 1;
3028f3e7eeaSChristopher Kilgour } else {
3038f3e7eeaSChristopher Kilgour // advertising PDU
3048f3e7eeaSChristopher Kilgour (*pkt)->length = (*pkt)->symbols[5] & 0x3f;
3058f3e7eeaSChristopher Kilgour (*pkt)->adv_type = (*pkt)->symbols[4] & 0xf;
3068f3e7eeaSChristopher Kilgour (*pkt)->adv_tx_add = (*pkt)->symbols[4] & 0x40 ? 1 : 0;
3078f3e7eeaSChristopher Kilgour (*pkt)->adv_rx_add = (*pkt)->symbols[4] & 0x80 ? 1 : 0;
3088f3e7eeaSChristopher Kilgour (*pkt)->flags.as_bits.access_address_ok = ((*pkt)->access_address == 0x8e89bed6);
3098f3e7eeaSChristopher Kilgour (*pkt)->access_address_offenses = (*pkt)->flags.as_bits.access_address_ok ? 0 :
3108f3e7eeaSChristopher Kilgour (aa_access_channel_off_by_one((*pkt)->access_address) ? 1 : 32);
3118f3e7eeaSChristopher Kilgour }
3128f3e7eeaSChristopher Kilgour }
3138f3e7eeaSChristopher Kilgour
lell_packet_is_data(const lell_packet * pkt)3148f3e7eeaSChristopher Kilgour unsigned lell_packet_is_data(const lell_packet *pkt)
3158f3e7eeaSChristopher Kilgour {
3168f3e7eeaSChristopher Kilgour return (unsigned) (pkt->channel_idx < 37);
3178f3e7eeaSChristopher Kilgour }
3188f3e7eeaSChristopher Kilgour
lell_get_access_address(const lell_packet * pkt)3198f3e7eeaSChristopher Kilgour uint32_t lell_get_access_address(const lell_packet *pkt)
3208f3e7eeaSChristopher Kilgour {
3218f3e7eeaSChristopher Kilgour return pkt->access_address;
3228f3e7eeaSChristopher Kilgour }
3238f3e7eeaSChristopher Kilgour
lell_get_access_address_offenses(const lell_packet * pkt)3248f3e7eeaSChristopher Kilgour unsigned lell_get_access_address_offenses(const lell_packet *pkt)
3258f3e7eeaSChristopher Kilgour {
3268f3e7eeaSChristopher Kilgour return pkt->access_address_offenses;
3278f3e7eeaSChristopher Kilgour }
3288f3e7eeaSChristopher Kilgour
lell_get_channel_index(const lell_packet * pkt)3298f3e7eeaSChristopher Kilgour unsigned lell_get_channel_index(const lell_packet *pkt)
3308f3e7eeaSChristopher Kilgour {
3318f3e7eeaSChristopher Kilgour return pkt->channel_idx;
3328f3e7eeaSChristopher Kilgour }
3338f3e7eeaSChristopher Kilgour
lell_get_channel_k(const lell_packet * pkt)3348f3e7eeaSChristopher Kilgour unsigned lell_get_channel_k(const lell_packet *pkt)
3358f3e7eeaSChristopher Kilgour {
3368f3e7eeaSChristopher Kilgour return pkt->channel_k;
3378f3e7eeaSChristopher Kilgour }
3388f3e7eeaSChristopher Kilgour
lell_get_adv_type_str(const lell_packet * pkt)3398f3e7eeaSChristopher Kilgour const char * lell_get_adv_type_str(const lell_packet *pkt)
3408f3e7eeaSChristopher Kilgour {
3418f3e7eeaSChristopher Kilgour if (lell_packet_is_data(pkt))
342e25b118aSDominic Spill return NULL;
3438f3e7eeaSChristopher Kilgour if (pkt->adv_type < COUNT_OF(ADV_TYPE_NAMES))
3448f3e7eeaSChristopher Kilgour return ADV_TYPE_NAMES[pkt->adv_type];
345e25b118aSDominic Spill return "UNKNOWN";
346e25b118aSDominic Spill }
347e25b118aSDominic Spill
_dump_addr(const char * name,const uint8_t * buf,int offset,int random)3488f3e7eeaSChristopher Kilgour static void _dump_addr(const char *name, const uint8_t *buf, int offset, int random) {
349e25b118aSDominic Spill int i;
350e25b118aSDominic Spill printf(" %s%02x", name, buf[offset+5]);
351e25b118aSDominic Spill for (i = 4; i >= 0; --i)
352e25b118aSDominic Spill printf(":%02x", buf[offset+i]);
353e25b118aSDominic Spill printf(" (%s)\n", random ? "random" : "public");
354e25b118aSDominic Spill }
355e25b118aSDominic Spill
_dump_8(const char * name,const uint8_t * buf,int offset)3568f3e7eeaSChristopher Kilgour static void _dump_8(const char *name, const uint8_t *buf, int offset) {
357e25b118aSDominic Spill printf(" %s%02x (%d)\n", name, buf[offset], buf[offset]);
358e25b118aSDominic Spill }
359e25b118aSDominic Spill
_dump_16(const char * name,const uint8_t * buf,int offset)3608f3e7eeaSChristopher Kilgour static void _dump_16(const char *name, const uint8_t *buf, int offset) {
361e25b118aSDominic Spill uint16_t val = buf[offset+1] << 8 | buf[offset];
362e25b118aSDominic Spill printf(" %s%04x (%d)\n", name, val, val);
363e25b118aSDominic Spill }
364e25b118aSDominic Spill
_dump_24(char * name,const uint8_t * buf,int offset)365c6bb3715SMike Ryan static void _dump_24(char *name, const uint8_t *buf, int offset) {
366c6bb3715SMike Ryan uint32_t val = buf[offset+2] << 16 | buf[offset+1] << 8 | buf[offset];
367e25b118aSDominic Spill printf(" %s%06x\n", name, val);
368e25b118aSDominic Spill }
369e25b118aSDominic Spill
_dump_32(const char * name,const uint8_t * buf,int offset)3708f3e7eeaSChristopher Kilgour static void _dump_32(const char *name, const uint8_t *buf, int offset) {
371e25b118aSDominic Spill uint32_t val = buf[offset+3] << 24 |
372e25b118aSDominic Spill buf[offset+2] << 16 |
373e25b118aSDominic Spill buf[offset+1] << 8 |
374e25b118aSDominic Spill buf[offset+0];
375e25b118aSDominic Spill printf(" %s%08x\n", name, val);
376e25b118aSDominic Spill }
377e25b118aSDominic Spill
_dump_uuid(const uint8_t * uuid)3788f3e7eeaSChristopher Kilgour static void _dump_uuid(const uint8_t *uuid) {
379e25b118aSDominic Spill int i;
380e25b118aSDominic Spill for (i = 0; i < 4; ++i)
381e25b118aSDominic Spill printf("%02x", uuid[i]);
382e25b118aSDominic Spill printf("-");
383e25b118aSDominic Spill for (i = 4; i < 6; ++i)
384e25b118aSDominic Spill printf("%02x", uuid[i]);
385e25b118aSDominic Spill printf("-");
386e25b118aSDominic Spill for (i = 6; i < 8; ++i)
387e25b118aSDominic Spill printf("%02x", uuid[i]);
388e25b118aSDominic Spill printf("-");
389e25b118aSDominic Spill for (i = 8; i < 10; ++i)
390e25b118aSDominic Spill printf("%02x", uuid[i]);
391e25b118aSDominic Spill printf("-");
392e25b118aSDominic Spill for (i = 10; i < 16; ++i)
393e25b118aSDominic Spill printf("%02x", uuid[i]);
394e25b118aSDominic Spill }
395e25b118aSDominic Spill
396e25b118aSDominic Spill // Refer to pg 1735 of Bluetooth Core Spec 4.0
_dump_scan_rsp_data(const uint8_t * buf,int len)3978f3e7eeaSChristopher Kilgour static void _dump_scan_rsp_data(const uint8_t *buf, int len) {
398e25b118aSDominic Spill int pos = 0;
399e25b118aSDominic Spill int sublen, i;
400e25b118aSDominic Spill uint8_t type;
401e25b118aSDominic Spill uint16_t val;
402e25b118aSDominic Spill char *cval;
403e25b118aSDominic Spill
404e25b118aSDominic Spill while (pos < len) {
405e25b118aSDominic Spill sublen = buf[pos];
406e25b118aSDominic Spill ++pos;
407e25b118aSDominic Spill if (pos + sublen > len) {
408e25b118aSDominic Spill printf("Error: attempt to read past end of buffer (%d + %d > %d)\n", pos, sublen, len);
409e25b118aSDominic Spill return;
410e25b118aSDominic Spill }
411e25b118aSDominic Spill if (sublen == 0) {
412e25b118aSDominic Spill printf("Early return due to 0 length\n");
413e25b118aSDominic Spill return;
414e25b118aSDominic Spill }
415e25b118aSDominic Spill type = buf[pos];
416e25b118aSDominic Spill printf(" Type %02x", type);
417e25b118aSDominic Spill switch (type) {
418e25b118aSDominic Spill case 0x01:
419e25b118aSDominic Spill printf(" (Flags)\n");
420e25b118aSDominic Spill printf(" ");
421e25b118aSDominic Spill for (i = 0; i < 8; ++i)
422e25b118aSDominic Spill printf("%d", buf[pos+1] & (1 << (7-i)) ? 1 : 0);
423e25b118aSDominic Spill printf("\n");
424*ab0dd8d7SMike Ryan for (i = 0; i < 8; ++i) {
425*ab0dd8d7SMike Ryan if (buf[pos+1] & (1 << i)) {
426*ab0dd8d7SMike Ryan printf(" ");
427*ab0dd8d7SMike Ryan printf("%s\n", FLAGS[i]);
428*ab0dd8d7SMike Ryan }
429*ab0dd8d7SMike Ryan }
430*ab0dd8d7SMike Ryan printf("\n");
431e25b118aSDominic Spill break;
43200c7e1b3SMike Ryan case 0x02:
43300c7e1b3SMike Ryan printf(" (16-bit Service UUIDs, more available)\n");
43400c7e1b3SMike Ryan goto print16;
43500c7e1b3SMike Ryan case 0x03:
43600c7e1b3SMike Ryan printf(" (16-bit Service UUIDs) \n");
43700c7e1b3SMike Ryan print16:
43800c7e1b3SMike Ryan if ((sublen - 1) % 2 == 0) {
43900c7e1b3SMike Ryan for (i = 0; i < sublen - 1; i += 2) {
44000c7e1b3SMike Ryan uint16_t *uuid = (uint16_t *)&buf[pos+1+i];
44100c7e1b3SMike Ryan printf(" %04x\n", *uuid);
44200c7e1b3SMike Ryan }
44300c7e1b3SMike Ryan }
44400c7e1b3SMike Ryan break;
44545000095SMike Ryan case 0x06:
44645000095SMike Ryan printf(" (128-bit Service UUIDs, more available)\n");
44745000095SMike Ryan goto print128;
448e25b118aSDominic Spill case 0x07:
449e25b118aSDominic Spill printf(" (128-bit Service UUIDs)\n");
45045000095SMike Ryan print128:
451e25b118aSDominic Spill if ((sublen - 1) % 16 == 0) {
452e25b118aSDominic Spill uint8_t uuid[16];
453e25b118aSDominic Spill for (i = 0; i < sublen - 1; ++i) {
454e25b118aSDominic Spill uuid[15 - (i % 16)] = buf[pos+1+i];
455e25b118aSDominic Spill if ((i & 15) == 15) {
456e25b118aSDominic Spill printf(" ");
457e25b118aSDominic Spill _dump_uuid(uuid);
458e25b118aSDominic Spill printf("\n");
459e25b118aSDominic Spill }
460e25b118aSDominic Spill }
461e25b118aSDominic Spill }
462e25b118aSDominic Spill else {
463e25b118aSDominic Spill printf("Wrong length (%d, must be divisible by 16)\n", sublen-1);
464e25b118aSDominic Spill }
465e25b118aSDominic Spill break;
466e25b118aSDominic Spill case 0x09:
467e25b118aSDominic Spill printf(" (Complete Local Name)\n");
468e25b118aSDominic Spill printf(" ");
469e25b118aSDominic Spill for (i = 1; i < sublen; ++i)
470e25b118aSDominic Spill printf("%c", isprint(buf[pos+i]) ? buf[pos+i] : '.');
471e25b118aSDominic Spill printf("\n");
472e25b118aSDominic Spill break;
473e25b118aSDominic Spill case 0x0a:
474e25b118aSDominic Spill printf(" (Tx Power Level)\n");
475e25b118aSDominic Spill printf(" ");
476e25b118aSDominic Spill if (sublen-1 == 1) {
477e25b118aSDominic Spill cval = (char *)&buf[pos+1];
478e25b118aSDominic Spill printf("%d dBm\n", *cval);
479e25b118aSDominic Spill } else {
480e25b118aSDominic Spill printf("Wrong length (%d, should be 1)\n", sublen-1);
481e25b118aSDominic Spill }
482e25b118aSDominic Spill break;
483e25b118aSDominic Spill case 0x12:
484e25b118aSDominic Spill printf(" (Slave Connection Interval Range)\n");
485e25b118aSDominic Spill printf(" ");
486e25b118aSDominic Spill if (sublen-1 == 4) {
487e25b118aSDominic Spill val = (buf[pos+2] << 8) | buf[pos+1];
488e25b118aSDominic Spill printf("(%0.2f, ", val * 1.25);
489e25b118aSDominic Spill val = (buf[pos+4] << 8) | buf[pos+3];
490e25b118aSDominic Spill printf("%0.2f) ms\n", val * 1.25);
491e25b118aSDominic Spill }
492e25b118aSDominic Spill else {
493e25b118aSDominic Spill printf("Wrong length (%d, should be 4)\n", sublen-1);
494e25b118aSDominic Spill }
495e25b118aSDominic Spill break;
496e25b118aSDominic Spill case 0x16:
497e25b118aSDominic Spill printf(" (Service Data)\n");
498e25b118aSDominic Spill printf(" ");
499e25b118aSDominic Spill if (sublen-1 >= 2) {
500e25b118aSDominic Spill val = (buf[pos+2] << 8) | buf[pos+1];
501e25b118aSDominic Spill printf("UUID: %02x", val);
502e25b118aSDominic Spill if (sublen-1 > 2) {
503e25b118aSDominic Spill printf(", Additional:");
504e25b118aSDominic Spill for (i = 3; i < sublen; ++i)
505e25b118aSDominic Spill printf(" %02x", buf[pos+i]);
506e25b118aSDominic Spill }
507e25b118aSDominic Spill printf("\n");
508e25b118aSDominic Spill }
509e25b118aSDominic Spill else {
510e25b118aSDominic Spill printf("Wrong length (%d, should be >= 2)\n", sublen-1);
511e25b118aSDominic Spill }
512e25b118aSDominic Spill break;
513f25ef1fbSMike Ryan case 0xff:
514f25ef1fbSMike Ryan printf(" (Manufacturer Specific Data)\n");
515f25ef1fbSMike Ryan printf(" ");
516f25ef1fbSMike Ryan if (sublen - 1 >= 2) {
517f25ef1fbSMike Ryan uint16_t company = (buf[pos+2] << 8) | buf[pos+1];
518f25ef1fbSMike Ryan printf("Company: %s\n", bt_compidtostr(company));
519f25ef1fbSMike Ryan printf(" ");
520f25ef1fbSMike Ryan printf("Data:");
521f25ef1fbSMike Ryan for (i = 3; i < sublen; ++i)
522f25ef1fbSMike Ryan printf(" %02x", buf[pos+i]);
523f25ef1fbSMike Ryan printf("\n");
524f25ef1fbSMike Ryan }
525f25ef1fbSMike Ryan else {
526f25ef1fbSMike Ryan printf("Wrong length (%d, should be >= 2)\n", sublen-1);
527f25ef1fbSMike Ryan }
528f25ef1fbSMike Ryan break;
529e25b118aSDominic Spill default:
530e25b118aSDominic Spill printf("\n");
531e25b118aSDominic Spill printf(" ");
532e25b118aSDominic Spill for (i = 1; i < sublen; ++i)
533e25b118aSDominic Spill printf(" %02x", buf[pos+i]);
534e25b118aSDominic Spill printf("\n");
535e25b118aSDominic Spill }
536e25b118aSDominic Spill pos += sublen;
537e25b118aSDominic Spill }
538e25b118aSDominic Spill }
539e25b118aSDominic Spill
lell_print(const lell_packet * pkt)5408f3e7eeaSChristopher Kilgour void lell_print(const lell_packet *pkt)
5418f3e7eeaSChristopher Kilgour {
542387b6603SIvan Krasin int i, opcode;
5438f3e7eeaSChristopher Kilgour if (lell_packet_is_data(pkt)) {
5448f3e7eeaSChristopher Kilgour int llid = pkt->symbols[4] & 0x3;
545e25b118aSDominic Spill static const char *llid_str[] = {
546e25b118aSDominic Spill "Reserved",
547e25b118aSDominic Spill "LL Data PDU / empty or L2CAP continuation",
548e25b118aSDominic Spill "LL Data PDU / L2CAP start",
549e25b118aSDominic Spill "LL Control PDU",
550e25b118aSDominic Spill };
551e25b118aSDominic Spill
5528f3e7eeaSChristopher Kilgour printf("Data / AA %08x (%s) / %2d bytes\n", pkt->access_address,
5538f3e7eeaSChristopher Kilgour pkt->flags.as_bits.access_address_ok ? "valid" : "invalid",
5548f3e7eeaSChristopher Kilgour pkt->length);
5558f3e7eeaSChristopher Kilgour printf(" Channel Index: %d\n", pkt->channel_idx);
556e25b118aSDominic Spill printf(" LLID: %d / %s\n", llid, llid_str[llid]);
5578f3e7eeaSChristopher Kilgour printf(" NESN: %d SN: %d MD: %d\n", (pkt->symbols[4] >> 2) & 1,
5588f3e7eeaSChristopher Kilgour (pkt->symbols[4] >> 3) & 1,
5598f3e7eeaSChristopher Kilgour (pkt->symbols[4] >> 4) & 1);
560387b6603SIvan Krasin switch (llid) {
561387b6603SIvan Krasin case 3: // LL Control PDU
5628f3e7eeaSChristopher Kilgour opcode = pkt->symbols[6];
563387b6603SIvan Krasin static const char *opcode_str[] = {
564387b6603SIvan Krasin "LL_CONNECTION_UPDATE_REQ",
565387b6603SIvan Krasin "LL_CHANNEL_MAP_REQ",
566387b6603SIvan Krasin "LL_TERMINATE_IND",
567387b6603SIvan Krasin "LL_ENC_REQ",
568387b6603SIvan Krasin "LL_ENC_RSP",
569387b6603SIvan Krasin "LL_START_ENC_REQ",
570387b6603SIvan Krasin "LL_START_ENC_RSP",
571387b6603SIvan Krasin "LL_UNKNOWN_RSP",
572387b6603SIvan Krasin "LL_FEATURE_REQ",
573387b6603SIvan Krasin "LL_FEATURE_RSP",
574387b6603SIvan Krasin "LL_PAUSE_ENC_REQ",
575387b6603SIvan Krasin "LL_PAUSE_ENC_RSP",
576387b6603SIvan Krasin "LL_VERSION_IND",
577387b6603SIvan Krasin "LL_REJECT_IND",
578b3394904SMike Ryan "LL_SLAVE_FEATURE_REQ",
579b3394904SMike Ryan "LL_CONNECTION_PARAM_REQ",
580b3394904SMike Ryan "LL_CONNECTION_PARAM_RSP",
581b3394904SMike Ryan "LL_REJECT_IND_EXT",
582b3394904SMike Ryan "LL_PING_REQ",
583b3394904SMike Ryan "LL_PING_RSP",
584387b6603SIvan Krasin "Reserved for Future Use",
585387b6603SIvan Krasin };
586ba100f3dSMike Ryan printf(" Opcode: %d / %s\n", opcode, opcode_str[(opcode<0x14)?opcode:0x14]);
587387b6603SIvan Krasin break;
588387b6603SIvan Krasin default:
589387b6603SIvan Krasin break;
590387b6603SIvan Krasin }
591e25b118aSDominic Spill } else {
5928f3e7eeaSChristopher Kilgour printf("Advertising / AA %08x (%s)/ %2d bytes\n", pkt->access_address,
5938f3e7eeaSChristopher Kilgour pkt->flags.as_bits.access_address_ok ? "valid" : "invalid",
5948f3e7eeaSChristopher Kilgour pkt->length);
5958f3e7eeaSChristopher Kilgour printf(" Channel Index: %d\n", pkt->channel_idx);
5968f3e7eeaSChristopher Kilgour printf(" Type: %s\n", lell_get_adv_type_str(pkt));
597e25b118aSDominic Spill
5988f3e7eeaSChristopher Kilgour switch(pkt->adv_type) {
599e25b118aSDominic Spill case ADV_IND:
600ee0d4df0SMike Ryan case ADV_NONCONN_IND:
601ee0d4df0SMike Ryan case ADV_SCAN_IND:
6028f3e7eeaSChristopher Kilgour _dump_addr("AdvA: ", pkt->symbols, 6, pkt->adv_tx_add);
6038f3e7eeaSChristopher Kilgour if (pkt->length-6 > 0) {
604e25b118aSDominic Spill printf(" AdvData:");
6058f3e7eeaSChristopher Kilgour for (i = 0; i < pkt->length - 6; ++i)
6068f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[12+i]);
607e25b118aSDominic Spill printf("\n");
6088f3e7eeaSChristopher Kilgour _dump_scan_rsp_data(&pkt->symbols[12], pkt->length-6);
609e25b118aSDominic Spill }
610e25b118aSDominic Spill break;
611ee0d4df0SMike Ryan case ADV_DIRECT_IND:
612ee0d4df0SMike Ryan _dump_addr("AdvA: ", pkt->symbols, 6, pkt->adv_tx_add);
613ee0d4df0SMike Ryan _dump_addr("InitA: ", pkt->symbols, 12, pkt->adv_rx_add);
614ee0d4df0SMike Ryan break;
615e25b118aSDominic Spill case SCAN_REQ:
6168f3e7eeaSChristopher Kilgour _dump_addr("ScanA: ", pkt->symbols, 6, pkt->adv_tx_add);
6178f3e7eeaSChristopher Kilgour _dump_addr("AdvA: ", pkt->symbols, 12, pkt->adv_rx_add);
618e25b118aSDominic Spill break;
619e25b118aSDominic Spill case SCAN_RSP:
6208f3e7eeaSChristopher Kilgour _dump_addr("AdvA: ", pkt->symbols, 6, pkt->adv_tx_add);
621e25b118aSDominic Spill printf(" ScanRspData:");
6228f3e7eeaSChristopher Kilgour for (i = 0; i < pkt->length - 6; ++i)
6238f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[12+i]);
624e25b118aSDominic Spill printf("\n");
6258f3e7eeaSChristopher Kilgour _dump_scan_rsp_data(&pkt->symbols[12], pkt->length-6);
626e25b118aSDominic Spill break;
627e25b118aSDominic Spill case CONNECT_REQ:
6288f3e7eeaSChristopher Kilgour _dump_addr("InitA: ", pkt->symbols, 6, pkt->adv_tx_add);
6298f3e7eeaSChristopher Kilgour _dump_addr("AdvA: ", pkt->symbols, 12, pkt->adv_rx_add);
6308f3e7eeaSChristopher Kilgour _dump_32("AA: ", pkt->symbols, 18);
6318f3e7eeaSChristopher Kilgour _dump_24("CRCInit: ", pkt->symbols, 22);
6328f3e7eeaSChristopher Kilgour _dump_8("WinSize: ", pkt->symbols, 25);
6338f3e7eeaSChristopher Kilgour _dump_16("WinOffset: ", pkt->symbols, 26);
6348f3e7eeaSChristopher Kilgour _dump_16("Interval: ", pkt->symbols, 28);
6358f3e7eeaSChristopher Kilgour _dump_16("Latency: ", pkt->symbols, 30);
6368f3e7eeaSChristopher Kilgour _dump_16("Timeout: ", pkt->symbols, 32);
637e25b118aSDominic Spill
638e25b118aSDominic Spill printf(" ChM:");
639e25b118aSDominic Spill for (i = 0; i < 5; ++i)
6408f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[34+i]);
641e25b118aSDominic Spill printf("\n");
642e25b118aSDominic Spill
6438f3e7eeaSChristopher Kilgour printf(" Hop: %d\n", pkt->symbols[39] & 0x1f);
644e25b118aSDominic Spill printf(" SCA: %d, %s\n",
6458f3e7eeaSChristopher Kilgour pkt->symbols[39] >> 5,
6468f3e7eeaSChristopher Kilgour CONNECT_SCA[pkt->symbols[39] >> 5]);
647e25b118aSDominic Spill break;
648e25b118aSDominic Spill }
649e25b118aSDominic Spill }
650e25b118aSDominic Spill
651e25b118aSDominic Spill printf("\n");
652e25b118aSDominic Spill printf(" Data: ");
6538f3e7eeaSChristopher Kilgour for (i = 6; i < 6 + pkt->length; ++i)
6548f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[i]);
655e25b118aSDominic Spill printf("\n");
656e25b118aSDominic Spill
657e25b118aSDominic Spill printf(" CRC: ");
658e25b118aSDominic Spill for (i = 0; i < 3; ++i)
6598f3e7eeaSChristopher Kilgour printf(" %02x", pkt->symbols[6 + pkt->length + i]);
660e25b118aSDominic Spill printf("\n");
661e25b118aSDominic Spill }
662