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