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