xref: /libbtbb/lib/src/bluetooth_le_packet.c (revision e25b118a40ed6b5c2ea76bae29e388cfbc2f6e92)
1*e25b118aSDominic Spill /* -*- c -*- */
2*e25b118aSDominic Spill /*
3*e25b118aSDominic Spill  * Copyright 2007 - 2012 Mike Ryan, Dominic Spill, Michael Ossmann
4*e25b118aSDominic Spill  * Copyright 2005, 2006 Free Software Foundation, Inc.
5*e25b118aSDominic Spill  *
6*e25b118aSDominic Spill  * This file is part of libbtbb
7*e25b118aSDominic Spill  *
8*e25b118aSDominic Spill  * This program is free software; you can redistribute it and/or modify
9*e25b118aSDominic Spill  * it under the terms of the GNU General Public License as published by
10*e25b118aSDominic Spill  * the Free Software Foundation; either version 2, or (at your option)
11*e25b118aSDominic Spill  * any later version.
12*e25b118aSDominic Spill  *
13*e25b118aSDominic Spill  * This program is distributed in the hope that it will be useful,
14*e25b118aSDominic Spill  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*e25b118aSDominic Spill  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*e25b118aSDominic Spill  * GNU General Public License for more details.
17*e25b118aSDominic Spill  *
18*e25b118aSDominic Spill  * You should have received a copy of the GNU General Public License
19*e25b118aSDominic Spill  * along with libbtbb; see the file COPYING.  If not, write to
20*e25b118aSDominic Spill  * the Free Software Foundation, Inc., 51 Franklin Street,
21*e25b118aSDominic Spill  * Boston, MA 02110-1301, USA.
22*e25b118aSDominic Spill  */
23*e25b118aSDominic Spill 
24*e25b118aSDominic Spill #ifdef HAVE_CONFIG_H
25*e25b118aSDominic Spill #include "config.h"
26*e25b118aSDominic Spill #endif
27*e25b118aSDominic Spill 
28*e25b118aSDominic Spill #include <string.h>
29*e25b118aSDominic Spill #include "bluetooth_le_packet.h"
30*e25b118aSDominic Spill #include <ctype.h>
31*e25b118aSDominic Spill 
32*e25b118aSDominic Spill /* string representations of advertising packet type */
33*e25b118aSDominic Spill static const char *ADV_TYPE_NAMES[] = {
34*e25b118aSDominic Spill 	"ADV_IND", "ADV_DIRECT_IND", "ADV_NONCONN_IND", "SCAN_REQ",
35*e25b118aSDominic Spill 	"SCAN_RSP", "CONNECT_REQ", "ADV_SCAN_IND",
36*e25b118aSDominic Spill };
37*e25b118aSDominic Spill 
38*e25b118aSDominic Spill /* source clock accuracy in a connect packet */
39*e25b118aSDominic Spill static const char *CONNECT_SCA[] = {
40*e25b118aSDominic Spill 	"251 ppm to 500 ppm", "151 ppm to 250 ppm", "101 ppm to 150 ppm",
41*e25b118aSDominic Spill 	"76 ppm to 100 ppm", "51 ppm to 75 ppm", "31 ppm to 50 ppm",
42*e25b118aSDominic Spill 	"21 ppm to 30 ppm", "0 ppm to 20 ppm",
43*e25b118aSDominic Spill };
44*e25b118aSDominic Spill 
45*e25b118aSDominic Spill // count of objects in an array, shamelessly stolen from Chrome
46*e25b118aSDominic Spill #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
47*e25b118aSDominic Spill 
48*e25b118aSDominic Spill void decode_le(uint8_t *stream, uint16_t phys_channel, uint32_t clk100ns, le_packet_t *p) {
49*e25b118aSDominic Spill 	memcpy(p->symbols, stream, MAX_LE_SYMBOLS);
50*e25b118aSDominic Spill 
51*e25b118aSDominic Spill 	p->channel_idx = le_channel_index(phys_channel);
52*e25b118aSDominic Spill 	p->clk100ns = clk100ns;
53*e25b118aSDominic Spill 
54*e25b118aSDominic Spill 	p->access_address = 0;
55*e25b118aSDominic Spill 	p->access_address |= p->symbols[0];
56*e25b118aSDominic Spill 	p->access_address |= p->symbols[1] << 8;
57*e25b118aSDominic Spill 	p->access_address |= p->symbols[2] << 16;
58*e25b118aSDominic Spill 	p->access_address |= p->symbols[3] << 24;
59*e25b118aSDominic Spill 
60*e25b118aSDominic Spill 	if (le_packet_is_data(p)) {
61*e25b118aSDominic Spill 		// data PDU
62*e25b118aSDominic Spill 		p->length = p->symbols[5] & 0x1f;
63*e25b118aSDominic Spill 	} else {
64*e25b118aSDominic Spill 		// advertising PDU
65*e25b118aSDominic Spill 		p->length = p->symbols[5] & 0x3f;
66*e25b118aSDominic Spill 		p->adv_type = p->symbols[4] & 0xf;
67*e25b118aSDominic Spill 		p->adv_tx_add = p->symbols[4] & 0x40 ? 1 : 0;
68*e25b118aSDominic Spill 		p->adv_rx_add = p->symbols[4] & 0x80 ? 1 : 0;
69*e25b118aSDominic Spill 	}
70*e25b118aSDominic Spill }
71*e25b118aSDominic Spill 
72*e25b118aSDominic Spill int le_packet_is_data(le_packet_t *p) {
73*e25b118aSDominic Spill 	return p->channel_idx < 37;
74*e25b118aSDominic Spill }
75*e25b118aSDominic Spill 
76*e25b118aSDominic Spill uint8_t le_channel_index(uint16_t phys_channel) {
77*e25b118aSDominic Spill 	uint8_t ret;
78*e25b118aSDominic Spill 	if (phys_channel == 2402) {
79*e25b118aSDominic Spill 		ret = 37;
80*e25b118aSDominic Spill 	} else if (phys_channel < 2426) { // 0 - 10
81*e25b118aSDominic Spill 		ret = (phys_channel - 2404) / 2;
82*e25b118aSDominic Spill 	} else if (phys_channel == 2426) {
83*e25b118aSDominic Spill 		ret = 38;
84*e25b118aSDominic Spill 	} else if (phys_channel < 2480) { // 11 - 36
85*e25b118aSDominic Spill 		ret = 11 + (phys_channel - 2428) / 2;
86*e25b118aSDominic Spill 	} else {
87*e25b118aSDominic Spill 		ret = 39;
88*e25b118aSDominic Spill 	}
89*e25b118aSDominic Spill 	return ret;
90*e25b118aSDominic Spill }
91*e25b118aSDominic Spill 
92*e25b118aSDominic Spill const char *le_adv_type(le_packet_t *p) {
93*e25b118aSDominic Spill 	if (le_packet_is_data(p))
94*e25b118aSDominic Spill 		return NULL;
95*e25b118aSDominic Spill 	if (p->adv_type < COUNT_OF(ADV_TYPE_NAMES))
96*e25b118aSDominic Spill 		return ADV_TYPE_NAMES[p->adv_type];
97*e25b118aSDominic Spill 	return "UNKNOWN";
98*e25b118aSDominic Spill }
99*e25b118aSDominic Spill 
100*e25b118aSDominic Spill static void _dump_addr(char *name, uint8_t *buf, int offset, int random) {
101*e25b118aSDominic Spill 	int i;
102*e25b118aSDominic Spill 	printf("    %s%02x", name, buf[offset+5]);
103*e25b118aSDominic Spill 	for (i = 4; i >= 0; --i)
104*e25b118aSDominic Spill 		printf(":%02x", buf[offset+i]);
105*e25b118aSDominic Spill 	printf(" (%s)\n", random ? "random" : "public");
106*e25b118aSDominic Spill }
107*e25b118aSDominic Spill 
108*e25b118aSDominic Spill static void _dump_8(char *name, uint8_t *buf, int offset) {
109*e25b118aSDominic Spill 	printf("    %s%02x (%d)\n", name, buf[offset], buf[offset]);
110*e25b118aSDominic Spill }
111*e25b118aSDominic Spill 
112*e25b118aSDominic Spill static void _dump_16(char *name, uint8_t *buf, int offset) {
113*e25b118aSDominic Spill 	uint16_t val = buf[offset+1] << 8 | buf[offset];
114*e25b118aSDominic Spill 	printf("    %s%04x (%d)\n", name, val, val);
115*e25b118aSDominic Spill }
116*e25b118aSDominic Spill 
117*e25b118aSDominic Spill static void _dump_24(char *name, uint8_t *buf, int offset) {
118*e25b118aSDominic Spill 	uint16_t val = buf[offset+2] << 16 | buf[offset+1] << 8 | buf[offset];
119*e25b118aSDominic Spill 	printf("    %s%06x\n", name, val);
120*e25b118aSDominic Spill }
121*e25b118aSDominic Spill 
122*e25b118aSDominic Spill static void _dump_32(char *name, uint8_t *buf, int offset) {
123*e25b118aSDominic Spill 	uint32_t val = buf[offset+3] << 24 |
124*e25b118aSDominic Spill 				   buf[offset+2] << 16 |
125*e25b118aSDominic Spill 				   buf[offset+1] << 8 |
126*e25b118aSDominic Spill 				   buf[offset+0];
127*e25b118aSDominic Spill 	printf("    %s%08x\n", name, val);
128*e25b118aSDominic Spill }
129*e25b118aSDominic Spill 
130*e25b118aSDominic Spill static void _dump_uuid(uint8_t *uuid) {
131*e25b118aSDominic Spill 	int i;
132*e25b118aSDominic Spill 	for (i = 0; i < 4; ++i)
133*e25b118aSDominic Spill 		printf("%02x", uuid[i]);
134*e25b118aSDominic Spill 	printf("-");
135*e25b118aSDominic Spill 	for (i = 4; i < 6; ++i)
136*e25b118aSDominic Spill 		printf("%02x", uuid[i]);
137*e25b118aSDominic Spill 	printf("-");
138*e25b118aSDominic Spill 	for (i = 6; i < 8; ++i)
139*e25b118aSDominic Spill 		printf("%02x", uuid[i]);
140*e25b118aSDominic Spill 	printf("-");
141*e25b118aSDominic Spill 	for (i = 8; i < 10; ++i)
142*e25b118aSDominic Spill 		printf("%02x", uuid[i]);
143*e25b118aSDominic Spill 	printf("-");
144*e25b118aSDominic Spill 	for (i = 10; i < 16; ++i)
145*e25b118aSDominic Spill 		printf("%02x", uuid[i]);
146*e25b118aSDominic Spill }
147*e25b118aSDominic Spill 
148*e25b118aSDominic Spill // Refer to pg 1735 of Bluetooth Core Spec 4.0
149*e25b118aSDominic Spill static void _dump_scan_rsp_data(uint8_t *buf, int len) {
150*e25b118aSDominic Spill 	int pos = 0;
151*e25b118aSDominic Spill 	int sublen, i;
152*e25b118aSDominic Spill 	uint8_t type;
153*e25b118aSDominic Spill 	uint16_t val;
154*e25b118aSDominic Spill 	char *cval;
155*e25b118aSDominic Spill 
156*e25b118aSDominic Spill 	while (pos < len) {
157*e25b118aSDominic Spill 		sublen = buf[pos];
158*e25b118aSDominic Spill 		++pos;
159*e25b118aSDominic Spill 		if (pos + sublen > len) {
160*e25b118aSDominic Spill 			printf("Error: attempt to read past end of buffer (%d + %d > %d)\n", pos, sublen, len);
161*e25b118aSDominic Spill 			return;
162*e25b118aSDominic Spill 		}
163*e25b118aSDominic Spill 		if (sublen == 0) {
164*e25b118aSDominic Spill 			printf("Early return due to 0 length\n");
165*e25b118aSDominic Spill 			return;
166*e25b118aSDominic Spill 		}
167*e25b118aSDominic Spill 		type = buf[pos];
168*e25b118aSDominic Spill 		printf("        Type %02x", type);
169*e25b118aSDominic Spill 		switch (type) {
170*e25b118aSDominic Spill 			case 0x01:
171*e25b118aSDominic Spill 				printf(" (Flags)\n");
172*e25b118aSDominic Spill 				printf("           ");
173*e25b118aSDominic Spill 				for (i = 0; i < 8; ++i)
174*e25b118aSDominic Spill 					printf("%d", buf[pos+1] & (1 << (7-i)) ? 1 : 0);
175*e25b118aSDominic Spill 				printf("\n");
176*e25b118aSDominic Spill 				break;
177*e25b118aSDominic Spill 			case 0x07:
178*e25b118aSDominic Spill 				printf(" (128-bit Service UUIDs)\n");
179*e25b118aSDominic Spill 				if ((sublen - 1) % 16 == 0) {
180*e25b118aSDominic Spill 					uint8_t uuid[16];
181*e25b118aSDominic Spill 					for (i = 0; i < sublen - 1; ++i) {
182*e25b118aSDominic Spill 						uuid[15 - (i % 16)] = buf[pos+1+i];
183*e25b118aSDominic Spill 						if ((i & 15) == 15) {
184*e25b118aSDominic Spill 							printf("           ");
185*e25b118aSDominic Spill 							_dump_uuid(uuid);
186*e25b118aSDominic Spill 							printf("\n");
187*e25b118aSDominic Spill 						}
188*e25b118aSDominic Spill 					}
189*e25b118aSDominic Spill 				}
190*e25b118aSDominic Spill 				else {
191*e25b118aSDominic Spill 					printf("Wrong length (%d, must be divisible by 16)\n", sublen-1);
192*e25b118aSDominic Spill 				}
193*e25b118aSDominic Spill 				break;
194*e25b118aSDominic Spill 			case 0x09:
195*e25b118aSDominic Spill 				printf(" (Complete Local Name)\n");
196*e25b118aSDominic Spill 				printf("           ");
197*e25b118aSDominic Spill 				for (i = 1; i < sublen; ++i)
198*e25b118aSDominic Spill 					printf("%c", isprint(buf[pos+i]) ? buf[pos+i] : '.');
199*e25b118aSDominic Spill 				printf("\n");
200*e25b118aSDominic Spill 				break;
201*e25b118aSDominic Spill 			case 0x0a:
202*e25b118aSDominic Spill 				printf(" (Tx Power Level)\n");
203*e25b118aSDominic Spill 				printf("           ");
204*e25b118aSDominic Spill 				if (sublen-1 == 1) {
205*e25b118aSDominic Spill 					cval = (char *)&buf[pos+1];
206*e25b118aSDominic Spill 					printf("%d dBm\n", *cval);
207*e25b118aSDominic Spill 				} else {
208*e25b118aSDominic Spill 					printf("Wrong length (%d, should be 1)\n", sublen-1);
209*e25b118aSDominic Spill 				}
210*e25b118aSDominic Spill 				break;
211*e25b118aSDominic Spill 			case 0x12:
212*e25b118aSDominic Spill 				printf(" (Slave Connection Interval Range)\n");
213*e25b118aSDominic Spill 				printf("           ");
214*e25b118aSDominic Spill 				if (sublen-1 == 4) {
215*e25b118aSDominic Spill 					val = (buf[pos+2] << 8) | buf[pos+1];
216*e25b118aSDominic Spill 					printf("(%0.2f, ", val * 1.25);
217*e25b118aSDominic Spill 					val = (buf[pos+4] << 8) | buf[pos+3];
218*e25b118aSDominic Spill 					printf("%0.2f) ms\n", val * 1.25);
219*e25b118aSDominic Spill 				}
220*e25b118aSDominic Spill 				else {
221*e25b118aSDominic Spill 					printf("Wrong length (%d, should be 4)\n", sublen-1);
222*e25b118aSDominic Spill 				}
223*e25b118aSDominic Spill 				break;
224*e25b118aSDominic Spill 			case 0x16:
225*e25b118aSDominic Spill 				printf(" (Service Data)\n");
226*e25b118aSDominic Spill 				printf("           ");
227*e25b118aSDominic Spill 				if (sublen-1 >= 2) {
228*e25b118aSDominic Spill 					val = (buf[pos+2] << 8) | buf[pos+1];
229*e25b118aSDominic Spill 					printf("UUID: %02x", val);
230*e25b118aSDominic Spill 					if (sublen-1 > 2) {
231*e25b118aSDominic Spill 						printf(", Additional:");
232*e25b118aSDominic Spill 						for (i = 3; i < sublen; ++i)
233*e25b118aSDominic Spill 							printf(" %02x", buf[pos+i]);
234*e25b118aSDominic Spill 					}
235*e25b118aSDominic Spill 					printf("\n");
236*e25b118aSDominic Spill 				}
237*e25b118aSDominic Spill 				else {
238*e25b118aSDominic Spill 					printf("Wrong length (%d, should be >= 2)\n", sublen-1);
239*e25b118aSDominic Spill 				}
240*e25b118aSDominic Spill 				break;
241*e25b118aSDominic Spill 			default:
242*e25b118aSDominic Spill 				printf("\n");
243*e25b118aSDominic Spill 				printf("           ");
244*e25b118aSDominic Spill 				for (i = 1; i < sublen; ++i)
245*e25b118aSDominic Spill 					printf(" %02x", buf[pos+i]);
246*e25b118aSDominic Spill 				printf("\n");
247*e25b118aSDominic Spill 		}
248*e25b118aSDominic Spill 		pos += sublen;
249*e25b118aSDominic Spill 	}
250*e25b118aSDominic Spill }
251*e25b118aSDominic Spill 
252*e25b118aSDominic Spill void le_print(le_packet_t *p) {
253*e25b118aSDominic Spill 	int i;
254*e25b118aSDominic Spill 	if (le_packet_is_data(p)) {
255*e25b118aSDominic Spill 		int llid = p->symbols[4] & 0x3;
256*e25b118aSDominic Spill 		static const char *llid_str[] = {
257*e25b118aSDominic Spill 			"Reserved",
258*e25b118aSDominic Spill 			"LL Data PDU / empty or L2CAP continuation",
259*e25b118aSDominic Spill 			"LL Data PDU / L2CAP start",
260*e25b118aSDominic Spill 			"LL Control PDU",
261*e25b118aSDominic Spill 		};
262*e25b118aSDominic Spill 
263*e25b118aSDominic Spill 		printf("Data / AA %08x / %2d bytes\n", p->access_address, p->length);
264*e25b118aSDominic Spill 		printf("    Channel Index: %d\n", p->channel_idx);
265*e25b118aSDominic Spill 		printf("    LLID: %d / %s\n", llid, llid_str[llid]);
266*e25b118aSDominic Spill 		printf("    NESN: %d  SN: %d  MD: %d\n", (p->symbols[4] >> 2) & 1,
267*e25b118aSDominic Spill 												 (p->symbols[4] >> 3) & 1,
268*e25b118aSDominic Spill 												 (p->symbols[4] >> 4) & 1);
269*e25b118aSDominic Spill 	} else {
270*e25b118aSDominic Spill 		printf("Advertising / AA %08x / %2d bytes\n", p->access_address, p->length);
271*e25b118aSDominic Spill 		printf("    Channel Index: %d\n", p->channel_idx);
272*e25b118aSDominic Spill 		printf("    Type:  %s\n", le_adv_type(p));
273*e25b118aSDominic Spill 
274*e25b118aSDominic Spill 		switch(p->adv_type) {
275*e25b118aSDominic Spill 			case ADV_IND:
276*e25b118aSDominic Spill 				_dump_addr("AdvA:  ", p->symbols, 6, p->adv_tx_add);
277*e25b118aSDominic Spill 				if (p->length-6 > 0) {
278*e25b118aSDominic Spill 					printf("    AdvData:");
279*e25b118aSDominic Spill 					for (i = 0; i < p->length - 6; ++i)
280*e25b118aSDominic Spill 						printf(" %02x", p->symbols[12+i]);
281*e25b118aSDominic Spill 					printf("\n");
282*e25b118aSDominic Spill 					_dump_scan_rsp_data(&p->symbols[12], p->length-6);
283*e25b118aSDominic Spill 				}
284*e25b118aSDominic Spill 				break;
285*e25b118aSDominic Spill 			case SCAN_REQ:
286*e25b118aSDominic Spill 				_dump_addr("ScanA: ", p->symbols, 6, p->adv_tx_add);
287*e25b118aSDominic Spill 				_dump_addr("AdvA:  ", p->symbols, 12, p->adv_rx_add);
288*e25b118aSDominic Spill 				break;
289*e25b118aSDominic Spill 			case SCAN_RSP:
290*e25b118aSDominic Spill 				_dump_addr("AdvA:  ", p->symbols, 6, p->adv_tx_add);
291*e25b118aSDominic Spill 				printf("    ScanRspData:");
292*e25b118aSDominic Spill 				for (i = 0; i < p->length - 6; ++i)
293*e25b118aSDominic Spill 					printf(" %02x", p->symbols[12+i]);
294*e25b118aSDominic Spill 				printf("\n");
295*e25b118aSDominic Spill 				_dump_scan_rsp_data(&p->symbols[12], p->length-6);
296*e25b118aSDominic Spill 				break;
297*e25b118aSDominic Spill 			case CONNECT_REQ:
298*e25b118aSDominic Spill 				_dump_addr("InitA: ", p->symbols, 6, p->adv_tx_add);
299*e25b118aSDominic Spill 				_dump_addr("AdvA:  ", p->symbols, 12, p->adv_rx_add);
300*e25b118aSDominic Spill 				_dump_32("AA:    ", p->symbols, 18);
301*e25b118aSDominic Spill 				_dump_24("CRCInit: ", p->symbols, 22);
302*e25b118aSDominic Spill 				_dump_8("WinSize: ", p->symbols, 25);
303*e25b118aSDominic Spill 				_dump_16("WinOffset: ", p->symbols, 26);
304*e25b118aSDominic Spill 				_dump_16("Interval: ", p->symbols, 28);
305*e25b118aSDominic Spill 				_dump_16("Latency: ", p->symbols, 30);
306*e25b118aSDominic Spill 				_dump_16("Timeout: ", p->symbols, 32);
307*e25b118aSDominic Spill 
308*e25b118aSDominic Spill 				printf("    ChM:");
309*e25b118aSDominic Spill 				for (i = 0; i < 5; ++i)
310*e25b118aSDominic Spill 					printf(" %02x", p->symbols[34+i]);
311*e25b118aSDominic Spill 				printf("\n");
312*e25b118aSDominic Spill 
313*e25b118aSDominic Spill 				printf("    Hop: %d\n", p->symbols[37] & 0x1f);
314*e25b118aSDominic Spill 				printf("    SCA: %d, %s\n",
315*e25b118aSDominic Spill 						p->symbols[37] >> 5,
316*e25b118aSDominic Spill 						CONNECT_SCA[p->symbols[37] >> 5]);
317*e25b118aSDominic Spill 				break;
318*e25b118aSDominic Spill 		}
319*e25b118aSDominic Spill 	}
320*e25b118aSDominic Spill 
321*e25b118aSDominic Spill 	printf("\n");
322*e25b118aSDominic Spill 	printf("    Data: ");
323*e25b118aSDominic Spill 	for (i = 6; i < 6 + p->length; ++i)
324*e25b118aSDominic Spill 		printf(" %02x", p->symbols[i]);
325*e25b118aSDominic Spill 	printf("\n");
326*e25b118aSDominic Spill 
327*e25b118aSDominic Spill 	printf("    CRC:  ");
328*e25b118aSDominic Spill 	for (i = 0; i < 3; ++i)
329*e25b118aSDominic Spill 		printf(" %02x", p->symbols[6 + p->length + i]);
330*e25b118aSDominic Spill 	printf("\n");
331*e25b118aSDominic Spill }
332