csr.c revision e435ed5cf8b7c352b607cb8601a2eefdb7bfc17d
1/*
2 *
3 *  Bluetooth packet analyzer - CSR parser
4 *
5 *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 *
22 *
23 *  $Id$
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <errno.h>
30#include <string.h>
31
32#include <sys/types.h>
33#include <netinet/in.h>
34
35#include "parser.h"
36
37#define CSR_U8(frm)  (get_u8(frm))
38#define CSR_U16(frm) (btohs(htons(get_u16(frm))))
39#define CSR_U32(frm) (btohl(htonl(get_u32(frm))))
40
41static char *type2str(uint16_t type)
42{
43	switch (type) {
44	case 0x0000:
45		return "Get req";
46	case 0x0001:
47		return "Get rsp";
48	case 0x0002:
49		return "Set req";
50	default:
51		return "Reserved";
52	}
53}
54
55static inline void uint16_dump(int level, char *str, struct frame *frm)
56{
57	uint16_t value;
58
59	value = CSR_U16(frm);
60
61	p_indent(level, frm);
62	printf("%s: value %d (0x%4.4x)\n", str, value, value);
63}
64
65static inline void uint32_dump(int level, char *str, struct frame *frm)
66{
67	uint32_t value;
68
69	value = CSR_U32(frm);
70
71	p_indent(level, frm);
72	printf("%s: value %d (0x%4.4x)\n", str, value, value);
73}
74
75static inline void bdaddr_dump(int level, char *str, struct frame *frm)
76{
77	char addr[18];
78
79	ba2str(frm->ptr, addr);
80
81	p_indent(level, frm);
82	printf("%s: bdaddr %s\n", str, addr);
83}
84
85static inline void features_dump(int level, char *str, struct frame *frm)
86{
87	unsigned char features[8];
88	int i;
89
90	memcpy(features, frm->ptr, 8);
91
92	p_indent(level, frm);
93	printf("%s: features", str);
94	for (i = 0; i < 8; i++)
95		printf(" 0x%02x", features[i]);
96	printf("\n");
97}
98
99static inline void handle_length_dump(int level, char *str, struct frame *frm)
100{
101	uint16_t handle, length;
102
103	handle = CSR_U16(frm);
104	length = CSR_U16(frm);
105
106	p_indent(level, frm);
107	printf("%s: handle %d length %d\n", str, handle, length);
108}
109
110static inline void pskey_dump(int level, struct frame *frm)
111{
112	uint16_t key, length, stores;
113
114	key    = CSR_U16(frm);
115	length = CSR_U16(frm);
116	stores = CSR_U16(frm);
117
118	p_indent(level, frm);
119	printf("PSKEY: key 0x%4.4x len %d stores %d\n", key, length, stores);
120
121	switch (key) {
122	case 0x0001:
123		bdaddr_dump(level + 1, "BDADDR", frm);
124		break;
125	case 0x00da:
126		uint16_dump(level + 1, "ENC_KEY_LMIN", frm);
127		break;
128	case 0x00db:
129		uint16_dump(level + 1, "ENC_KEY_LMAX", frm);
130		break;
131	case 0x00ef:
132		features_dump(level + 1, "LOCAL_SUPPORTED_FEATURES", frm);
133		break;
134	case 0x010d:
135		uint16_dump(level + 1, "HCI_LMP_LOCAL_VERSION", frm);
136		break;
137	case 0x010e:
138		uint16_dump(level + 1, "LMP_REMOTE_VERSION", frm);
139		break;
140	case 0x01ab:
141		uint16_dump(level + 1, "HOSTIO_MAP_SCO_PCM", frm);
142		break;
143	case 0x01be:
144		uint16_dump(level + 1, "UART_BAUDRATE", frm);
145		break;
146	case 0x01f9:
147		uint16_dump(level + 1, "HOST_INTERFACE", frm);
148		break;
149	case 0x02be:
150		uint16_dump(level + 1, "USB_VENDOR_ID", frm);
151		break;
152	case 0x02bf:
153		uint16_dump(level + 1, "USB_PRODUCT_ID", frm);
154		break;
155	case 0x02cb:
156		uint16_dump(level + 1, "USB_DFU_PRODUCT_ID", frm);
157		break;
158	case 0x03cd:
159		uint16_dump(level + 1, "INITIAL_BOOTMODE", frm);
160		break;
161	default:
162		raw_dump(level + 1, frm);
163		break;
164	}
165}
166
167static inline void bccmd_dump(int level, struct frame *frm)
168{
169	uint16_t type, length, seqno, varid, status;
170
171	type   = CSR_U16(frm);
172	length = CSR_U16(frm);
173	seqno  = CSR_U16(frm);
174	varid  = CSR_U16(frm);
175	status = CSR_U16(frm);
176
177	p_indent(level, frm);
178	printf("BCCMD: %s: len %d seqno %d varid 0x%4.4x status %d\n",
179			type2str(type), length, seqno, varid, status);
180
181	if (!(parser.flags & DUMP_VERBOSE)) {
182		raw_dump(level + 1, frm);
183		return;
184	}
185
186	switch (varid) {
187	case 0x2819:
188		uint16_dump(level + 1, "BUILDID", frm);
189		break;
190	case 0x281a:
191		uint16_dump(level + 1, "CHIPVER", frm);
192		break;
193	case 0x281b:
194		uint16_dump(level + 1, "CHIPREV", frm);
195		break;
196	case 0x2825:
197		uint16_dump(level + 1, "INTERFACE_VERSION", frm);
198		break;
199	case 0x282a:
200		uint16_dump(level + 1, "RAND", frm);
201		break;
202	case 0x282c:
203		uint16_dump(level + 1, "MAX_CRYPT_KEY_LENGTH", frm);
204		break;
205	case 0x2836:
206		uint16_dump(level + 1, "CHIPANAREV", frm);
207		break;
208	case 0x2838:
209		uint16_dump(level + 1, "BUILDID_LOADER", frm);
210		break;
211	case 0x2c00:
212		uint32_dump(level + 1, "BT_CLOCK", frm);
213		break;
214	case 0x3008:
215		handle_length_dump(level + 1, "CRYPT_KEY_LENGTH", frm);
216		break;
217	case 0x481c:
218		uint16_dump(level + 1, "MAP_SCO_PCM", frm);
219		break;
220	case 0x6802:
221		uint16_dump(level + 1, "CONFIG_UART", frm);
222		break;
223	case 0x6805:
224		uint16_dump(level + 1, "PANIC_ARG", frm);
225		break;
226	case 0x6806:
227		uint16_dump(level + 1, "FAULT_ARG", frm);
228		break;
229	case 0x7003:
230		pskey_dump(level + 1, frm);
231		break;
232	default:
233		raw_dump(level + 1, frm);
234		break;
235	}
236}
237
238static char *cid2str(uint8_t cid)
239{
240	switch (cid & 0x3f) {
241	case 0:
242		return "BCSP Internal";
243	case 1:
244		return "BCSP Link";
245	case 2:
246		return "BCCMD";
247	case 3:
248		return "HQ";
249	case 4:
250		return "Device Mgt";
251	case 5:
252		return "HCI Cmd/Evt";
253	case 6:
254		return "HCI ACL";
255	case 7:
256		return "HCI SCO";
257	case 8:
258		return "L2CAP";
259	case 9:
260		return "RFCOMM";
261	case 10:
262		return "SDP";
263	case 11:
264		return "Debug";
265	case 12:
266		return "DFU";
267	case 13:
268		return "VM";
269	case 14:
270		return "Unused";
271	case 15:
272		return "Reserved";
273	default:
274		return "Unknown";
275	}
276}
277
278static char *frag2str(uint8_t frag)
279{
280	switch (frag & 0xc0) {
281	case 0x00:
282		return " middle fragment";
283	case 0x40:
284		return " first fragment";
285	case 0x80:
286		return " last fragment";
287	default:
288		return "";
289	}
290}
291
292void csr_dump(int level, struct frame *frm)
293{
294	uint8_t desc, cid, type;
295	uint16_t handle, master, addr;
296
297	desc = CSR_U8(frm);
298
299	cid = desc & 0x3f;
300
301	switch (cid) {
302	case 2:
303		bccmd_dump(level, frm);
304		break;
305
306	case 20:
307		type = CSR_U8(frm);
308
309		if (!p_filter(FILT_LMP)) {
310			switch (type) {
311			case 0x0f:
312				frm->handle =  ((uint8_t *) frm->ptr)[17];
313				frm->master = 0;
314				frm->len--;
315				lmp_dump(level, frm);
316				return;
317			case 0x10:
318				frm->handle = ((uint8_t *) frm->ptr)[17];
319				frm->master = 1;
320				frm->len--;
321				lmp_dump(level, frm);
322				return;
323			case 0x12:
324				handle = CSR_U16(frm);
325				master = CSR_U16(frm);
326				addr = CSR_U16(frm);
327				p_indent(level, frm);
328				printf("FHS: handle %d addr %d (%s)\n", handle,
329					addr, master ? "master" : "slave");
330				if (!master)
331					raw_dump(level, frm);
332				return;
333			case 0x7b:
334				p_indent(level, frm);
335				printf("LMP(r): duplicate (same SEQN)\n");
336				return;
337			}
338		}
339
340		p_indent(level, frm);
341		printf("CSR: Debug (type 0x%2.2x)\n", type);
342		raw_dump(level, frm);
343		break;
344
345	default:
346		p_indent(level, frm);
347		printf("CSR: %s (channel %d)%s\n", cid2str(cid), cid, frag2str(desc));
348		raw_dump(level, frm);
349		break;
350	}
351}
352