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 */
count_bits(uint8_t n)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 *
btbb_piconet_new(void)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
btbb_piconet_ref(btbb_piconet * pn)50e25b118aSDominic Spill btbb_piconet_ref(btbb_piconet *pn)
51e25b118aSDominic Spill {
52e25b118aSDominic Spill pn->refcount++;
53e25b118aSDominic Spill }
54e25b118aSDominic Spill
55e25b118aSDominic Spill void
btbb_piconet_unref(btbb_piconet * pn)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;
btbb_init_survey()65647977deSDominic Spill int btbb_init_survey() {
66647977deSDominic Spill survey_mode = 1;
67647977deSDominic Spill return 0;
68647977deSDominic Spill }
69647977deSDominic Spill
btbb_init_piconet(btbb_piconet * pn,uint32_t lap)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
btbb_piconet_set_flag(btbb_piconet * pn,int flag,int val)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
btbb_piconet_get_flag(const btbb_piconet * pn,const int flag)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
btbb_piconet_set_uap(btbb_piconet * pn,uint8_t uap)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
btbb_piconet_get_uap(const btbb_piconet * pn)968f3e7eeaSChristopher Kilgour uint8_t btbb_piconet_get_uap(const btbb_piconet *pn)
97e25b118aSDominic Spill {
98e25b118aSDominic Spill return pn->UAP;
99e25b118aSDominic Spill }
100e25b118aSDominic Spill
btbb_piconet_get_lap(const btbb_piconet * pn)1018f3e7eeaSChristopher Kilgour uint32_t btbb_piconet_get_lap(const btbb_piconet *pn)
102e25b118aSDominic Spill {
103e25b118aSDominic Spill return pn->LAP;
104e25b118aSDominic Spill }
105e25b118aSDominic Spill
btbb_piconet_get_nap(const btbb_piconet * pn)1068f3e7eeaSChristopher Kilgour uint16_t btbb_piconet_get_nap(const btbb_piconet *pn)
107e25b118aSDominic Spill {
108e25b118aSDominic Spill return pn->NAP;
109e25b118aSDominic Spill }
110e25b118aSDominic Spill
btbb_piconet_get_bdaddr(const btbb_piconet * pn)11150438040SDominic Spill uint64_t btbb_piconet_get_bdaddr(const btbb_piconet *pn)
11250438040SDominic Spill {
113*a648d971SDominic Spill return ((uint64_t) pn->NAP) << 32 | ((uint32_t) pn->UAP) << 24 | pn->LAP;
11450438040SDominic Spill }
11550438040SDominic Spill
btbb_piconet_get_clk_offset(const btbb_piconet * pn)1168f3e7eeaSChristopher Kilgour int btbb_piconet_get_clk_offset(const btbb_piconet *pn)
117e25b118aSDominic Spill {
118e25b118aSDominic Spill return pn->clk_offset;
119e25b118aSDominic Spill }
120e25b118aSDominic Spill
btbb_piconet_set_clk_offset(btbb_piconet * pn,int clk_offset)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
btbb_piconet_set_afh_map(btbb_piconet * pn,uint8_t * afh_map)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
btbb_piconet_get_afh_map(btbb_piconet * pn)138e25b118aSDominic Spill uint8_t *btbb_piconet_get_afh_map(btbb_piconet *pn) {
139e25b118aSDominic Spill return pn->afh_map;
140e25b118aSDominic Spill }
141e25b118aSDominic Spill
btbb_piconet_set_channel_seen(btbb_piconet * pn,uint8_t channel)14275358bb0SHannes 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++;
14775358bb0SHannes Ellinger return 1;
148f1965e4dSHannes Ellinger }
14975358bb0SHannes Ellinger return 0;
15075358bb0SHannes Ellinger }
15175358bb0SHannes Ellinger
btbb_piconet_clear_channel_seen(btbb_piconet * pn,uint8_t channel)15275358bb0SHannes Ellinger uint8_t btbb_piconet_clear_channel_seen(btbb_piconet *pn, uint8_t channel)
15375358bb0SHannes Ellinger {
15475358bb0SHannes Ellinger if((pn->afh_map[channel/8] & 0x1 << (channel % 8))) {
15575358bb0SHannes Ellinger pn->afh_map[channel/8] &= ~(0x1 << (channel % 8));
15675358bb0SHannes Ellinger pn->used_channels--;
15775358bb0SHannes Ellinger return 1;
15875358bb0SHannes Ellinger }
15975358bb0SHannes Ellinger return 0;
160f1965e4dSHannes Ellinger }
161f1965e4dSHannes Ellinger
btbb_piconet_get_channel_seen(btbb_piconet * pn,uint8_t channel)162f1965e4dSHannes Ellinger uint8_t btbb_piconet_get_channel_seen(btbb_piconet *pn, uint8_t channel)
163f1965e4dSHannes Ellinger {
1645d9f832cSMike Ryan if(channel < BT_NUM_CHANNELS)
165f1965e4dSHannes Ellinger return ( pn->afh_map[channel/8] & (1 << (channel % 8)) ) != 0;
166f1965e4dSHannes Ellinger else
167f1965e4dSHannes Ellinger return 1;
168e25b118aSDominic Spill }
169e25b118aSDominic Spill
170e25b118aSDominic Spill /* do all the precalculation that can be done before knowing the address */
precalc(btbb_piconet * pn)171e25b118aSDominic Spill void precalc(btbb_piconet *pn)
172e25b118aSDominic Spill {
173f1965e4dSHannes Ellinger int i = 0;
174f1965e4dSHannes Ellinger int j = 0;
175f1965e4dSHannes Ellinger int chan;
176e25b118aSDominic Spill
177e25b118aSDominic Spill /* populate frequency register bank*/
178f1965e4dSHannes Ellinger for (i = 0; i < BT_NUM_CHANNELS; i++) {
179f1965e4dSHannes Ellinger
180f1965e4dSHannes Ellinger /* AFH is used, hopping sequence contains only used channels */
181f1965e4dSHannes Ellinger if(btbb_piconet_get_flag(pn, BTBB_IS_AFH)) {
182f1965e4dSHannes Ellinger chan = (i * 2) % BT_NUM_CHANNELS;
183f1965e4dSHannes Ellinger if(btbb_piconet_get_channel_seen(pn, chan))
184f1965e4dSHannes Ellinger pn->bank[j++] = chan;
185f1965e4dSHannes Ellinger }
186f1965e4dSHannes Ellinger
187f1965e4dSHannes Ellinger /* all channels are used */
188f1965e4dSHannes Ellinger else {
189e25b118aSDominic Spill pn->bank[i] = ((i * 2) % BT_NUM_CHANNELS);
190f1965e4dSHannes Ellinger }
191f1965e4dSHannes Ellinger }
192e25b118aSDominic Spill /* actual frequency is 2402 + pn->bank[i] MHz */
193e25b118aSDominic Spill
194e25b118aSDominic Spill }
195e25b118aSDominic Spill
196e25b118aSDominic Spill /* do precalculation that requires the address */
address_precalc(int address,btbb_piconet * pn)197e25b118aSDominic Spill void address_precalc(int address, btbb_piconet *pn)
198e25b118aSDominic Spill {
199e25b118aSDominic Spill /* precalculate some of single_hop()/gen_hop()'s variables */
200e25b118aSDominic Spill pn->a1 = (address >> 23) & 0x1f;
201e25b118aSDominic Spill pn->b = (address >> 19) & 0x0f;
202e25b118aSDominic Spill pn->c1 = ((address >> 4) & 0x10) +
203e25b118aSDominic Spill ((address >> 3) & 0x08) +
204e25b118aSDominic Spill ((address >> 2) & 0x04) +
205e25b118aSDominic Spill ((address >> 1) & 0x02) +
206e25b118aSDominic Spill (address & 0x01);
207e25b118aSDominic Spill pn->d1 = (address >> 10) & 0x1ff;
208e25b118aSDominic Spill pn->e = ((address >> 7) & 0x40) +
209e25b118aSDominic Spill ((address >> 6) & 0x20) +
210e25b118aSDominic Spill ((address >> 5) & 0x10) +
211e25b118aSDominic Spill ((address >> 4) & 0x08) +
212e25b118aSDominic Spill ((address >> 3) & 0x04) +
213e25b118aSDominic Spill ((address >> 2) & 0x02) +
214e25b118aSDominic Spill ((address >> 1) & 0x01);
215e25b118aSDominic Spill }
216e25b118aSDominic Spill
217e25b118aSDominic Spill #ifdef WC4
218e25b118aSDominic Spill /* These are optimization experiments, which don't help much for
219e25b118aSDominic Spill * x86. Hold on to them to see whether they're useful on ARM. */
220e25b118aSDominic Spill
221e25b118aSDominic Spill #ifdef NEVER
222e25b118aSDominic Spill #define BUTTERFLY(z,p,c,a,b) \
223e25b118aSDominic Spill if ( ((p&(1<<c))!=0) & (((z&(1<<a))!=0) ^ ((z&(1<<b))!=0)) ) \
224e25b118aSDominic Spill z ^= ((1<<a)|(1<<b))
225e25b118aSDominic Spill #endif
226e25b118aSDominic Spill
227e25b118aSDominic Spill #define BUTTERFLY(z,p,c,a,b) \
228e25b118aSDominic Spill if ( (((z>>a)^(z>>b)) & (p>>c)) & 0x1 ) \
229e25b118aSDominic Spill z ^= ((1<<a)|(1<<b))
230e25b118aSDominic Spill
perm5(int z,int p_high,int p_low)231e25b118aSDominic Spill int perm5(int z, int p_high, int p_low)
232e25b118aSDominic Spill {
233e25b118aSDominic Spill int p = (p_high << 5) | p_low;
234e25b118aSDominic Spill BUTTERFLY(z,p,13,1,2);
235e25b118aSDominic Spill BUTTERFLY(z,p,12,0,3);
236e25b118aSDominic Spill BUTTERFLY(z,p,11,1,3);
237e25b118aSDominic Spill BUTTERFLY(z,p,10,2,4);
238e25b118aSDominic Spill BUTTERFLY(z,p, 9,0,3);
239e25b118aSDominic Spill BUTTERFLY(z,p, 8,1,4);
240e25b118aSDominic Spill BUTTERFLY(z,p, 7,3,4);
241e25b118aSDominic Spill BUTTERFLY(z,p, 6,0,2);
242e25b118aSDominic Spill BUTTERFLY(z,p, 5,1,3);
243e25b118aSDominic Spill BUTTERFLY(z,p, 4,0,4);
244e25b118aSDominic Spill BUTTERFLY(z,p, 3,3,4);
245e25b118aSDominic Spill BUTTERFLY(z,p, 2,1,2);
246e25b118aSDominic Spill BUTTERFLY(z,p, 1,2,3);
247e25b118aSDominic Spill BUTTERFLY(z,p, 0,0,1);
248e25b118aSDominic Spill
249e25b118aSDominic Spill return z;
250e25b118aSDominic Spill }
251e25b118aSDominic Spill #endif // WC4
252e25b118aSDominic Spill
253e25b118aSDominic Spill /* 5 bit permutation */
254e25b118aSDominic Spill /* assumes z is constrained to 5 bits, p_high to 5 bits, p_low to 9 bits */
perm5(int z,int p_high,int p_low)255e25b118aSDominic Spill int perm5(int z, int p_high, int p_low)
256e25b118aSDominic Spill {
257e25b118aSDominic Spill int i, tmp, output, z_bit[5], p[14];
258e25b118aSDominic Spill int index1[] = {0, 2, 1, 3, 0, 1, 0, 3, 1, 0, 2, 1, 0, 1};
259e25b118aSDominic Spill int index2[] = {1, 3, 2, 4, 4, 3, 2, 4, 4, 3, 4, 3, 3, 2};
260e25b118aSDominic Spill
261e25b118aSDominic Spill /* bits of p_low and p_high are control signals */
262e25b118aSDominic Spill for (i = 0; i < 9; i++)
263e25b118aSDominic Spill p[i] = (p_low >> i) & 0x01;
264e25b118aSDominic Spill for (i = 0; i < 5; i++)
265e25b118aSDominic Spill p[i+9] = (p_high >> i) & 0x01;
266e25b118aSDominic Spill
267e25b118aSDominic Spill /* bit swapping will be easier with an array of bits */
268e25b118aSDominic Spill for (i = 0; i < 5; i++)
269e25b118aSDominic Spill z_bit[i] = (z >> i) & 0x01;
270e25b118aSDominic Spill
271e25b118aSDominic Spill /* butterfly operations */
272e25b118aSDominic Spill for (i = 13; i >= 0; i--) {
273e25b118aSDominic Spill /* swap bits according to index arrays if control signal tells us to */
274e25b118aSDominic Spill if (p[i]) {
275e25b118aSDominic Spill tmp = z_bit[index1[i]];
276e25b118aSDominic Spill z_bit[index1[i]] = z_bit[index2[i]];
277e25b118aSDominic Spill z_bit[index2[i]] = tmp;
278e25b118aSDominic Spill }
279e25b118aSDominic Spill }
280e25b118aSDominic Spill
281e25b118aSDominic Spill /* reconstruct output from rearranged bits */
282e25b118aSDominic Spill output = 0;
283e25b118aSDominic Spill for (i = 0; i < 5; i++)
284e25b118aSDominic Spill output += z_bit[i] << i;
285e25b118aSDominic Spill
286e25b118aSDominic Spill return(output);
287e25b118aSDominic Spill }
288e25b118aSDominic Spill
perm_table_init(void)289e25b118aSDominic Spill void perm_table_init(void)
290e25b118aSDominic Spill {
291e25b118aSDominic Spill /* populate perm_table for all possible inputs */
292e25b118aSDominic Spill int z, p_high, p_low;
293e25b118aSDominic Spill for (z = 0; z < 0x20; z++)
294e25b118aSDominic Spill for (p_high = 0; p_high < 0x20; p_high++)
295e25b118aSDominic Spill for (p_low = 0; p_low < 0x200; p_low++)
296e25b118aSDominic Spill perm_table[z][p_high][p_low] = perm5(z, p_high, p_low);
297e25b118aSDominic Spill }
298e25b118aSDominic Spill
299e25b118aSDominic Spill /* drop-in replacement for perm5() using lookup table */
fast_perm(int z,int p_high,int p_low)3001e7f449bSDominic Spill int fast_perm(int z, int p_high, int p_low)
301e25b118aSDominic Spill {
302e25b118aSDominic Spill if (!perm_table_initialized) {
303e25b118aSDominic Spill perm_table_init();
304e25b118aSDominic Spill perm_table_initialized = 1;
305e25b118aSDominic Spill }
306e25b118aSDominic Spill
307e25b118aSDominic Spill return(perm_table[z][p_high][p_low]);
308e25b118aSDominic Spill }
309e25b118aSDominic Spill
310e25b118aSDominic Spill /* generate the complete hopping sequence */
gen_hops(btbb_piconet * pn)311e25b118aSDominic Spill static void gen_hops(btbb_piconet *pn)
312e25b118aSDominic Spill {
313114033a2SHannes Ellinger /* a, b, c, d, e, f, x, y1, y2 are variable names used in section 2.6 of the spec */
314114033a2SHannes Ellinger /* b is already defined */
315114033a2SHannes Ellinger /* e is already defined */
316114033a2SHannes Ellinger int a, c, d, x;
317114033a2SHannes Ellinger uint32_t base_f, f, f_dash;
318114033a2SHannes Ellinger int h, i, j, k, c_flipped, perm_in, perm_out;
319e25b118aSDominic Spill
320114033a2SHannes Ellinger /* sequence index = clock >> 1 */
321114033a2SHannes Ellinger /* (hops only happen at every other clock value) */
322114033a2SHannes Ellinger int index = 0;
323114033a2SHannes Ellinger base_f = 0;
324114033a2SHannes Ellinger f = 0;
325114033a2SHannes Ellinger f_dash = 0;
326e25b118aSDominic Spill
327114033a2SHannes Ellinger /* nested loops for optimization (not recalculating every variable with every clock tick) */
328114033a2SHannes Ellinger for (h = 0; h < 0x04; h++) { /* clock bits 26-27 */
329114033a2SHannes Ellinger for (i = 0; i < 0x20; i++) { /* clock bits 21-25 */
330114033a2SHannes Ellinger a = pn->a1 ^ i;
331114033a2SHannes Ellinger for (j = 0; j < 0x20; j++) { /* clock bits 16-20 */
332114033a2SHannes Ellinger c = pn->c1 ^ j;
333114033a2SHannes Ellinger c_flipped = c ^ 0x1f;
334114033a2SHannes Ellinger for (k = 0; k < 0x200; k++) { /* clock bits 7-15 */
335114033a2SHannes Ellinger d = pn->d1 ^ k;
336114033a2SHannes Ellinger for (x = 0; x < 0x20; x++) { /* clock bits 2-6 */
337114033a2SHannes Ellinger perm_in = ((x + a) % 32) ^ pn->b;
338f1965e4dSHannes Ellinger
339114033a2SHannes Ellinger /* y1 (clock bit 1) = 0, y2 = 0 */
340114033a2SHannes Ellinger perm_out = fast_perm(perm_in, c, d);
341114033a2SHannes Ellinger if (btbb_piconet_get_flag(pn, BTBB_IS_AFH))
342114033a2SHannes Ellinger pn->sequence[index] = pn->bank[(perm_out + pn->e + f_dash) % pn->used_channels];
343114033a2SHannes Ellinger else
344114033a2SHannes Ellinger pn->sequence[index] = pn->bank[(perm_out + pn->e + f) % BT_NUM_CHANNELS];
345f1965e4dSHannes Ellinger
346114033a2SHannes Ellinger /* y1 (clock bit 1) = 1, y2 = 32 */
347114033a2SHannes Ellinger perm_out = fast_perm(perm_in, c_flipped, d);
348114033a2SHannes Ellinger if (btbb_piconet_get_flag(pn, BTBB_IS_AFH))
349114033a2SHannes Ellinger pn->sequence[index + 1] = pn->bank[(perm_out + pn->e + f_dash + 32) % pn->used_channels];
350114033a2SHannes Ellinger else
351114033a2SHannes Ellinger pn->sequence[index + 1] = pn->bank[(perm_out + pn->e + f + 32) % BT_NUM_CHANNELS];
352114033a2SHannes Ellinger
353114033a2SHannes Ellinger index += 2;
354114033a2SHannes Ellinger }
355114033a2SHannes Ellinger base_f += 16;
356114033a2SHannes Ellinger f = base_f % BT_NUM_CHANNELS;
357114033a2SHannes Ellinger f_dash = f % pn->used_channels;
358114033a2SHannes Ellinger }
359114033a2SHannes Ellinger }
360114033a2SHannes Ellinger }
361e25b118aSDominic Spill }
362e25b118aSDominic Spill }
363e25b118aSDominic Spill
364e25b118aSDominic Spill /* Function to calculate piconet hopping patterns and add to hash map */
gen_hop_pattern(btbb_piconet * pn)365e25b118aSDominic Spill void gen_hop_pattern(btbb_piconet *pn)
366e25b118aSDominic Spill {
367e25b118aSDominic Spill printf("\nCalculating complete hopping sequence.\n");
368e25b118aSDominic Spill /* this holds the entire hopping sequence */
369e25b118aSDominic Spill pn->sequence = (char*) malloc(SEQUENCE_LENGTH);
370e25b118aSDominic Spill
371e25b118aSDominic Spill precalc(pn);
372e25b118aSDominic Spill address_precalc(((pn->UAP<<24) | pn->LAP) & 0xfffffff, pn);
373e25b118aSDominic Spill gen_hops(pn);
374e25b118aSDominic Spill
375e25b118aSDominic Spill printf("Hopping sequence calculated.\n");
376e25b118aSDominic Spill }
377e25b118aSDominic Spill
378e25b118aSDominic Spill /* Container for hopping pattern */
379e25b118aSDominic Spill typedef struct {
38083d85db8SHannes Ellinger uint64_t key; /* afh flag + address */
381e25b118aSDominic Spill char *sequence;
382e25b118aSDominic Spill UT_hash_handle hh;
383e25b118aSDominic Spill } hopping_struct;
384e25b118aSDominic Spill
385e25b118aSDominic Spill static hopping_struct *hopping_map = NULL;
386e25b118aSDominic Spill
387e25b118aSDominic Spill /* Function to fetch piconet hopping patterns */
get_hop_pattern(btbb_piconet * pn)388e25b118aSDominic Spill void get_hop_pattern(btbb_piconet *pn)
389e25b118aSDominic Spill {
39083d85db8SHannes Ellinger hopping_struct *s;
39183d85db8SHannes Ellinger uint64_t key;
392e25b118aSDominic Spill
39383d85db8SHannes Ellinger /* Two stages to avoid "left shift count >= width of type" warning */
39483d85db8SHannes Ellinger key = btbb_piconet_get_flag(pn, BTBB_IS_AFH);
395*a648d971SDominic Spill key = (key<<39) | ((uint64_t)pn->used_channels<<32) | ((uint32_t)pn->UAP<<24) | pn->LAP;
39683d85db8SHannes Ellinger HASH_FIND(hh, hopping_map, &key, 4, s);
397e25b118aSDominic Spill
398e25b118aSDominic Spill if (s == NULL) {
399e25b118aSDominic Spill gen_hop_pattern(pn);
40083d85db8SHannes Ellinger s = malloc(sizeof(hopping_struct));
40183d85db8SHannes Ellinger s->key = key;
402e25b118aSDominic Spill s->sequence = pn->sequence;
40383d85db8SHannes Ellinger HASH_ADD(hh, hopping_map, key, 4, s);
404e25b118aSDominic Spill } else {
405e25b118aSDominic Spill printf("\nFound hopping sequence in cache.\n");
406e25b118aSDominic Spill pn->sequence = s->sequence;
407e25b118aSDominic Spill }
408e25b118aSDominic Spill }
409e25b118aSDominic Spill
410e25b118aSDominic Spill /* determine channel for a particular hop */
411f1965e4dSHannes Ellinger /* borrowed from ubertooth firmware to support AFH */
single_hop(int clock,btbb_piconet * pn)412e25b118aSDominic Spill char single_hop(int clock, btbb_piconet *pn)
413e25b118aSDominic Spill {
414f1965e4dSHannes Ellinger int a, c, d, x, y1, y2, perm, next_channel;
415f1965e4dSHannes Ellinger uint32_t base_f, f, f_dash;
416e25b118aSDominic Spill
417e25b118aSDominic Spill /* following variable names used in section 2.6 of the spec */
418e25b118aSDominic Spill x = (clock >> 2) & 0x1f;
419e25b118aSDominic Spill y1 = (clock >> 1) & 0x01;
420e25b118aSDominic Spill y2 = y1 << 5;
421e25b118aSDominic Spill a = (pn->a1 ^ (clock >> 21)) & 0x1f;
422e25b118aSDominic Spill /* b is already defined */
423e25b118aSDominic Spill c = (pn->c1 ^ (clock >> 16)) & 0x1f;
424e25b118aSDominic Spill d = (pn->d1 ^ (clock >> 7)) & 0x1ff;
425e25b118aSDominic Spill /* e is already defined */
426f1965e4dSHannes Ellinger base_f = (clock >> 3) & 0x1fffff0;
427f1965e4dSHannes Ellinger f = base_f % BT_NUM_CHANNELS;
428e25b118aSDominic Spill
429f1965e4dSHannes Ellinger perm = fast_perm(
430f1965e4dSHannes Ellinger ((x + a) % 32) ^ pn->b,
431f1965e4dSHannes Ellinger (y1 * 0x1f) ^ c,
432f1965e4dSHannes Ellinger d);
433e25b118aSDominic Spill /* hop selection */
434f1965e4dSHannes Ellinger if(btbb_piconet_get_flag(pn, BTBB_IS_AFH)) {
435f1965e4dSHannes Ellinger f_dash = base_f % pn->used_channels;
436f1965e4dSHannes Ellinger next_channel = pn->bank[(perm + pn->e + f_dash + y2) % pn->used_channels];
437f1965e4dSHannes Ellinger } else {
438f1965e4dSHannes Ellinger next_channel = pn->bank[(perm + pn->e + f + y2) % BT_NUM_CHANNELS];
439f1965e4dSHannes Ellinger }
440f1965e4dSHannes Ellinger return next_channel;
441e25b118aSDominic Spill }
442e25b118aSDominic Spill
443e25b118aSDominic Spill /* look up channel for a particular hop */
hop(int clock,btbb_piconet * pn)444e25b118aSDominic Spill char hop(int clock, btbb_piconet *pn)
445e25b118aSDominic Spill {
446e25b118aSDominic Spill return pn->sequence[clock];
447e25b118aSDominic Spill }
448e25b118aSDominic Spill
aliased_channel(char channel)449e25b118aSDominic Spill static char aliased_channel(char channel)
450e25b118aSDominic Spill {
451e25b118aSDominic Spill return ((channel + 24) % ALIASED_CHANNELS) + 26;
452e25b118aSDominic Spill }
453e25b118aSDominic Spill
454e25b118aSDominic Spill /* create list of initial candidate clock values (hops with same channel as first observed hop) */
init_candidates(char channel,int known_clock_bits,btbb_piconet * pn)455e25b118aSDominic Spill static int init_candidates(char channel, int known_clock_bits, btbb_piconet *pn)
456e25b118aSDominic Spill {
457e25b118aSDominic Spill int i;
458e25b118aSDominic Spill int count = 0; /* total number of candidates */
459e25b118aSDominic Spill char observable_channel; /* accounts for aliasing if necessary */
460e25b118aSDominic Spill
461e25b118aSDominic Spill /* only try clock values that match our known bits */
462e25b118aSDominic Spill for (i = known_clock_bits; i < SEQUENCE_LENGTH; i += 0x40) {
463e25b118aSDominic Spill if (pn->aliased)
464e25b118aSDominic Spill observable_channel = aliased_channel(pn->sequence[i]);
465e25b118aSDominic Spill else
466e25b118aSDominic Spill observable_channel = pn->sequence[i];
467e25b118aSDominic Spill if (observable_channel == channel)
468e25b118aSDominic Spill pn->clock_candidates[count++] = i;
469e25b118aSDominic Spill //FIXME ought to throw exception if count gets too big
470e25b118aSDominic Spill }
471e25b118aSDominic Spill return count;
472e25b118aSDominic Spill }
473e25b118aSDominic Spill
474e25b118aSDominic Spill /* initialize the hop reversal process */
btbb_init_hop_reversal(int aliased,btbb_piconet * pn)475e25b118aSDominic Spill int btbb_init_hop_reversal(int aliased, btbb_piconet *pn)
476e25b118aSDominic Spill {
477e25b118aSDominic Spill int max_candidates;
478e25b118aSDominic Spill uint32_t clock;
479e25b118aSDominic Spill
480e25b118aSDominic Spill get_hop_pattern(pn);
481e25b118aSDominic Spill
482e25b118aSDominic Spill if(aliased)
483e25b118aSDominic Spill max_candidates = (SEQUENCE_LENGTH / ALIASED_CHANNELS) / 32;
484e25b118aSDominic Spill else
485e25b118aSDominic Spill max_candidates = (SEQUENCE_LENGTH / BT_NUM_CHANNELS) / 32;
486e25b118aSDominic Spill /* this can hold twice the approximate number of initial candidates */
487e25b118aSDominic Spill pn->clock_candidates = (uint32_t*) malloc(sizeof(uint32_t) * max_candidates);
488e25b118aSDominic Spill
489e25b118aSDominic Spill clock = (pn->clk_offset + pn->first_pkt_time) & 0x3f;
490e25b118aSDominic Spill pn->num_candidates = init_candidates(pn->pattern_channels[0], clock, pn);
491e25b118aSDominic Spill pn->winnowed = 0;
492e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_HOP_REVERSAL_INIT, 1);
493e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 0);
494e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_IS_ALIASED, aliased);
495e25b118aSDominic Spill
496e25b118aSDominic Spill printf("%d initial CLK1-27 candidates\n", pn->num_candidates);
497e25b118aSDominic Spill
498e25b118aSDominic Spill return pn->num_candidates;
499e25b118aSDominic Spill }
500e25b118aSDominic Spill
try_hop(btbb_packet * pkt,btbb_piconet * pn)501e25b118aSDominic Spill void try_hop(btbb_packet *pkt, btbb_piconet *pn)
502e25b118aSDominic Spill {
503e25b118aSDominic Spill uint8_t filter_uap = pn->UAP;
504e25b118aSDominic Spill
505e25b118aSDominic Spill /* Decode packet - fixing clock drift in the process */
5060c071729SHannes Ellinger btbb_decode(pkt);
507e25b118aSDominic Spill
508e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_HOP_REVERSAL_INIT)) {
509e25b118aSDominic Spill //pn->winnowed = 0;
510e25b118aSDominic Spill pn->pattern_indices[pn->packets_observed] =
511e25b118aSDominic Spill pkt->clkn - pn->first_pkt_time;
512e25b118aSDominic Spill pn->pattern_channels[pn->packets_observed] = pkt->channel;
513e25b118aSDominic Spill pn->packets_observed++;
514e25b118aSDominic Spill pn->total_packets_observed++;
515e25b118aSDominic Spill btbb_winnow(pn);
516e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) {
517e25b118aSDominic Spill printf("got CLK1-27\n");
518e25b118aSDominic Spill printf("clock offset = %d.\n", pn->clk_offset);
519e25b118aSDominic Spill }
520e25b118aSDominic Spill } else {
521e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK6_VALID)) {
522e25b118aSDominic Spill btbb_uap_from_header(pkt, pn);
523e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) {
524e25b118aSDominic Spill printf("got CLK1-27\n");
525e25b118aSDominic Spill printf("clock offset = %d.\n", pn->clk_offset);
526e25b118aSDominic Spill }
527e25b118aSDominic Spill } else {
528e25b118aSDominic Spill if (btbb_uap_from_header(pkt, pn)) {
529e25b118aSDominic Spill if (filter_uap == pn->UAP) {
530e25b118aSDominic Spill btbb_init_hop_reversal(0, pn);
531e25b118aSDominic Spill btbb_winnow(pn);
532e25b118aSDominic Spill } else {
533e25b118aSDominic Spill printf("failed to confirm UAP\n");
534e25b118aSDominic Spill }
535e25b118aSDominic Spill }
536e25b118aSDominic Spill }
537e25b118aSDominic Spill }
538e25b118aSDominic Spill
539e25b118aSDominic Spill if(!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) {
540e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1);
541e25b118aSDominic Spill pn->UAP = filter_uap;
542e25b118aSDominic Spill }
543e25b118aSDominic Spill }
544e25b118aSDominic Spill
545e25b118aSDominic Spill /* return the observable channel (26-50) for a given channel (0-78) */
546e25b118aSDominic Spill /* reset UAP/clock discovery */
reset(btbb_piconet * pn)547e25b118aSDominic Spill static void reset(btbb_piconet *pn)
548e25b118aSDominic Spill {
549e25b118aSDominic Spill //printf("no candidates remaining! starting over . . .\n");
550e25b118aSDominic Spill
551e25b118aSDominic Spill if(btbb_piconet_get_flag(pn, BTBB_HOP_REVERSAL_INIT)) {
552e25b118aSDominic Spill free(pn->clock_candidates);
55383d85db8SHannes Ellinger pn->sequence = NULL;
554e25b118aSDominic Spill }
555e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_GOT_FIRST_PACKET, 0);
556e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_HOP_REVERSAL_INIT, 0);
557e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 0);
558e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 0);
559e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 0);
560e25b118aSDominic Spill pn->packets_observed = 0;
561e25b118aSDominic Spill
562e25b118aSDominic Spill /*
563e25b118aSDominic Spill * If we have recently observed two packets in a row on the same
564e25b118aSDominic Spill * channel, try AFH next time. If not, don't.
565e25b118aSDominic Spill */
566e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_IS_AFH,
567e25b118aSDominic Spill btbb_piconet_get_flag(pn, BTBB_LOOKS_LIKE_AFH));
568f1965e4dSHannes Ellinger // btbb_piconet_set_flag(pn, BTBB_LOOKS_LIKE_AFH, 0);
569e25b118aSDominic Spill //int i;
570e25b118aSDominic Spill //for(i=0; i<10; i++)
571e25b118aSDominic Spill // pn->afh_map[i] = 0;
572e25b118aSDominic Spill }
573e25b118aSDominic Spill
574e25b118aSDominic Spill /* narrow a list of candidate clock values based on a single observed hop */
channel_winnow(int offset,char channel,btbb_piconet * pn)575e25b118aSDominic Spill static int channel_winnow(int offset, char channel, btbb_piconet *pn)
576e25b118aSDominic Spill {
577e25b118aSDominic Spill int i;
578e25b118aSDominic Spill int new_count = 0; /* number of candidates after winnowing */
579e25b118aSDominic Spill char observable_channel; /* accounts for aliasing if necessary */
580e25b118aSDominic Spill
581e25b118aSDominic Spill /* check every candidate */
582e25b118aSDominic Spill for (i = 0; i < pn->num_candidates; i++) {
583e25b118aSDominic Spill if (pn->aliased)
584e25b118aSDominic Spill observable_channel = aliased_channel(pn->sequence[(pn->clock_candidates[i] + offset) % SEQUENCE_LENGTH]);
585e25b118aSDominic Spill else
586e25b118aSDominic Spill observable_channel = pn->sequence[(pn->clock_candidates[i] + offset) % SEQUENCE_LENGTH];
587e25b118aSDominic Spill if (observable_channel == channel) {
588e25b118aSDominic Spill /* this candidate matches the latest hop */
589e25b118aSDominic Spill /* blow away old list of candidates with new one */
590e25b118aSDominic Spill /* safe because new_count can never be greater than i */
591e25b118aSDominic Spill pn->clock_candidates[new_count++] = pn->clock_candidates[i];
592e25b118aSDominic Spill }
593e25b118aSDominic Spill }
594e25b118aSDominic Spill pn->num_candidates = new_count;
595e25b118aSDominic Spill
596e25b118aSDominic Spill if (new_count == 1) {
597e25b118aSDominic Spill // Calculate clock offset for CLKN, not CLK1-27
598e25b118aSDominic Spill pn->clk_offset = ((pn->clock_candidates[0]<<1) - (pn->first_pkt_time<<1));
599e25b118aSDominic Spill printf("\nAcquired CLK1-27 = 0x%07x\n", pn->clock_candidates[0]);
600e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 1);
601e25b118aSDominic Spill }
602e25b118aSDominic Spill else if (new_count == 0) {
603e25b118aSDominic Spill reset(pn);
604e25b118aSDominic Spill }
60583d85db8SHannes Ellinger //else {
60683d85db8SHannes Ellinger //printf("%d CLK1-27 candidates remaining (channel=%d)\n", new_count, channel);
60783d85db8SHannes Ellinger //}
608e25b118aSDominic Spill
609e25b118aSDominic Spill return new_count;
610e25b118aSDominic Spill }
611e25b118aSDominic Spill
612e25b118aSDominic Spill /* narrow a list of candidate clock values based on all observed hops */
btbb_winnow(btbb_piconet * pn)613e25b118aSDominic Spill int btbb_winnow(btbb_piconet *pn)
614e25b118aSDominic Spill {
615e25b118aSDominic Spill int new_count = pn->num_candidates;
616e25b118aSDominic Spill int index, last_index;
617e25b118aSDominic Spill uint8_t channel, last_channel;
618e25b118aSDominic Spill
619e25b118aSDominic Spill for (; pn->winnowed < pn->packets_observed; pn->winnowed++) {
620e25b118aSDominic Spill index = pn->pattern_indices[pn->winnowed];
621e25b118aSDominic Spill channel = pn->pattern_channels[pn->winnowed];
622e25b118aSDominic Spill new_count = channel_winnow(index, channel, pn);
623e25b118aSDominic Spill if (new_count <= 1)
624e25b118aSDominic Spill break;
625e25b118aSDominic Spill
626e25b118aSDominic Spill if (pn->packets_observed > 0) {
627e25b118aSDominic Spill last_index = pn->pattern_indices[pn->winnowed - 1];
628e25b118aSDominic Spill last_channel = pn->pattern_channels[pn->winnowed - 1];
629e25b118aSDominic Spill /*
630e25b118aSDominic Spill * Two packets in a row on the same channel should only
631e25b118aSDominic Spill * happen if adaptive frequency hopping is in use.
632e25b118aSDominic Spill * There can be false positives, though, especially if
633e25b118aSDominic Spill * there is aliasing.
634e25b118aSDominic Spill */
635e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_LOOKS_LIKE_AFH)
636e25b118aSDominic Spill && (index == last_index + 1)
637e25b118aSDominic Spill && (channel == last_channel)) {
638e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_LOOKS_LIKE_AFH, 1);
639e25b118aSDominic Spill printf("Hopping pattern appears to be AFH\n");
640e25b118aSDominic Spill }
641e25b118aSDominic Spill }
642e25b118aSDominic Spill }
643e25b118aSDominic Spill
644e25b118aSDominic Spill return new_count;
645e25b118aSDominic Spill }
646e25b118aSDominic Spill
647e25b118aSDominic Spill /* use packet headers to determine UAP */
btbb_uap_from_header(btbb_packet * pkt,btbb_piconet * pn)648e25b118aSDominic Spill int btbb_uap_from_header(btbb_packet *pkt, btbb_piconet *pn)
649e25b118aSDominic Spill {
650e25b118aSDominic Spill uint8_t UAP;
651e25b118aSDominic Spill int count, crc_chk, first_clock = 0;
652e25b118aSDominic Spill
653e25b118aSDominic Spill int starting = 0;
654e25b118aSDominic Spill int remaining = 0;
655e25b118aSDominic Spill uint32_t clkn = pkt->clkn;
656e25b118aSDominic Spill
657c0d170f2SDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET))
658e25b118aSDominic Spill pn->first_pkt_time = clkn;
659e25b118aSDominic Spill
660e25b118aSDominic Spill // Set afh channel map
661f1965e4dSHannes Ellinger btbb_piconet_set_channel_seen(pn, pkt->channel);
662e25b118aSDominic Spill
663e25b118aSDominic Spill if (pn->packets_observed < MAX_PATTERN_LENGTH) {
664e25b118aSDominic Spill pn->pattern_indices[pn->packets_observed] = clkn - pn->first_pkt_time;
665e25b118aSDominic Spill pn->pattern_channels[pn->packets_observed] = pkt->channel;
666e25b118aSDominic Spill } else {
667e25b118aSDominic Spill printf("Oops. More hops than we can remember.\n");
668e25b118aSDominic Spill reset(pn);
669e25b118aSDominic Spill return 0; //FIXME ought to throw exception
670e25b118aSDominic Spill }
671e25b118aSDominic Spill pn->packets_observed++;
672e25b118aSDominic Spill pn->total_packets_observed++;
673e25b118aSDominic Spill
674e25b118aSDominic Spill /* try every possible first packet clock value */
675e25b118aSDominic Spill for (count = 0; count < 64; count++) {
676e25b118aSDominic Spill /* skip eliminated candidates unless this is our first time through */
677c0d170f2SDominic Spill if (pn->clock6_candidates[count] > -1
678c0d170f2SDominic Spill || !btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET)) {
679e25b118aSDominic Spill /* clock value for the current packet assuming count was the clock of the first packet */
680e25b118aSDominic Spill int clock = (count + clkn - pn->first_pkt_time) % 64;
681e25b118aSDominic Spill starting++;
682e25b118aSDominic Spill UAP = try_clock(clock, pkt);
683e25b118aSDominic Spill crc_chk = -1;
684e25b118aSDominic Spill
685e25b118aSDominic Spill /* if this is the first packet: populate the candidate list */
686e25b118aSDominic Spill /* if not: check CRCs if UAPs match */
687c0d170f2SDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET)
688c0d170f2SDominic Spill || UAP == pn->clock6_candidates[count])
689e25b118aSDominic Spill crc_chk = crc_check(clock, pkt);
690e25b118aSDominic Spill
691e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_UAP_VALID) &&
692e25b118aSDominic Spill (UAP != pn->UAP))
693e25b118aSDominic Spill crc_chk = -1;
694e25b118aSDominic Spill
695e25b118aSDominic Spill switch(crc_chk) {
696e25b118aSDominic Spill case -1: /* UAP mismatch */
697e25b118aSDominic Spill case 0: /* CRC failure */
698e25b118aSDominic Spill pn->clock6_candidates[count] = -1;
699e25b118aSDominic Spill break;
700e25b118aSDominic Spill
701e25b118aSDominic Spill case 1: /* inconclusive result */
702c0d170f2SDominic Spill case 2: /* Inconclusive, but looks better */
703e25b118aSDominic Spill pn->clock6_candidates[count] = UAP;
704e25b118aSDominic Spill /* remember this count because it may be the correct clock of the first packet */
705e25b118aSDominic Spill first_clock = count;
706e25b118aSDominic Spill remaining++;
707e25b118aSDominic Spill break;
708e25b118aSDominic Spill
709e25b118aSDominic Spill default: /* CRC success */
710e25b118aSDominic Spill pn->clk_offset = (count - (pn->first_pkt_time & 0x3f)) & 0x3f;
711e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_UAP_VALID))
712e25b118aSDominic Spill printf("Correct CRC! UAP = 0x%x found after %d total packets.\n",
713e25b118aSDominic Spill UAP, pn->total_packets_observed);
714e25b118aSDominic Spill else
715e25b118aSDominic Spill printf("Correct CRC! CLK6 = 0x%x found after %d total packets.\n",
716e25b118aSDominic Spill pn->clk_offset, pn->total_packets_observed);
717e25b118aSDominic Spill pn->UAP = UAP;
718e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 1);
719e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1);
720e25b118aSDominic Spill pn->total_packets_observed = 0;
721e25b118aSDominic Spill return 1;
722e25b118aSDominic Spill }
723e25b118aSDominic Spill }
724e25b118aSDominic Spill }
725e25b118aSDominic Spill
726c0d170f2SDominic Spill btbb_piconet_set_flag(pn, BTBB_GOT_FIRST_PACKET, 1);
727e25b118aSDominic Spill
728e25b118aSDominic Spill //printf("reduced from %d to %d CLK1-6 candidates\n", starting, remaining);
729e25b118aSDominic Spill
730e25b118aSDominic Spill if (remaining == 1) {
731e25b118aSDominic Spill pn->clk_offset = (first_clock - (pn->first_pkt_time & 0x3f)) & 0x3f;
732e25b118aSDominic Spill if (!btbb_piconet_get_flag(pn, BTBB_UAP_VALID))
733d73cdf28SDominic Spill printf("UAP = 0x%x found after %d total packets.\n",
734e25b118aSDominic Spill pn->clock6_candidates[first_clock], pn->total_packets_observed);
735e25b118aSDominic Spill else
736d73cdf28SDominic Spill printf("CLK6 = 0x%x found after %d total packets.\n",
737e25b118aSDominic Spill pn->clk_offset, pn->total_packets_observed);
738e25b118aSDominic Spill pn->UAP = pn->clock6_candidates[first_clock];
739e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 1);
740e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1);
741e25b118aSDominic Spill pn->total_packets_observed = 0;
742e25b118aSDominic Spill return 1;
743e25b118aSDominic Spill }
744e25b118aSDominic Spill
745e25b118aSDominic Spill if (remaining == 0) {
746e25b118aSDominic Spill reset(pn);
747e25b118aSDominic Spill }
748e25b118aSDominic Spill
749e25b118aSDominic Spill return 0;
750e25b118aSDominic Spill }
751e25b118aSDominic Spill
75214430aa0SDominic Spill /* FIXME: comment out enqueue and dequeue because they are
75314430aa0SDominic Spill * never used. Try to find out what tey were meant to be
75414430aa0SDominic Spill * used for before the next release.
75514430aa0SDominic Spill */
75614430aa0SDominic Spill ///* add a packet to the queue */
75714430aa0SDominic Spill //static void enqueue(btbb_packet *pkt, btbb_piconet *pn)
75814430aa0SDominic Spill //{
75914430aa0SDominic Spill // pkt_queue *head;
76014430aa0SDominic Spill // //pkt_queue item;
76114430aa0SDominic Spill //
76214430aa0SDominic Spill // btbb_packet_ref(pkt);
76314430aa0SDominic Spill // pkt_queue item = {pkt, NULL};
76414430aa0SDominic Spill // head = pn->queue;
76514430aa0SDominic Spill //
76614430aa0SDominic Spill // if (head == NULL) {
76714430aa0SDominic Spill // pn->queue = &item;
76814430aa0SDominic Spill // } else {
76914430aa0SDominic Spill // for(; head->next != NULL; head = head->next)
77014430aa0SDominic Spill // ;
77114430aa0SDominic Spill // head->next = &item;
77214430aa0SDominic Spill // }
77314430aa0SDominic Spill //}
77414430aa0SDominic Spill //
77514430aa0SDominic Spill ///* pull the first packet from the queue (FIFO) */
77614430aa0SDominic Spill //static btbb_packet *dequeue(btbb_piconet *pn)
77714430aa0SDominic Spill //{
77814430aa0SDominic Spill // btbb_packet *pkt;
77914430aa0SDominic Spill //
78014430aa0SDominic Spill // if (pn->queue == NULL) {
78114430aa0SDominic Spill // pkt = NULL;
78214430aa0SDominic Spill // } else {
78314430aa0SDominic Spill // pkt = pn->queue->pkt;
78414430aa0SDominic Spill // pn->queue = pn->queue->next;
78514430aa0SDominic Spill // btbb_packet_unref(pkt);
78614430aa0SDominic Spill // }
78714430aa0SDominic Spill //
78814430aa0SDominic Spill // return pkt;
78914430aa0SDominic Spill //}
790e25b118aSDominic Spill
791e25b118aSDominic Spill /* Print AFH map from observed packets */
btbb_print_afh_map(btbb_piconet * pn)792e25b118aSDominic Spill void btbb_print_afh_map(btbb_piconet *pn) {
7931e7f449bSDominic Spill uint8_t *afh_map;
794e25b118aSDominic Spill afh_map = pn->afh_map;
795e25b118aSDominic Spill
796f1965e4dSHannes Ellinger /* Print like hcitool does */
797f1965e4dSHannes Ellinger printf("AFH map: 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
798f1965e4dSHannes Ellinger afh_map[0], afh_map[1], afh_map[2], afh_map[3], afh_map[4],
799f1965e4dSHannes Ellinger afh_map[5], afh_map[6], afh_map[7], afh_map[8], afh_map[9]);
800f1965e4dSHannes Ellinger
801f1965e4dSHannes Ellinger // /* Printed ch78 -> ch0 */
802f1965e4dSHannes Ellinger // printf("\tAFH Map=0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
803f1965e4dSHannes Ellinger // afh_map[9], afh_map[8], afh_map[7], afh_map[6], afh_map[5],
804f1965e4dSHannes Ellinger // afh_map[4], afh_map[3], afh_map[2], afh_map[1], afh_map[0]);
805e25b118aSDominic Spill }
806e25b118aSDominic Spill
807e25b118aSDominic Spill /* Container for survey piconets */
808e25b118aSDominic Spill typedef struct {
809e25b118aSDominic Spill uint32_t key; /* LAP */
810e25b118aSDominic Spill btbb_piconet *pn;
811e25b118aSDominic Spill UT_hash_handle hh;
812e25b118aSDominic Spill } survey_hash;
813e25b118aSDominic Spill
814e25b118aSDominic Spill static survey_hash *piconet_survey = NULL;
815e25b118aSDominic Spill
816e25b118aSDominic Spill /* Check for existing piconets in survey results */
get_piconet(uint32_t lap)817e25b118aSDominic Spill btbb_piconet *get_piconet(uint32_t lap)
818e25b118aSDominic Spill {
819e25b118aSDominic Spill survey_hash *s;
820e25b118aSDominic Spill btbb_piconet *pn;
821e25b118aSDominic Spill HASH_FIND(hh, piconet_survey, &lap, 4, s);
822e25b118aSDominic Spill
823e25b118aSDominic Spill if (s == NULL) {
824e25b118aSDominic Spill pn = btbb_piconet_new();
825e25b118aSDominic Spill btbb_init_piconet(pn, lap);
826e25b118aSDominic Spill
827e25b118aSDominic Spill s = malloc(sizeof(survey_hash));
828e25b118aSDominic Spill s->key = lap;
829e25b118aSDominic Spill s->pn = pn;
830e25b118aSDominic Spill HASH_ADD(hh, piconet_survey, key, 4, s);
831e25b118aSDominic Spill } else {
832e25b118aSDominic Spill pn = s->pn;
833e25b118aSDominic Spill }
834e25b118aSDominic Spill return pn;
835e25b118aSDominic Spill }
836e25b118aSDominic Spill
837e25b118aSDominic Spill /* Destructively iterate over survey results */
btbb_next_survey_result()838e25b118aSDominic Spill btbb_piconet *btbb_next_survey_result() {
839e25b118aSDominic Spill btbb_piconet *pn = NULL;
840e25b118aSDominic Spill survey_hash *tmp;
841e25b118aSDominic Spill
842e25b118aSDominic Spill if (piconet_survey != NULL) {
843e25b118aSDominic Spill pn = piconet_survey->pn;
844e25b118aSDominic Spill tmp = piconet_survey;
845e25b118aSDominic Spill piconet_survey = piconet_survey->hh.next;
846e25b118aSDominic Spill free(tmp);
847e25b118aSDominic Spill }
848e25b118aSDominic Spill return pn;
849e25b118aSDominic Spill }
850e25b118aSDominic Spill
btbb_process_packet(btbb_packet * pkt,btbb_piconet * pn)851e25b118aSDominic Spill int btbb_process_packet(btbb_packet *pkt, btbb_piconet *pn) {
852e25b118aSDominic Spill if (survey_mode) {
853e25b118aSDominic Spill pn = get_piconet(btbb_packet_get_lap(pkt));
854e25b118aSDominic Spill btbb_piconet_set_channel_seen(pn, pkt->channel);
855e25b118aSDominic Spill if(btbb_header_present(pkt) && !btbb_piconet_get_flag(pn, BTBB_UAP_VALID))
856e25b118aSDominic Spill btbb_uap_from_header(pkt, pn);
857e25b118aSDominic Spill return 0;
858e25b118aSDominic Spill }
85926a99405SDominic Spill
86026a99405SDominic Spill if(pn)
86126a99405SDominic Spill btbb_piconet_set_channel_seen(pn, pkt->channel);
86226a99405SDominic Spill
863e25b118aSDominic Spill /* If piconet structure is given, a LAP is given, and packet
864e25b118aSDominic Spill * header is readable, do further analysis. If UAP has not yet
865e25b118aSDominic Spill * been determined, attempt to calculate it from headers. Once
866e25b118aSDominic Spill * UAP is known, try to determine clk6 and clk27. Once clocks
867e25b118aSDominic Spill * are known, follow the piconet. */
868e25b118aSDominic Spill if (pn && btbb_piconet_get_flag(pn, BTBB_LAP_VALID) &&
869e25b118aSDominic Spill btbb_header_present(pkt)) {
870e25b118aSDominic Spill
871e25b118aSDominic Spill /* Have LAP/UAP/clocks, now hopping along with the piconet. */
872e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_FOLLOWING)) {
873e25b118aSDominic Spill btbb_packet_set_uap(pkt, btbb_piconet_get_uap(pn));
874e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_CLK6_VALID, 1);
875e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_CLK27_VALID, 1);
876e25b118aSDominic Spill
8770c071729SHannes Ellinger if(btbb_decode(pkt))
878e25b118aSDominic Spill btbb_print_packet(pkt);
879e25b118aSDominic Spill else
880e25b118aSDominic Spill printf("Failed to decode packet\n");
881e25b118aSDominic Spill }
882e25b118aSDominic Spill
883e25b118aSDominic Spill /* Have LAP/UAP, need clocks. */
884e25b118aSDominic Spill else if (btbb_piconet_get_uap(pn)) {
885e25b118aSDominic Spill try_hop(pkt, pn);
886e25b118aSDominic Spill if (btbb_piconet_get_flag(pn, BTBB_CLK6_VALID) &&
887e25b118aSDominic Spill btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) {
888e25b118aSDominic Spill btbb_piconet_set_flag(pn, BTBB_FOLLOWING, 1);
889e25b118aSDominic Spill return -1;
890e25b118aSDominic Spill }
891e25b118aSDominic Spill }
892e25b118aSDominic Spill
893e25b118aSDominic Spill /* Have LAP, need UAP. */
894e25b118aSDominic Spill else {
895e25b118aSDominic Spill btbb_uap_from_header(pkt, pn);
896e25b118aSDominic Spill }
897e25b118aSDominic Spill }
898e25b118aSDominic Spill return 0;
899e25b118aSDominic Spill }
900