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 <stdio.h>
24e25b118aSDominic Spill #include <stdlib.h>
25e25b118aSDominic Spill
26e25b118aSDominic Spill #include "bluetooth_packet.h"
27e25b118aSDominic Spill #include "uthash.h"
28e25b118aSDominic Spill #include "sw_check_tables.h"
29e25b118aSDominic Spill
3095079a24SDominic Spill #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
3195079a24SDominic Spill
32e25b118aSDominic Spill /* Maximum number of AC errors supported by library. Caller may
33e25b118aSDominic Spill * specify any value <= AC_ERROR_LIMIT in btbb_init(). */
34e25b118aSDominic Spill #define AC_ERROR_LIMIT 5
35e25b118aSDominic Spill
36e25b118aSDominic Spill /* maximum number of bit errors for known syncwords */
37e25b118aSDominic Spill #define MAX_SYNCWORD_ERRS 5
38e25b118aSDominic Spill
39e25b118aSDominic Spill /* maximum number of bit errors in */
40e25b118aSDominic Spill #define MAX_BARKER_ERRORS 1
41e25b118aSDominic Spill
42e25b118aSDominic Spill /* default codeword modified for PN sequence and barker code */
43e25b118aSDominic Spill #define DEFAULT_CODEWORD 0xb0000002c7820e7eULL
44e25b118aSDominic Spill
45e25b118aSDominic Spill /* Default access code, used for calculating syndromes */
46e25b118aSDominic Spill #define DEFAULT_AC 0xcc7b7268ff614e1bULL
47e25b118aSDominic Spill
48e25b118aSDominic Spill /* index into whitening data array */
49e25b118aSDominic Spill static const uint8_t INDICES[] = {99, 85, 17, 50, 102, 58, 108, 45, 92, 62, 32, 118, 88, 11, 80, 2, 37, 69, 55, 8, 20, 40, 74, 114, 15, 106, 30, 78, 53, 72, 28, 26, 68, 7, 39, 113, 105, 77, 71, 25, 84, 49, 57, 44, 61, 117, 10, 1, 123, 124, 22, 125, 111, 23, 42, 126, 6, 112, 76, 24, 48, 43, 116, 0};
50e25b118aSDominic Spill
51e25b118aSDominic Spill /* whitening data */
52e25b118aSDominic Spill static const uint8_t WHITENING_DATA[] = {1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1};
53e25b118aSDominic Spill
54e25b118aSDominic Spill /* lookup table for barker code hamming distance */
55e25b118aSDominic Spill static const uint8_t BARKER_DISTANCE[] = {
56e25b118aSDominic Spill 3,3,3,2,3,2,2,1,2,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,1,2,2,3,2,3,3,3,
57e25b118aSDominic Spill 3,2,2,1,2,1,1,0,3,3,3,2,3,2,2,1,3,3,3,2,3,2,2,1,2,3,3,3,3,3,3,2,
58e25b118aSDominic Spill 2,3,3,3,3,3,3,2,1,2,2,3,2,3,3,3,1,2,2,3,2,3,3,3,0,1,1,2,1,2,2,3,
59e25b118aSDominic Spill 3,3,3,2,3,2,2,1,2,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,1,2,2,3,2,3,3,3};
60e25b118aSDominic Spill
61e25b118aSDominic Spill /* string representations of packet type */
62e25b118aSDominic Spill static const char * const TYPE_NAMES[] = {
63e25b118aSDominic Spill "NULL", "POLL", "FHS", "DM1", "DH1/2-DH1", "HV1", "HV2/2-EV3", "HV3/EV3/3-EV3",
64e25b118aSDominic Spill "DV/3-DH1", "AUX1", "DM3/2-DH3", "DH3/3-DH3", "EV4/2-EV5", "EV5/3-EV5", "DM5/2-DH5", "DH5/3-DH5"
65e25b118aSDominic Spill };
66e25b118aSDominic Spill
67e25b118aSDominic Spill /*
68e25b118aSDominic Spill * generator matrix for sync word (64,30) linear block code
69e25b118aSDominic Spill * based on polynomial 0260534236651
70e25b118aSDominic Spill * thanks to http://www.ee.unb.ca/cgi-bin/tervo/polygen.pl
71e25b118aSDominic Spill * modified for barker code
72e25b118aSDominic Spill */
73e25b118aSDominic Spill static const uint64_t sw_matrix[] = {
74e25b118aSDominic Spill 0xfe000002a0d1c014ULL, 0x01000003f0b9201fULL, 0x008000033ae40edbULL, 0x004000035fca99b9ULL,
75e25b118aSDominic Spill 0x002000036d5dd208ULL, 0x00100001b6aee904ULL, 0x00080000db577482ULL, 0x000400006dabba41ULL,
76e25b118aSDominic Spill 0x00020002f46d43f4ULL, 0x000100017a36a1faULL, 0x00008000bd1b50fdULL, 0x000040029c3536aaULL,
77e25b118aSDominic Spill 0x000020014e1a9b55ULL, 0x0000100265b5d37eULL, 0x0000080132dae9bfULL, 0x000004025bd5ea0bULL,
78e25b118aSDominic Spill 0x00000203ef526bd1ULL, 0x000001033511ab3cULL, 0x000000819a88d59eULL, 0x00000040cd446acfULL,
79e25b118aSDominic Spill 0x00000022a41aabb3ULL, 0x0000001390b5cb0dULL, 0x0000000b0ae27b52ULL, 0x0000000585713da9ULL};
80e25b118aSDominic Spill
81e25b118aSDominic Spill static const uint64_t barker_correct[] = {
82e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
83e25b118aSDominic Spill 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
84e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
85e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
86e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
87e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
88e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL,
89e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
90e25b118aSDominic Spill 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
91e25b118aSDominic Spill 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
92e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
93e25b118aSDominic Spill 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
94e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
95e25b118aSDominic Spill 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
96e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
97e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
98e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
99e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
100e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL,
101e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
102e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL,
103e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
104e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL,
105e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL,
106e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
107e25b118aSDominic Spill 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
108e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
109e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
110e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL,
111e25b118aSDominic Spill 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL,
112e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL,
113e25b118aSDominic Spill 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL};
114e25b118aSDominic Spill
115e25b118aSDominic Spill static const uint64_t pn = 0x83848D96BBCC54FCULL;
116e25b118aSDominic Spill
117e25b118aSDominic Spill static const uint16_t fec23_gen_matrix[] = {
118e25b118aSDominic Spill 0x2c01, 0x5802, 0x1c04, 0x3808, 0x7010,
119e25b118aSDominic Spill 0x4c20, 0x3440, 0x6880, 0x7d00, 0x5600};
120e25b118aSDominic Spill
121e25b118aSDominic Spill typedef struct {
122e25b118aSDominic Spill uint64_t syndrome; /* key */
123e25b118aSDominic Spill uint64_t error;
124e25b118aSDominic Spill UT_hash_handle hh;
125e25b118aSDominic Spill } syndrome_struct;
126e25b118aSDominic Spill
127e25b118aSDominic Spill static syndrome_struct *syndrome_map = NULL;
128e25b118aSDominic Spill
add_syndrome(uint64_t syndrome,uint64_t error)129e25b118aSDominic Spill static void add_syndrome(uint64_t syndrome, uint64_t error)
130e25b118aSDominic Spill {
131e25b118aSDominic Spill syndrome_struct *s;
132e25b118aSDominic Spill s = malloc(sizeof(syndrome_struct));
133e25b118aSDominic Spill s->syndrome = syndrome;
134e25b118aSDominic Spill s->error = error;
135e25b118aSDominic Spill
136e25b118aSDominic Spill HASH_ADD(hh, syndrome_map, syndrome, 8, s);
137e25b118aSDominic Spill }
138e25b118aSDominic Spill
find_syndrome(uint64_t syndrome)139e25b118aSDominic Spill static syndrome_struct *find_syndrome(uint64_t syndrome)
140e25b118aSDominic Spill {
141e25b118aSDominic Spill syndrome_struct *s;
142e25b118aSDominic Spill
143e25b118aSDominic Spill HASH_FIND(hh, syndrome_map, &syndrome, 8, s);
144e25b118aSDominic Spill return s;
145e25b118aSDominic Spill }
146e25b118aSDominic Spill
gen_syndrome(uint64_t codeword)147e25b118aSDominic Spill static uint64_t gen_syndrome(uint64_t codeword)
148e25b118aSDominic Spill {
149e25b118aSDominic Spill uint64_t syndrome = codeword & 0xffffffff;
150e25b118aSDominic Spill codeword >>= 32;
151e25b118aSDominic Spill syndrome ^= sw_check_table4[codeword & 0xff];
152e25b118aSDominic Spill codeword >>= 8;
153e25b118aSDominic Spill syndrome ^= sw_check_table5[codeword & 0xff];
154e25b118aSDominic Spill codeword >>= 8;
155e25b118aSDominic Spill syndrome ^= sw_check_table6[codeword & 0xff];
156e25b118aSDominic Spill codeword >>= 8;
157e25b118aSDominic Spill syndrome ^= sw_check_table7[codeword & 0xff];
158e25b118aSDominic Spill return syndrome;
159e25b118aSDominic Spill }
160e25b118aSDominic Spill
cycle(uint64_t error,int start,int depth,uint64_t codeword)161e25b118aSDominic Spill static void cycle(uint64_t error, int start, int depth, uint64_t codeword)
162e25b118aSDominic Spill {
163e25b118aSDominic Spill uint64_t new_error, syndrome, base;
164e25b118aSDominic Spill int i;
165e25b118aSDominic Spill base = 1;
166e25b118aSDominic Spill depth -= 1;
167e25b118aSDominic Spill for (i = start; i < 58; i++)
168e25b118aSDominic Spill {
169e25b118aSDominic Spill new_error = (base << i);
170e25b118aSDominic Spill new_error |= error;
171e25b118aSDominic Spill if (depth)
172e25b118aSDominic Spill cycle(new_error, i + 1, depth, codeword);
173e25b118aSDominic Spill else {
174e25b118aSDominic Spill syndrome = gen_syndrome(codeword ^ new_error);
175e25b118aSDominic Spill add_syndrome(syndrome, new_error);
176e25b118aSDominic Spill }
177e25b118aSDominic Spill }
178e25b118aSDominic Spill }
179e25b118aSDominic Spill
gen_syndrome_map(int bit_errors)180e25b118aSDominic Spill static void gen_syndrome_map(int bit_errors)
181e25b118aSDominic Spill {
182e25b118aSDominic Spill int i;
183e25b118aSDominic Spill for(i = 1; i <= bit_errors; i++)
184e25b118aSDominic Spill cycle(0, 0, i, DEFAULT_AC);
185e25b118aSDominic Spill }
186e25b118aSDominic Spill
187e25b118aSDominic Spill /* Generate Sync Word from an LAP */
btbb_gen_syncword(const int LAP)1888f3e7eeaSChristopher Kilgour uint64_t btbb_gen_syncword(const int LAP)
189e25b118aSDominic Spill {
190e25b118aSDominic Spill int i;
191e25b118aSDominic Spill uint64_t codeword = DEFAULT_CODEWORD;
192e25b118aSDominic Spill
193e25b118aSDominic Spill /* the sync word generated is in host order, not air order */
194e25b118aSDominic Spill for (i = 0; i < 24; i++)
195e25b118aSDominic Spill if (LAP & (0x800000 >> i))
196e25b118aSDominic Spill codeword ^= sw_matrix[i];
197e25b118aSDominic Spill
198e25b118aSDominic Spill return codeword;
199e25b118aSDominic Spill }
200e25b118aSDominic Spill
init_packet(btbb_packet * pkt,uint32_t lap,uint8_t ac_errors)201e25b118aSDominic Spill static void init_packet(btbb_packet *pkt, uint32_t lap, uint8_t ac_errors)
202e25b118aSDominic Spill {
203e25b118aSDominic Spill pkt->LAP = lap;
204e25b118aSDominic Spill pkt->ac_errors = ac_errors;
205e25b118aSDominic Spill
206e25b118aSDominic Spill pkt->flags = 0;
207e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_WHITENED, 1);
208e25b118aSDominic Spill }
209e25b118aSDominic Spill
210e25b118aSDominic Spill /* Convert some number of bits of an air order array to a host order integer */
air_to_host8(const char * air_order,const int bits)2118f3e7eeaSChristopher Kilgour static uint8_t air_to_host8(const char *air_order, const int bits)
212e25b118aSDominic Spill {
213e25b118aSDominic Spill int i;
214e25b118aSDominic Spill uint8_t host_order = 0;
215e25b118aSDominic Spill for (i = 0; i < bits; i++)
216e25b118aSDominic Spill host_order |= ((uint8_t)air_order[i] << i);
217e25b118aSDominic Spill return host_order;
218e25b118aSDominic Spill }
air_to_host16(const char * air_order,const int bits)2198f3e7eeaSChristopher Kilgour static uint16_t air_to_host16(const char *air_order, const int bits)
220e25b118aSDominic Spill {
221e25b118aSDominic Spill int i;
222e25b118aSDominic Spill uint16_t host_order = 0;
223e25b118aSDominic Spill for (i = 0; i < bits; i++)
224e25b118aSDominic Spill host_order |= ((uint16_t)air_order[i] << i);
225e25b118aSDominic Spill return host_order;
226e25b118aSDominic Spill }
air_to_host32(const char * air_order,const int bits)2278f3e7eeaSChristopher Kilgour static uint32_t air_to_host32(const char *air_order, const int bits)
228e25b118aSDominic Spill {
229e25b118aSDominic Spill int i;
230e25b118aSDominic Spill uint32_t host_order = 0;
231e25b118aSDominic Spill for (i = 0; i < bits; i++)
232e25b118aSDominic Spill host_order |= ((uint32_t)air_order[i] << i);
233e25b118aSDominic Spill return host_order;
234e25b118aSDominic Spill }
air_to_host64(const char * air_order,const int bits)2358f3e7eeaSChristopher Kilgour static uint64_t air_to_host64(const char *air_order, const int bits)
236e25b118aSDominic Spill {
237e25b118aSDominic Spill int i;
238e25b118aSDominic Spill uint64_t host_order = 0;
239e25b118aSDominic Spill for (i = 0; i < bits; i++)
240e25b118aSDominic Spill host_order |= ((uint64_t)air_order[i] << i);
241e25b118aSDominic Spill return host_order;
242e25b118aSDominic Spill }
243e25b118aSDominic Spill
24414430aa0SDominic Spill ///* Convert some number of bits in a host order integer to an air order array */
24514430aa0SDominic Spill //static void host_to_air(const uint8_t host_order, char *air_order, const int bits)
24614430aa0SDominic Spill //{
24714430aa0SDominic Spill // int i;
24814430aa0SDominic Spill // for (i = 0; i < bits; i++)
24914430aa0SDominic Spill // air_order[i] = (host_order >> i) & 0x01;
25014430aa0SDominic Spill //}
25114430aa0SDominic Spill
252e25b118aSDominic Spill /* count the number of 1 bits in a uint64_t */
count_bits(uint64_t n)253e25b118aSDominic Spill static uint8_t count_bits(uint64_t n)
254e25b118aSDominic Spill {
2551f3ebb40SDominic Spill #ifdef __GNUC__
2561f3ebb40SDominic Spill return (uint8_t) __builtin_popcountll (n);
2571f3ebb40SDominic Spill #else
258e25b118aSDominic Spill uint8_t i = 0;
259e25b118aSDominic Spill for (i = 0; n != 0; i++)
260e25b118aSDominic Spill n &= n - 1;
261e25b118aSDominic Spill return i;
2621f3ebb40SDominic Spill #endif
263e25b118aSDominic Spill }
264e25b118aSDominic Spill
2657469b4d1SDominic Spill #ifndef RELEASE
2667469b4d1SDominic Spill #define RELEASE "unknown"
2677469b4d1SDominic Spill #endif
btbb_get_release(void)268*088a90e8SDominic Spill const char* btbb_get_release(void) {
2697469b4d1SDominic Spill return RELEASE;
2707469b4d1SDominic Spill }
2717469b4d1SDominic Spill
2727469b4d1SDominic Spill #ifndef VERSION
2737469b4d1SDominic Spill #define VERSION "unknown"
2747469b4d1SDominic Spill #endif
btbb_get_version(void)275*088a90e8SDominic Spill const char* btbb_get_version(void) {
2767469b4d1SDominic Spill return VERSION;
2777469b4d1SDominic Spill }
2787469b4d1SDominic Spill
btbb_init(int max_ac_errors)279e25b118aSDominic Spill int btbb_init(int max_ac_errors)
280e25b118aSDominic Spill {
281e25b118aSDominic Spill /* Sanity check max_ac_errors. */
282e25b118aSDominic Spill if ( (max_ac_errors < 0) || (max_ac_errors > AC_ERROR_LIMIT) ) {
283e25b118aSDominic Spill fprintf(stderr, "%s: max_ac_errors out of range\n",
284e25b118aSDominic Spill __FUNCTION__);
285e25b118aSDominic Spill return -1;
286e25b118aSDominic Spill }
287e25b118aSDominic Spill
28814233ba7SDominic Spill if ((syndrome_map == NULL) && (max_ac_errors))
289e25b118aSDominic Spill gen_syndrome_map(max_ac_errors);
290e25b118aSDominic Spill
291e25b118aSDominic Spill return 0;
292e25b118aSDominic Spill }
293e25b118aSDominic Spill
294e25b118aSDominic Spill btbb_packet *
btbb_packet_new(void)295e25b118aSDominic Spill btbb_packet_new(void)
296e25b118aSDominic Spill {
297e25b118aSDominic Spill btbb_packet *pkt = (btbb_packet *)calloc(1, sizeof(btbb_packet));
29876d46d8bSDominic Spill if(pkt)
299e25b118aSDominic Spill pkt->refcount = 1;
300c79c92daSDominic Spill else
301c79c92daSDominic Spill fprintf(stderr, "Unable to allocate packet");
302e25b118aSDominic Spill return pkt;
303e25b118aSDominic Spill }
304e25b118aSDominic Spill
305e25b118aSDominic Spill void
btbb_packet_ref(btbb_packet * pkt)306e25b118aSDominic Spill btbb_packet_ref(btbb_packet *pkt)
307e25b118aSDominic Spill {
308e25b118aSDominic Spill pkt->refcount++;
309e25b118aSDominic Spill }
310e25b118aSDominic Spill
311e25b118aSDominic Spill void
btbb_packet_unref(btbb_packet * pkt)312e25b118aSDominic Spill btbb_packet_unref(btbb_packet *pkt)
313e25b118aSDominic Spill {
314e25b118aSDominic Spill pkt->refcount--;
315e25b118aSDominic Spill if (pkt->refcount == 0)
316e25b118aSDominic Spill free(pkt);
317e25b118aSDominic Spill }
318e25b118aSDominic Spill
btbb_packet_get_lap(const btbb_packet * pkt)3198f3e7eeaSChristopher Kilgour uint32_t btbb_packet_get_lap(const btbb_packet *pkt)
320e25b118aSDominic Spill {
321e25b118aSDominic Spill return pkt->LAP;
322e25b118aSDominic Spill }
323e25b118aSDominic Spill
btbb_packet_set_uap(btbb_packet * pkt,uint8_t uap)324e25b118aSDominic Spill void btbb_packet_set_uap(btbb_packet *pkt, uint8_t uap)
325e25b118aSDominic Spill {
326e25b118aSDominic Spill pkt->UAP = uap;
327e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_UAP_VALID, 1);
328e25b118aSDominic Spill }
329e25b118aSDominic Spill
btbb_packet_get_uap(const btbb_packet * pkt)3308f3e7eeaSChristopher Kilgour uint8_t btbb_packet_get_uap(const btbb_packet *pkt)
331e25b118aSDominic Spill {
332e25b118aSDominic Spill return pkt->UAP;
333e25b118aSDominic Spill }
334e25b118aSDominic Spill
btbb_packet_get_nap(const btbb_packet * pkt)3358f3e7eeaSChristopher Kilgour uint16_t btbb_packet_get_nap(const btbb_packet *pkt)
336e25b118aSDominic Spill {
337e25b118aSDominic Spill return pkt->NAP;
338e25b118aSDominic Spill }
339e25b118aSDominic Spill
btbb_packet_get_clkn(const btbb_packet * pkt)3408f3e7eeaSChristopher Kilgour uint32_t btbb_packet_get_clkn(const btbb_packet *pkt) {
341e25b118aSDominic Spill return pkt->clkn;
342e25b118aSDominic Spill }
343e25b118aSDominic Spill
btbb_packet_get_channel(const btbb_packet * pkt)3448f3e7eeaSChristopher Kilgour uint8_t btbb_packet_get_channel(const btbb_packet *pkt) {
345e25b118aSDominic Spill return pkt->channel;
346e25b118aSDominic Spill }
347e25b118aSDominic Spill
btbb_packet_set_modulation(btbb_packet * pkt,uint8_t modulation)348f83b85cfSDominic Spill void btbb_packet_set_modulation(btbb_packet *pkt, uint8_t modulation) {
349f83b85cfSDominic Spill pkt->modulation = modulation;
350f83b85cfSDominic Spill }
351f83b85cfSDominic Spill
btbb_packet_get_modulation(const btbb_packet * pkt)352f83b85cfSDominic Spill uint8_t btbb_packet_get_modulation(const btbb_packet *pkt) {
353f83b85cfSDominic Spill return pkt->modulation;
354f83b85cfSDominic Spill }
355f83b85cfSDominic Spill
btbb_packet_set_transport(btbb_packet * pkt,uint8_t transport)356f83b85cfSDominic Spill void btbb_packet_set_transport(btbb_packet *pkt, uint8_t transport) {
357f83b85cfSDominic Spill pkt->transport = transport;
358f83b85cfSDominic Spill }
359f83b85cfSDominic Spill
btbb_packet_get_transport(const btbb_packet * pkt)360f83b85cfSDominic Spill uint8_t btbb_packet_get_transport(const btbb_packet *pkt) {
361f83b85cfSDominic Spill return pkt->transport;
362f83b85cfSDominic Spill }
363f83b85cfSDominic Spill
btbb_packet_get_ac_errors(const btbb_packet * pkt)3648f3e7eeaSChristopher Kilgour uint8_t btbb_packet_get_ac_errors(const btbb_packet *pkt) {
365e25b118aSDominic Spill return pkt->ac_errors;
366e25b118aSDominic Spill }
367e25b118aSDominic Spill
promiscuous_packet_search(char * stream,int search_length,uint32_t * lap,int max_ac_errors,uint8_t * ac_errors)36814430aa0SDominic Spill int promiscuous_packet_search(char *stream, int search_length, uint32_t *lap,
36914430aa0SDominic Spill int max_ac_errors, uint8_t *ac_errors) {
37014430aa0SDominic Spill uint64_t syncword, codeword, syndrome, corrected_barker;
371e25b118aSDominic Spill syndrome_struct *errors;
372e25b118aSDominic Spill char *symbols;
373fd495f50SDominic Spill int count, offset = -1;
374e25b118aSDominic Spill
375fd495f50SDominic Spill /* Barker code at end of sync word (includes
376fd495f50SDominic Spill * MSB of LAP) is used as a rough filter.
377fd495f50SDominic Spill */
378e25b118aSDominic Spill uint8_t barker = air_to_host8(&stream[57], 6);
379e25b118aSDominic Spill barker <<= 1;
380e25b118aSDominic Spill
381e25b118aSDominic Spill for (count = 0; count < search_length; count++) {
382e25b118aSDominic Spill symbols = &stream[count];
383e25b118aSDominic Spill barker >>= 1;
384e25b118aSDominic Spill barker |= (symbols[63] << 6);
385e25b118aSDominic Spill if (BARKER_DISTANCE[barker] <= MAX_BARKER_ERRORS) {
386e25b118aSDominic Spill // Error correction
387e25b118aSDominic Spill syncword = air_to_host64(symbols, 64);
388e25b118aSDominic Spill
389e25b118aSDominic Spill /* correct the barker code with a simple comparison */
390e25b118aSDominic Spill corrected_barker = barker_correct[(uint8_t)(syncword >> 57)];
391e25b118aSDominic Spill syncword = (syncword & 0x01ffffffffffffffULL) | corrected_barker;
392e25b118aSDominic Spill
393e25b118aSDominic Spill codeword = syncword ^ pn;
394e25b118aSDominic Spill
395e25b118aSDominic Spill /* Zero syndrome -> good codeword. */
396e25b118aSDominic Spill syndrome = gen_syndrome(codeword);
397fd495f50SDominic Spill *ac_errors = 0;
398e25b118aSDominic Spill
399e25b118aSDominic Spill /* Try to fix errors in bad codeword. */
400e25b118aSDominic Spill if (syndrome) {
401e25b118aSDominic Spill errors = find_syndrome(syndrome);
402e25b118aSDominic Spill if (errors != NULL) {
403e25b118aSDominic Spill syncword ^= errors->error;
404fd495f50SDominic Spill *ac_errors = count_bits(errors->error);
405e25b118aSDominic Spill syndrome = 0;
406e25b118aSDominic Spill }
407e25b118aSDominic Spill else {
408fd495f50SDominic Spill *ac_errors = 0xff; // fail
409e25b118aSDominic Spill }
410e25b118aSDominic Spill }
411e25b118aSDominic Spill
412fd495f50SDominic Spill if (*ac_errors <= max_ac_errors) {
413e4e5d017SDominic Spill *lap = (syncword >> 34) & 0xffffff;
414e25b118aSDominic Spill offset = count;
415e25b118aSDominic Spill break;
416e25b118aSDominic Spill }
417e25b118aSDominic Spill }
418e25b118aSDominic Spill }
419fd495f50SDominic Spill return offset;
420e25b118aSDominic Spill }
421e25b118aSDominic Spill
422fd495f50SDominic Spill /* Matching a specific LAP */
find_known_lap(char * stream,int search_length,uint32_t lap,int max_ac_errors,uint8_t * ac_errors)42314430aa0SDominic Spill int find_known_lap(char *stream, int search_length, uint32_t lap,
42414430aa0SDominic Spill int max_ac_errors, uint8_t *ac_errors) {
42514430aa0SDominic Spill uint64_t syncword, ac;
426fd495f50SDominic Spill char *symbols;
427fd495f50SDominic Spill int count, offset = -1;
428fd495f50SDominic Spill
429e25b118aSDominic Spill ac = btbb_gen_syncword(lap);
430e25b118aSDominic Spill for (count = 0; count < search_length; count++) {
431e25b118aSDominic Spill symbols = &stream[count];
432e25b118aSDominic Spill syncword = air_to_host64(symbols, 64);
433fd495f50SDominic Spill *ac_errors = count_bits(syncword ^ ac);
434e25b118aSDominic Spill
435fd495f50SDominic Spill if (*ac_errors <= max_ac_errors) {
436e25b118aSDominic Spill offset = count;
437e25b118aSDominic Spill break;
438e25b118aSDominic Spill }
439e25b118aSDominic Spill }
440fd495f50SDominic Spill return offset;
441e25b118aSDominic Spill }
442e25b118aSDominic Spill
443fd495f50SDominic Spill /* Looks for an AC in the stream */
btbb_find_ac(char * stream,int search_length,uint32_t lap,int max_ac_errors,btbb_packet ** pkt_ptr)44414430aa0SDominic Spill int btbb_find_ac(char *stream, int search_length, uint32_t lap,
44514430aa0SDominic Spill int max_ac_errors, btbb_packet **pkt_ptr) {
446fd495f50SDominic Spill int offset;
447fd495f50SDominic Spill uint8_t ac_errors;
448fd495f50SDominic Spill
449fd495f50SDominic Spill /* Matching any LAP */
450fd495f50SDominic Spill if (lap == LAP_ANY)
451e4e5d017SDominic Spill offset = promiscuous_packet_search(stream, search_length, &lap,
452fd495f50SDominic Spill max_ac_errors, &ac_errors);
453fd495f50SDominic Spill else
454fd495f50SDominic Spill offset = find_known_lap(stream, search_length, lap,
455fd495f50SDominic Spill max_ac_errors, &ac_errors);
456fd495f50SDominic Spill
457e25b118aSDominic Spill if (offset >= 0) {
458e25b118aSDominic Spill if (*pkt_ptr == NULL)
459e25b118aSDominic Spill *pkt_ptr = btbb_packet_new();
460e25b118aSDominic Spill init_packet(*pkt_ptr, lap, ac_errors);
461e25b118aSDominic Spill }
462e25b118aSDominic Spill
463e25b118aSDominic Spill return offset;
464e25b118aSDominic Spill }
465e25b118aSDominic Spill
466e25b118aSDominic Spill /* Copy data (symbols) into packet and set rx data. */
btbb_packet_set_data(btbb_packet * pkt,char * data,int length,uint8_t channel,uint32_t clkn)46714430aa0SDominic Spill void btbb_packet_set_data(btbb_packet *pkt, char *data, int length,
46814430aa0SDominic Spill uint8_t channel, uint32_t clkn)
469e25b118aSDominic Spill {
470e25b118aSDominic Spill int i;
471e25b118aSDominic Spill
472e25b118aSDominic Spill if (length > MAX_SYMBOLS)
473e25b118aSDominic Spill length = MAX_SYMBOLS;
474e25b118aSDominic Spill for (i = 0; i < length; i++)
475e25b118aSDominic Spill pkt->symbols[i] = data[i];
476e25b118aSDominic Spill
477e25b118aSDominic Spill pkt->length = length;
478e25b118aSDominic Spill pkt->channel = channel;
479e25b118aSDominic Spill pkt->clkn = clkn >> 1; // really CLK1
480e25b118aSDominic Spill }
481e25b118aSDominic Spill
btbb_packet_set_flag(btbb_packet * pkt,int flag,int val)482e25b118aSDominic Spill void btbb_packet_set_flag(btbb_packet *pkt, int flag, int val)
483e25b118aSDominic Spill {
484e25b118aSDominic Spill uint32_t mask = 1L << flag;
485e25b118aSDominic Spill pkt->flags &= ~mask;
486e25b118aSDominic Spill if (val)
487e25b118aSDominic Spill pkt->flags |= mask;
488e25b118aSDominic Spill }
489e25b118aSDominic Spill
btbb_packet_get_flag(const btbb_packet * pkt,int flag)4908f3e7eeaSChristopher Kilgour int btbb_packet_get_flag(const btbb_packet *pkt, int flag)
491e25b118aSDominic Spill {
492e25b118aSDominic Spill uint32_t mask = 1L << flag;
493e25b118aSDominic Spill return ((pkt->flags & mask) != 0);
494e25b118aSDominic Spill }
495e25b118aSDominic Spill
btbb_get_symbols(const btbb_packet * pkt)4968f3e7eeaSChristopher Kilgour const char *btbb_get_symbols(const btbb_packet* pkt)
497e25b118aSDominic Spill {
498e25b118aSDominic Spill return (const char*) pkt->symbols;
499e25b118aSDominic Spill }
500e25b118aSDominic Spill
btbb_packet_get_payload_length(const btbb_packet * pkt)5018f3e7eeaSChristopher Kilgour int btbb_packet_get_payload_length(const btbb_packet* pkt)
502e25b118aSDominic Spill {
503e25b118aSDominic Spill return pkt->payload_length;
504e25b118aSDominic Spill }
505e25b118aSDominic Spill
btbb_get_payload(const btbb_packet * pkt)5068f3e7eeaSChristopher Kilgour const char *btbb_get_payload(const btbb_packet* pkt)
507e25b118aSDominic Spill {
508e25b118aSDominic Spill return (const char*) pkt->payload;
509e25b118aSDominic Spill }
510e25b118aSDominic Spill
btbb_get_payload_packed(const btbb_packet * pkt,char * dst)5118f3e7eeaSChristopher Kilgour int btbb_get_payload_packed(const btbb_packet* pkt, char *dst)
512e25b118aSDominic Spill {
513e25b118aSDominic Spill int i;
514e25b118aSDominic Spill for(i=0;i<pkt->payload_length;i++)
515e25b118aSDominic Spill dst[i] = (char) air_to_host8(&pkt->payload[i*8], 8);
516e25b118aSDominic Spill return pkt->payload_length;
517e25b118aSDominic Spill }
518e25b118aSDominic Spill
btbb_packet_get_type(const btbb_packet * pkt)5198f3e7eeaSChristopher Kilgour uint8_t btbb_packet_get_type(const btbb_packet* pkt)
520e25b118aSDominic Spill {
521e25b118aSDominic Spill return pkt->packet_type;
522e25b118aSDominic Spill }
523e25b118aSDominic Spill
btbb_packet_get_lt_addr(const btbb_packet * pkt)5248f3e7eeaSChristopher Kilgour uint8_t btbb_packet_get_lt_addr(const btbb_packet* pkt)
525e25b118aSDominic Spill {
526e25b118aSDominic Spill return pkt->packet_lt_addr;
527e25b118aSDominic Spill }
528e25b118aSDominic Spill
btbb_packet_get_header_flags(const btbb_packet * pkt)5298f3e7eeaSChristopher Kilgour uint8_t btbb_packet_get_header_flags(const btbb_packet* pkt)
530e25b118aSDominic Spill {
531e25b118aSDominic Spill return pkt->packet_flags;
532e25b118aSDominic Spill }
533e25b118aSDominic Spill
btbb_packet_get_hec(const btbb_packet * pkt)5348f3e7eeaSChristopher Kilgour uint8_t btbb_packet_get_hec(const btbb_packet* pkt)
535e25b118aSDominic Spill {
536e25b118aSDominic Spill return pkt->packet_hec;
537e25b118aSDominic Spill }
538e25b118aSDominic Spill
btbb_packet_get_header_packed(const btbb_packet * pkt)5398f3e7eeaSChristopher Kilgour uint32_t btbb_packet_get_header_packed(const btbb_packet* pkt)
5408f3e7eeaSChristopher Kilgour {
5418f3e7eeaSChristopher Kilgour return air_to_host32(&pkt->packet_header[0], 18);
5428f3e7eeaSChristopher Kilgour }
5438f3e7eeaSChristopher Kilgour
544e25b118aSDominic Spill /* Reverse the bits in a byte */
reverse(char byte)545e25b118aSDominic Spill static uint8_t reverse(char byte)
546e25b118aSDominic Spill {
547e25b118aSDominic Spill return (byte & 0x80) >> 7 | (byte & 0x40) >> 5 | (byte & 0x20) >> 3 | (byte & 0x10) >> 1 | (byte & 0x08) << 1 | (byte & 0x04) << 3 | (byte & 0x02) << 5 | (byte & 0x01) << 7;
548e25b118aSDominic Spill }
549e25b118aSDominic Spill
550e25b118aSDominic Spill
551e25b118aSDominic Spill /* Decode 1/3 rate FEC, three like symbols in a row */
unfec13(char * input,char * output,int length)552e25b118aSDominic Spill static int unfec13(char *input, char *output, int length)
553e25b118aSDominic Spill {
554e25b118aSDominic Spill int a, b, c, i;
555e25b118aSDominic Spill int be = 0; /* bit errors */
556e25b118aSDominic Spill
557e25b118aSDominic Spill for (i = 0; i < length; i++) {
558e25b118aSDominic Spill a = 3 * i;
559e25b118aSDominic Spill b = a + 1;
560e25b118aSDominic Spill c = a + 2;
561e25b118aSDominic Spill output[i] = ((input[a] & input[b]) | (input[b] & input[c]) |
562e25b118aSDominic Spill (input[c] & input[a]));
563e25b118aSDominic Spill be += ((input[a] ^ input[b]) | (input[b] ^ input[c]) |
564e25b118aSDominic Spill (input[c] ^ input[a]));
565e25b118aSDominic Spill }
566e25b118aSDominic Spill
567e25b118aSDominic Spill return (be < (length / 4));
568e25b118aSDominic Spill }
569e25b118aSDominic Spill
570e25b118aSDominic Spill /* encode 10 bits with 2/3 rate FEC code, a (15,10) shortened Hamming code */
fec23(uint16_t data)571e25b118aSDominic Spill static uint16_t fec23(uint16_t data)
572e25b118aSDominic Spill {
573e25b118aSDominic Spill int i;
574e25b118aSDominic Spill uint16_t codeword = 0;
575e25b118aSDominic Spill
576e25b118aSDominic Spill /* host order, not air order */
577e25b118aSDominic Spill for (i = 0; i < 10; i++)
578e25b118aSDominic Spill if (data & (1 << i))
579e25b118aSDominic Spill codeword ^= fec23_gen_matrix[i];
580e25b118aSDominic Spill
581e25b118aSDominic Spill return codeword;
582e25b118aSDominic Spill }
583e25b118aSDominic Spill
584e25b118aSDominic Spill /* Decode 2/3 rate FEC, a (15,10) shortened Hamming code */
unfec23(char * input,int length)585e25b118aSDominic Spill static char *unfec23(char *input, int length)
586e25b118aSDominic Spill {
587e25b118aSDominic Spill /* input points to the input data
588e25b118aSDominic Spill * length is length in bits of the data
589e25b118aSDominic Spill * before it was encoded with fec2/3 */
590e25b118aSDominic Spill int iptr, optr, count;
591e25b118aSDominic Spill char* output;
592e25b118aSDominic Spill uint8_t diff, check;
593e25b118aSDominic Spill uint16_t data, codeword;
594e25b118aSDominic Spill
595e25b118aSDominic Spill diff = length % 10;
596e25b118aSDominic Spill // padding at end of data
597e25b118aSDominic Spill if(0!=diff)
598e25b118aSDominic Spill length += (10 - diff);
599e25b118aSDominic Spill
600e25b118aSDominic Spill output = (char *) malloc(length);
601e25b118aSDominic Spill
602e25b118aSDominic Spill for (iptr = 0, optr = 0; optr<length; iptr += 15, optr += 10) {
603e25b118aSDominic Spill // copy data to output
604e25b118aSDominic Spill for(count=0;count<10;count++)
605e25b118aSDominic Spill output[optr+count] = input[iptr+count];
606e25b118aSDominic Spill
607e25b118aSDominic Spill // grab data and error check in host format
608e25b118aSDominic Spill data = air_to_host16(input+iptr, 10);
609e25b118aSDominic Spill check = air_to_host8(input+iptr+10, 5);
610e25b118aSDominic Spill
611e25b118aSDominic Spill // call fec23 on data to generate the codeword
612e25b118aSDominic Spill codeword = fec23(data);
613e25b118aSDominic Spill diff = check ^ (codeword >> 10);
614e25b118aSDominic Spill
615e25b118aSDominic Spill /* no errors or single bit errors (errors in the parity bit):
616e25b118aSDominic Spill * (a strong hint it's a real packet)
617e25b118aSDominic Spill * Otherwise we need to corret the output*/
618e25b118aSDominic Spill if (diff & (diff - 1)) {
619e25b118aSDominic Spill switch (diff) {
620e25b118aSDominic Spill /* comments are the bit that's wrong and the value
621e25b118aSDominic Spill * of diff in air order, from the BT spec */
622e25b118aSDominic Spill // 1000000000 11010
623e25b118aSDominic Spill case 0x0b: output[optr] ^= 1; break;
624e25b118aSDominic Spill // 0100000000 01101
625e25b118aSDominic Spill case 0x16: output[optr+1] ^= 1; break;
626e25b118aSDominic Spill // 0010000000 11100
627e25b118aSDominic Spill case 0x07: output[optr+2] ^= 1; break;
628e25b118aSDominic Spill // 0001000000 01110
629e25b118aSDominic Spill case 0x0e: output[optr+3] ^= 1; break;
630e25b118aSDominic Spill // 0000100000 00111
631e25b118aSDominic Spill case 0x1c: output[optr+4] ^= 1; break;
632e25b118aSDominic Spill // 0000010000 11001
633e25b118aSDominic Spill case 0x13: output[optr+5] ^= 1; break;
634e25b118aSDominic Spill // 0000001000 10110
635e25b118aSDominic Spill case 0x0d: output[optr+6] ^= 1; break;
636e25b118aSDominic Spill // 0000000100 01011
637e25b118aSDominic Spill case 0x1a: output[optr+7] ^= 1; break;
638e25b118aSDominic Spill // 0000000010 11111
639e25b118aSDominic Spill case 0x1f: output[optr+8] ^= 1; break;
640e25b118aSDominic Spill // 0000000001 10101
641e25b118aSDominic Spill case 0x15: output[optr+9] ^= 1; break;
642e25b118aSDominic Spill /* not one of these errors, probably multiple bit errors
643e25b118aSDominic Spill * or maybe not a real packet, safe to drop it? */
644e25b118aSDominic Spill default: free(output); return 0;
645e25b118aSDominic Spill }
646e25b118aSDominic Spill }
647e25b118aSDominic Spill }
648e25b118aSDominic Spill return output;
649e25b118aSDominic Spill }
650e25b118aSDominic Spill
651e25b118aSDominic Spill
652e25b118aSDominic Spill /* Remove the whitening from an air order array */
unwhiten(char * input,char * output,int clock,int length,int skip,btbb_packet * pkt)653e25b118aSDominic Spill static void unwhiten(char* input, char* output, int clock, int length, int skip, btbb_packet* pkt)
654e25b118aSDominic Spill {
655e25b118aSDominic Spill int count, index;
656e25b118aSDominic Spill index = INDICES[clock & 0x3f];
657e25b118aSDominic Spill index += skip;
658e25b118aSDominic Spill index %= 127;
659e25b118aSDominic Spill
660e25b118aSDominic Spill for(count = 0; count < length; count++)
661e25b118aSDominic Spill {
662e25b118aSDominic Spill /* unwhiten if whitened, otherwise just copy input to output */
663e25b118aSDominic Spill output[count] = btbb_packet_get_flag(pkt, BTBB_WHITENED) ?
664e25b118aSDominic Spill input[count] ^ WHITENING_DATA[index] : input[count];
665e25b118aSDominic Spill index += 1;
666e25b118aSDominic Spill index %= 127;
667e25b118aSDominic Spill }
668e25b118aSDominic Spill }
669e25b118aSDominic Spill
670e25b118aSDominic Spill /* Pointer to start of packet, length of packet in bits, UAP */
crcgen(char * payload,int length,int UAP)671e25b118aSDominic Spill static uint16_t crcgen(char *payload, int length, int UAP)
672e25b118aSDominic Spill {
673e25b118aSDominic Spill char bit;
674e25b118aSDominic Spill uint16_t reg, count;
675e25b118aSDominic Spill
676e25b118aSDominic Spill reg = (reverse(UAP) << 8) & 0xff00;
677e25b118aSDominic Spill for(count = 0; count < length; count++)
678e25b118aSDominic Spill {
679e25b118aSDominic Spill bit = payload[count];
680e25b118aSDominic Spill
681e25b118aSDominic Spill reg = (reg >> 1) | (((reg & 0x0001) ^ (bit & 0x01))<<15);
682e25b118aSDominic Spill
683e25b118aSDominic Spill /*Bit 5*/
684e25b118aSDominic Spill reg ^= ((reg & 0x8000)>>5);
685e25b118aSDominic Spill
686e25b118aSDominic Spill /*Bit 12*/
687e25b118aSDominic Spill reg ^= ((reg & 0x8000)>>12);
688e25b118aSDominic Spill }
689e25b118aSDominic Spill return reg;
690e25b118aSDominic Spill }
691e25b118aSDominic Spill
692e25b118aSDominic Spill /* extract UAP by reversing the HEC computation */
uap_from_hec(uint16_t data,uint8_t hec)693672715e8SDominic Spill static uint8_t uap_from_hec(uint16_t data, uint8_t hec)
694e25b118aSDominic Spill {
695e25b118aSDominic Spill int i;
696e25b118aSDominic Spill
697e25b118aSDominic Spill for (i = 9; i >= 0; i--) {
698e25b118aSDominic Spill /* 0x65 is xor'd if MSB is 1, else 0x00 (which does nothing) */
699e25b118aSDominic Spill if (hec & 0x80)
700e25b118aSDominic Spill hec ^= 0x65;
701e25b118aSDominic Spill
702e25b118aSDominic Spill hec = (hec << 1) | (((hec >> 7) ^ (data >> i)) & 0x01);
703e25b118aSDominic Spill }
704e25b118aSDominic Spill return reverse(hec);
705e25b118aSDominic Spill }
706e25b118aSDominic Spill
707e25b118aSDominic Spill /* check if the packet's CRC is correct for a given clock (CLK1-6) */
crc_check(int clock,btbb_packet * pkt)708e25b118aSDominic Spill int crc_check(int clock, btbb_packet* pkt)
709e25b118aSDominic Spill {
710e25b118aSDominic Spill /*
711e25b118aSDominic Spill * return value of 1 represents inconclusive result (default)
712e25b118aSDominic Spill * return value > 1 represents positive result (e.g. CRC match)
713e25b118aSDominic Spill * return value of 0 represents negative result (e.g. CRC failure without
714e25b118aSDominic Spill * the possibility that we have assumed the wrong logical transport)
715e25b118aSDominic Spill */
716e25b118aSDominic Spill int retval = 1;
717e25b118aSDominic Spill
718e25b118aSDominic Spill switch(pkt->packet_type)
719e25b118aSDominic Spill {
72095079a24SDominic Spill case PACKET_TYPE_FHS:
721e25b118aSDominic Spill retval = fhs(clock, pkt);
722e25b118aSDominic Spill break;
723e25b118aSDominic Spill
72495079a24SDominic Spill case PACKET_TYPE_DV:
72595079a24SDominic Spill case PACKET_TYPE_DM1:
72695079a24SDominic Spill case PACKET_TYPE_DM3:
72795079a24SDominic Spill case PACKET_TYPE_DM5:
728e25b118aSDominic Spill retval = DM(clock, pkt);
729e25b118aSDominic Spill break;
730e25b118aSDominic Spill
73195079a24SDominic Spill case PACKET_TYPE_DH1:
73295079a24SDominic Spill case PACKET_TYPE_DH3:
73395079a24SDominic Spill case PACKET_TYPE_DH5:
734e25b118aSDominic Spill retval = DH(clock, pkt);
735e25b118aSDominic Spill break;
736e25b118aSDominic Spill
73795079a24SDominic Spill case PACKET_TYPE_HV3: /* EV3 */
738e25b118aSDominic Spill retval = EV3(clock, pkt);
739e25b118aSDominic Spill break;
74095079a24SDominic Spill case PACKET_TYPE_EV4:
741e25b118aSDominic Spill retval = EV4(clock, pkt);
742e25b118aSDominic Spill break;
74395079a24SDominic Spill case PACKET_TYPE_EV5:
744e25b118aSDominic Spill retval = EV5(clock, pkt);
745e25b118aSDominic Spill break;
746e25b118aSDominic Spill
74795079a24SDominic Spill case PACKET_TYPE_HV1:
748e25b118aSDominic Spill retval = HV(clock, pkt);
749e25b118aSDominic Spill break;
750e25b118aSDominic Spill
751e25b118aSDominic Spill /* some types can't help us */
752e25b118aSDominic Spill default:
753e25b118aSDominic Spill break;
754e25b118aSDominic Spill }
755e25b118aSDominic Spill /*
756e25b118aSDominic Spill * never return a zero result unless this is a FHS, DM1, or HV1. any
757e25b118aSDominic Spill * other type could have actually been something else (another logical
758e25b118aSDominic Spill * transport)
759e25b118aSDominic Spill */
760e25b118aSDominic Spill if (retval == 0 && (pkt->packet_type != 2 && pkt->packet_type != 3 &&
761e25b118aSDominic Spill pkt->packet_type != 5))
762e25b118aSDominic Spill return 1;
763e25b118aSDominic Spill
764e25b118aSDominic Spill /* EV3 and EV5 have a relatively high false positive rate */
765e25b118aSDominic Spill if (retval > 1 && (pkt->packet_type == 7 || pkt->packet_type == 13))
766e25b118aSDominic Spill return 1;
767e25b118aSDominic Spill
768e25b118aSDominic Spill return retval;
769e25b118aSDominic Spill }
770e25b118aSDominic Spill
771e25b118aSDominic Spill /* verify the payload CRC */
payload_crc(btbb_packet * pkt)772e25b118aSDominic Spill static int payload_crc(btbb_packet* pkt)
773e25b118aSDominic Spill {
774e25b118aSDominic Spill uint16_t crc; /* CRC calculated from payload data */
775e25b118aSDominic Spill uint16_t check; /* CRC supplied by packet */
776e25b118aSDominic Spill
777e25b118aSDominic Spill crc = crcgen(pkt->payload, (pkt->payload_length - 2) * 8, pkt->UAP);
778e25b118aSDominic Spill check = air_to_host16(&pkt->payload[(pkt->payload_length - 2) * 8], 16);
779e25b118aSDominic Spill
780e25b118aSDominic Spill return (crc == check);
781e25b118aSDominic Spill }
782e25b118aSDominic Spill
fhs(int clock,btbb_packet * pkt)783e25b118aSDominic Spill int fhs(int clock, btbb_packet* pkt)
784e25b118aSDominic Spill {
785e25b118aSDominic Spill /* skip the access code and packet header */
786e25b118aSDominic Spill char *stream = pkt->symbols + 122;
787e25b118aSDominic Spill /* number of symbols remaining after access code and packet header */
788e25b118aSDominic Spill int size = pkt->length - 122;
789e25b118aSDominic Spill
790e25b118aSDominic Spill pkt->payload_length = 20;
791e25b118aSDominic Spill
792e25b118aSDominic Spill if (size < pkt->payload_length * 12)
793e25b118aSDominic Spill return 1; //FIXME should throw exception
794e25b118aSDominic Spill
795e25b118aSDominic Spill char *corrected = unfec23(stream, pkt->payload_length * 8);
796e25b118aSDominic Spill if (!corrected)
797e25b118aSDominic Spill return 0;
798e25b118aSDominic Spill
799e25b118aSDominic Spill /* try to unwhiten with known clock bits */
800e25b118aSDominic Spill unwhiten(corrected, pkt->payload, clock, pkt->payload_length * 8, 18, pkt);
801e25b118aSDominic Spill if (payload_crc(pkt)) {
802e25b118aSDominic Spill free(corrected);
803e25b118aSDominic Spill return 1000;
804e25b118aSDominic Spill }
805e25b118aSDominic Spill
806e25b118aSDominic Spill /* try all 32 possible X-input values instead */
807e25b118aSDominic Spill for (clock = 32; clock < 64; clock++) {
808e25b118aSDominic Spill unwhiten(corrected, pkt->payload, clock, pkt->payload_length * 8, 18, pkt);
809e25b118aSDominic Spill if (payload_crc(pkt)) {
810e25b118aSDominic Spill free(corrected);
811e25b118aSDominic Spill return 1000;
812e25b118aSDominic Spill }
813e25b118aSDominic Spill }
814e25b118aSDominic Spill
815e25b118aSDominic Spill /* failed to unwhiten */
816e25b118aSDominic Spill free(corrected);
817e25b118aSDominic Spill return 0;
818e25b118aSDominic Spill }
819e25b118aSDominic Spill
820e25b118aSDominic Spill /* decode payload header, return value indicates success */
decode_payload_header(char * stream,int clock,int header_bytes,int size,int fec,btbb_packet * pkt)821e25b118aSDominic Spill static int decode_payload_header(char *stream, int clock, int header_bytes, int size, int fec, btbb_packet* pkt)
822e25b118aSDominic Spill {
823e25b118aSDominic Spill if(header_bytes == 2)
824e25b118aSDominic Spill {
825e25b118aSDominic Spill if(size < 16)
826e25b118aSDominic Spill return 0; //FIXME should throw exception
827e25b118aSDominic Spill if(fec) {
828e25b118aSDominic Spill if(size < 30)
829e25b118aSDominic Spill return 0; //FIXME should throw exception
830e25b118aSDominic Spill char *corrected = unfec23(stream, 16);
831e25b118aSDominic Spill if (!corrected)
832e25b118aSDominic Spill return 0;
833e25b118aSDominic Spill unwhiten(corrected, pkt->payload_header, clock, 16, 18, pkt);
834e25b118aSDominic Spill free(corrected);
835e25b118aSDominic Spill } else {
836e25b118aSDominic Spill unwhiten(stream, pkt->payload_header, clock, 16, 18, pkt);
837e25b118aSDominic Spill }
838e25b118aSDominic Spill /* payload length is payload body length + 2 bytes payload header + 2 bytes CRC */
839e25b118aSDominic Spill pkt->payload_length = air_to_host16(&pkt->payload_header[3], 10) + 4;
840e25b118aSDominic Spill } else {
841e25b118aSDominic Spill if(size < 8)
842e25b118aSDominic Spill return 0; //FIXME should throw exception
843e25b118aSDominic Spill if(fec) {
844e25b118aSDominic Spill if(size < 15)
845e25b118aSDominic Spill return 0; //FIXME should throw exception
846e25b118aSDominic Spill char *corrected = unfec23(stream, 8);
847e25b118aSDominic Spill if (!corrected)
848e25b118aSDominic Spill return 0;
849e25b118aSDominic Spill unwhiten(corrected, pkt->payload_header, clock, 8, 18, pkt);
850e25b118aSDominic Spill free(corrected);
851e25b118aSDominic Spill } else {
852e25b118aSDominic Spill unwhiten(stream, pkt->payload_header, clock, 8, 18, pkt);
853e25b118aSDominic Spill }
854e25b118aSDominic Spill /* payload length is payload body length + 1 byte payload header + 2 bytes CRC */
855e25b118aSDominic Spill pkt->payload_length = air_to_host8(&pkt->payload_header[3], 5) + 3;
856e25b118aSDominic Spill }
85795079a24SDominic Spill /* Try to set the max payload length to a sensible value,
85895079a24SDominic Spill * especially when using strange data
85995079a24SDominic Spill */
86095079a24SDominic Spill int max_length = 0;
86195079a24SDominic Spill switch(pkt->packet_type) {
86295079a24SDominic Spill case PACKET_TYPE_DM1:
86395079a24SDominic Spill max_length = 20;
86495079a24SDominic Spill break;
86595079a24SDominic Spill case PACKET_TYPE_DH1:
86695079a24SDominic Spill /* assuming DH1 but could be 2-DH1 (58) */
86795079a24SDominic Spill max_length = 30;
86895079a24SDominic Spill break;
86995079a24SDominic Spill case PACKET_TYPE_DV:
87095079a24SDominic Spill /* assuming DV but could be 3-DH1 (87) */
87195079a24SDominic Spill max_length = 12; /* + 10bytes of voice data */
87295079a24SDominic Spill break;
87395079a24SDominic Spill case PACKET_TYPE_DM3:
87495079a24SDominic Spill /* assuming DM3 but could be 2-DH3 (371) */
87595079a24SDominic Spill max_length = 125;
87695079a24SDominic Spill break;
87795079a24SDominic Spill case PACKET_TYPE_DH3:
87895079a24SDominic Spill /* assuming DH3 but could be 3-DH3 (556) */
87995079a24SDominic Spill max_length = 187;
88095079a24SDominic Spill break;
88195079a24SDominic Spill case PACKET_TYPE_DM5:
88295079a24SDominic Spill /* assuming DM5 but could be 2-DH5 (683) */
88395079a24SDominic Spill max_length = 228;
88495079a24SDominic Spill break;
88595079a24SDominic Spill case PACKET_TYPE_DH5:
88695079a24SDominic Spill /* assuming DH5 but could be 3-DH5 (1025) */
88795079a24SDominic Spill max_length = 343;
88895079a24SDominic Spill break;
88995079a24SDominic Spill }
89095079a24SDominic Spill pkt->payload_length = MIN(pkt->payload_length, max_length);
891e25b118aSDominic Spill pkt->payload_llid = air_to_host8(&pkt->payload_header[0], 2);
892e25b118aSDominic Spill pkt->payload_flow = air_to_host8(&pkt->payload_header[2], 1);
893e25b118aSDominic Spill pkt->payload_header_length = header_bytes;
894e25b118aSDominic Spill return 1;
895e25b118aSDominic Spill }
896e25b118aSDominic Spill
897e25b118aSDominic Spill /* DM 1/3/5 packet (and DV)*/
DM(int clock,btbb_packet * pkt)898e25b118aSDominic Spill int DM(int clock, btbb_packet* pkt)
899e25b118aSDominic Spill {
900e25b118aSDominic Spill int bitlength;
901e25b118aSDominic Spill /* number of bytes in the payload header */
902e25b118aSDominic Spill int header_bytes = 2;
903e25b118aSDominic Spill /* maximum payload length */
904e25b118aSDominic Spill int max_length;
905e25b118aSDominic Spill /* skip the access code and packet header */
906e25b118aSDominic Spill char *stream = pkt->symbols + 122;
907e25b118aSDominic Spill /* number of symbols remaining after access code and packet header */
908e25b118aSDominic Spill int size = pkt->length - 122;
909e25b118aSDominic Spill
910e25b118aSDominic Spill switch(pkt->packet_type)
911e25b118aSDominic Spill {
91295079a24SDominic Spill case PACKET_TYPE_DV:
913e25b118aSDominic Spill /* skip 80 voice bits, then treat the rest like a DM1 */
914e25b118aSDominic Spill stream += 80;
915e25b118aSDominic Spill size -= 80;
916e25b118aSDominic Spill header_bytes = 1;
917e25b118aSDominic Spill /* I don't think the length of the voice field ("synchronous data
918e25b118aSDominic Spill * field") is included in the length indicated by the payload
919e25b118aSDominic Spill * header in the data field ("asynchronous data field"), but I
920e25b118aSDominic Spill * could be wrong.
921e25b118aSDominic Spill */
922e25b118aSDominic Spill max_length = 12;
923e25b118aSDominic Spill break;
92495079a24SDominic Spill case PACKET_TYPE_DM1:
925e25b118aSDominic Spill header_bytes = 1;
926e25b118aSDominic Spill max_length = 20;
927e25b118aSDominic Spill break;
92895079a24SDominic Spill case PACKET_TYPE_DM3:
929e25b118aSDominic Spill max_length = 125;
930e25b118aSDominic Spill break;
93195079a24SDominic Spill case PACKET_TYPE_DM5:
932e25b118aSDominic Spill max_length = 228;
933e25b118aSDominic Spill break;
934e25b118aSDominic Spill default: /* not a DM1/3/5 or DV */
935e25b118aSDominic Spill return 0;
936e25b118aSDominic Spill }
937e25b118aSDominic Spill if(!decode_payload_header(stream, clock, header_bytes, size, 1, pkt))
938e25b118aSDominic Spill return 0;
939e25b118aSDominic Spill /* check that the length indicated in the payload header is within spec */
940e25b118aSDominic Spill if(pkt->payload_length > max_length)
941e25b118aSDominic Spill /* could be encrypted */
942e25b118aSDominic Spill return 1;
943e25b118aSDominic Spill bitlength = pkt->payload_length*8;
944e25b118aSDominic Spill if(bitlength > size)
945e25b118aSDominic Spill return 1; //FIXME should throw exception
946e25b118aSDominic Spill
947e25b118aSDominic Spill char *corrected = unfec23(stream, bitlength);
948e25b118aSDominic Spill if (!corrected)
949e25b118aSDominic Spill return 0;
950e25b118aSDominic Spill unwhiten(corrected, pkt->payload, clock, bitlength, 18, pkt);
951e25b118aSDominic Spill free(corrected);
952e25b118aSDominic Spill
953e25b118aSDominic Spill if (payload_crc(pkt))
954e25b118aSDominic Spill return 10;
955e25b118aSDominic Spill
956e25b118aSDominic Spill /* could be encrypted */
9576b21c2c9SDominic Spill return 2;
958e25b118aSDominic Spill }
959e25b118aSDominic Spill
960e25b118aSDominic Spill /* DH 1/3/5 packet (and AUX1) */
961e25b118aSDominic Spill /* similar to DM 1/3/5 but without FEC */
DH(int clock,btbb_packet * pkt)962e25b118aSDominic Spill int DH(int clock, btbb_packet* pkt)
963e25b118aSDominic Spill {
964e25b118aSDominic Spill int bitlength;
965e25b118aSDominic Spill /* number of bytes in the payload header */
966e25b118aSDominic Spill int header_bytes = 2;
967e25b118aSDominic Spill /* maximum payload length */
968e25b118aSDominic Spill int max_length;
969e25b118aSDominic Spill /* skip the access code and packet header */
970e25b118aSDominic Spill char *stream = pkt->symbols + 122;
971e25b118aSDominic Spill /* number of symbols remaining after access code and packet header */
972e25b118aSDominic Spill int size = pkt->length - 122;
973e25b118aSDominic Spill
974e25b118aSDominic Spill switch(pkt->packet_type)
975e25b118aSDominic Spill {
97695079a24SDominic Spill case PACKET_TYPE_AUX1:
97795079a24SDominic Spill case PACKET_TYPE_DH1:
978e25b118aSDominic Spill header_bytes = 1;
979e25b118aSDominic Spill max_length = 30;
980e25b118aSDominic Spill break;
98195079a24SDominic Spill case PACKET_TYPE_DH3:
982e25b118aSDominic Spill max_length = 187;
983e25b118aSDominic Spill break;
98495079a24SDominic Spill case PACKET_TYPE_DH5:
985e25b118aSDominic Spill max_length = 343;
986e25b118aSDominic Spill break;
987e25b118aSDominic Spill default: /* not a DH1/3/5 */
988e25b118aSDominic Spill return 0;
989e25b118aSDominic Spill }
990e25b118aSDominic Spill if(!decode_payload_header(stream, clock, header_bytes, size, 0, pkt))
991e25b118aSDominic Spill return 0;
992e25b118aSDominic Spill /* check that the length indicated in the payload header is within spec */
993e25b118aSDominic Spill if(pkt->payload_length > max_length)
994e25b118aSDominic Spill /* could be encrypted */
995e25b118aSDominic Spill return 1;
996e25b118aSDominic Spill bitlength = pkt->payload_length*8;
997e25b118aSDominic Spill if(bitlength > size)
998e25b118aSDominic Spill return 1; //FIXME should throw exception
999e25b118aSDominic Spill
1000e25b118aSDominic Spill unwhiten(stream, pkt->payload, clock, bitlength, 18, pkt);
1001e25b118aSDominic Spill
1002e25b118aSDominic Spill /* AUX1 has no CRC */
1003e25b118aSDominic Spill if (pkt->packet_type == 9)
10046b21c2c9SDominic Spill return 2;
1005e25b118aSDominic Spill
1006e25b118aSDominic Spill if (payload_crc(pkt))
1007e25b118aSDominic Spill return 10;
1008e25b118aSDominic Spill
1009e25b118aSDominic Spill /* could be encrypted */
10106b21c2c9SDominic Spill return 2;
1011e25b118aSDominic Spill }
1012e25b118aSDominic Spill
EV3(int clock,btbb_packet * pkt)1013e25b118aSDominic Spill int EV3(int clock, btbb_packet* pkt)
1014e25b118aSDominic Spill {
1015e25b118aSDominic Spill /* skip the access code and packet header */
1016e25b118aSDominic Spill char *stream = pkt->symbols + 122;
1017e25b118aSDominic Spill
1018e25b118aSDominic Spill /* number of symbols remaining after access code and packet header */
1019e25b118aSDominic Spill int size = pkt->length - 122;
1020e25b118aSDominic Spill
1021e25b118aSDominic Spill /* maximum payload length is 30 bytes + 2 bytes CRC */
1022e25b118aSDominic Spill int maxlength = 32;
1023e25b118aSDominic Spill
1024e25b118aSDominic Spill /* number of bits we have decoded */
1025e25b118aSDominic Spill int bits;
1026e25b118aSDominic Spill
1027e25b118aSDominic Spill /* check CRC for any integer byte length up to maxlength */
1028e25b118aSDominic Spill for (pkt->payload_length = 0;
1029e25b118aSDominic Spill pkt->payload_length < maxlength; pkt->payload_length++) {
1030e25b118aSDominic Spill
1031e25b118aSDominic Spill bits = pkt->payload_length * 8;
1032e25b118aSDominic Spill
1033e25b118aSDominic Spill /* unwhiten next byte */
1034e25b118aSDominic Spill if ((bits + 8) > size)
1035e25b118aSDominic Spill return 1; //FIXME should throw exception
1036e25b118aSDominic Spill unwhiten(stream, pkt->payload + bits, clock, 8, 18 + bits, pkt);
1037e25b118aSDominic Spill
1038e25b118aSDominic Spill if ((pkt->payload_length > 2) && (payload_crc(pkt)))
1039e25b118aSDominic Spill return 10;
1040e25b118aSDominic Spill }
10416b21c2c9SDominic Spill return 2;
1042e25b118aSDominic Spill }
1043e25b118aSDominic Spill
EV4(int clock,btbb_packet * pkt)1044e25b118aSDominic Spill int EV4(int clock, btbb_packet* pkt)
1045e25b118aSDominic Spill {
1046e25b118aSDominic Spill char *corrected;
1047e25b118aSDominic Spill
1048e25b118aSDominic Spill /* skip the access code and packet header */
1049e25b118aSDominic Spill char *stream = pkt->symbols + 122;
1050e25b118aSDominic Spill
1051e25b118aSDominic Spill /* number of symbols remaining after access code and packet header */
1052e25b118aSDominic Spill int size = pkt->length - 122;
1053e25b118aSDominic Spill
1054e25b118aSDominic Spill /*
1055e25b118aSDominic Spill * maximum payload length is 120 bytes + 2 bytes CRC
1056e25b118aSDominic Spill * after FEC2/3, this results in a maximum of 1470 symbols
1057e25b118aSDominic Spill */
1058e25b118aSDominic Spill int maxlength = 1470;
1059e25b118aSDominic Spill
1060e25b118aSDominic Spill /*
1061e25b118aSDominic Spill * minumum payload length is 1 bytes + 2 bytes CRC
1062e25b118aSDominic Spill * after FEC2/3, this results in a minimum of 45 symbols
1063e25b118aSDominic Spill */
1064e25b118aSDominic Spill int minlength = 45;
1065e25b118aSDominic Spill
1066e25b118aSDominic Spill int syms = 0; /* number of symbols we have decoded */
1067e25b118aSDominic Spill int bits = 0; /* number of payload bits we have decoded */
1068e25b118aSDominic Spill
1069e25b118aSDominic Spill pkt->payload_length = 1;
1070e25b118aSDominic Spill
1071e25b118aSDominic Spill while (syms < maxlength) {
1072e25b118aSDominic Spill
1073e25b118aSDominic Spill /* unfec/unwhiten next block (15 symbols -> 10 bits) */
1074e25b118aSDominic Spill if (syms + 15 > size)
1075e25b118aSDominic Spill return 1; //FIXME should throw exception
1076e25b118aSDominic Spill corrected = unfec23(stream + syms, 10);
1077e25b118aSDominic Spill if (!corrected) {
1078e25b118aSDominic Spill free(corrected);
1079e25b118aSDominic Spill if (syms < minlength)
1080e25b118aSDominic Spill return 0;
1081e25b118aSDominic Spill else
1082e25b118aSDominic Spill return 1;
1083e25b118aSDominic Spill }
1084e25b118aSDominic Spill unwhiten(corrected, pkt->payload + bits, clock, 10, 18 + bits, pkt);
1085e25b118aSDominic Spill free(corrected);
1086e25b118aSDominic Spill
1087e25b118aSDominic Spill /* check CRC one byte at a time */
1088e25b118aSDominic Spill while (pkt->payload_length * 8 <= bits) {
1089e25b118aSDominic Spill if (payload_crc(pkt))
1090e25b118aSDominic Spill return 10;
1091e25b118aSDominic Spill pkt->payload_length++;
1092e25b118aSDominic Spill }
1093e25b118aSDominic Spill syms += 15;
1094e25b118aSDominic Spill bits += 10;
1095e25b118aSDominic Spill }
10966b21c2c9SDominic Spill return 2;
1097e25b118aSDominic Spill }
1098e25b118aSDominic Spill
EV5(int clock,btbb_packet * pkt)1099e25b118aSDominic Spill int EV5(int clock, btbb_packet* pkt)
1100e25b118aSDominic Spill {
1101e25b118aSDominic Spill /* skip the access code and packet header */
1102e25b118aSDominic Spill char *stream = pkt->symbols + 122;
1103e25b118aSDominic Spill
1104e25b118aSDominic Spill /* number of symbols remaining after access code and packet header */
1105e25b118aSDominic Spill int size = pkt->length - 122;
1106e25b118aSDominic Spill
1107e25b118aSDominic Spill /* maximum payload length is 180 bytes + 2 bytes CRC */
1108e25b118aSDominic Spill int maxlength = 182;
1109e25b118aSDominic Spill
1110e25b118aSDominic Spill /* number of bits we have decoded */
1111e25b118aSDominic Spill int bits;
1112e25b118aSDominic Spill
1113e25b118aSDominic Spill /* check CRC for any integer byte length up to maxlength */
1114e25b118aSDominic Spill for (pkt->payload_length = 0;
1115e25b118aSDominic Spill pkt->payload_length < maxlength; pkt->payload_length++) {
1116e25b118aSDominic Spill
1117e25b118aSDominic Spill bits = pkt->payload_length * 8;
1118e25b118aSDominic Spill
1119e25b118aSDominic Spill /* unwhiten next byte */
1120e25b118aSDominic Spill if ((bits + 8) > size)
1121e25b118aSDominic Spill return 1; //FIXME should throw exception
1122e25b118aSDominic Spill unwhiten(stream, pkt->payload + bits, clock, 8, 18 + bits, pkt);
1123e25b118aSDominic Spill
1124e25b118aSDominic Spill if ((pkt->payload_length > 2) && (payload_crc(pkt)))
1125e25b118aSDominic Spill return 10;
1126e25b118aSDominic Spill }
11276b21c2c9SDominic Spill return 2;
1128e25b118aSDominic Spill }
1129e25b118aSDominic Spill
1130e25b118aSDominic Spill /* HV packet type payload parser */
HV(int clock,btbb_packet * pkt)1131e25b118aSDominic Spill int HV(int clock, btbb_packet* pkt)
1132e25b118aSDominic Spill {
1133e25b118aSDominic Spill /* skip the access code and packet header */
1134e25b118aSDominic Spill char *stream = pkt->symbols + 122;
1135e25b118aSDominic Spill /* number of symbols remaining after access code and packet header */
1136e25b118aSDominic Spill int size = pkt->length - 122;
1137e25b118aSDominic Spill
1138e25b118aSDominic Spill pkt->payload_header_length = 0;
1139e25b118aSDominic Spill if(size < 240) {
1140e25b118aSDominic Spill pkt->payload_length = 0;
1141e25b118aSDominic Spill return 1; //FIXME should throw exception
1142e25b118aSDominic Spill }
1143e25b118aSDominic Spill
1144e25b118aSDominic Spill switch (pkt->packet_type) {
114595079a24SDominic Spill case PACKET_TYPE_HV1:
1146e25b118aSDominic Spill {
1147e25b118aSDominic Spill char corrected[80];
1148e25b118aSDominic Spill if (!unfec13(stream, corrected, 80))
1149e25b118aSDominic Spill return 0;
1150e25b118aSDominic Spill pkt->payload_length = 10;
1151e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 1);
1152e25b118aSDominic Spill unwhiten(corrected, pkt->payload, clock, pkt->payload_length*8, 18, pkt);
1153e25b118aSDominic Spill }
1154e25b118aSDominic Spill break;
115595079a24SDominic Spill case PACKET_TYPE_HV2:
1156e25b118aSDominic Spill {
1157e25b118aSDominic Spill char *corrected = unfec23(stream, 160);
1158e25b118aSDominic Spill if (!corrected)
1159e25b118aSDominic Spill return 0;
1160e25b118aSDominic Spill pkt->payload_length = 20;
1161e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 1);
1162e25b118aSDominic Spill unwhiten(corrected, pkt->payload, clock, pkt->payload_length*8, 18, pkt);
1163e25b118aSDominic Spill free(corrected);
1164e25b118aSDominic Spill }
1165e25b118aSDominic Spill break;
116695079a24SDominic Spill case PACKET_TYPE_HV3:
1167e25b118aSDominic Spill pkt->payload_length = 30;
1168e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 1);
1169e25b118aSDominic Spill unwhiten(stream, pkt->payload, clock, pkt->payload_length*8, 18, pkt);
1170e25b118aSDominic Spill break;
1171e25b118aSDominic Spill }
1172e25b118aSDominic Spill
11736b21c2c9SDominic Spill return 2;
1174e25b118aSDominic Spill }
1175e25b118aSDominic Spill /* try a clock value (CLK1-6) to unwhiten packet header,
1176e25b118aSDominic Spill * sets resultant p->packet_type and p->UAP, returns UAP.
1177e25b118aSDominic Spill */
try_clock(int clock,btbb_packet * pkt)1178e25b118aSDominic Spill uint8_t try_clock(int clock, btbb_packet* pkt)
1179e25b118aSDominic Spill {
1180e25b118aSDominic Spill /* skip 72 bit access code */
1181e25b118aSDominic Spill char *stream = pkt->symbols + 68;
1182e25b118aSDominic Spill /* 18 bit packet header */
1183e25b118aSDominic Spill char header[18];
1184e25b118aSDominic Spill char unwhitened[18];
1185e25b118aSDominic Spill
1186e25b118aSDominic Spill if (!unfec13(stream, header, 18))
1187e25b118aSDominic Spill return 0;
1188e25b118aSDominic Spill unwhiten(header, unwhitened, clock, 18, 0, pkt);
1189e25b118aSDominic Spill uint16_t hdr_data = air_to_host16(unwhitened, 10);
1190e25b118aSDominic Spill uint8_t hec = air_to_host8(&unwhitened[10], 8);
1191672715e8SDominic Spill pkt->UAP = uap_from_hec(hdr_data, hec);
1192e25b118aSDominic Spill pkt->packet_type = air_to_host8(&unwhitened[3], 4);
1193e25b118aSDominic Spill
1194e25b118aSDominic Spill return pkt->UAP;
1195e25b118aSDominic Spill }
1196e25b118aSDominic Spill
1197e25b118aSDominic Spill /* decode the packet header */
btbb_decode_header(btbb_packet * pkt)1198e25b118aSDominic Spill int btbb_decode_header(btbb_packet* pkt)
1199e25b118aSDominic Spill {
1200e25b118aSDominic Spill /* skip 72 bit access code */
1201e25b118aSDominic Spill char *stream = pkt->symbols + 68;
1202e25b118aSDominic Spill /* 18 bit packet header */
1203e25b118aSDominic Spill char header[18];
1204e25b118aSDominic Spill uint8_t UAP;
1205e25b118aSDominic Spill
1206e25b118aSDominic Spill if (btbb_packet_get_flag(pkt, BTBB_CLK6_VALID) && unfec13(stream, header, 18)) {
1207c4e05ee8SHannes Ellinger unwhiten(header, pkt->packet_header, pkt->clkn, 18, 0, pkt);
1208e25b118aSDominic Spill uint16_t hdr_data = air_to_host16(pkt->packet_header, 10);
1209e25b118aSDominic Spill uint8_t hec = air_to_host8(&pkt->packet_header[10], 8);
1210672715e8SDominic Spill UAP = uap_from_hec(hdr_data, hec);
1211e25b118aSDominic Spill if (UAP == pkt->UAP) {
1212e25b118aSDominic Spill pkt->packet_lt_addr = air_to_host8(&pkt->packet_header[0], 3);
1213e25b118aSDominic Spill pkt->packet_type = air_to_host8(&pkt->packet_header[3], 4);
1214e25b118aSDominic Spill pkt->packet_flags = air_to_host8(&pkt->packet_header[7], 3);
1215e25b118aSDominic Spill pkt->packet_hec = hec;
1216e25b118aSDominic Spill return 1;
1217e25b118aSDominic Spill }
1218e25b118aSDominic Spill }
1219e25b118aSDominic Spill
1220e25b118aSDominic Spill return 0;
1221e25b118aSDominic Spill }
1222e25b118aSDominic Spill
btbb_decode_payload(btbb_packet * pkt)1223e25b118aSDominic Spill int btbb_decode_payload(btbb_packet* pkt)
1224e25b118aSDominic Spill {
1225e25b118aSDominic Spill int rv = 0;
1226e25b118aSDominic Spill pkt->payload_header_length = 0;
1227e25b118aSDominic Spill
1228e25b118aSDominic Spill switch(pkt->packet_type)
1229e25b118aSDominic Spill {
123095079a24SDominic Spill case PACKET_TYPE_NULL:
1231e25b118aSDominic Spill /* no payload to decode */
1232e25b118aSDominic Spill pkt->payload_length = 0;
1233e25b118aSDominic Spill rv = 1;
1234e25b118aSDominic Spill break;
123595079a24SDominic Spill case PACKET_TYPE_POLL:
1236e25b118aSDominic Spill /* no payload to decode */
1237e25b118aSDominic Spill pkt->payload_length = 0;
1238e25b118aSDominic Spill rv = 1;
1239e25b118aSDominic Spill break;
124095079a24SDominic Spill case PACKET_TYPE_FHS:
1241c4e05ee8SHannes Ellinger rv = fhs(pkt->clkn, pkt);
1242e25b118aSDominic Spill break;
124395079a24SDominic Spill case PACKET_TYPE_DM1:
1244c4e05ee8SHannes Ellinger rv = DM(pkt->clkn, pkt);
1245e25b118aSDominic Spill break;
124695079a24SDominic Spill case PACKET_TYPE_DH1:
1247e25b118aSDominic Spill /* assuming DH1 but could be 2-DH1 */
1248c4e05ee8SHannes Ellinger rv = DH(pkt->clkn, pkt);
1249e25b118aSDominic Spill break;
125095079a24SDominic Spill case PACKET_TYPE_HV1:
1251c4e05ee8SHannes Ellinger rv = HV(pkt->clkn, pkt);
1252e25b118aSDominic Spill break;
125395079a24SDominic Spill case PACKET_TYPE_HV2:
1254c4e05ee8SHannes Ellinger rv = HV(pkt->clkn, pkt);
1255e25b118aSDominic Spill break;
125695079a24SDominic Spill case PACKET_TYPE_HV3: /* HV3/EV3/3-EV3 */
1257e25b118aSDominic Spill /* decode as EV3 if CRC checks out */
1258c4e05ee8SHannes Ellinger if ((rv = EV3(pkt->clkn, pkt)) <= 1)
1259e25b118aSDominic Spill /* otherwise assume HV3 */
1260c4e05ee8SHannes Ellinger rv = HV(pkt->clkn, pkt);
1261e25b118aSDominic Spill /* don't know how to decode 3-EV3 */
1262e25b118aSDominic Spill break;
126395079a24SDominic Spill case PACKET_TYPE_DV:
1264e25b118aSDominic Spill /* assuming DV but could be 3-DH1 */
1265c4e05ee8SHannes Ellinger rv = DM(pkt->clkn, pkt);
1266e25b118aSDominic Spill break;
126795079a24SDominic Spill case PACKET_TYPE_AUX1:
1268c4e05ee8SHannes Ellinger rv = DH(pkt->clkn, pkt);
1269e25b118aSDominic Spill break;
127095079a24SDominic Spill case PACKET_TYPE_DM3:
1271e25b118aSDominic Spill /* assuming DM3 but could be 2-DH3 */
1272c4e05ee8SHannes Ellinger rv = DM(pkt->clkn, pkt);
1273e25b118aSDominic Spill break;
127495079a24SDominic Spill case PACKET_TYPE_DH3:
1275e25b118aSDominic Spill /* assuming DH3 but could be 3-DH3 */
1276c4e05ee8SHannes Ellinger rv = DH(pkt->clkn, pkt);
1277e25b118aSDominic Spill break;
127895079a24SDominic Spill case PACKET_TYPE_EV4:
1279e25b118aSDominic Spill /* assuming EV4 but could be 2-EV5 */
1280c4e05ee8SHannes Ellinger rv = EV4(pkt->clkn, pkt);
1281e25b118aSDominic Spill break;
128295079a24SDominic Spill case PACKET_TYPE_EV5:
1283e25b118aSDominic Spill /* assuming EV5 but could be 3-EV5 */
1284c4e05ee8SHannes Ellinger rv = EV5(pkt->clkn, pkt);
1285389f0c69SDominic Spill break;
128695079a24SDominic Spill case PACKET_TYPE_DM5:
1287e25b118aSDominic Spill /* assuming DM5 but could be 2-DH5 */
1288c4e05ee8SHannes Ellinger rv = DM(pkt->clkn, pkt);
1289e25b118aSDominic Spill break;
129095079a24SDominic Spill case PACKET_TYPE_DH5:
1291e25b118aSDominic Spill /* assuming DH5 but could be 3-DH5 */
1292c4e05ee8SHannes Ellinger rv = DH(pkt->clkn, pkt);
1293e25b118aSDominic Spill break;
1294e25b118aSDominic Spill }
1295e25b118aSDominic Spill btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 1);
1296e25b118aSDominic Spill return rv;
1297e25b118aSDominic Spill }
1298e25b118aSDominic Spill
1299194e638bSHannes Ellinger /* decode the whole packet */
btbb_decode(btbb_packet * pkt)1300194e638bSHannes Ellinger int btbb_decode(btbb_packet* pkt)
1301194e638bSHannes Ellinger {
1302194e638bSHannes Ellinger int rv = 0;
1303194e638bSHannes Ellinger
1304194e638bSHannes Ellinger btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 0);
1305194e638bSHannes Ellinger
1306194e638bSHannes Ellinger if (btbb_decode_header(pkt)) {
1307194e638bSHannes Ellinger rv = btbb_decode_payload(pkt);
1308194e638bSHannes Ellinger }
1309194e638bSHannes Ellinger
1310194e638bSHannes Ellinger /* If we were successful, print the packet */
1311194e638bSHannes Ellinger if(rv > 0) {
1312194e638bSHannes Ellinger printf("Packet decoded with clock 0x%02x (rv=%d)\n", pkt->clkn & 0x3f, rv);
1313194e638bSHannes Ellinger btbb_print_packet(pkt);
1314194e638bSHannes Ellinger }
1315194e638bSHannes Ellinger
1316194e638bSHannes Ellinger return rv;
1317194e638bSHannes Ellinger }
1318194e638bSHannes Ellinger
1319e25b118aSDominic Spill /* print packet information */
btbb_print_packet(const btbb_packet * pkt)13208f3e7eeaSChristopher Kilgour void btbb_print_packet(const btbb_packet* pkt)
1321e25b118aSDominic Spill {
1322e25b118aSDominic Spill if (btbb_packet_get_flag(pkt, BTBB_HAS_PAYLOAD)) {
1323e25b118aSDominic Spill printf(" Type: %s\n", TYPE_NAMES[pkt->packet_type]);
1324e25b118aSDominic Spill if (pkt->payload_header_length > 0) {
1325e25b118aSDominic Spill printf(" LT_ADDR: %d\n", pkt->packet_lt_addr);
1326e25b118aSDominic Spill printf(" LLID: %d\n", pkt->payload_llid);
1327e25b118aSDominic Spill printf(" flow: %d\n", pkt->payload_flow);
1328e25b118aSDominic Spill printf(" payload length: %d\n", pkt->payload_length);
1329e25b118aSDominic Spill }
1330e25b118aSDominic Spill if (pkt->payload_length) {
1331e25b118aSDominic Spill printf(" Data: ");
1332e25b118aSDominic Spill int i;
1333e25b118aSDominic Spill for(i=0; i<pkt->payload_length; i++)
1334e25b118aSDominic Spill printf(" %02x", air_to_host8(pkt->payload + 8*i, 8));
1335e25b118aSDominic Spill printf("\n");
1336e25b118aSDominic Spill }
1337e25b118aSDominic Spill }
1338e25b118aSDominic Spill }
1339e25b118aSDominic Spill
tun_format(btbb_packet * pkt)1340e25b118aSDominic Spill char *tun_format(btbb_packet* pkt)
1341e25b118aSDominic Spill {
1342e25b118aSDominic Spill /* include 6 bytes for meta data, 3 bytes for packet header */
1343e25b118aSDominic Spill int length = 9 + pkt->payload_length;
1344e25b118aSDominic Spill char *tun_format = (char *) malloc(length);
1345e25b118aSDominic Spill int i;
1346e25b118aSDominic Spill
1347e25b118aSDominic Spill /* meta data */
1348c4e05ee8SHannes Ellinger tun_format[0] = pkt->clkn & 0xff;
1349c4e05ee8SHannes Ellinger tun_format[1] = (pkt->clkn >> 8) & 0xff;
1350c4e05ee8SHannes Ellinger tun_format[2] = (pkt->clkn >> 16) & 0xff;
1351c4e05ee8SHannes Ellinger tun_format[3] = (pkt->clkn >> 24) & 0xff;
1352e25b118aSDominic Spill tun_format[4] = pkt->channel;
1353e25b118aSDominic Spill tun_format[5] = btbb_packet_get_flag(pkt, BTBB_CLK27_VALID) |
1354e25b118aSDominic Spill (btbb_packet_get_flag(pkt, BTBB_NAP_VALID) << 1);
1355e25b118aSDominic Spill
1356e25b118aSDominic Spill /* packet header modified to fit byte boundaries */
1357e25b118aSDominic Spill /* lt_addr and type */
1358e25b118aSDominic Spill tun_format[6] = (char) air_to_host8(&pkt->packet_header[0], 7);
1359e25b118aSDominic Spill /* flags */
1360e25b118aSDominic Spill tun_format[7] = (char) air_to_host8(&pkt->packet_header[7], 3);
1361e25b118aSDominic Spill /* HEC */
1362e25b118aSDominic Spill tun_format[8] = (char) air_to_host8(&pkt->packet_header[10], 8);
1363e25b118aSDominic Spill
1364e25b118aSDominic Spill for(i=0;i<pkt->payload_length;i++)
1365e25b118aSDominic Spill tun_format[i+9] = (char) air_to_host8(&pkt->payload[i*8], 8);
1366e25b118aSDominic Spill
1367e25b118aSDominic Spill return tun_format;
1368e25b118aSDominic Spill }
1369e25b118aSDominic Spill
1370e25b118aSDominic Spill /* check to see if the packet has a header */
btbb_header_present(const btbb_packet * pkt)13718f3e7eeaSChristopher Kilgour int btbb_header_present(const btbb_packet* pkt)
1372e25b118aSDominic Spill {
1373e25b118aSDominic Spill /* skip to last bit of sync word */
13748f3e7eeaSChristopher Kilgour const char *stream = pkt->symbols + 63;
1375e25b118aSDominic Spill int be = 0; /* bit errors */
1376e25b118aSDominic Spill char msb; /* most significant (last) bit of sync word */
1377e25b118aSDominic Spill int a, b, c;
1378e25b118aSDominic Spill
1379e25b118aSDominic Spill /* check that we have enough symbols */
1380e25b118aSDominic Spill if (pkt->length < 122)
1381e25b118aSDominic Spill return 0;
1382e25b118aSDominic Spill
1383e25b118aSDominic Spill /* check that the AC trailer is correct */
1384e25b118aSDominic Spill msb = stream[0];
1385e25b118aSDominic Spill be += stream[1] ^ !msb;
1386e25b118aSDominic Spill be += stream[2] ^ msb;
1387e25b118aSDominic Spill be += stream[3] ^ !msb;
1388e25b118aSDominic Spill be += stream[4] ^ msb;
1389e25b118aSDominic Spill
1390e25b118aSDominic Spill /*
1391e25b118aSDominic Spill * Each bit of the 18 bit header is repeated three times. Without
1392e25b118aSDominic Spill * checking the correctness of any particular bit, just count the
1393e25b118aSDominic Spill * number of times three symbols in a row don't all agree.
1394e25b118aSDominic Spill */
1395e25b118aSDominic Spill stream += 5;
1396e25b118aSDominic Spill for (a = 0; a < 54; a += 3) {
1397e25b118aSDominic Spill b = a + 1;
1398e25b118aSDominic Spill c = a + 2;
1399e25b118aSDominic Spill be += ((stream[a] ^ stream[b]) |
1400e25b118aSDominic Spill (stream[b] ^ stream[c]) | (stream[c] ^ stream[a]));
1401e25b118aSDominic Spill }
1402e25b118aSDominic Spill
1403e25b118aSDominic Spill /*
1404e25b118aSDominic Spill * Few bit errors indicates presence of a header. Many bit errors
1405e25b118aSDominic Spill * indicates no header is present (i.e. it is an ID packet).
1406e25b118aSDominic Spill */
1407e25b118aSDominic Spill return (be < ID_THRESHOLD);
1408e25b118aSDominic Spill }
1409e25b118aSDominic Spill
1410e25b118aSDominic Spill /* extract LAP from FHS payload */
lap_from_fhs(btbb_packet * pkt)1411e25b118aSDominic Spill uint32_t lap_from_fhs(btbb_packet* pkt)
1412e25b118aSDominic Spill {
1413e25b118aSDominic Spill /* caller should check got_payload() and get_type() */
1414e25b118aSDominic Spill return air_to_host32(&pkt->payload[34], 24);
1415e25b118aSDominic Spill }
1416e25b118aSDominic Spill
1417e25b118aSDominic Spill /* extract UAP from FHS payload */
uap_from_fhs(btbb_packet * pkt)1418e25b118aSDominic Spill uint8_t uap_from_fhs(btbb_packet* pkt)
1419e25b118aSDominic Spill {
1420e25b118aSDominic Spill /* caller should check got_payload() and get_type() */
1421e25b118aSDominic Spill return air_to_host8(&pkt->payload[64], 8);
1422e25b118aSDominic Spill }
1423e25b118aSDominic Spill
1424e25b118aSDominic Spill /* extract NAP from FHS payload */
nap_from_fhs(btbb_packet * pkt)1425e25b118aSDominic Spill uint16_t nap_from_fhs(btbb_packet* pkt)
1426e25b118aSDominic Spill {
1427e25b118aSDominic Spill /* caller should check got_payload() and get_type() */
14281eecca51SDominic Spill return air_to_host16(&pkt->payload[72], 16);
1429e25b118aSDominic Spill }
1430e25b118aSDominic Spill
1431e25b118aSDominic Spill /* extract clock from FHS payload */
clock_from_fhs(btbb_packet * pkt)1432e25b118aSDominic Spill uint32_t clock_from_fhs(btbb_packet* pkt)
1433e25b118aSDominic Spill {
1434e25b118aSDominic Spill /*
1435e25b118aSDominic Spill * caller should check got_payload() and get_type()
1436e25b118aSDominic Spill *
1437e25b118aSDominic Spill * This is CLK2-27 (units of 1.25 ms).
1438e25b118aSDominic Spill * CLK0 and CLK1 are implicitly zero.
1439e25b118aSDominic Spill */
1440e25b118aSDominic Spill return air_to_host32(&pkt->payload[115], 26);
1441e25b118aSDominic Spill }
1442