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