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
opcode2str(uint8_t opcode)39 static 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
hi2str(uint8_t hi)141 static 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
parse_headers(int level,struct frame * frm)189 static 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
obex_dump(int level,struct frame * frm)259 void 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