1e25b118aSDominic Spill /* -*- c -*- */ 2e25b118aSDominic Spill /* 3e25b118aSDominic Spill * Copyright 2007 - 2013 Dominic Spill, Michael Ossmann, Will Code 4e25b118aSDominic Spill * 5e25b118aSDominic Spill * This file is part of libbtbb 6e25b118aSDominic Spill * 7e25b118aSDominic Spill * This program is free software; you can redistribute it and/or modify 8e25b118aSDominic Spill * it under the terms of the GNU General Public License as published by 9e25b118aSDominic Spill * the Free Software Foundation; either version 2, or (at your option) 10e25b118aSDominic Spill * any later version. 11e25b118aSDominic Spill * 12e25b118aSDominic Spill * This program is distributed in the hope that it will be useful, 13e25b118aSDominic Spill * but WITHOUT ANY WARRANTY; without even the implied warranty of 14e25b118aSDominic Spill * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15e25b118aSDominic Spill * GNU General Public License for more details. 16e25b118aSDominic Spill * 17e25b118aSDominic Spill * You should have received a copy of the GNU General Public License 18e25b118aSDominic Spill * along with libbtbb; see the file COPYING. If not, write to 19e25b118aSDominic Spill * the Free Software Foundation, Inc., 51 Franklin Street, 20e25b118aSDominic Spill * Boston, MA 02110-1301, USA. 21e25b118aSDominic Spill */ 22e25b118aSDominic Spill 23e25b118aSDominic Spill #include "bluetooth_packet.h" 24e25b118aSDominic Spill #include "bluetooth_piconet.h" 25e25b118aSDominic Spill #include "uthash.h" 26e25b118aSDominic Spill #include <stdlib.h> 27e25b118aSDominic Spill #include <stdio.h> 28e25b118aSDominic Spill 29e25b118aSDominic Spill int perm_table_initialized = 0; 30e25b118aSDominic Spill char perm_table[0x20][0x20][0x200]; 31e25b118aSDominic Spill 32f1965e4dSHannes Ellinger /* count the number of 1 bits in a uint64_t */ 33f1965e4dSHannes Ellinger int count_bits(uint8_t n) 34f1965e4dSHannes Ellinger { 35f1965e4dSHannes Ellinger int i = 0; 36f1965e4dSHannes Ellinger for (i = 0; n != 0; i++) 37f1965e4dSHannes Ellinger n &= n - 1; 38f1965e4dSHannes Ellinger return i; 39f1965e4dSHannes Ellinger } 40f1965e4dSHannes Ellinger 41e25b118aSDominic Spill btbb_piconet * 42e25b118aSDominic Spill btbb_piconet_new(void) 43e25b118aSDominic Spill { 44e25b118aSDominic Spill btbb_piconet *pn = (btbb_piconet *)calloc(1, sizeof(btbb_piconet)); 45e25b118aSDominic Spill pn->refcount = 1; 46e25b118aSDominic Spill return pn; 47e25b118aSDominic Spill } 48e25b118aSDominic Spill 49e25b118aSDominic Spill void 50e25b118aSDominic Spill btbb_piconet_ref(btbb_piconet *pn) 51e25b118aSDominic Spill { 52e25b118aSDominic Spill pn->refcount++; 53e25b118aSDominic Spill } 54e25b118aSDominic Spill 55e25b118aSDominic Spill void 56e25b118aSDominic Spill btbb_piconet_unref(btbb_piconet *pn) 57e25b118aSDominic Spill { 58e25b118aSDominic Spill pn->refcount--; 59e25b118aSDominic Spill if (pn->refcount == 0) 60e25b118aSDominic Spill free(pn); 61e25b118aSDominic Spill } 62e25b118aSDominic Spill 63647977deSDominic Spill /* A bit of a hack? to set survey mode */ 64647977deSDominic Spill static int survey_mode = 0; 65647977deSDominic Spill int btbb_init_survey() { 66647977deSDominic Spill survey_mode = 1; 67647977deSDominic Spill return 0; 68647977deSDominic Spill } 69647977deSDominic Spill 70e25b118aSDominic Spill void btbb_init_piconet(btbb_piconet *pn, uint32_t lap) 71e25b118aSDominic Spill { 72e25b118aSDominic Spill pn->LAP = lap; 73e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_LAP_VALID, 1); 74e25b118aSDominic Spill } 75e25b118aSDominic Spill 76e25b118aSDominic Spill void btbb_piconet_set_flag(btbb_piconet *pn, int flag, int val) 77e25b118aSDominic Spill { 78e25b118aSDominic Spill uint32_t mask = 1L << flag; 79e25b118aSDominic Spill pn->flags &= ~mask; 80e25b118aSDominic Spill if (val) 81e25b118aSDominic Spill pn->flags |= mask; 82e25b118aSDominic Spill } 83e25b118aSDominic Spill 848f3e7eeaSChristopher Kilgour int btbb_piconet_get_flag(const btbb_piconet *pn, const int flag) 85e25b118aSDominic Spill { 86e25b118aSDominic Spill uint32_t mask = 1L << flag; 87e25b118aSDominic Spill return ((pn->flags & mask) != 0); 88e25b118aSDominic Spill } 89e25b118aSDominic Spill 90e25b118aSDominic Spill void btbb_piconet_set_uap(btbb_piconet *pn, uint8_t uap) 91e25b118aSDominic Spill { 92e25b118aSDominic Spill pn->UAP = uap; 93e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); 94e25b118aSDominic Spill } 95e25b118aSDominic Spill 968f3e7eeaSChristopher Kilgour uint8_t btbb_piconet_get_uap(const btbb_piconet *pn) 97e25b118aSDominic Spill { 98e25b118aSDominic Spill return pn->UAP; 99e25b118aSDominic Spill } 100e25b118aSDominic Spill 1018f3e7eeaSChristopher Kilgour uint32_t btbb_piconet_get_lap(const btbb_piconet *pn) 102e25b118aSDominic Spill { 103e25b118aSDominic Spill return pn->LAP; 104e25b118aSDominic Spill } 105e25b118aSDominic Spill 1068f3e7eeaSChristopher Kilgour uint16_t btbb_piconet_get_nap(const btbb_piconet *pn) 107e25b118aSDominic Spill { 108e25b118aSDominic Spill return pn->NAP; 109e25b118aSDominic Spill } 110e25b118aSDominic Spill 11150438040SDominic Spill uint64_t btbb_piconet_get_bdaddr(const btbb_piconet *pn) 11250438040SDominic Spill { 11350438040SDominic Spill return ((uint64_t) pn->NAP) << 32 | pn->UAP << 24 | pn->LAP; 11450438040SDominic Spill } 11550438040SDominic Spill 1168f3e7eeaSChristopher Kilgour int btbb_piconet_get_clk_offset(const btbb_piconet *pn) 117e25b118aSDominic Spill { 118e25b118aSDominic Spill return pn->clk_offset; 119e25b118aSDominic Spill } 120e25b118aSDominic Spill 121e25b118aSDominic Spill void btbb_piconet_set_clk_offset(btbb_piconet *pn, int clk_offset) 122e25b118aSDominic Spill { 123e25b118aSDominic Spill pn->clk_offset = clk_offset; 124e25b118aSDominic Spill } 125e25b118aSDominic Spill 126e25b118aSDominic Spill void btbb_piconet_set_afh_map(btbb_piconet *pn, uint8_t *afh_map) { 127e25b118aSDominic Spill int i; 128f1965e4dSHannes Ellinger pn->used_channels = 0; 129e25b118aSDominic Spill // DGS: Unroll this? 130f1965e4dSHannes Ellinger for(i=0; i<10; i++) { 131e25b118aSDominic Spill pn->afh_map[i] = afh_map[i]; 132f1965e4dSHannes Ellinger pn->used_channels += count_bits(pn->afh_map[i]); 133f1965e4dSHannes Ellinger } 134d73cdf28SDominic Spill if(btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) 135f1965e4dSHannes Ellinger get_hop_pattern(pn); 136e25b118aSDominic Spill } 137e25b118aSDominic Spill 138e25b118aSDominic Spill uint8_t *btbb_piconet_get_afh_map(btbb_piconet *pn) { 139e25b118aSDominic Spill return pn->afh_map; 140e25b118aSDominic Spill } 141e25b118aSDominic Spill 142*75358bb0SHannes Ellinger uint8_t btbb_piconet_set_channel_seen(btbb_piconet *pn, uint8_t channel) 143e25b118aSDominic Spill { 144f1965e4dSHannes Ellinger if(!(pn->afh_map[channel/8] & 0x1 << (channel % 8))) { 145e25b118aSDominic Spill pn->afh_map[channel/8] |= 0x1 << (channel % 8); 146f1965e4dSHannes Ellinger pn->used_channels++; 147647977deSDominic Spill if(btbb_piconet_get_flag(pn, BTBB_UAP_VALID) && !survey_mode) 148f1965e4dSHannes Ellinger get_hop_pattern(pn); 149*75358bb0SHannes Ellinger return 1; 150f1965e4dSHannes Ellinger } 151*75358bb0SHannes Ellinger return 0; 152*75358bb0SHannes Ellinger } 153*75358bb0SHannes Ellinger 154*75358bb0SHannes Ellinger uint8_t btbb_piconet_clear_channel_seen(btbb_piconet *pn, uint8_t channel) 155*75358bb0SHannes Ellinger { 156*75358bb0SHannes Ellinger if((pn->afh_map[channel/8] & 0x1 << (channel % 8))) { 157*75358bb0SHannes Ellinger pn->afh_map[channel/8] &= ~(0x1 << (channel % 8)); 158*75358bb0SHannes Ellinger pn->used_channels--; 159*75358bb0SHannes Ellinger return 1; 160*75358bb0SHannes Ellinger } 161*75358bb0SHannes Ellinger return 0; 162f1965e4dSHannes Ellinger } 163f1965e4dSHannes Ellinger 164f1965e4dSHannes Ellinger uint8_t btbb_piconet_get_channel_seen(btbb_piconet *pn, uint8_t channel) 165f1965e4dSHannes Ellinger { 1665d9f832cSMike Ryan if(channel < BT_NUM_CHANNELS) 167f1965e4dSHannes Ellinger return ( pn->afh_map[channel/8] & (1 << (channel % 8)) ) != 0; 168f1965e4dSHannes Ellinger else 169f1965e4dSHannes Ellinger return 1; 170e25b118aSDominic Spill } 171e25b118aSDominic Spill 172e25b118aSDominic Spill /* do all the precalculation that can be done before knowing the address */ 173e25b118aSDominic Spill void precalc(btbb_piconet *pn) 174e25b118aSDominic Spill { 175f1965e4dSHannes Ellinger int i = 0; 176f1965e4dSHannes Ellinger int j = 0; 177f1965e4dSHannes Ellinger int chan; 178e25b118aSDominic Spill 179e25b118aSDominic Spill /* populate frequency register bank*/ 180f1965e4dSHannes Ellinger for (i = 0; i < BT_NUM_CHANNELS; i++) { 181f1965e4dSHannes Ellinger 182f1965e4dSHannes Ellinger /* AFH is used, hopping sequence contains only used channels */ 183f1965e4dSHannes Ellinger if(btbb_piconet_get_flag(pn, BTBB_IS_AFH)) { 184f1965e4dSHannes Ellinger chan = (i * 2) % BT_NUM_CHANNELS; 185f1965e4dSHannes Ellinger if(btbb_piconet_get_channel_seen(pn, chan)) 186f1965e4dSHannes Ellinger pn->bank[j++] = chan; 187f1965e4dSHannes Ellinger } 188f1965e4dSHannes Ellinger 189f1965e4dSHannes Ellinger /* all channels are used */ 190f1965e4dSHannes Ellinger else { 191e25b118aSDominic Spill pn->bank[i] = ((i * 2) % BT_NUM_CHANNELS); 192f1965e4dSHannes Ellinger } 193f1965e4dSHannes Ellinger } 194e25b118aSDominic Spill /* actual frequency is 2402 + pn->bank[i] MHz */ 195e25b118aSDominic Spill 196e25b118aSDominic Spill } 197e25b118aSDominic Spill 198e25b118aSDominic Spill /* do precalculation that requires the address */ 199e25b118aSDominic Spill void address_precalc(int address, btbb_piconet *pn) 200e25b118aSDominic Spill { 201e25b118aSDominic Spill /* precalculate some of single_hop()/gen_hop()'s variables */ 202e25b118aSDominic Spill pn->a1 = (address >> 23) & 0x1f; 203e25b118aSDominic Spill pn->b = (address >> 19) & 0x0f; 204e25b118aSDominic Spill pn->c1 = ((address >> 4) & 0x10) + 205e25b118aSDominic Spill ((address >> 3) & 0x08) + 206e25b118aSDominic Spill ((address >> 2) & 0x04) + 207e25b118aSDominic Spill ((address >> 1) & 0x02) + 208e25b118aSDominic Spill (address & 0x01); 209e25b118aSDominic Spill pn->d1 = (address >> 10) & 0x1ff; 210e25b118aSDominic Spill pn->e = ((address >> 7) & 0x40) + 211e25b118aSDominic Spill ((address >> 6) & 0x20) + 212e25b118aSDominic Spill ((address >> 5) & 0x10) + 213e25b118aSDominic Spill ((address >> 4) & 0x08) + 214e25b118aSDominic Spill ((address >> 3) & 0x04) + 215e25b118aSDominic Spill ((address >> 2) & 0x02) + 216e25b118aSDominic Spill ((address >> 1) & 0x01); 217e25b118aSDominic Spill } 218e25b118aSDominic Spill 219e25b118aSDominic Spill #ifdef WC4 220e25b118aSDominic Spill /* These are optimization experiments, which don't help much for 221e25b118aSDominic Spill * x86. Hold on to them to see whether they're useful on ARM. */ 222e25b118aSDominic Spill 223e25b118aSDominic Spill #ifdef NEVER 224e25b118aSDominic Spill #define BUTTERFLY(z,p,c,a,b) \ 225e25b118aSDominic Spill if ( ((p&(1<<c))!=0) & (((z&(1<<a))!=0) ^ ((z&(1<<b))!=0)) ) \ 226e25b118aSDominic Spill z ^= ((1<<a)|(1<<b)) 227e25b118aSDominic Spill #endif 228e25b118aSDominic Spill 229e25b118aSDominic Spill #define BUTTERFLY(z,p,c,a,b) \ 230e25b118aSDominic Spill if ( (((z>>a)^(z>>b)) & (p>>c)) & 0x1 ) \ 231e25b118aSDominic Spill z ^= ((1<<a)|(1<<b)) 232e25b118aSDominic Spill 233e25b118aSDominic Spill int perm5(int z, int p_high, int p_low) 234e25b118aSDominic Spill { 235e25b118aSDominic Spill int p = (p_high << 5) | p_low; 236e25b118aSDominic Spill BUTTERFLY(z,p,13,1,2); 237e25b118aSDominic Spill BUTTERFLY(z,p,12,0,3); 238e25b118aSDominic Spill BUTTERFLY(z,p,11,1,3); 239e25b118aSDominic Spill BUTTERFLY(z,p,10,2,4); 240e25b118aSDominic Spill BUTTERFLY(z,p, 9,0,3); 241e25b118aSDominic Spill BUTTERFLY(z,p, 8,1,4); 242e25b118aSDominic Spill BUTTERFLY(z,p, 7,3,4); 243e25b118aSDominic Spill BUTTERFLY(z,p, 6,0,2); 244e25b118aSDominic Spill BUTTERFLY(z,p, 5,1,3); 245e25b118aSDominic Spill BUTTERFLY(z,p, 4,0,4); 246e25b118aSDominic Spill BUTTERFLY(z,p, 3,3,4); 247e25b118aSDominic Spill BUTTERFLY(z,p, 2,1,2); 248e25b118aSDominic Spill BUTTERFLY(z,p, 1,2,3); 249e25b118aSDominic Spill BUTTERFLY(z,p, 0,0,1); 250e25b118aSDominic Spill 251e25b118aSDominic Spill return z; 252e25b118aSDominic Spill } 253e25b118aSDominic Spill #endif // WC4 254e25b118aSDominic Spill 255e25b118aSDominic Spill /* 5 bit permutation */ 256e25b118aSDominic Spill /* assumes z is constrained to 5 bits, p_high to 5 bits, p_low to 9 bits */ 257e25b118aSDominic Spill int perm5(int z, int p_high, int p_low) 258e25b118aSDominic Spill { 259e25b118aSDominic Spill int i, tmp, output, z_bit[5], p[14]; 260e25b118aSDominic Spill int index1[] = {0, 2, 1, 3, 0, 1, 0, 3, 1, 0, 2, 1, 0, 1}; 261e25b118aSDominic Spill int index2[] = {1, 3, 2, 4, 4, 3, 2, 4, 4, 3, 4, 3, 3, 2}; 262e25b118aSDominic Spill 263e25b118aSDominic Spill /* bits of p_low and p_high are control signals */ 264e25b118aSDominic Spill for (i = 0; i < 9; i++) 265e25b118aSDominic Spill p[i] = (p_low >> i) & 0x01; 266e25b118aSDominic Spill for (i = 0; i < 5; i++) 267e25b118aSDominic Spill p[i+9] = (p_high >> i) & 0x01; 268e25b118aSDominic Spill 269e25b118aSDominic Spill /* bit swapping will be easier with an array of bits */ 270e25b118aSDominic Spill for (i = 0; i < 5; i++) 271e25b118aSDominic Spill z_bit[i] = (z >> i) & 0x01; 272e25b118aSDominic Spill 273e25b118aSDominic Spill /* butterfly operations */ 274e25b118aSDominic Spill for (i = 13; i >= 0; i--) { 275e25b118aSDominic Spill /* swap bits according to index arrays if control signal tells us to */ 276e25b118aSDominic Spill if (p[i]) { 277e25b118aSDominic Spill tmp = z_bit[index1[i]]; 278e25b118aSDominic Spill z_bit[index1[i]] = z_bit[index2[i]]; 279e25b118aSDominic Spill z_bit[index2[i]] = tmp; 280e25b118aSDominic Spill } 281e25b118aSDominic Spill } 282e25b118aSDominic Spill 283e25b118aSDominic Spill /* reconstruct output from rearranged bits */ 284e25b118aSDominic Spill output = 0; 285e25b118aSDominic Spill for (i = 0; i < 5; i++) 286e25b118aSDominic Spill output += z_bit[i] << i; 287e25b118aSDominic Spill 288e25b118aSDominic Spill return(output); 289e25b118aSDominic Spill } 290e25b118aSDominic Spill 291e25b118aSDominic Spill void perm_table_init(void) 292e25b118aSDominic Spill { 293e25b118aSDominic Spill /* populate perm_table for all possible inputs */ 294e25b118aSDominic Spill int z, p_high, p_low; 295e25b118aSDominic Spill for (z = 0; z < 0x20; z++) 296e25b118aSDominic Spill for (p_high = 0; p_high < 0x20; p_high++) 297e25b118aSDominic Spill for (p_low = 0; p_low < 0x200; p_low++) 298e25b118aSDominic Spill perm_table[z][p_high][p_low] = perm5(z, p_high, p_low); 299e25b118aSDominic Spill } 300e25b118aSDominic Spill 301e25b118aSDominic Spill /* drop-in replacement for perm5() using lookup table */ 3021e7f449bSDominic Spill int fast_perm(int z, int p_high, int p_low) 303e25b118aSDominic Spill { 304e25b118aSDominic Spill if (!perm_table_initialized) { 305e25b118aSDominic Spill perm_table_init(); 306e25b118aSDominic Spill perm_table_initialized = 1; 307e25b118aSDominic Spill } 308e25b118aSDominic Spill 309e25b118aSDominic Spill return(perm_table[z][p_high][p_low]); 310e25b118aSDominic Spill } 311e25b118aSDominic Spill 312e25b118aSDominic Spill /* generate the complete hopping sequence */ 313e25b118aSDominic Spill static void gen_hops(btbb_piconet *pn) 314e25b118aSDominic Spill { 315114033a2SHannes Ellinger /* a, b, c, d, e, f, x, y1, y2 are variable names used in section 2.6 of the spec */ 316114033a2SHannes Ellinger /* b is already defined */ 317114033a2SHannes Ellinger /* e is already defined */ 318114033a2SHannes Ellinger int a, c, d, x; 319114033a2SHannes Ellinger uint32_t base_f, f, f_dash; 320114033a2SHannes Ellinger int h, i, j, k, c_flipped, perm_in, perm_out; 321e25b118aSDominic Spill 322114033a2SHannes Ellinger /* sequence index = clock >> 1 */ 323114033a2SHannes Ellinger /* (hops only happen at every other clock value) */ 324114033a2SHannes Ellinger int index = 0; 325114033a2SHannes Ellinger base_f = 0; 326114033a2SHannes Ellinger f = 0; 327114033a2SHannes Ellinger f_dash = 0; 328e25b118aSDominic Spill 329114033a2SHannes Ellinger /* nested loops for optimization (not recalculating every variable with every clock tick) */ 330114033a2SHannes Ellinger for (h = 0; h < 0x04; h++) { /* clock bits 26-27 */ 331114033a2SHannes Ellinger for (i = 0; i < 0x20; i++) { /* clock bits 21-25 */ 332114033a2SHannes Ellinger a = pn->a1 ^ i; 333114033a2SHannes Ellinger for (j = 0; j < 0x20; j++) { /* clock bits 16-20 */ 334114033a2SHannes Ellinger c = pn->c1 ^ j; 335114033a2SHannes Ellinger c_flipped = c ^ 0x1f; 336114033a2SHannes Ellinger for (k = 0; k < 0x200; k++) { /* clock bits 7-15 */ 337114033a2SHannes Ellinger d = pn->d1 ^ k; 338114033a2SHannes Ellinger for (x = 0; x < 0x20; x++) { /* clock bits 2-6 */ 339114033a2SHannes Ellinger perm_in = ((x + a) % 32) ^ pn->b; 340f1965e4dSHannes Ellinger 341114033a2SHannes Ellinger /* y1 (clock bit 1) = 0, y2 = 0 */ 342114033a2SHannes Ellinger perm_out = fast_perm(perm_in, c, d); 343114033a2SHannes Ellinger if (btbb_piconet_get_flag(pn, BTBB_IS_AFH)) 344114033a2SHannes Ellinger pn->sequence[index] = pn->bank[(perm_out + pn->e + f_dash) % pn->used_channels]; 345114033a2SHannes Ellinger else 346114033a2SHannes Ellinger pn->sequence[index] = pn->bank[(perm_out + pn->e + f) % BT_NUM_CHANNELS]; 347f1965e4dSHannes Ellinger 348114033a2SHannes Ellinger /* y1 (clock bit 1) = 1, y2 = 32 */ 349114033a2SHannes Ellinger perm_out = fast_perm(perm_in, c_flipped, d); 350114033a2SHannes Ellinger if (btbb_piconet_get_flag(pn, BTBB_IS_AFH)) 351114033a2SHannes Ellinger pn->sequence[index + 1] = pn->bank[(perm_out + pn->e + f_dash + 32) % pn->used_channels]; 352114033a2SHannes Ellinger else 353114033a2SHannes Ellinger pn->sequence[index + 1] = pn->bank[(perm_out + pn->e + f + 32) % BT_NUM_CHANNELS]; 354114033a2SHannes Ellinger 355114033a2SHannes Ellinger index += 2; 356114033a2SHannes Ellinger } 357114033a2SHannes Ellinger base_f += 16; 358114033a2SHannes Ellinger f = base_f % BT_NUM_CHANNELS; 359114033a2SHannes Ellinger f_dash = f % pn->used_channels; 360114033a2SHannes Ellinger } 361114033a2SHannes Ellinger } 362114033a2SHannes Ellinger } 363e25b118aSDominic Spill } 364e25b118aSDominic Spill } 365e25b118aSDominic Spill 366e25b118aSDominic Spill /* Function to calculate piconet hopping patterns and add to hash map */ 367e25b118aSDominic Spill void gen_hop_pattern(btbb_piconet *pn) 368e25b118aSDominic Spill { 369e25b118aSDominic Spill printf("\nCalculating complete hopping sequence.\n"); 370e25b118aSDominic Spill /* this holds the entire hopping sequence */ 371e25b118aSDominic Spill pn->sequence = (char*) malloc(SEQUENCE_LENGTH); 372e25b118aSDominic Spill 373e25b118aSDominic Spill precalc(pn); 374e25b118aSDominic Spill address_precalc(((pn->UAP<<24) | pn->LAP) & 0xfffffff, pn); 375e25b118aSDominic Spill gen_hops(pn); 376e25b118aSDominic Spill 377e25b118aSDominic Spill printf("Hopping sequence calculated.\n"); 378e25b118aSDominic Spill } 379e25b118aSDominic Spill 380e25b118aSDominic Spill /* Container for hopping pattern */ 381e25b118aSDominic Spill typedef struct { 382*75358bb0SHannes Ellinger char key[14]; /* afh channel map + address */ 383e25b118aSDominic Spill char *sequence; 384e25b118aSDominic Spill UT_hash_handle hh; 385e25b118aSDominic Spill } hopping_struct; 386e25b118aSDominic Spill 387e25b118aSDominic Spill static hopping_struct *hopping_map = NULL; 388e25b118aSDominic Spill 389e25b118aSDominic Spill /* Function to fetch piconet hopping patterns */ 390e25b118aSDominic Spill void get_hop_pattern(btbb_piconet *pn) 391e25b118aSDominic Spill { 392*75358bb0SHannes Ellinger hopping_struct* s = NULL; 393*75358bb0SHannes Ellinger char key[14]; 394*75358bb0SHannes Ellinger int i; 395e25b118aSDominic Spill 396*75358bb0SHannes Ellinger for(i=0;i<10;i++) 397*75358bb0SHannes Ellinger if(btbb_piconet_get_flag(pn, BTBB_IS_AFH)) 398*75358bb0SHannes Ellinger key[i+4] = pn->afh_map[i]; 399*75358bb0SHannes Ellinger else 400*75358bb0SHannes Ellinger key[i+4] = 0xff; 401*75358bb0SHannes Ellinger key[3] = pn->UAP; 402*75358bb0SHannes Ellinger key[2] = (pn->LAP >> 16) & 0xff; 403*75358bb0SHannes Ellinger key[1] = (pn->LAP >> 8) & 0xff; 404*75358bb0SHannes Ellinger key[0] = (pn->LAP) & 0xff; 405*75358bb0SHannes Ellinger HASH_FIND(hh,hopping_map,key,14,s); 406e25b118aSDominic Spill 407e25b118aSDominic Spill if (s == NULL) { 408e25b118aSDominic Spill gen_hop_pattern(pn); 409*75358bb0SHannes Ellinger s = (hopping_struct*)malloc(sizeof(hopping_struct)); 410*75358bb0SHannes Ellinger memcpy(s->key, key, 14); 411e25b118aSDominic Spill s->sequence = pn->sequence; 412*75358bb0SHannes Ellinger HASH_ADD(hh,hopping_map,key[0],14,s); 413e25b118aSDominic Spill } else { 414e25b118aSDominic Spill printf("\nFound hopping sequence in cache.\n"); 415e25b118aSDominic Spill pn->sequence = s->sequence; 416e25b118aSDominic Spill } 417e25b118aSDominic Spill } 418e25b118aSDominic Spill 419e25b118aSDominic Spill /* determine channel for a particular hop */ 420f1965e4dSHannes Ellinger /* borrowed from ubertooth firmware to support AFH */ 421e25b118aSDominic Spill char single_hop(int clock, btbb_piconet *pn) 422e25b118aSDominic Spill { 423f1965e4dSHannes Ellinger int a, c, d, x, y1, y2, perm, next_channel; 424f1965e4dSHannes Ellinger uint32_t base_f, f, f_dash; 425e25b118aSDominic Spill 426e25b118aSDominic Spill /* following variable names used in section 2.6 of the spec */ 427e25b118aSDominic Spill x = (clock >> 2) & 0x1f; 428e25b118aSDominic Spill y1 = (clock >> 1) & 0x01; 429e25b118aSDominic Spill y2 = y1 << 5; 430e25b118aSDominic Spill a = (pn->a1 ^ (clock >> 21)) & 0x1f; 431e25b118aSDominic Spill /* b is already defined */ 432e25b118aSDominic Spill c = (pn->c1 ^ (clock >> 16)) & 0x1f; 433e25b118aSDominic Spill d = (pn->d1 ^ (clock >> 7)) & 0x1ff; 434e25b118aSDominic Spill /* e is already defined */ 435f1965e4dSHannes Ellinger base_f = (clock >> 3) & 0x1fffff0; 436f1965e4dSHannes Ellinger f = base_f % BT_NUM_CHANNELS; 437e25b118aSDominic Spill 438f1965e4dSHannes Ellinger perm = fast_perm( 439f1965e4dSHannes Ellinger ((x + a) % 32) ^ pn->b, 440f1965e4dSHannes Ellinger (y1 * 0x1f) ^ c, 441f1965e4dSHannes Ellinger d); 442e25b118aSDominic Spill /* hop selection */ 443f1965e4dSHannes Ellinger if(btbb_piconet_get_flag(pn, BTBB_IS_AFH)) { 444f1965e4dSHannes Ellinger f_dash = base_f % pn->used_channels; 445f1965e4dSHannes Ellinger next_channel = pn->bank[(perm + pn->e + f_dash + y2) % pn->used_channels]; 446f1965e4dSHannes Ellinger } else { 447f1965e4dSHannes Ellinger next_channel = pn->bank[(perm + pn->e + f + y2) % BT_NUM_CHANNELS]; 448f1965e4dSHannes Ellinger } 449f1965e4dSHannes Ellinger return next_channel; 450e25b118aSDominic Spill } 451e25b118aSDominic Spill 452e25b118aSDominic Spill /* look up channel for a particular hop */ 453e25b118aSDominic Spill char hop(int clock, btbb_piconet *pn) 454e25b118aSDominic Spill { 455e25b118aSDominic Spill return pn->sequence[clock]; 456e25b118aSDominic Spill } 457e25b118aSDominic Spill 458e25b118aSDominic Spill static char aliased_channel(char channel) 459e25b118aSDominic Spill { 460e25b118aSDominic Spill return ((channel + 24) % ALIASED_CHANNELS) + 26; 461e25b118aSDominic Spill } 462e25b118aSDominic Spill 463e25b118aSDominic Spill /* create list of initial candidate clock values (hops with same channel as first observed hop) */ 464e25b118aSDominic Spill static int init_candidates(char channel, int known_clock_bits, btbb_piconet *pn) 465e25b118aSDominic Spill { 466e25b118aSDominic Spill int i; 467e25b118aSDominic Spill int count = 0; /* total number of candidates */ 468e25b118aSDominic Spill char observable_channel; /* accounts for aliasing if necessary */ 469e25b118aSDominic Spill 470e25b118aSDominic Spill /* only try clock values that match our known bits */ 471e25b118aSDominic Spill for (i = known_clock_bits; i < SEQUENCE_LENGTH; i += 0x40) { 472e25b118aSDominic Spill if (pn->aliased) 473e25b118aSDominic Spill observable_channel = aliased_channel(pn->sequence[i]); 474e25b118aSDominic Spill else 475e25b118aSDominic Spill observable_channel = pn->sequence[i]; 476e25b118aSDominic Spill if (observable_channel == channel) 477e25b118aSDominic Spill pn->clock_candidates[count++] = i; 478e25b118aSDominic Spill //FIXME ought to throw exception if count gets too big 479e25b118aSDominic Spill } 480e25b118aSDominic Spill return count; 481e25b118aSDominic Spill } 482e25b118aSDominic Spill 483e25b118aSDominic Spill /* initialize the hop reversal process */ 484e25b118aSDominic Spill int btbb_init_hop_reversal(int aliased, btbb_piconet *pn) 485e25b118aSDominic Spill { 486e25b118aSDominic Spill int max_candidates; 487e25b118aSDominic Spill uint32_t clock; 488e25b118aSDominic Spill 489e25b118aSDominic Spill get_hop_pattern(pn); 490e25b118aSDominic Spill 491e25b118aSDominic Spill if(aliased) 492e25b118aSDominic Spill max_candidates = (SEQUENCE_LENGTH / ALIASED_CHANNELS) / 32; 493*75358bb0SHannes Ellinger else if (btbb_piconet_get_flag(pn, BTBB_IS_AFH)) 494*75358bb0SHannes Ellinger max_candidates = (SEQUENCE_LENGTH / pn->used_channels) / 32; 495e25b118aSDominic Spill else 496e25b118aSDominic Spill max_candidates = (SEQUENCE_LENGTH / BT_NUM_CHANNELS) / 32; 497e25b118aSDominic Spill /* this can hold twice the approximate number of initial candidates */ 498e25b118aSDominic Spill pn->clock_candidates = (uint32_t*) malloc(sizeof(uint32_t) * max_candidates); 499e25b118aSDominic Spill 500e25b118aSDominic Spill clock = (pn->clk_offset + pn->first_pkt_time) & 0x3f; 501e25b118aSDominic Spill pn->num_candidates = init_candidates(pn->pattern_channels[0], clock, pn); 502e25b118aSDominic Spill pn->winnowed = 0; 503e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_HOP_REVERSAL_INIT, 1); 504e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 0); 505e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_IS_ALIASED, aliased); 506e25b118aSDominic Spill 507e25b118aSDominic Spill printf("%d initial CLK1-27 candidates\n", pn->num_candidates); 508e25b118aSDominic Spill 509e25b118aSDominic Spill return pn->num_candidates; 510e25b118aSDominic Spill } 511e25b118aSDominic Spill 512e25b118aSDominic Spill void try_hop(btbb_packet *pkt, btbb_piconet *pn) 513e25b118aSDominic Spill { 514e25b118aSDominic Spill uint8_t filter_uap = pn->UAP; 515e25b118aSDominic Spill 516e25b118aSDominic Spill /* Decode packet - fixing clock drift in the process */ 517e25b118aSDominic Spill btbb_decode(pkt, pn); 518e25b118aSDominic Spill 519e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_HOP_REVERSAL_INIT)) { 520e25b118aSDominic Spill //pn->winnowed = 0; 521e25b118aSDominic Spill pn->pattern_indices[pn->packets_observed] = 522e25b118aSDominic Spill pkt->clkn - pn->first_pkt_time; 523e25b118aSDominic Spill pn->pattern_channels[pn->packets_observed] = pkt->channel; 524e25b118aSDominic Spill pn->packets_observed++; 525e25b118aSDominic Spill pn->total_packets_observed++; 526e25b118aSDominic Spill btbb_winnow(pn); 527e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { 528e25b118aSDominic Spill printf("got CLK1-27\n"); 529e25b118aSDominic Spill printf("clock offset = %d.\n", pn->clk_offset); 530e25b118aSDominic Spill } 531e25b118aSDominic Spill } else { 532e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK6_VALID)) { 533e25b118aSDominic Spill btbb_uap_from_header(pkt, pn); 534e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { 535e25b118aSDominic Spill printf("got CLK1-27\n"); 536e25b118aSDominic Spill printf("clock offset = %d.\n", pn->clk_offset); 537e25b118aSDominic Spill } 538e25b118aSDominic Spill } else { 539e25b118aSDominic Spill if (btbb_uap_from_header(pkt, pn)) { 540e25b118aSDominic Spill if (filter_uap == pn->UAP) { 541e25b118aSDominic Spill btbb_init_hop_reversal(0, pn); 542e25b118aSDominic Spill btbb_winnow(pn); 543e25b118aSDominic Spill } else { 544e25b118aSDominic Spill printf("failed to confirm UAP\n"); 545e25b118aSDominic Spill } 546e25b118aSDominic Spill } 547e25b118aSDominic Spill } 548e25b118aSDominic Spill } 549e25b118aSDominic Spill 550e25b118aSDominic Spill if(!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) { 551e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); 552e25b118aSDominic Spill pn->UAP = filter_uap; 553e25b118aSDominic Spill } 554e25b118aSDominic Spill } 555e25b118aSDominic Spill 556e25b118aSDominic Spill /* return the observable channel (26-50) for a given channel (0-78) */ 557e25b118aSDominic Spill /* reset UAP/clock discovery */ 558e25b118aSDominic Spill static void reset(btbb_piconet *pn) 559e25b118aSDominic Spill { 560e25b118aSDominic Spill //printf("no candidates remaining! starting over . . .\n"); 561e25b118aSDominic Spill 562e25b118aSDominic Spill if(btbb_piconet_get_flag(pn, BTBB_HOP_REVERSAL_INIT)) { 563e25b118aSDominic Spill free(pn->clock_candidates); 564*75358bb0SHannes Ellinger // pn->sequence = NULL; 565e25b118aSDominic Spill } 566e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_GOT_FIRST_PACKET, 0); 567e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_HOP_REVERSAL_INIT, 0); 568e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 0); 569e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 0); 570e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 0); 571e25b118aSDominic Spill pn->packets_observed = 0; 572e25b118aSDominic Spill 573e25b118aSDominic Spill /* 574e25b118aSDominic Spill * If we have recently observed two packets in a row on the same 575e25b118aSDominic Spill * channel, try AFH next time. If not, don't. 576e25b118aSDominic Spill */ 577e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_IS_AFH, 578e25b118aSDominic Spill btbb_piconet_get_flag(pn, BTBB_LOOKS_LIKE_AFH)); 579f1965e4dSHannes Ellinger // btbb_piconet_set_flag(pn, BTBB_LOOKS_LIKE_AFH, 0); 580e25b118aSDominic Spill //int i; 581e25b118aSDominic Spill //for(i=0; i<10; i++) 582e25b118aSDominic Spill // pn->afh_map[i] = 0; 583e25b118aSDominic Spill } 584e25b118aSDominic Spill 585e25b118aSDominic Spill /* narrow a list of candidate clock values based on a single observed hop */ 586e25b118aSDominic Spill static int channel_winnow(int offset, char channel, btbb_piconet *pn) 587e25b118aSDominic Spill { 588e25b118aSDominic Spill int i; 589e25b118aSDominic Spill int new_count = 0; /* number of candidates after winnowing */ 590e25b118aSDominic Spill char observable_channel; /* accounts for aliasing if necessary */ 591e25b118aSDominic Spill 592e25b118aSDominic Spill /* check every candidate */ 593e25b118aSDominic Spill for (i = 0; i < pn->num_candidates; i++) { 594e25b118aSDominic Spill if (pn->aliased) 595e25b118aSDominic Spill observable_channel = aliased_channel(pn->sequence[(pn->clock_candidates[i] + offset) % SEQUENCE_LENGTH]); 596e25b118aSDominic Spill else 597e25b118aSDominic Spill observable_channel = pn->sequence[(pn->clock_candidates[i] + offset) % SEQUENCE_LENGTH]; 598e25b118aSDominic Spill if (observable_channel == channel) { 599e25b118aSDominic Spill /* this candidate matches the latest hop */ 600e25b118aSDominic Spill /* blow away old list of candidates with new one */ 601e25b118aSDominic Spill /* safe because new_count can never be greater than i */ 602e25b118aSDominic Spill pn->clock_candidates[new_count++] = pn->clock_candidates[i]; 603e25b118aSDominic Spill } 604e25b118aSDominic Spill } 605e25b118aSDominic Spill pn->num_candidates = new_count; 606e25b118aSDominic Spill 607e25b118aSDominic Spill if (new_count == 1) { 608e25b118aSDominic Spill // Calculate clock offset for CLKN, not CLK1-27 609e25b118aSDominic Spill pn->clk_offset = ((pn->clock_candidates[0]<<1) - (pn->first_pkt_time<<1)); 610e25b118aSDominic Spill printf("\nAcquired CLK1-27 = 0x%07x\n", pn->clock_candidates[0]); 611e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 1); 612e25b118aSDominic Spill } 613e25b118aSDominic Spill else if (new_count == 0) { 614e25b118aSDominic Spill reset(pn); 615e25b118aSDominic Spill } 616*75358bb0SHannes Ellinger else { 617*75358bb0SHannes Ellinger printf("%d CLK1-27 candidates remaining (channel=%d)\n", new_count, channel); 618*75358bb0SHannes Ellinger } 619e25b118aSDominic Spill 620e25b118aSDominic Spill return new_count; 621e25b118aSDominic Spill } 622e25b118aSDominic Spill 623e25b118aSDominic Spill /* narrow a list of candidate clock values based on all observed hops */ 624e25b118aSDominic Spill int btbb_winnow(btbb_piconet *pn) 625e25b118aSDominic Spill { 626e25b118aSDominic Spill int new_count = pn->num_candidates; 627e25b118aSDominic Spill int index, last_index; 628e25b118aSDominic Spill uint8_t channel, last_channel; 629e25b118aSDominic Spill 630e25b118aSDominic Spill for (; pn->winnowed < pn->packets_observed; pn->winnowed++) { 631e25b118aSDominic Spill index = pn->pattern_indices[pn->winnowed]; 632e25b118aSDominic Spill channel = pn->pattern_channels[pn->winnowed]; 633e25b118aSDominic Spill new_count = channel_winnow(index, channel, pn); 634e25b118aSDominic Spill if (new_count <= 1) 635e25b118aSDominic Spill break; 636e25b118aSDominic Spill 637e25b118aSDominic Spill if (pn->packets_observed > 0) { 638e25b118aSDominic Spill last_index = pn->pattern_indices[pn->winnowed - 1]; 639e25b118aSDominic Spill last_channel = pn->pattern_channels[pn->winnowed - 1]; 640e25b118aSDominic Spill /* 641e25b118aSDominic Spill * Two packets in a row on the same channel should only 642e25b118aSDominic Spill * happen if adaptive frequency hopping is in use. 643e25b118aSDominic Spill * There can be false positives, though, especially if 644e25b118aSDominic Spill * there is aliasing. 645e25b118aSDominic Spill */ 646e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_LOOKS_LIKE_AFH) 647e25b118aSDominic Spill && (index == last_index + 1) 648e25b118aSDominic Spill && (channel == last_channel)) { 649e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_LOOKS_LIKE_AFH, 1); 650e25b118aSDominic Spill printf("Hopping pattern appears to be AFH\n"); 651e25b118aSDominic Spill } 652e25b118aSDominic Spill } 653e25b118aSDominic Spill } 654e25b118aSDominic Spill 655e25b118aSDominic Spill return new_count; 656e25b118aSDominic Spill } 657e25b118aSDominic Spill 658e25b118aSDominic Spill /* use packet headers to determine UAP */ 659e25b118aSDominic Spill int btbb_uap_from_header(btbb_packet *pkt, btbb_piconet *pn) 660e25b118aSDominic Spill { 661e25b118aSDominic Spill uint8_t UAP; 662e25b118aSDominic Spill int count, crc_chk, first_clock = 0; 663e25b118aSDominic Spill 664e25b118aSDominic Spill int starting = 0; 665e25b118aSDominic Spill int remaining = 0; 666e25b118aSDominic Spill uint32_t clkn = pkt->clkn; 667e25b118aSDominic Spill 668c0d170f2SDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET)) 669e25b118aSDominic Spill pn->first_pkt_time = clkn; 670e25b118aSDominic Spill 671e25b118aSDominic Spill // Set afh channel map 672f1965e4dSHannes Ellinger btbb_piconet_set_channel_seen(pn, pkt->channel); 673e25b118aSDominic Spill 674e25b118aSDominic Spill if (pn->packets_observed < MAX_PATTERN_LENGTH) { 675e25b118aSDominic Spill pn->pattern_indices[pn->packets_observed] = clkn - pn->first_pkt_time; 676e25b118aSDominic Spill pn->pattern_channels[pn->packets_observed] = pkt->channel; 677e25b118aSDominic Spill } else { 678e25b118aSDominic Spill printf("Oops. More hops than we can remember.\n"); 679e25b118aSDominic Spill reset(pn); 680e25b118aSDominic Spill return 0; //FIXME ought to throw exception 681e25b118aSDominic Spill } 682e25b118aSDominic Spill pn->packets_observed++; 683e25b118aSDominic Spill pn->total_packets_observed++; 684e25b118aSDominic Spill 685e25b118aSDominic Spill /* try every possible first packet clock value */ 686e25b118aSDominic Spill for (count = 0; count < 64; count++) { 687e25b118aSDominic Spill /* skip eliminated candidates unless this is our first time through */ 688c0d170f2SDominic Spill if (pn->clock6_candidates[count] > -1 689c0d170f2SDominic Spill || !btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET)) { 690e25b118aSDominic Spill /* clock value for the current packet assuming count was the clock of the first packet */ 691e25b118aSDominic Spill int clock = (count + clkn - pn->first_pkt_time) % 64; 692e25b118aSDominic Spill starting++; 693e25b118aSDominic Spill UAP = try_clock(clock, pkt); 694e25b118aSDominic Spill crc_chk = -1; 695e25b118aSDominic Spill 696e25b118aSDominic Spill /* if this is the first packet: populate the candidate list */ 697e25b118aSDominic Spill /* if not: check CRCs if UAPs match */ 698c0d170f2SDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET) 699c0d170f2SDominic Spill || UAP == pn->clock6_candidates[count]) 700e25b118aSDominic Spill crc_chk = crc_check(clock, pkt); 701e25b118aSDominic Spill 702e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_UAP_VALID) && 703e25b118aSDominic Spill (UAP != pn->UAP)) 704e25b118aSDominic Spill crc_chk = -1; 705e25b118aSDominic Spill 706e25b118aSDominic Spill switch(crc_chk) { 707e25b118aSDominic Spill case -1: /* UAP mismatch */ 708e25b118aSDominic Spill case 0: /* CRC failure */ 709e25b118aSDominic Spill pn->clock6_candidates[count] = -1; 710e25b118aSDominic Spill break; 711e25b118aSDominic Spill 712e25b118aSDominic Spill case 1: /* inconclusive result */ 713c0d170f2SDominic Spill case 2: /* Inconclusive, but looks better */ 714e25b118aSDominic Spill pn->clock6_candidates[count] = UAP; 715e25b118aSDominic Spill /* remember this count because it may be the correct clock of the first packet */ 716e25b118aSDominic Spill first_clock = count; 717e25b118aSDominic Spill remaining++; 718e25b118aSDominic Spill break; 719e25b118aSDominic Spill 720e25b118aSDominic Spill default: /* CRC success */ 721e25b118aSDominic Spill pn->clk_offset = (count - (pn->first_pkt_time & 0x3f)) & 0x3f; 722e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) 723e25b118aSDominic Spill printf("Correct CRC! UAP = 0x%x found after %d total packets.\n", 724e25b118aSDominic Spill UAP, pn->total_packets_observed); 725e25b118aSDominic Spill else 726e25b118aSDominic Spill printf("Correct CRC! CLK6 = 0x%x found after %d total packets.\n", 727e25b118aSDominic Spill pn->clk_offset, pn->total_packets_observed); 728e25b118aSDominic Spill pn->UAP = UAP; 729e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 1); 730e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); 731e25b118aSDominic Spill pn->total_packets_observed = 0; 732e25b118aSDominic Spill return 1; 733e25b118aSDominic Spill } 734e25b118aSDominic Spill } 735e25b118aSDominic Spill } 736e25b118aSDominic Spill 737c0d170f2SDominic Spill btbb_piconet_set_flag(pn, BTBB_GOT_FIRST_PACKET, 1); 738e25b118aSDominic Spill 739e25b118aSDominic Spill //printf("reduced from %d to %d CLK1-6 candidates\n", starting, remaining); 740e25b118aSDominic Spill 741e25b118aSDominic Spill if (remaining == 1) { 742e25b118aSDominic Spill pn->clk_offset = (first_clock - (pn->first_pkt_time & 0x3f)) & 0x3f; 743e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) 744d73cdf28SDominic Spill printf("UAP = 0x%x found after %d total packets.\n", 745e25b118aSDominic Spill pn->clock6_candidates[first_clock], pn->total_packets_observed); 746e25b118aSDominic Spill else 747d73cdf28SDominic Spill printf("CLK6 = 0x%x found after %d total packets.\n", 748e25b118aSDominic Spill pn->clk_offset, pn->total_packets_observed); 749e25b118aSDominic Spill pn->UAP = pn->clock6_candidates[first_clock]; 750e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 1); 751e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); 752e25b118aSDominic Spill pn->total_packets_observed = 0; 753e25b118aSDominic Spill return 1; 754e25b118aSDominic Spill } 755e25b118aSDominic Spill 756e25b118aSDominic Spill if (remaining == 0) { 757e25b118aSDominic Spill reset(pn); 758e25b118aSDominic Spill } 759e25b118aSDominic Spill 760e25b118aSDominic Spill return 0; 761e25b118aSDominic Spill } 762e25b118aSDominic Spill 76314430aa0SDominic Spill /* FIXME: comment out enqueue and dequeue because they are 76414430aa0SDominic Spill * never used. Try to find out what tey were meant to be 76514430aa0SDominic Spill * used for before the next release. 76614430aa0SDominic Spill */ 76714430aa0SDominic Spill ///* add a packet to the queue */ 76814430aa0SDominic Spill //static void enqueue(btbb_packet *pkt, btbb_piconet *pn) 76914430aa0SDominic Spill //{ 77014430aa0SDominic Spill // pkt_queue *head; 77114430aa0SDominic Spill // //pkt_queue item; 77214430aa0SDominic Spill // 77314430aa0SDominic Spill // btbb_packet_ref(pkt); 77414430aa0SDominic Spill // pkt_queue item = {pkt, NULL}; 77514430aa0SDominic Spill // head = pn->queue; 77614430aa0SDominic Spill // 77714430aa0SDominic Spill // if (head == NULL) { 77814430aa0SDominic Spill // pn->queue = &item; 77914430aa0SDominic Spill // } else { 78014430aa0SDominic Spill // for(; head->next != NULL; head = head->next) 78114430aa0SDominic Spill // ; 78214430aa0SDominic Spill // head->next = &item; 78314430aa0SDominic Spill // } 78414430aa0SDominic Spill //} 78514430aa0SDominic Spill // 78614430aa0SDominic Spill ///* pull the first packet from the queue (FIFO) */ 78714430aa0SDominic Spill //static btbb_packet *dequeue(btbb_piconet *pn) 78814430aa0SDominic Spill //{ 78914430aa0SDominic Spill // btbb_packet *pkt; 79014430aa0SDominic Spill // 79114430aa0SDominic Spill // if (pn->queue == NULL) { 79214430aa0SDominic Spill // pkt = NULL; 79314430aa0SDominic Spill // } else { 79414430aa0SDominic Spill // pkt = pn->queue->pkt; 79514430aa0SDominic Spill // pn->queue = pn->queue->next; 79614430aa0SDominic Spill // btbb_packet_unref(pkt); 79714430aa0SDominic Spill // } 79814430aa0SDominic Spill // 79914430aa0SDominic Spill // return pkt; 80014430aa0SDominic Spill //} 801e25b118aSDominic Spill 802e25b118aSDominic Spill /* decode the whole packet */ 803e25b118aSDominic Spill int btbb_decode(btbb_packet* pkt, btbb_piconet *pn) 804e25b118aSDominic Spill { 805e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 0); 8066b21c2c9SDominic Spill uint8_t clk6, i, best_clk; 8076b21c2c9SDominic Spill int rv = 0, max_rv = 0; 808e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { 8096b21c2c9SDominic Spill /* Removing this section until we can more reliably handle AFH */ 8106b21c2c9SDominic Spill //if(pn->sequence == NULL) 8116b21c2c9SDominic Spill // get_hop_pattern(pn); 8126b21c2c9SDominic Spill //clk6 = pkt->clock & 0x3f; 8136b21c2c9SDominic Spill //for(i=0; i<64; i++) { 8146b21c2c9SDominic Spill // pkt->clock = (pkt->clock & 0xffffffc0) | ((clk6 + i) & 0x3f); 8156b21c2c9SDominic Spill // if ((pn->sequence[pkt->clock] == pkt->channel) && (btbb_decode_header(pkt))) { 8166b21c2c9SDominic Spill // rv = btbb_decode_payload(pkt); 8176b21c2c9SDominic Spill // if(rv > max_rv) { 8186b21c2c9SDominic Spill // max_rv = rv; 8196b21c2c9SDominic Spill // best_clk = (clk6 + i) & 0x3f; 8206b21c2c9SDominic Spill // } 8216b21c2c9SDominic Spill // } 8226b21c2c9SDominic Spill //} 8236b21c2c9SDominic Spill 8246b21c2c9SDominic Spill // If we found nothing, try again, ignoring channel 8256b21c2c9SDominic Spill if(max_rv <= 1) { 826e25b118aSDominic Spill clk6 = pkt->clock & 0x3f; 827e25b118aSDominic Spill for(i=0; i<64; i++) { 828e25b118aSDominic Spill pkt->clock = (pkt->clock & 0xffffffc0) | ((clk6 + i) & 0x3f); 829e25b118aSDominic Spill if (btbb_decode_header(pkt)) { 830e25b118aSDominic Spill rv = btbb_decode_payload(pkt); 8316b21c2c9SDominic Spill if(rv > max_rv) { 8326b21c2c9SDominic Spill //printf("Packet decoded with clock 0x%07x (rv=%d)\n", pkt->clock, rv); 8336b21c2c9SDominic Spill //btbb_print_packet(pkt); 8346b21c2c9SDominic Spill max_rv = rv; 8356b21c2c9SDominic Spill best_clk = (clk6 + i) & 0x3f; 836e25b118aSDominic Spill } 837e25b118aSDominic Spill } 838e25b118aSDominic Spill } 839e25b118aSDominic Spill } 840e25b118aSDominic Spill } else 8416b21c2c9SDominic Spill if (btbb_decode_header(pkt)) { 8426b21c2c9SDominic Spill for(i=0; i<64; i++) { 8436b21c2c9SDominic Spill pkt->clock = (pkt->clock & 0xffffffc0) | (i & 0x3f); 8446b21c2c9SDominic Spill if (btbb_decode_header(pkt)) { 845e25b118aSDominic Spill rv = btbb_decode_payload(pkt); 8466b21c2c9SDominic Spill if(rv > max_rv) { 8476b21c2c9SDominic Spill //printf("Packet decoded with clock 0x%02x (rv=%d)\n", i, rv); 8486b21c2c9SDominic Spill //btbb_print_packet(pkt); 8496b21c2c9SDominic Spill max_rv = rv; 8506b21c2c9SDominic Spill best_clk = i & 0x3f; 8516b21c2c9SDominic Spill } 8526b21c2c9SDominic Spill } 8536b21c2c9SDominic Spill } 8546b21c2c9SDominic Spill } 8556b21c2c9SDominic Spill /* If we were successful, print the packet */ 8566b21c2c9SDominic Spill if(max_rv > 0) { 8576b21c2c9SDominic Spill pkt->clock = (pkt->clock & 0xffffffc0) | (best_clk & 0x3f); 8586b21c2c9SDominic Spill btbb_decode_payload(pkt); 8596b21c2c9SDominic Spill printf("Packet decoded with clock 0x%02x (rv=%d)\n", i, rv); 8606b21c2c9SDominic Spill btbb_print_packet(pkt); 8616b21c2c9SDominic Spill } 862e25b118aSDominic Spill 8636b21c2c9SDominic Spill return max_rv; 864e25b118aSDominic Spill } 865e25b118aSDominic Spill 866e25b118aSDominic Spill /* Print AFH map from observed packets */ 867e25b118aSDominic Spill void btbb_print_afh_map(btbb_piconet *pn) { 8681e7f449bSDominic Spill uint8_t *afh_map; 869e25b118aSDominic Spill afh_map = pn->afh_map; 870e25b118aSDominic Spill 871f1965e4dSHannes Ellinger /* Print like hcitool does */ 872f1965e4dSHannes Ellinger printf("AFH map: 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", 873f1965e4dSHannes Ellinger afh_map[0], afh_map[1], afh_map[2], afh_map[3], afh_map[4], 874f1965e4dSHannes Ellinger afh_map[5], afh_map[6], afh_map[7], afh_map[8], afh_map[9]); 875f1965e4dSHannes Ellinger 876f1965e4dSHannes Ellinger // /* Printed ch78 -> ch0 */ 877f1965e4dSHannes Ellinger // printf("\tAFH Map=0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", 878f1965e4dSHannes Ellinger // afh_map[9], afh_map[8], afh_map[7], afh_map[6], afh_map[5], 879f1965e4dSHannes Ellinger // afh_map[4], afh_map[3], afh_map[2], afh_map[1], afh_map[0]); 880e25b118aSDominic Spill } 881e25b118aSDominic Spill 882e25b118aSDominic Spill /* Container for survey piconets */ 883e25b118aSDominic Spill typedef struct { 884e25b118aSDominic Spill uint32_t key; /* LAP */ 885e25b118aSDominic Spill btbb_piconet *pn; 886e25b118aSDominic Spill UT_hash_handle hh; 887e25b118aSDominic Spill } survey_hash; 888e25b118aSDominic Spill 889e25b118aSDominic Spill static survey_hash *piconet_survey = NULL; 890e25b118aSDominic Spill 891e25b118aSDominic Spill /* Check for existing piconets in survey results */ 892e25b118aSDominic Spill btbb_piconet *get_piconet(uint32_t lap) 893e25b118aSDominic Spill { 894e25b118aSDominic Spill survey_hash *s; 895e25b118aSDominic Spill btbb_piconet *pn; 896e25b118aSDominic Spill HASH_FIND(hh, piconet_survey, &lap, 4, s); 897e25b118aSDominic Spill 898e25b118aSDominic Spill if (s == NULL) { 899e25b118aSDominic Spill pn = btbb_piconet_new(); 900e25b118aSDominic Spill btbb_init_piconet(pn, lap); 901e25b118aSDominic Spill 902e25b118aSDominic Spill s = malloc(sizeof(survey_hash)); 903e25b118aSDominic Spill s->key = lap; 904e25b118aSDominic Spill s->pn = pn; 905e25b118aSDominic Spill HASH_ADD(hh, piconet_survey, key, 4, s); 906e25b118aSDominic Spill } else { 907e25b118aSDominic Spill pn = s->pn; 908e25b118aSDominic Spill } 909e25b118aSDominic Spill return pn; 910e25b118aSDominic Spill } 911e25b118aSDominic Spill 912e25b118aSDominic Spill /* Destructively iterate over survey results */ 913e25b118aSDominic Spill btbb_piconet *btbb_next_survey_result() { 914e25b118aSDominic Spill btbb_piconet *pn = NULL; 915e25b118aSDominic Spill survey_hash *tmp; 916e25b118aSDominic Spill 917e25b118aSDominic Spill if (piconet_survey != NULL) { 918e25b118aSDominic Spill pn = piconet_survey->pn; 919e25b118aSDominic Spill tmp = piconet_survey; 920e25b118aSDominic Spill piconet_survey = piconet_survey->hh.next; 921e25b118aSDominic Spill free(tmp); 922e25b118aSDominic Spill } 923e25b118aSDominic Spill return pn; 924e25b118aSDominic Spill } 925e25b118aSDominic Spill 926e25b118aSDominic Spill int btbb_process_packet(btbb_packet *pkt, btbb_piconet *pn) { 927e25b118aSDominic Spill if (survey_mode) { 928e25b118aSDominic Spill pn = get_piconet(btbb_packet_get_lap(pkt)); 929e25b118aSDominic Spill btbb_piconet_set_channel_seen(pn, pkt->channel); 930e25b118aSDominic Spill if(btbb_header_present(pkt) && !btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) 931e25b118aSDominic Spill btbb_uap_from_header(pkt, pn); 932e25b118aSDominic Spill return 0; 933e25b118aSDominic Spill } 93426a99405SDominic Spill 93526a99405SDominic Spill if(pn) 93626a99405SDominic Spill btbb_piconet_set_channel_seen(pn, pkt->channel); 93726a99405SDominic Spill 938e25b118aSDominic Spill /* If piconet structure is given, a LAP is given, and packet 939e25b118aSDominic Spill * header is readable, do further analysis. If UAP has not yet 940e25b118aSDominic Spill * been determined, attempt to calculate it from headers. Once 941e25b118aSDominic Spill * UAP is known, try to determine clk6 and clk27. Once clocks 942e25b118aSDominic Spill * are known, follow the piconet. */ 943e25b118aSDominic Spill if (pn && btbb_piconet_get_flag(pn, BTBB_LAP_VALID) && 944e25b118aSDominic Spill btbb_header_present(pkt)) { 945e25b118aSDominic Spill 946e25b118aSDominic Spill /* Have LAP/UAP/clocks, now hopping along with the piconet. */ 947e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_FOLLOWING)) { 948e25b118aSDominic Spill btbb_packet_set_uap(pkt, btbb_piconet_get_uap(pn)); 949e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_CLK6_VALID, 1); 950e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_CLK27_VALID, 1); 951e25b118aSDominic Spill 952e25b118aSDominic Spill if(btbb_decode(pkt, pn)) 953e25b118aSDominic Spill btbb_print_packet(pkt); 954e25b118aSDominic Spill else 955e25b118aSDominic Spill printf("Failed to decode packet\n"); 956e25b118aSDominic Spill } 957e25b118aSDominic Spill 958e25b118aSDominic Spill /* Have LAP/UAP, need clocks. */ 959e25b118aSDominic Spill else if (btbb_piconet_get_uap(pn)) { 960e25b118aSDominic Spill try_hop(pkt, pn); 961e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK6_VALID) && 962e25b118aSDominic Spill btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { 963e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_FOLLOWING, 1); 964e25b118aSDominic Spill return -1; 965e25b118aSDominic Spill } 966e25b118aSDominic Spill } 967e25b118aSDominic Spill 968e25b118aSDominic Spill /* Have LAP, need UAP. */ 969e25b118aSDominic Spill else { 970e25b118aSDominic Spill btbb_uap_from_header(pkt, pn); 971e25b118aSDominic Spill } 972e25b118aSDominic Spill } 973e25b118aSDominic Spill return 0; 974e25b118aSDominic Spill } 975