1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2004-2011  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <stdio.h>
29#include <errno.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include <sys/types.h>
35#include <netinet/in.h>
36
37#include "parser.h"
38
39static char *opcode2str(uint8_t opcode)
40{
41	switch (opcode & 0x7f) {
42	case 0x00:
43		return "Connect";
44	case 0x01:
45		return "Disconnect";
46	case 0x02:
47		return "Put";
48	case 0x03:
49		return "Get";
50	case 0x04:
51		return "Reserved";
52	case 0x05:
53		return "SetPath";
54	case 0x06:
55		return "Reserved";
56	case 0x07:
57		return "Session";
58	case 0x7f:
59		return "Abort";
60	case 0x10:
61		return "Continue";
62	case 0x20:
63		return "Success";
64	case 0x21:
65		return "Created";
66	case 0x22:
67		return "Accepted";
68	case 0x23:
69		return "Non-authoritative information";
70	case 0x24:
71		return "No content";
72	case 0x25:
73		return "Reset content";
74	case 0x26:
75		return "Partial content";
76	case 0x30:
77		return "Multiple choices";
78	case 0x31:
79		return "Moved permanently";
80	case 0x32:
81		return "Moved temporarily";
82	case 0x33:
83		return "See other";
84	case 0x34:
85		return "Not modified";
86	case 0x35:
87		return "Use Proxy";
88	case 0x40:
89		return "Bad request";
90	case 0x41:
91		return "Unauthorized";
92	case 0x42:
93		return "Payment required";
94	case 0x43:
95		return "Forbidden";
96	case 0x44:
97		return "Not found";
98	case 0x45:
99		return "Method not allowed";
100	case 0x46:
101		return "Not acceptable";
102	case 0x47:
103		return "Proxy authentication required";
104	case 0x48:
105		return "Request timeout";
106	case 0x49:
107		return "Conflict";
108	case 0x4a:
109		return "Gone";
110	case 0x4b:
111		return "Length required";
112	case 0x4c:
113		return "Precondition failed";
114	case 0x4d:
115		return "Requested entity too large";
116	case 0x4e:
117		return "Requested URL too large";
118	case 0x4f:
119		return "Unsupported media type";
120	case 0x50:
121		return "Internal server error";
122	case 0x51:
123		return "Not implemented";
124	case 0x52:
125		return "Bad gateway";
126	case 0x53:
127		return "Service unavailable";
128	case 0x54:
129		return "Gateway timeout";
130	case 0x55:
131		return "HTTP version not supported";
132	case 0x60:
133		return "Database full";
134	case 0x61:
135		return "Database locked";
136	default:
137		return "Unknown";
138	}
139}
140
141static char *hi2str(uint8_t hi)
142{
143	switch (hi & 0x3f) {
144	case 0x00:
145		return "Count";
146	case 0x01:
147		return "Name";
148	case 0x02:
149		return "Type";
150	case 0x03:
151		return "Length";
152	case 0x04:
153		return "Time";
154	case 0x05:
155		return "Description";
156	case 0x06:
157		return "Target";
158	case 0x07:
159		return "HTTP";
160	case 0x08:
161		return "Body";
162	case 0x09:
163		return "End of Body";
164	case 0x0a:
165		return "Who";
166	case 0x0b:
167		return "Connection ID";
168	case 0x0c:
169		return "App. Parameters";
170	case 0x0d:
171		return "Auth. Challenge";
172	case 0x0e:
173		return "Auth. Response";
174	case 0x0f:
175		return "Creator ID";
176	case 0x10:
177		return "WAN UUID";
178	case 0x11:
179		return "Object Class";
180	case 0x12:
181		return "Session Parameters";
182	case 0x13:
183		return "Session Sequence Number";
184	default:
185		return "Unknown";
186	}
187}
188
189static void parse_headers(int level, struct frame *frm)
190{
191	uint8_t hi, hv8;
192	uint16_t len;
193	uint32_t hv32;
194
195	while (frm->len > 0) {
196		hi = get_u8(frm);
197
198		p_indent(level, frm);
199
200		printf("%s (0x%02x)", hi2str(hi), hi);
201		switch (hi & 0xc0) {
202		case 0x00:	/* Unicode */
203			if (frm->len < 2) {
204				printf("\n");
205				return;
206			}
207
208			len = get_u16(frm) - 3;
209			printf(" = Unicode length %d\n", len);
210
211			if (frm->len < len)
212				return;
213
214			raw_ndump(level, frm, len);
215			frm->ptr += len;
216			frm->len -= len;
217			break;
218
219		case 0x40:	/* Byte sequence */
220			if (frm->len < 2) {
221				printf("\n");
222				return;
223			}
224
225			len = get_u16(frm) - 3;
226			printf(" = Sequence length %d\n", len);
227
228			if (frm->len < len)
229				return;
230
231			raw_ndump(level, frm, len);
232			frm->ptr += len;
233			frm->len -= len;
234			break;
235
236		case 0x80:	/* One byte */
237			if (frm->len < 1) {
238				printf("\n");
239				return;
240			}
241
242			hv8 = get_u8(frm);
243			printf(" = %d\n", hv8);
244			break;
245
246		case 0xc0:	/* Four bytes */
247			if (frm->len < 4) {
248				printf("\n");
249				return;
250			}
251
252			hv32 = get_u32(frm);
253			printf(" = %u\n", hv32);
254			break;
255		}
256	}
257}
258
259void obex_dump(int level, struct frame *frm)
260{
261	uint8_t last_opcode, opcode, status;
262	uint8_t version, flags, constants;
263	uint16_t length, pktlen;
264
265	frm = add_frame(frm);
266
267	while (frm->len > 2) {
268		opcode = get_u8(frm);
269		length = get_u16(frm);
270		status = opcode & 0x7f;
271
272		if ((int) frm->len < length - 3) {
273			frm->ptr -= 3;
274			frm->len += 3;
275			return;
276		}
277
278		p_indent(level, frm);
279
280		last_opcode = get_opcode(frm->handle, frm->dlci);
281
282		if (!(opcode & 0x70)) {
283			printf("OBEX: %s cmd(%c): len %d",
284					opcode2str(opcode),
285					opcode & 0x80 ? 'f' : 'c', length);
286			set_opcode(frm->handle, frm->dlci, opcode);
287		} else {
288			printf("OBEX: %s rsp(%c): status %x%02d len %d",
289					opcode2str(last_opcode),
290					opcode & 0x80 ? 'f' : 'c',
291					status >> 4, status & 0xf, length);
292			opcode = last_opcode;
293		}
294
295		if (get_status(frm->handle, frm->dlci) == 0x10)
296			printf(" (continue)");
297
298		set_status(frm->handle, frm->dlci, status);
299
300		if (frm->len == 0) {
301			printf("\n");
302			break;
303		}
304
305		switch (opcode & 0x7f) {
306		case 0x00:	/* Connect */
307			if (frm->len < 4) {
308				printf("\n");
309				return;
310			}
311
312			version = get_u8(frm);
313			flags   = get_u8(frm);
314			pktlen  = get_u16(frm);
315			printf(" version %d.%d flags %d mtu %d\n",
316				version >> 4, version & 0xf, flags, pktlen);
317			break;
318
319		case 0x05:	/* SetPath */
320			if (frm->len < 2) {
321				printf("\n");
322				return;
323			}
324
325			flags     = get_u8(frm);
326			constants = get_u8(frm);
327			printf(" flags %d constants %d\n", flags, constants);
328			break;
329
330		default:
331			printf("\n");
332			break;
333		}
334
335		if ((status & 0x70) && (parser.flags & DUMP_VERBOSE)) {
336			p_indent(level, frm);
337			printf("Status %x%02d = %s\n",
338					status >> 4, status & 0xf,
339							opcode2str(status));
340		}
341
342		parse_headers(level, frm);
343	}
344}
345