1*e25b118aSDominic Spill /* -*- c -*- */ 2*e25b118aSDominic Spill /* 3*e25b118aSDominic Spill * Copyright 2007 - 2013 Dominic Spill, Michael Ossmann, Will Code 4*e25b118aSDominic Spill * 5*e25b118aSDominic Spill * This file is part of libbtbb 6*e25b118aSDominic Spill * 7*e25b118aSDominic Spill * This program is free software; you can redistribute it and/or modify 8*e25b118aSDominic Spill * it under the terms of the GNU General Public License as published by 9*e25b118aSDominic Spill * the Free Software Foundation; either version 2, or (at your option) 10*e25b118aSDominic Spill * any later version. 11*e25b118aSDominic Spill * 12*e25b118aSDominic Spill * This program is distributed in the hope that it will be useful, 13*e25b118aSDominic Spill * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*e25b118aSDominic Spill * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*e25b118aSDominic Spill * GNU General Public License for more details. 16*e25b118aSDominic Spill * 17*e25b118aSDominic Spill * You should have received a copy of the GNU General Public License 18*e25b118aSDominic Spill * along with libbtbb; see the file COPYING. If not, write to 19*e25b118aSDominic Spill * the Free Software Foundation, Inc., 51 Franklin Street, 20*e25b118aSDominic Spill * Boston, MA 02110-1301, USA. 21*e25b118aSDominic Spill */ 22*e25b118aSDominic Spill 23*e25b118aSDominic Spill #include "bluetooth_packet.h" 24*e25b118aSDominic Spill #include "bluetooth_piconet.h" 25*e25b118aSDominic Spill #include "uthash.h" 26*e25b118aSDominic Spill #include <stdlib.h> 27*e25b118aSDominic Spill #include <stdio.h> 28*e25b118aSDominic Spill 29*e25b118aSDominic Spill int perm_table_initialized = 0; 30*e25b118aSDominic Spill char perm_table[0x20][0x20][0x200]; 31*e25b118aSDominic Spill 32*e25b118aSDominic Spill btbb_piconet * 33*e25b118aSDominic Spill btbb_piconet_new(void) 34*e25b118aSDominic Spill { 35*e25b118aSDominic Spill btbb_piconet *pn = (btbb_piconet *)calloc(1, sizeof(btbb_piconet)); 36*e25b118aSDominic Spill pn->refcount = 1; 37*e25b118aSDominic Spill return pn; 38*e25b118aSDominic Spill } 39*e25b118aSDominic Spill 40*e25b118aSDominic Spill void 41*e25b118aSDominic Spill btbb_piconet_ref(btbb_piconet *pn) 42*e25b118aSDominic Spill { 43*e25b118aSDominic Spill pn->refcount++; 44*e25b118aSDominic Spill } 45*e25b118aSDominic Spill 46*e25b118aSDominic Spill void 47*e25b118aSDominic Spill btbb_piconet_unref(btbb_piconet *pn) 48*e25b118aSDominic Spill { 49*e25b118aSDominic Spill pn->refcount--; 50*e25b118aSDominic Spill if (pn->refcount == 0) 51*e25b118aSDominic Spill free(pn); 52*e25b118aSDominic Spill } 53*e25b118aSDominic Spill 54*e25b118aSDominic Spill void btbb_init_piconet(btbb_piconet *pn, uint32_t lap) 55*e25b118aSDominic Spill { 56*e25b118aSDominic Spill pn->LAP = lap; 57*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_LAP_VALID, 1); 58*e25b118aSDominic Spill } 59*e25b118aSDominic Spill 60*e25b118aSDominic Spill void btbb_piconet_set_flag(btbb_piconet *pn, int flag, int val) 61*e25b118aSDominic Spill { 62*e25b118aSDominic Spill uint32_t mask = 1L << flag; 63*e25b118aSDominic Spill pn->flags &= ~mask; 64*e25b118aSDominic Spill if (val) 65*e25b118aSDominic Spill pn->flags |= mask; 66*e25b118aSDominic Spill } 67*e25b118aSDominic Spill 68*e25b118aSDominic Spill int btbb_piconet_get_flag(btbb_piconet *pn, int flag) 69*e25b118aSDominic Spill { 70*e25b118aSDominic Spill uint32_t mask = 1L << flag; 71*e25b118aSDominic Spill return ((pn->flags & mask) != 0); 72*e25b118aSDominic Spill } 73*e25b118aSDominic Spill 74*e25b118aSDominic Spill void btbb_piconet_set_uap(btbb_piconet *pn, uint8_t uap) 75*e25b118aSDominic Spill { 76*e25b118aSDominic Spill pn->UAP = uap; 77*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); 78*e25b118aSDominic Spill } 79*e25b118aSDominic Spill 80*e25b118aSDominic Spill uint8_t btbb_piconet_get_uap(btbb_piconet *pn) 81*e25b118aSDominic Spill { 82*e25b118aSDominic Spill return pn->UAP; 83*e25b118aSDominic Spill } 84*e25b118aSDominic Spill 85*e25b118aSDominic Spill uint32_t btbb_piconet_get_lap(btbb_piconet *pn) 86*e25b118aSDominic Spill { 87*e25b118aSDominic Spill return pn->LAP; 88*e25b118aSDominic Spill } 89*e25b118aSDominic Spill 90*e25b118aSDominic Spill uint16_t btbb_piconet_get_nap(btbb_piconet *pn) 91*e25b118aSDominic Spill { 92*e25b118aSDominic Spill return pn->NAP; 93*e25b118aSDominic Spill } 94*e25b118aSDominic Spill 95*e25b118aSDominic Spill int btbb_piconet_get_clk_offset(btbb_piconet *pn) 96*e25b118aSDominic Spill { 97*e25b118aSDominic Spill return pn->clk_offset; 98*e25b118aSDominic Spill } 99*e25b118aSDominic Spill 100*e25b118aSDominic Spill void btbb_piconet_set_clk_offset(btbb_piconet *pn, int clk_offset) 101*e25b118aSDominic Spill { 102*e25b118aSDominic Spill pn->clk_offset = clk_offset; 103*e25b118aSDominic Spill } 104*e25b118aSDominic Spill 105*e25b118aSDominic Spill void btbb_piconet_set_afh_map(btbb_piconet *pn, uint8_t *afh_map) { 106*e25b118aSDominic Spill int i; 107*e25b118aSDominic Spill // DGS: Unroll this? 108*e25b118aSDominic Spill for(i=0; i<10; i++) 109*e25b118aSDominic Spill pn->afh_map[i] = afh_map[i]; 110*e25b118aSDominic Spill } 111*e25b118aSDominic Spill 112*e25b118aSDominic Spill uint8_t *btbb_piconet_get_afh_map(btbb_piconet *pn) { 113*e25b118aSDominic Spill return pn->afh_map; 114*e25b118aSDominic Spill } 115*e25b118aSDominic Spill 116*e25b118aSDominic Spill void btbb_piconet_set_channel_seen(btbb_piconet *pn, uint8_t channel) 117*e25b118aSDominic Spill { 118*e25b118aSDominic Spill pn->afh_map[channel/8] |= 0x1 << (channel % 8); 119*e25b118aSDominic Spill } 120*e25b118aSDominic Spill 121*e25b118aSDominic Spill /* do all the precalculation that can be done before knowing the address */ 122*e25b118aSDominic Spill void precalc(btbb_piconet *pn) 123*e25b118aSDominic Spill { 124*e25b118aSDominic Spill int i; 125*e25b118aSDominic Spill 126*e25b118aSDominic Spill /* populate frequency register bank*/ 127*e25b118aSDominic Spill for (i = 0; i < BT_NUM_CHANNELS; i++) 128*e25b118aSDominic Spill pn->bank[i] = ((i * 2) % BT_NUM_CHANNELS); 129*e25b118aSDominic Spill /* actual frequency is 2402 + pn->bank[i] MHz */ 130*e25b118aSDominic Spill 131*e25b118aSDominic Spill } 132*e25b118aSDominic Spill 133*e25b118aSDominic Spill /* do precalculation that requires the address */ 134*e25b118aSDominic Spill void address_precalc(int address, btbb_piconet *pn) 135*e25b118aSDominic Spill { 136*e25b118aSDominic Spill /* precalculate some of single_hop()/gen_hop()'s variables */ 137*e25b118aSDominic Spill pn->a1 = (address >> 23) & 0x1f; 138*e25b118aSDominic Spill pn->b = (address >> 19) & 0x0f; 139*e25b118aSDominic Spill pn->c1 = ((address >> 4) & 0x10) + 140*e25b118aSDominic Spill ((address >> 3) & 0x08) + 141*e25b118aSDominic Spill ((address >> 2) & 0x04) + 142*e25b118aSDominic Spill ((address >> 1) & 0x02) + 143*e25b118aSDominic Spill (address & 0x01); 144*e25b118aSDominic Spill pn->d1 = (address >> 10) & 0x1ff; 145*e25b118aSDominic Spill pn->e = ((address >> 7) & 0x40) + 146*e25b118aSDominic Spill ((address >> 6) & 0x20) + 147*e25b118aSDominic Spill ((address >> 5) & 0x10) + 148*e25b118aSDominic Spill ((address >> 4) & 0x08) + 149*e25b118aSDominic Spill ((address >> 3) & 0x04) + 150*e25b118aSDominic Spill ((address >> 2) & 0x02) + 151*e25b118aSDominic Spill ((address >> 1) & 0x01); 152*e25b118aSDominic Spill } 153*e25b118aSDominic Spill 154*e25b118aSDominic Spill #ifdef WC4 155*e25b118aSDominic Spill /* These are optimization experiments, which don't help much for 156*e25b118aSDominic Spill * x86. Hold on to them to see whether they're useful on ARM. */ 157*e25b118aSDominic Spill 158*e25b118aSDominic Spill #ifdef NEVER 159*e25b118aSDominic Spill #define BUTTERFLY(z,p,c,a,b) \ 160*e25b118aSDominic Spill if ( ((p&(1<<c))!=0) & (((z&(1<<a))!=0) ^ ((z&(1<<b))!=0)) ) \ 161*e25b118aSDominic Spill z ^= ((1<<a)|(1<<b)) 162*e25b118aSDominic Spill #endif 163*e25b118aSDominic Spill 164*e25b118aSDominic Spill #define BUTTERFLY(z,p,c,a,b) \ 165*e25b118aSDominic Spill if ( (((z>>a)^(z>>b)) & (p>>c)) & 0x1 ) \ 166*e25b118aSDominic Spill z ^= ((1<<a)|(1<<b)) 167*e25b118aSDominic Spill 168*e25b118aSDominic Spill int perm5(int z, int p_high, int p_low) 169*e25b118aSDominic Spill { 170*e25b118aSDominic Spill int p = (p_high << 5) | p_low; 171*e25b118aSDominic Spill BUTTERFLY(z,p,13,1,2); 172*e25b118aSDominic Spill BUTTERFLY(z,p,12,0,3); 173*e25b118aSDominic Spill BUTTERFLY(z,p,11,1,3); 174*e25b118aSDominic Spill BUTTERFLY(z,p,10,2,4); 175*e25b118aSDominic Spill BUTTERFLY(z,p, 9,0,3); 176*e25b118aSDominic Spill BUTTERFLY(z,p, 8,1,4); 177*e25b118aSDominic Spill BUTTERFLY(z,p, 7,3,4); 178*e25b118aSDominic Spill BUTTERFLY(z,p, 6,0,2); 179*e25b118aSDominic Spill BUTTERFLY(z,p, 5,1,3); 180*e25b118aSDominic Spill BUTTERFLY(z,p, 4,0,4); 181*e25b118aSDominic Spill BUTTERFLY(z,p, 3,3,4); 182*e25b118aSDominic Spill BUTTERFLY(z,p, 2,1,2); 183*e25b118aSDominic Spill BUTTERFLY(z,p, 1,2,3); 184*e25b118aSDominic Spill BUTTERFLY(z,p, 0,0,1); 185*e25b118aSDominic Spill 186*e25b118aSDominic Spill return z; 187*e25b118aSDominic Spill } 188*e25b118aSDominic Spill #endif // WC4 189*e25b118aSDominic Spill 190*e25b118aSDominic Spill /* 5 bit permutation */ 191*e25b118aSDominic Spill /* assumes z is constrained to 5 bits, p_high to 5 bits, p_low to 9 bits */ 192*e25b118aSDominic Spill int perm5(int z, int p_high, int p_low) 193*e25b118aSDominic Spill { 194*e25b118aSDominic Spill int i, tmp, output, z_bit[5], p[14]; 195*e25b118aSDominic Spill int index1[] = {0, 2, 1, 3, 0, 1, 0, 3, 1, 0, 2, 1, 0, 1}; 196*e25b118aSDominic Spill int index2[] = {1, 3, 2, 4, 4, 3, 2, 4, 4, 3, 4, 3, 3, 2}; 197*e25b118aSDominic Spill 198*e25b118aSDominic Spill /* bits of p_low and p_high are control signals */ 199*e25b118aSDominic Spill for (i = 0; i < 9; i++) 200*e25b118aSDominic Spill p[i] = (p_low >> i) & 0x01; 201*e25b118aSDominic Spill for (i = 0; i < 5; i++) 202*e25b118aSDominic Spill p[i+9] = (p_high >> i) & 0x01; 203*e25b118aSDominic Spill 204*e25b118aSDominic Spill /* bit swapping will be easier with an array of bits */ 205*e25b118aSDominic Spill for (i = 0; i < 5; i++) 206*e25b118aSDominic Spill z_bit[i] = (z >> i) & 0x01; 207*e25b118aSDominic Spill 208*e25b118aSDominic Spill /* butterfly operations */ 209*e25b118aSDominic Spill for (i = 13; i >= 0; i--) { 210*e25b118aSDominic Spill /* swap bits according to index arrays if control signal tells us to */ 211*e25b118aSDominic Spill if (p[i]) { 212*e25b118aSDominic Spill tmp = z_bit[index1[i]]; 213*e25b118aSDominic Spill z_bit[index1[i]] = z_bit[index2[i]]; 214*e25b118aSDominic Spill z_bit[index2[i]] = tmp; 215*e25b118aSDominic Spill } 216*e25b118aSDominic Spill } 217*e25b118aSDominic Spill 218*e25b118aSDominic Spill /* reconstruct output from rearranged bits */ 219*e25b118aSDominic Spill output = 0; 220*e25b118aSDominic Spill for (i = 0; i < 5; i++) 221*e25b118aSDominic Spill output += z_bit[i] << i; 222*e25b118aSDominic Spill 223*e25b118aSDominic Spill return(output); 224*e25b118aSDominic Spill } 225*e25b118aSDominic Spill 226*e25b118aSDominic Spill void perm_table_init(void) 227*e25b118aSDominic Spill { 228*e25b118aSDominic Spill /* populate perm_table for all possible inputs */ 229*e25b118aSDominic Spill int z, p_high, p_low; 230*e25b118aSDominic Spill for (z = 0; z < 0x20; z++) 231*e25b118aSDominic Spill for (p_high = 0; p_high < 0x20; p_high++) 232*e25b118aSDominic Spill for (p_low = 0; p_low < 0x200; p_low++) 233*e25b118aSDominic Spill perm_table[z][p_high][p_low] = perm5(z, p_high, p_low); 234*e25b118aSDominic Spill } 235*e25b118aSDominic Spill 236*e25b118aSDominic Spill /* drop-in replacement for perm5() using lookup table */ 237*e25b118aSDominic Spill int fast_perm(int z, int p_high, int p_low, btbb_piconet *pn) 238*e25b118aSDominic Spill { 239*e25b118aSDominic Spill if (!perm_table_initialized) { 240*e25b118aSDominic Spill perm_table_init(); 241*e25b118aSDominic Spill perm_table_initialized = 1; 242*e25b118aSDominic Spill } 243*e25b118aSDominic Spill 244*e25b118aSDominic Spill return(perm_table[z][p_high][p_low]); 245*e25b118aSDominic Spill } 246*e25b118aSDominic Spill 247*e25b118aSDominic Spill /* generate the complete hopping sequence */ 248*e25b118aSDominic Spill static void gen_hops(btbb_piconet *pn) 249*e25b118aSDominic Spill { 250*e25b118aSDominic Spill /* a, b, c, d, e, f, x, y1, y2 are variable names used in section 2.6 of the spec */ 251*e25b118aSDominic Spill /* b is already defined */ 252*e25b118aSDominic Spill /* e is already defined */ 253*e25b118aSDominic Spill int a, c, d, f, x; 254*e25b118aSDominic Spill int h, i, j, k, c_flipped, perm_in, perm_out; 255*e25b118aSDominic Spill 256*e25b118aSDominic Spill /* sequence index = clock >> 1 */ 257*e25b118aSDominic Spill /* (hops only happen at every other clock value) */ 258*e25b118aSDominic Spill int index = 0; 259*e25b118aSDominic Spill f = 0; 260*e25b118aSDominic Spill 261*e25b118aSDominic Spill /* nested loops for optimization (not recalculating every variable with every clock tick) */ 262*e25b118aSDominic Spill for (h = 0; h < 0x04; h++) { /* clock bits 26-27 */ 263*e25b118aSDominic Spill for (i = 0; i < 0x20; i++) { /* clock bits 21-25 */ 264*e25b118aSDominic Spill a = pn->a1 ^ i; 265*e25b118aSDominic Spill for (j = 0; j < 0x20; j++) { /* clock bits 16-20 */ 266*e25b118aSDominic Spill c = pn->c1 ^ j; 267*e25b118aSDominic Spill c_flipped = c ^ 0x1f; 268*e25b118aSDominic Spill for (k = 0; k < 0x200; k++) { /* clock bits 7-15 */ 269*e25b118aSDominic Spill d = pn->d1 ^ k; 270*e25b118aSDominic Spill for (x = 0; x < 0x20; x++) { /* clock bits 2-6 */ 271*e25b118aSDominic Spill perm_in = ((x + a) % 32) ^ pn->b; 272*e25b118aSDominic Spill /* y1 (clock bit 1) = 0, y2 = 0 */ 273*e25b118aSDominic Spill perm_out = fast_perm(perm_in, c, d, pn); 274*e25b118aSDominic Spill pn->sequence[index] = pn->bank[(perm_out + pn->e + f) % BT_NUM_CHANNELS]; 275*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_IS_AFH)) { 276*e25b118aSDominic Spill pn->sequence[index + 1] = pn->sequence[index]; 277*e25b118aSDominic Spill } else { 278*e25b118aSDominic Spill /* y1 (clock bit 1) = 1, y2 = 32 */ 279*e25b118aSDominic Spill perm_out = fast_perm(perm_in, c_flipped, d, pn); 280*e25b118aSDominic Spill pn->sequence[index + 1] = pn->bank[(perm_out + pn->e + f + 32) % BT_NUM_CHANNELS]; 281*e25b118aSDominic Spill } 282*e25b118aSDominic Spill index += 2; 283*e25b118aSDominic Spill } 284*e25b118aSDominic Spill f += 16; 285*e25b118aSDominic Spill } 286*e25b118aSDominic Spill } 287*e25b118aSDominic Spill } 288*e25b118aSDominic Spill } 289*e25b118aSDominic Spill } 290*e25b118aSDominic Spill 291*e25b118aSDominic Spill /* Function to calculate piconet hopping patterns and add to hash map */ 292*e25b118aSDominic Spill void gen_hop_pattern(btbb_piconet *pn) 293*e25b118aSDominic Spill { 294*e25b118aSDominic Spill printf("\nCalculating complete hopping sequence.\n"); 295*e25b118aSDominic Spill /* this holds the entire hopping sequence */ 296*e25b118aSDominic Spill pn->sequence = (char*) malloc(SEQUENCE_LENGTH); 297*e25b118aSDominic Spill 298*e25b118aSDominic Spill precalc(pn); 299*e25b118aSDominic Spill address_precalc(((pn->UAP<<24) | pn->LAP) & 0xfffffff, pn); 300*e25b118aSDominic Spill gen_hops(pn); 301*e25b118aSDominic Spill 302*e25b118aSDominic Spill printf("Hopping sequence calculated.\n"); 303*e25b118aSDominic Spill } 304*e25b118aSDominic Spill 305*e25b118aSDominic Spill /* Container for hopping pattern */ 306*e25b118aSDominic Spill typedef struct { 307*e25b118aSDominic Spill uint64_t key; /* afh flag + address */ 308*e25b118aSDominic Spill char *sequence; 309*e25b118aSDominic Spill UT_hash_handle hh; 310*e25b118aSDominic Spill } hopping_struct; 311*e25b118aSDominic Spill 312*e25b118aSDominic Spill static hopping_struct *hopping_map = NULL; 313*e25b118aSDominic Spill 314*e25b118aSDominic Spill /* Function to fetch piconet hopping patterns */ 315*e25b118aSDominic Spill void get_hop_pattern(btbb_piconet *pn) 316*e25b118aSDominic Spill { 317*e25b118aSDominic Spill hopping_struct *s; 318*e25b118aSDominic Spill uint64_t key; 319*e25b118aSDominic Spill 320*e25b118aSDominic Spill /* Two stages to avoid "left shift count >= width of type" warning */ 321*e25b118aSDominic Spill key = btbb_piconet_get_flag(pn, BTBB_IS_AFH); 322*e25b118aSDominic Spill key = (key<<32) | (pn->UAP<<24) | pn->LAP; 323*e25b118aSDominic Spill HASH_FIND(hh, hopping_map, &key, 4, s); 324*e25b118aSDominic Spill 325*e25b118aSDominic Spill if (s == NULL) { 326*e25b118aSDominic Spill gen_hop_pattern(pn); 327*e25b118aSDominic Spill s = malloc(sizeof(hopping_struct)); 328*e25b118aSDominic Spill s->key = key; 329*e25b118aSDominic Spill s->sequence = pn->sequence; 330*e25b118aSDominic Spill HASH_ADD(hh, hopping_map, key, 4, s); 331*e25b118aSDominic Spill } else { 332*e25b118aSDominic Spill printf("\nFound hopping sequence in cache.\n"); 333*e25b118aSDominic Spill pn->sequence = s->sequence; 334*e25b118aSDominic Spill } 335*e25b118aSDominic Spill } 336*e25b118aSDominic Spill 337*e25b118aSDominic Spill /* determine channel for a particular hop */ 338*e25b118aSDominic Spill /* replaced with gen_hops() for a complete sequence but could still come in handy */ 339*e25b118aSDominic Spill char single_hop(int clock, btbb_piconet *pn) 340*e25b118aSDominic Spill { 341*e25b118aSDominic Spill int a, c, d, f, x, y1, y2; 342*e25b118aSDominic Spill 343*e25b118aSDominic Spill /* following variable names used in section 2.6 of the spec */ 344*e25b118aSDominic Spill x = (clock >> 2) & 0x1f; 345*e25b118aSDominic Spill y1 = (clock >> 1) & 0x01; 346*e25b118aSDominic Spill y2 = y1 << 5; 347*e25b118aSDominic Spill a = (pn->a1 ^ (clock >> 21)) & 0x1f; 348*e25b118aSDominic Spill /* b is already defined */ 349*e25b118aSDominic Spill c = (pn->c1 ^ (clock >> 16)) & 0x1f; 350*e25b118aSDominic Spill d = (pn->d1 ^ (clock >> 7)) & 0x1ff; 351*e25b118aSDominic Spill /* e is already defined */ 352*e25b118aSDominic Spill f = (clock >> 3) & 0x1fffff0; 353*e25b118aSDominic Spill 354*e25b118aSDominic Spill /* hop selection */ 355*e25b118aSDominic Spill return(pn->bank[(fast_perm(((x + a) % 32) ^ pn->b, (y1 * 0x1f) ^ c, d, pn) + pn->e + f + y2) % BT_NUM_CHANNELS]); 356*e25b118aSDominic Spill } 357*e25b118aSDominic Spill 358*e25b118aSDominic Spill /* look up channel for a particular hop */ 359*e25b118aSDominic Spill char hop(int clock, btbb_piconet *pn) 360*e25b118aSDominic Spill { 361*e25b118aSDominic Spill return pn->sequence[clock]; 362*e25b118aSDominic Spill } 363*e25b118aSDominic Spill 364*e25b118aSDominic Spill static char aliased_channel(char channel) 365*e25b118aSDominic Spill { 366*e25b118aSDominic Spill return ((channel + 24) % ALIASED_CHANNELS) + 26; 367*e25b118aSDominic Spill } 368*e25b118aSDominic Spill 369*e25b118aSDominic Spill /* create list of initial candidate clock values (hops with same channel as first observed hop) */ 370*e25b118aSDominic Spill static int init_candidates(char channel, int known_clock_bits, btbb_piconet *pn) 371*e25b118aSDominic Spill { 372*e25b118aSDominic Spill int i; 373*e25b118aSDominic Spill int count = 0; /* total number of candidates */ 374*e25b118aSDominic Spill char observable_channel; /* accounts for aliasing if necessary */ 375*e25b118aSDominic Spill 376*e25b118aSDominic Spill /* only try clock values that match our known bits */ 377*e25b118aSDominic Spill for (i = known_clock_bits; i < SEQUENCE_LENGTH; i += 0x40) { 378*e25b118aSDominic Spill if (pn->aliased) 379*e25b118aSDominic Spill observable_channel = aliased_channel(pn->sequence[i]); 380*e25b118aSDominic Spill else 381*e25b118aSDominic Spill observable_channel = pn->sequence[i]; 382*e25b118aSDominic Spill if (observable_channel == channel) 383*e25b118aSDominic Spill pn->clock_candidates[count++] = i; 384*e25b118aSDominic Spill //FIXME ought to throw exception if count gets too big 385*e25b118aSDominic Spill } 386*e25b118aSDominic Spill return count; 387*e25b118aSDominic Spill } 388*e25b118aSDominic Spill 389*e25b118aSDominic Spill /* initialize the hop reversal process */ 390*e25b118aSDominic Spill int btbb_init_hop_reversal(int aliased, btbb_piconet *pn) 391*e25b118aSDominic Spill { 392*e25b118aSDominic Spill int max_candidates; 393*e25b118aSDominic Spill uint32_t clock; 394*e25b118aSDominic Spill 395*e25b118aSDominic Spill get_hop_pattern(pn); 396*e25b118aSDominic Spill 397*e25b118aSDominic Spill if(aliased) 398*e25b118aSDominic Spill max_candidates = (SEQUENCE_LENGTH / ALIASED_CHANNELS) / 32; 399*e25b118aSDominic Spill else 400*e25b118aSDominic Spill max_candidates = (SEQUENCE_LENGTH / BT_NUM_CHANNELS) / 32; 401*e25b118aSDominic Spill /* this can hold twice the approximate number of initial candidates */ 402*e25b118aSDominic Spill pn->clock_candidates = (uint32_t*) malloc(sizeof(uint32_t) * max_candidates); 403*e25b118aSDominic Spill 404*e25b118aSDominic Spill clock = (pn->clk_offset + pn->first_pkt_time) & 0x3f; 405*e25b118aSDominic Spill pn->num_candidates = init_candidates(pn->pattern_channels[0], clock, pn); 406*e25b118aSDominic Spill pn->winnowed = 0; 407*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_HOP_REVERSAL_INIT, 1); 408*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 0); 409*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_IS_ALIASED, aliased); 410*e25b118aSDominic Spill 411*e25b118aSDominic Spill printf("%d initial CLK1-27 candidates\n", pn->num_candidates); 412*e25b118aSDominic Spill 413*e25b118aSDominic Spill return pn->num_candidates; 414*e25b118aSDominic Spill } 415*e25b118aSDominic Spill 416*e25b118aSDominic Spill void try_hop(btbb_packet *pkt, btbb_piconet *pn) 417*e25b118aSDominic Spill { 418*e25b118aSDominic Spill uint8_t filter_uap = pn->UAP; 419*e25b118aSDominic Spill 420*e25b118aSDominic Spill /* Decode packet - fixing clock drift in the process */ 421*e25b118aSDominic Spill btbb_decode(pkt, pn); 422*e25b118aSDominic Spill 423*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_HOP_REVERSAL_INIT)) { 424*e25b118aSDominic Spill //pn->winnowed = 0; 425*e25b118aSDominic Spill pn->pattern_indices[pn->packets_observed] = 426*e25b118aSDominic Spill pkt->clkn - pn->first_pkt_time; 427*e25b118aSDominic Spill pn->pattern_channels[pn->packets_observed] = pkt->channel; 428*e25b118aSDominic Spill pn->packets_observed++; 429*e25b118aSDominic Spill pn->total_packets_observed++; 430*e25b118aSDominic Spill btbb_winnow(pn); 431*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { 432*e25b118aSDominic Spill printf("got CLK1-27\n"); 433*e25b118aSDominic Spill printf("clock offset = %d.\n", pn->clk_offset); 434*e25b118aSDominic Spill } 435*e25b118aSDominic Spill } else { 436*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK6_VALID)) { 437*e25b118aSDominic Spill btbb_uap_from_header(pkt, pn); 438*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { 439*e25b118aSDominic Spill printf("got CLK1-27\n"); 440*e25b118aSDominic Spill printf("clock offset = %d.\n", pn->clk_offset); 441*e25b118aSDominic Spill } 442*e25b118aSDominic Spill } else { 443*e25b118aSDominic Spill if (btbb_uap_from_header(pkt, pn)) { 444*e25b118aSDominic Spill if (filter_uap == pn->UAP) { 445*e25b118aSDominic Spill printf("got CLK1-6\n"); 446*e25b118aSDominic Spill btbb_init_hop_reversal(0, pn); 447*e25b118aSDominic Spill btbb_winnow(pn); 448*e25b118aSDominic Spill } else { 449*e25b118aSDominic Spill printf("failed to confirm UAP\n"); 450*e25b118aSDominic Spill } 451*e25b118aSDominic Spill } 452*e25b118aSDominic Spill } 453*e25b118aSDominic Spill } 454*e25b118aSDominic Spill 455*e25b118aSDominic Spill if(!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) { 456*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); 457*e25b118aSDominic Spill pn->UAP = filter_uap; 458*e25b118aSDominic Spill } 459*e25b118aSDominic Spill } 460*e25b118aSDominic Spill 461*e25b118aSDominic Spill /* return the observable channel (26-50) for a given channel (0-78) */ 462*e25b118aSDominic Spill /* reset UAP/clock discovery */ 463*e25b118aSDominic Spill static void reset(btbb_piconet *pn) 464*e25b118aSDominic Spill { 465*e25b118aSDominic Spill //printf("no candidates remaining! starting over . . .\n"); 466*e25b118aSDominic Spill 467*e25b118aSDominic Spill if(btbb_piconet_get_flag(pn, BTBB_HOP_REVERSAL_INIT)) { 468*e25b118aSDominic Spill free(pn->clock_candidates); 469*e25b118aSDominic Spill pn->sequence = NULL; 470*e25b118aSDominic Spill } 471*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_GOT_FIRST_PACKET, 0); 472*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_HOP_REVERSAL_INIT, 0); 473*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 0); 474*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 0); 475*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 0); 476*e25b118aSDominic Spill pn->packets_observed = 0; 477*e25b118aSDominic Spill 478*e25b118aSDominic Spill /* 479*e25b118aSDominic Spill * If we have recently observed two packets in a row on the same 480*e25b118aSDominic Spill * channel, try AFH next time. If not, don't. 481*e25b118aSDominic Spill */ 482*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_IS_AFH, 483*e25b118aSDominic Spill btbb_piconet_get_flag(pn, BTBB_LOOKS_LIKE_AFH)); 484*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_LOOKS_LIKE_AFH, 0); 485*e25b118aSDominic Spill //int i; 486*e25b118aSDominic Spill //for(i=0; i<10; i++) 487*e25b118aSDominic Spill // pn->afh_map[i] = 0; 488*e25b118aSDominic Spill } 489*e25b118aSDominic Spill 490*e25b118aSDominic Spill /* narrow a list of candidate clock values based on a single observed hop */ 491*e25b118aSDominic Spill static int channel_winnow(int offset, char channel, btbb_piconet *pn) 492*e25b118aSDominic Spill { 493*e25b118aSDominic Spill int i; 494*e25b118aSDominic Spill int new_count = 0; /* number of candidates after winnowing */ 495*e25b118aSDominic Spill char observable_channel; /* accounts for aliasing if necessary */ 496*e25b118aSDominic Spill 497*e25b118aSDominic Spill /* check every candidate */ 498*e25b118aSDominic Spill for (i = 0; i < pn->num_candidates; i++) { 499*e25b118aSDominic Spill if (pn->aliased) 500*e25b118aSDominic Spill observable_channel = aliased_channel(pn->sequence[(pn->clock_candidates[i] + offset) % SEQUENCE_LENGTH]); 501*e25b118aSDominic Spill else 502*e25b118aSDominic Spill observable_channel = pn->sequence[(pn->clock_candidates[i] + offset) % SEQUENCE_LENGTH]; 503*e25b118aSDominic Spill if (observable_channel == channel) { 504*e25b118aSDominic Spill /* this candidate matches the latest hop */ 505*e25b118aSDominic Spill /* blow away old list of candidates with new one */ 506*e25b118aSDominic Spill /* safe because new_count can never be greater than i */ 507*e25b118aSDominic Spill pn->clock_candidates[new_count++] = pn->clock_candidates[i]; 508*e25b118aSDominic Spill } 509*e25b118aSDominic Spill } 510*e25b118aSDominic Spill pn->num_candidates = new_count; 511*e25b118aSDominic Spill 512*e25b118aSDominic Spill if (new_count == 1) { 513*e25b118aSDominic Spill // Calculate clock offset for CLKN, not CLK1-27 514*e25b118aSDominic Spill pn->clk_offset = ((pn->clock_candidates[0]<<1) - (pn->first_pkt_time<<1)); 515*e25b118aSDominic Spill printf("\nAcquired CLK1-27 = 0x%07x\n", pn->clock_candidates[0]); 516*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 1); 517*e25b118aSDominic Spill } 518*e25b118aSDominic Spill else if (new_count == 0) { 519*e25b118aSDominic Spill reset(pn); 520*e25b118aSDominic Spill } 521*e25b118aSDominic Spill //else { 522*e25b118aSDominic Spill //printf("%d CLK1-27 candidates remaining (channel=%d)\n", new_count, channel); 523*e25b118aSDominic Spill //} 524*e25b118aSDominic Spill 525*e25b118aSDominic Spill return new_count; 526*e25b118aSDominic Spill } 527*e25b118aSDominic Spill 528*e25b118aSDominic Spill /* narrow a list of candidate clock values based on all observed hops */ 529*e25b118aSDominic Spill int btbb_winnow(btbb_piconet *pn) 530*e25b118aSDominic Spill { 531*e25b118aSDominic Spill int new_count = pn->num_candidates; 532*e25b118aSDominic Spill int index, last_index; 533*e25b118aSDominic Spill uint8_t channel, last_channel; 534*e25b118aSDominic Spill 535*e25b118aSDominic Spill for (; pn->winnowed < pn->packets_observed; pn->winnowed++) { 536*e25b118aSDominic Spill index = pn->pattern_indices[pn->winnowed]; 537*e25b118aSDominic Spill channel = pn->pattern_channels[pn->winnowed]; 538*e25b118aSDominic Spill new_count = channel_winnow(index, channel, pn); 539*e25b118aSDominic Spill if (new_count <= 1) 540*e25b118aSDominic Spill break; 541*e25b118aSDominic Spill 542*e25b118aSDominic Spill if (pn->packets_observed > 0) { 543*e25b118aSDominic Spill last_index = pn->pattern_indices[pn->winnowed - 1]; 544*e25b118aSDominic Spill last_channel = pn->pattern_channels[pn->winnowed - 1]; 545*e25b118aSDominic Spill /* 546*e25b118aSDominic Spill * Two packets in a row on the same channel should only 547*e25b118aSDominic Spill * happen if adaptive frequency hopping is in use. 548*e25b118aSDominic Spill * There can be false positives, though, especially if 549*e25b118aSDominic Spill * there is aliasing. 550*e25b118aSDominic Spill */ 551*e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_LOOKS_LIKE_AFH) 552*e25b118aSDominic Spill && (index == last_index + 1) 553*e25b118aSDominic Spill && (channel == last_channel)) { 554*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_LOOKS_LIKE_AFH, 1); 555*e25b118aSDominic Spill printf("Hopping pattern appears to be AFH\n"); 556*e25b118aSDominic Spill } 557*e25b118aSDominic Spill } 558*e25b118aSDominic Spill } 559*e25b118aSDominic Spill 560*e25b118aSDominic Spill return new_count; 561*e25b118aSDominic Spill } 562*e25b118aSDominic Spill 563*e25b118aSDominic Spill /* use packet headers to determine UAP */ 564*e25b118aSDominic Spill int btbb_uap_from_header(btbb_packet *pkt, btbb_piconet *pn) 565*e25b118aSDominic Spill { 566*e25b118aSDominic Spill uint8_t UAP; 567*e25b118aSDominic Spill int count, crc_chk, first_clock = 0; 568*e25b118aSDominic Spill 569*e25b118aSDominic Spill int starting = 0; 570*e25b118aSDominic Spill int remaining = 0; 571*e25b118aSDominic Spill uint32_t clkn = pkt->clkn; 572*e25b118aSDominic Spill 573*e25b118aSDominic Spill if (!pn->got_first_packet) 574*e25b118aSDominic Spill pn->first_pkt_time = clkn; 575*e25b118aSDominic Spill 576*e25b118aSDominic Spill // Set afh channel map 577*e25b118aSDominic Spill pn->afh_map[pkt->channel/8] |= 0x1 << (pkt->channel % 8); 578*e25b118aSDominic Spill 579*e25b118aSDominic Spill if (pn->packets_observed < MAX_PATTERN_LENGTH) { 580*e25b118aSDominic Spill pn->pattern_indices[pn->packets_observed] = clkn - pn->first_pkt_time; 581*e25b118aSDominic Spill pn->pattern_channels[pn->packets_observed] = pkt->channel; 582*e25b118aSDominic Spill } else { 583*e25b118aSDominic Spill printf("Oops. More hops than we can remember.\n"); 584*e25b118aSDominic Spill reset(pn); 585*e25b118aSDominic Spill return 0; //FIXME ought to throw exception 586*e25b118aSDominic Spill } 587*e25b118aSDominic Spill pn->packets_observed++; 588*e25b118aSDominic Spill pn->total_packets_observed++; 589*e25b118aSDominic Spill 590*e25b118aSDominic Spill /* try every possible first packet clock value */ 591*e25b118aSDominic Spill for (count = 0; count < 64; count++) { 592*e25b118aSDominic Spill /* skip eliminated candidates unless this is our first time through */ 593*e25b118aSDominic Spill if (pn->clock6_candidates[count] > -1 || !pn->got_first_packet) { 594*e25b118aSDominic Spill /* clock value for the current packet assuming count was the clock of the first packet */ 595*e25b118aSDominic Spill int clock = (count + clkn - pn->first_pkt_time) % 64; 596*e25b118aSDominic Spill starting++; 597*e25b118aSDominic Spill UAP = try_clock(clock, pkt); 598*e25b118aSDominic Spill crc_chk = -1; 599*e25b118aSDominic Spill 600*e25b118aSDominic Spill /* if this is the first packet: populate the candidate list */ 601*e25b118aSDominic Spill /* if not: check CRCs if UAPs match */ 602*e25b118aSDominic Spill if (!pn->got_first_packet || UAP == pn->clock6_candidates[count]) 603*e25b118aSDominic Spill crc_chk = crc_check(clock, pkt); 604*e25b118aSDominic Spill 605*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_UAP_VALID) && 606*e25b118aSDominic Spill (UAP != pn->UAP)) 607*e25b118aSDominic Spill crc_chk = -1; 608*e25b118aSDominic Spill 609*e25b118aSDominic Spill switch(crc_chk) { 610*e25b118aSDominic Spill case -1: /* UAP mismatch */ 611*e25b118aSDominic Spill case 0: /* CRC failure */ 612*e25b118aSDominic Spill pn->clock6_candidates[count] = -1; 613*e25b118aSDominic Spill break; 614*e25b118aSDominic Spill 615*e25b118aSDominic Spill case 1: /* inconclusive result */ 616*e25b118aSDominic Spill pn->clock6_candidates[count] = UAP; 617*e25b118aSDominic Spill /* remember this count because it may be the correct clock of the first packet */ 618*e25b118aSDominic Spill first_clock = count; 619*e25b118aSDominic Spill remaining++; 620*e25b118aSDominic Spill break; 621*e25b118aSDominic Spill 622*e25b118aSDominic Spill default: /* CRC success */ 623*e25b118aSDominic Spill pn->clk_offset = (count - (pn->first_pkt_time & 0x3f)) & 0x3f; 624*e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) 625*e25b118aSDominic Spill printf("Correct CRC! UAP = 0x%x found after %d total packets.\n", 626*e25b118aSDominic Spill UAP, pn->total_packets_observed); 627*e25b118aSDominic Spill else 628*e25b118aSDominic Spill printf("Correct CRC! CLK6 = 0x%x found after %d total packets.\n", 629*e25b118aSDominic Spill pn->clk_offset, pn->total_packets_observed); 630*e25b118aSDominic Spill pn->UAP = UAP; 631*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 1); 632*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); 633*e25b118aSDominic Spill pn->total_packets_observed = 0; 634*e25b118aSDominic Spill return 1; 635*e25b118aSDominic Spill } 636*e25b118aSDominic Spill } 637*e25b118aSDominic Spill } 638*e25b118aSDominic Spill 639*e25b118aSDominic Spill pn->got_first_packet = 1; 640*e25b118aSDominic Spill 641*e25b118aSDominic Spill //printf("reduced from %d to %d CLK1-6 candidates\n", starting, remaining); 642*e25b118aSDominic Spill 643*e25b118aSDominic Spill if (remaining == 1) { 644*e25b118aSDominic Spill pn->clk_offset = (first_clock - (pn->first_pkt_time & 0x3f)) & 0x3f; 645*e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) 646*e25b118aSDominic Spill printf("We have a winner! UAP = 0x%x found after %d total packets.\n", 647*e25b118aSDominic Spill pn->clock6_candidates[first_clock], pn->total_packets_observed); 648*e25b118aSDominic Spill else 649*e25b118aSDominic Spill printf("We have a winner! CLK6 = 0x%x found after %d total packets.\n", 650*e25b118aSDominic Spill pn->clk_offset, pn->total_packets_observed); 651*e25b118aSDominic Spill pn->UAP = pn->clock6_candidates[first_clock]; 652*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 1); 653*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); 654*e25b118aSDominic Spill pn->total_packets_observed = 0; 655*e25b118aSDominic Spill return 1; 656*e25b118aSDominic Spill } 657*e25b118aSDominic Spill 658*e25b118aSDominic Spill if (remaining == 0) { 659*e25b118aSDominic Spill reset(pn); 660*e25b118aSDominic Spill } 661*e25b118aSDominic Spill 662*e25b118aSDominic Spill return 0; 663*e25b118aSDominic Spill } 664*e25b118aSDominic Spill 665*e25b118aSDominic Spill /* add a packet to the queue */ 666*e25b118aSDominic Spill static void enqueue(btbb_packet *pkt, btbb_piconet *pn) 667*e25b118aSDominic Spill { 668*e25b118aSDominic Spill pkt_queue *head; 669*e25b118aSDominic Spill //pkt_queue item; 670*e25b118aSDominic Spill 671*e25b118aSDominic Spill btbb_packet_ref(pkt); 672*e25b118aSDominic Spill pkt_queue item = {pkt, NULL}; 673*e25b118aSDominic Spill head = pn->queue; 674*e25b118aSDominic Spill 675*e25b118aSDominic Spill if (head == NULL) { 676*e25b118aSDominic Spill pn->queue = &item; 677*e25b118aSDominic Spill } else { 678*e25b118aSDominic Spill for(; head->next != NULL; head = head->next) 679*e25b118aSDominic Spill ; 680*e25b118aSDominic Spill head->next = &item; 681*e25b118aSDominic Spill } 682*e25b118aSDominic Spill } 683*e25b118aSDominic Spill 684*e25b118aSDominic Spill /* pull the first packet from the queue (FIFO) */ 685*e25b118aSDominic Spill static btbb_packet *dequeue(btbb_piconet *pn) 686*e25b118aSDominic Spill { 687*e25b118aSDominic Spill btbb_packet *pkt; 688*e25b118aSDominic Spill 689*e25b118aSDominic Spill if (pn->queue == NULL) { 690*e25b118aSDominic Spill pkt = NULL; 691*e25b118aSDominic Spill } else { 692*e25b118aSDominic Spill pkt = pn->queue->pkt; 693*e25b118aSDominic Spill pn->queue = pn->queue->next; 694*e25b118aSDominic Spill btbb_packet_unref(pkt); 695*e25b118aSDominic Spill } 696*e25b118aSDominic Spill 697*e25b118aSDominic Spill return pkt; 698*e25b118aSDominic Spill } 699*e25b118aSDominic Spill 700*e25b118aSDominic Spill /* decode the whole packet */ 701*e25b118aSDominic Spill int btbb_decode(btbb_packet* pkt, btbb_piconet *pn) 702*e25b118aSDominic Spill { 703*e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 0); 704*e25b118aSDominic Spill uint8_t clk6, i; 705*e25b118aSDominic Spill int rv = 0; 706*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { 707*e25b118aSDominic Spill if(pn->sequence == NULL) 708*e25b118aSDominic Spill get_hop_pattern(pn); 709*e25b118aSDominic Spill clk6 = pkt->clock & 0x3f; 710*e25b118aSDominic Spill for(i=0; i<64; i++) { 711*e25b118aSDominic Spill pkt->clock = (pkt->clock & 0xffffffc0) | ((clk6 + i) & 0x3f); 712*e25b118aSDominic Spill if ((pn->sequence[pkt->clock] == pkt->channel) && (btbb_decode_header(pkt))) { 713*e25b118aSDominic Spill rv = btbb_decode_payload(pkt); 714*e25b118aSDominic Spill if(rv > 0) { 715*e25b118aSDominic Spill printf("Packet decoded with clock 0x%07x (rv=%d)\n", pkt->clock, rv); 716*e25b118aSDominic Spill btbb_print_packet(pkt); 717*e25b118aSDominic Spill } 718*e25b118aSDominic Spill // TODO: make sure we use best result 719*e25b118aSDominic Spill } 720*e25b118aSDominic Spill } 721*e25b118aSDominic Spill if(rv == 0) { 722*e25b118aSDominic Spill clk6 = pkt->clock & 0x3f; 723*e25b118aSDominic Spill for(i=0; i<64; i++) { 724*e25b118aSDominic Spill pkt->clock = (pkt->clock & 0xffffffc0) | ((clk6 + i) & 0x3f); 725*e25b118aSDominic Spill if (btbb_decode_header(pkt)) { 726*e25b118aSDominic Spill rv = btbb_decode_payload(pkt); 727*e25b118aSDominic Spill if(rv > 0) { 728*e25b118aSDominic Spill printf("Packet decoded with clock 0x%07x (rv=%d)\n", pkt->clock, rv); 729*e25b118aSDominic Spill btbb_print_packet(pkt); 730*e25b118aSDominic Spill } 731*e25b118aSDominic Spill // TODO: make sure we use best result 732*e25b118aSDominic Spill } 733*e25b118aSDominic Spill } 734*e25b118aSDominic Spill } 735*e25b118aSDominic Spill } else 736*e25b118aSDominic Spill if (btbb_decode_header(pkt)) 737*e25b118aSDominic Spill rv = btbb_decode_payload(pkt); 738*e25b118aSDominic Spill 739*e25b118aSDominic Spill return rv; 740*e25b118aSDominic Spill } 741*e25b118aSDominic Spill 742*e25b118aSDominic Spill /* Print AFH map from observed packets */ 743*e25b118aSDominic Spill void btbb_print_afh_map(btbb_piconet *pn) { 744*e25b118aSDominic Spill uint8_t *afh_map, i; 745*e25b118aSDominic Spill afh_map = pn->afh_map; 746*e25b118aSDominic Spill 747*e25b118aSDominic Spill /* Printed ch78 -> ch0 */ 748*e25b118aSDominic Spill printf("\tAFH Map=0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", 749*e25b118aSDominic Spill afh_map[9], afh_map[8], afh_map[7], afh_map[6], afh_map[5], 750*e25b118aSDominic Spill afh_map[4], afh_map[3], afh_map[2], afh_map[1], afh_map[0]); 751*e25b118aSDominic Spill } 752*e25b118aSDominic Spill 753*e25b118aSDominic Spill /* Container for survey piconets */ 754*e25b118aSDominic Spill typedef struct { 755*e25b118aSDominic Spill uint32_t key; /* LAP */ 756*e25b118aSDominic Spill btbb_piconet *pn; 757*e25b118aSDominic Spill UT_hash_handle hh; 758*e25b118aSDominic Spill } survey_hash; 759*e25b118aSDominic Spill 760*e25b118aSDominic Spill static survey_hash *piconet_survey = NULL; 761*e25b118aSDominic Spill 762*e25b118aSDominic Spill /* A bit of a hack? to set survey mode */ 763*e25b118aSDominic Spill static int survey_mode = 0; 764*e25b118aSDominic Spill int btbb_init_survey() { 765*e25b118aSDominic Spill survey_mode = 1; 766*e25b118aSDominic Spill return 0; 767*e25b118aSDominic Spill } 768*e25b118aSDominic Spill 769*e25b118aSDominic Spill /* Check for existing piconets in survey results */ 770*e25b118aSDominic Spill btbb_piconet *get_piconet(uint32_t lap) 771*e25b118aSDominic Spill { 772*e25b118aSDominic Spill survey_hash *s; 773*e25b118aSDominic Spill btbb_piconet *pn; 774*e25b118aSDominic Spill HASH_FIND(hh, piconet_survey, &lap, 4, s); 775*e25b118aSDominic Spill 776*e25b118aSDominic Spill if (s == NULL) { 777*e25b118aSDominic Spill pn = btbb_piconet_new(); 778*e25b118aSDominic Spill btbb_init_piconet(pn, lap); 779*e25b118aSDominic Spill 780*e25b118aSDominic Spill s = malloc(sizeof(survey_hash)); 781*e25b118aSDominic Spill s->key = lap; 782*e25b118aSDominic Spill s->pn = pn; 783*e25b118aSDominic Spill HASH_ADD(hh, piconet_survey, key, 4, s); 784*e25b118aSDominic Spill } else { 785*e25b118aSDominic Spill pn = s->pn; 786*e25b118aSDominic Spill } 787*e25b118aSDominic Spill return pn; 788*e25b118aSDominic Spill } 789*e25b118aSDominic Spill 790*e25b118aSDominic Spill /* Destructively iterate over survey results */ 791*e25b118aSDominic Spill btbb_piconet *btbb_next_survey_result() { 792*e25b118aSDominic Spill btbb_piconet *pn = NULL; 793*e25b118aSDominic Spill survey_hash *tmp; 794*e25b118aSDominic Spill 795*e25b118aSDominic Spill if (piconet_survey != NULL) { 796*e25b118aSDominic Spill pn = piconet_survey->pn; 797*e25b118aSDominic Spill tmp = piconet_survey; 798*e25b118aSDominic Spill piconet_survey = piconet_survey->hh.next; 799*e25b118aSDominic Spill free(tmp); 800*e25b118aSDominic Spill } 801*e25b118aSDominic Spill return pn; 802*e25b118aSDominic Spill } 803*e25b118aSDominic Spill 804*e25b118aSDominic Spill int btbb_process_packet(btbb_packet *pkt, btbb_piconet *pn) { 805*e25b118aSDominic Spill if (survey_mode) { 806*e25b118aSDominic Spill pn = get_piconet(btbb_packet_get_lap(pkt)); 807*e25b118aSDominic Spill btbb_piconet_set_channel_seen(pn, pkt->channel); 808*e25b118aSDominic Spill if(btbb_header_present(pkt) && !btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) 809*e25b118aSDominic Spill btbb_uap_from_header(pkt, pn); 810*e25b118aSDominic Spill return 0; 811*e25b118aSDominic Spill } 812*e25b118aSDominic Spill 813*e25b118aSDominic Spill /* If piconet structure is given, a LAP is given, and packet 814*e25b118aSDominic Spill * header is readable, do further analysis. If UAP has not yet 815*e25b118aSDominic Spill * been determined, attempt to calculate it from headers. Once 816*e25b118aSDominic Spill * UAP is known, try to determine clk6 and clk27. Once clocks 817*e25b118aSDominic Spill * are known, follow the piconet. */ 818*e25b118aSDominic Spill if (pn && btbb_piconet_get_flag(pn, BTBB_LAP_VALID) && 819*e25b118aSDominic Spill btbb_header_present(pkt)) { 820*e25b118aSDominic Spill 821*e25b118aSDominic Spill /* Have LAP/UAP/clocks, now hopping along with the piconet. */ 822*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_FOLLOWING)) { 823*e25b118aSDominic Spill btbb_packet_set_uap(pkt, btbb_piconet_get_uap(pn)); 824*e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_CLK6_VALID, 1); 825*e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_CLK27_VALID, 1); 826*e25b118aSDominic Spill 827*e25b118aSDominic Spill if(btbb_decode(pkt, pn)) 828*e25b118aSDominic Spill btbb_print_packet(pkt); 829*e25b118aSDominic Spill else 830*e25b118aSDominic Spill printf("Failed to decode packet\n"); 831*e25b118aSDominic Spill } 832*e25b118aSDominic Spill 833*e25b118aSDominic Spill /* Have LAP/UAP, need clocks. */ 834*e25b118aSDominic Spill else if (btbb_piconet_get_uap(pn)) { 835*e25b118aSDominic Spill try_hop(pkt, pn); 836*e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK6_VALID) && 837*e25b118aSDominic Spill btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { 838*e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_FOLLOWING, 1); 839*e25b118aSDominic Spill return -1; 840*e25b118aSDominic Spill } 841*e25b118aSDominic Spill } 842*e25b118aSDominic Spill 843*e25b118aSDominic Spill /* Have LAP, need UAP. */ 844*e25b118aSDominic Spill else { 845*e25b118aSDominic Spill btbb_uap_from_header(pkt, pn); 846*e25b118aSDominic Spill } 847*e25b118aSDominic Spill } 848*e25b118aSDominic Spill return 0; 849*e25b118aSDominic Spill } 850