Home | History | Annotate | Download | only in parser
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2004-2011  Marcel Holtmann <marcel (at) 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 
     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 
    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 
    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 
    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