Home | History | Annotate | Download | only in parser
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2001-2002  Ricky Yuen <ryuen (at) qualcomm.com>
      6  *  Copyright (C) 2003-2007  Marcel Holtmann <marcel (at) holtmann.org>
      7  *
      8  *
      9  *  This program is free software; you can redistribute it and/or modify
     10  *  it under the terms of the GNU General Public License as published by
     11  *  the Free Software Foundation; either version 2 of the License, or
     12  *  (at your option) any later version.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <stdio.h>
     30 #include <errno.h>
     31 #include <ctype.h>
     32 #include <unistd.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 
     36 #include <sys/types.h>
     37 #include <netinet/in.h>
     38 
     39 #include "parser.h"
     40 #include "sdp.h"
     41 
     42 #define SDP_ERROR_RSP                                  0x01
     43 #define SDP_SERVICE_SEARCH_REQ                         0x02
     44 #define SDP_SERVICE_SEARCH_RSP                         0x03
     45 #define SDP_SERVICE_ATTR_REQ                           0x04
     46 #define SDP_SERVICE_ATTR_RSP                           0x05
     47 #define SDP_SERVICE_SEARCH_ATTR_REQ                    0x06
     48 #define SDP_SERVICE_SEARCH_ATTR_RSP                    0x07
     49 
     50 typedef struct {
     51 	uint8_t  pid;
     52 	uint16_t tid;
     53 	uint16_t len;
     54 } __attribute__ ((packed)) sdp_pdu_hdr;
     55 #define SDP_PDU_HDR_SIZE 5
     56 
     57 /* Data element type descriptor */
     58 #define SDP_DE_NULL   0
     59 #define SDP_DE_UINT   1
     60 #define SDP_DE_INT    2
     61 #define SDP_DE_UUID   3
     62 #define SDP_DE_STRING 4
     63 #define SDP_DE_BOOL   5
     64 #define SDP_DE_SEQ    6
     65 #define SDP_DE_ALT    7
     66 #define SDP_DE_URL    8
     67 
     68 /* Data element size index lookup table */
     69 typedef struct {
     70 	int addl_bits;
     71 	int num_bytes;
     72 } sdp_siz_idx_lookup_table_t;
     73 
     74 static sdp_siz_idx_lookup_table_t sdp_siz_idx_lookup_table[] = {
     75 	{ 0, 1  }, /* Size index = 0 */
     76 	{ 0, 2  }, /*              1 */
     77 	{ 0, 4  }, /*              2 */
     78 	{ 0, 8  }, /*              3 */
     79 	{ 0, 16 }, /*              4 */
     80 	{ 1, 1  }, /*              5 */
     81 	{ 1, 2  }, /*              6 */
     82 	{ 1, 4  }, /*              7 */
     83 };
     84 
     85 /* UUID name lookup table */
     86 typedef struct {
     87 	int   uuid;
     88 	char* name;
     89 } sdp_uuid_nam_lookup_table_t;
     90 
     91 static sdp_uuid_nam_lookup_table_t sdp_uuid_nam_lookup_table[] = {
     92 	{ SDP_UUID_SDP,                      "SDP"          },
     93 	{ SDP_UUID_UDP,                      "UDP"          },
     94 	{ SDP_UUID_RFCOMM,                   "RFCOMM"       },
     95 	{ SDP_UUID_TCP,                      "TCP"          },
     96 	{ SDP_UUID_TCS_BIN,                  "TCS-BIN"      },
     97 	{ SDP_UUID_TCS_AT,                   "TCS-AT"       },
     98 	{ SDP_UUID_OBEX,                     "OBEX"         },
     99 	{ SDP_UUID_IP,                       "IP"           },
    100 	{ SDP_UUID_FTP,                      "FTP"          },
    101 	{ SDP_UUID_HTTP,                     "HTTP"         },
    102 	{ SDP_UUID_WSP,                      "WSP"          },
    103 	{ SDP_UUID_L2CAP,                    "L2CAP"        },
    104 	{ SDP_UUID_BNEP,                     "BNEP"         }, /* PAN */
    105 	{ SDP_UUID_HIDP,                     "HIDP"         }, /* HID */
    106 	{ SDP_UUID_AVCTP,                    "AVCTP"        }, /* AVCTP */
    107 	{ SDP_UUID_AVDTP,                    "AVDTP"        }, /* AVDTP */
    108 	{ SDP_UUID_CMTP,                     "CMTP"         }, /* CIP */
    109 	{ SDP_UUID_UDI_C_PLANE,              "UDI_C-Plane"  }, /* UDI */
    110 	{ SDP_UUID_SERVICE_DISCOVERY_SERVER, "SDServer"     },
    111 	{ SDP_UUID_BROWSE_GROUP_DESCRIPTOR,  "BrwsGrpDesc"  },
    112 	{ SDP_UUID_PUBLIC_BROWSE_GROUP,      "PubBrwsGrp"   },
    113 	{ SDP_UUID_SERIAL_PORT,              "SP"           },
    114 	{ SDP_UUID_LAN_ACCESS_PPP,           "LAN"          },
    115 	{ SDP_UUID_DIALUP_NETWORKING,        "DUN"          },
    116 	{ SDP_UUID_IR_MC_SYNC,               "IRMCSync"     },
    117 	{ SDP_UUID_OBEX_OBJECT_PUSH,         "OBEXObjPush"  },
    118 	{ SDP_UUID_OBEX_FILE_TRANSFER,       "OBEXObjTrnsf" },
    119 	{ SDP_UUID_IR_MC_SYNC_COMMAND,       "IRMCSyncCmd"  },
    120 	{ SDP_UUID_HEADSET,                  "Headset"      },
    121 	{ SDP_UUID_CORDLESS_TELEPHONY,       "CordlessTel"  },
    122 	{ SDP_UUID_AUDIO_SOURCE,             "AudioSource"  }, /* A2DP */
    123 	{ SDP_UUID_AUDIO_SINK,               "AudioSink"    }, /* A2DP */
    124 	{ SDP_UUID_AV_REMOTE_TARGET,         "AVRemTarget"  }, /* AVRCP */
    125 	{ SDP_UUID_ADVANCED_AUDIO,           "AdvAudio"     }, /* A2DP */
    126 	{ SDP_UUID_AV_REMOTE,                "AVRemote"     }, /* AVRCP */
    127 	{ SDP_UUID_VIDEO_CONFERENCING,       "VideoConf"    }, /* VCP */
    128 	{ SDP_UUID_INTERCOM,                 "Intercom"     },
    129 	{ SDP_UUID_FAX,                      "Fax"          },
    130 	{ SDP_UUID_HEADSET_AUDIO_GATEWAY,    "Headset AG"   },
    131 	{ SDP_UUID_WAP,                      "WAP"          },
    132 	{ SDP_UUID_WAP_CLIENT,               "WAP Client"   },
    133 	{ SDP_UUID_PANU,                     "PANU"         }, /* PAN */
    134 	{ SDP_UUID_NAP,                      "NAP"          }, /* PAN */
    135 	{ SDP_UUID_GN,                       "GN"           }, /* PAN */
    136 	{ SDP_UUID_DIRECT_PRINTING,          "DirectPrint"  }, /* BPP */
    137 	{ SDP_UUID_REFERENCE_PRINTING,       "RefPrint"     }, /* BPP */
    138 	{ SDP_UUID_IMAGING,                  "Imaging"      }, /* BIP */
    139 	{ SDP_UUID_IMAGING_RESPONDER,        "ImagingResp"  }, /* BIP */
    140 	{ SDP_UUID_HANDSFREE,                "Handsfree"    },
    141 	{ SDP_UUID_HANDSFREE_AUDIO_GATEWAY,  "Handsfree AG" },
    142 	{ SDP_UUID_DIRECT_PRINTING_REF_OBJS, "RefObjsPrint" }, /* BPP */
    143 	{ SDP_UUID_REFLECTED_UI,             "ReflectedUI"  }, /* BPP */
    144 	{ SDP_UUID_BASIC_PRINTING,           "BasicPrint"   }, /* BPP */
    145 	{ SDP_UUID_PRINTING_STATUS,          "PrintStatus"  }, /* BPP */
    146 	{ SDP_UUID_HUMAN_INTERFACE_DEVICE,   "HID"          }, /* HID */
    147 	{ SDP_UUID_HARDCOPY_CABLE_REPLACE,   "HCRP"         }, /* HCRP */
    148 	{ SDP_UUID_HCR_PRINT,                "HCRPrint"     }, /* HCRP */
    149 	{ SDP_UUID_HCR_SCAN,                 "HCRScan"      }, /* HCRP */
    150 	{ SDP_UUID_COMMON_ISDN_ACCESS,       "CIP"          }, /* CIP */
    151 	{ SDP_UUID_VIDEO_CONFERENCING_GW,    "VideoConf GW" }, /* VCP */
    152 	{ SDP_UUID_UDI_MT,                   "UDI MT"       }, /* UDI */
    153 	{ SDP_UUID_UDI_TA,                   "UDI TA"       }, /* UDI */
    154 	{ SDP_UUID_AUDIO_VIDEO,              "AudioVideo"   }, /* VCP */
    155 	{ SDP_UUID_SIM_ACCESS,               "SAP"          }, /* SAP */
    156 	{ SDP_UUID_PHONEBOOK_ACCESS_PCE,     "PBAP PCE"     }, /* PBAP */
    157 	{ SDP_UUID_PHONEBOOK_ACCESS_PSE,     "PBAP PSE"     }, /* PBAP */
    158 	{ SDP_UUID_PHONEBOOK_ACCESS,         "PBAP"         }, /* PBAP */
    159 	{ SDP_UUID_PNP_INFORMATION,          "PNPInfo"      },
    160 	{ SDP_UUID_GENERIC_NETWORKING,       "Networking"   },
    161 	{ SDP_UUID_GENERIC_FILE_TRANSFER,    "FileTrnsf"    },
    162 	{ SDP_UUID_GENERIC_AUDIO,            "Audio"        },
    163 	{ SDP_UUID_GENERIC_TELEPHONY,        "Telephony"    },
    164 	{ SDP_UUID_UPNP_SERVICE,             "UPNP"         }, /* ESDP */
    165 	{ SDP_UUID_UPNP_IP_SERVICE,          "UPNP IP"      }, /* ESDP */
    166 	{ SDP_UUID_ESDP_UPNP_IP_PAN,         "UPNP PAN"     }, /* ESDP */
    167 	{ SDP_UUID_ESDP_UPNP_IP_LAP,         "UPNP LAP"     }, /* ESDP */
    168 	{ SDP_UUID_ESDP_UPNP_L2CAP,          "UPNP L2CAP"   }, /* ESDP */
    169 	{ SDP_UUID_VIDEO_SOURCE,             "VideoSource"  }, /* VDP */
    170 	{ SDP_UUID_VIDEO_SINK,               "VideoSink"    }, /* VDP */
    171 	{ SDP_UUID_VIDEO_DISTRIBUTION,       "VideoDist"    }, /* VDP */
    172 	{ SDP_UUID_APPLE_AGENT,              "AppleAgent"   },
    173 };
    174 
    175 #define SDP_UUID_NAM_LOOKUP_TABLE_SIZE \
    176 	(sizeof(sdp_uuid_nam_lookup_table)/sizeof(sdp_uuid_nam_lookup_table_t))
    177 
    178 /* AttrID name lookup table */
    179 typedef struct {
    180 	int   attr_id;
    181 	char* name;
    182 } sdp_attr_id_nam_lookup_table_t;
    183 
    184 static sdp_attr_id_nam_lookup_table_t sdp_attr_id_nam_lookup_table[] = {
    185 	{ SDP_ATTR_ID_SERVICE_RECORD_HANDLE,             "SrvRecHndl"         },
    186 	{ SDP_ATTR_ID_SERVICE_CLASS_ID_LIST,             "SrvClassIDList"     },
    187 	{ SDP_ATTR_ID_SERVICE_RECORD_STATE,              "SrvRecState"        },
    188 	{ SDP_ATTR_ID_SERVICE_SERVICE_ID,                "SrvID"              },
    189 	{ SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST,          "ProtocolDescList"   },
    190 	{ SDP_ATTR_ID_BROWSE_GROUP_LIST,                 "BrwGrpList"         },
    191 	{ SDP_ATTR_ID_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,   "LangBaseAttrIDList" },
    192 	{ SDP_ATTR_ID_SERVICE_INFO_TIME_TO_LIVE,         "SrvInfoTimeToLive"  },
    193 	{ SDP_ATTR_ID_SERVICE_AVAILABILITY,              "SrvAvail"           },
    194 	{ SDP_ATTR_ID_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, "BTProfileDescList"  },
    195 	{ SDP_ATTR_ID_DOCUMENTATION_URL,                 "DocURL"             },
    196 	{ SDP_ATTR_ID_CLIENT_EXECUTABLE_URL,             "ClientExeURL"       },
    197 	{ SDP_ATTR_ID_ICON_10,                           "Icon10"             },
    198 	{ SDP_ATTR_ID_ICON_URL,                          "IconURL"            },
    199 	{ SDP_ATTR_ID_SERVICE_NAME,                      "SrvName"            },
    200 	{ SDP_ATTR_ID_SERVICE_DESCRIPTION,               "SrvDesc"            },
    201 	{ SDP_ATTR_ID_PROVIDER_NAME,                     "ProviderName"       },
    202 	{ SDP_ATTR_ID_VERSION_NUMBER_LIST,               "VersionNumList"     },
    203 	{ SDP_ATTR_ID_GROUP_ID,                          "GrpID"              },
    204 	{ SDP_ATTR_ID_SERVICE_DATABASE_STATE,            "SrvDBState"         },
    205 	{ SDP_ATTR_ID_SERVICE_VERSION,                   "SrvVersion"         },
    206 	{ SDP_ATTR_ID_SECURITY_DESCRIPTION,              "SecurityDescription"}, /* PAN */
    207 	{ SDP_ATTR_ID_SUPPORTED_DATA_STORES_LIST,        "SuppDataStoresList" }, /* Synchronization */
    208 	{ SDP_ATTR_ID_SUPPORTED_FORMATS_LIST,            "SuppFormatsList"    }, /* OBEX Object Push */
    209 	{ SDP_ATTR_ID_NET_ACCESS_TYPE,                   "NetAccessType"      }, /* PAN */
    210 	{ SDP_ATTR_ID_MAX_NET_ACCESS_RATE,               "MaxNetAccessRate"   }, /* PAN */
    211 	{ SDP_ATTR_ID_IPV4_SUBNET,                       "IPv4Subnet"         }, /* PAN */
    212 	{ SDP_ATTR_ID_IPV6_SUBNET,                       "IPv6Subnet"         }, /* PAN */
    213 	{ SDP_ATTR_ID_SUPPORTED_CAPABILITIES,            "SuppCapabilities"   }, /* Imaging */
    214 	{ SDP_ATTR_ID_SUPPORTED_FEATURES,                "SuppFeatures"       }, /* Imaging and Hansfree */
    215 	{ SDP_ATTR_ID_SUPPORTED_FUNCTIONS,               "SuppFunctions"      }, /* Imaging */
    216 	{ SDP_ATTR_ID_TOTAL_IMAGING_DATA_CAPACITY,       "SuppTotalCapacity"  }, /* Imaging */
    217 	{ SDP_ATTR_ID_SUPPORTED_REPOSITORIES,            "SuppRepositories"   }, /* PBAP */
    218 };
    219 
    220 #define SDP_ATTR_ID_NAM_LOOKUP_TABLE_SIZE \
    221 	(sizeof(sdp_attr_id_nam_lookup_table)/sizeof(sdp_attr_id_nam_lookup_table_t))
    222 
    223 char* get_uuid_name(int uuid)
    224 {
    225 	int i;
    226 
    227 	for (i = 0; i < SDP_UUID_NAM_LOOKUP_TABLE_SIZE; i++) {
    228 		if (sdp_uuid_nam_lookup_table[i].uuid == uuid)
    229 			return sdp_uuid_nam_lookup_table[i].name;
    230 	}
    231 
    232 	return 0;
    233 }
    234 
    235 static inline char* get_attr_id_name(int attr_id)
    236 {
    237 	int i;
    238 
    239 	for (i = 0; i < SDP_ATTR_ID_NAM_LOOKUP_TABLE_SIZE; i++)
    240 		if (sdp_attr_id_nam_lookup_table[i].attr_id == attr_id)
    241 			return sdp_attr_id_nam_lookup_table[i].name;
    242 	return 0;
    243 }
    244 
    245 static inline uint8_t parse_de_hdr(struct frame *frm, int *n)
    246 {
    247 	uint8_t de_hdr = get_u8(frm);
    248 	uint8_t de_type = de_hdr >> 3;
    249 	uint8_t siz_idx = de_hdr & 0x07;
    250 
    251 	/* Get the number of bytes */
    252 	if (sdp_siz_idx_lookup_table[siz_idx].addl_bits) {
    253 		switch(sdp_siz_idx_lookup_table[siz_idx].num_bytes) {
    254 		case 1:
    255 			*n = get_u8(frm); break;
    256 		case 2:
    257 			*n = get_u16(frm); break;
    258 		case 4:
    259 			*n = get_u32(frm); break;
    260 		case 8:
    261 			*n = get_u64(frm); break;
    262 		}
    263 	} else
    264 		*n = sdp_siz_idx_lookup_table[siz_idx].num_bytes;
    265 
    266 	return de_type;
    267 }
    268 
    269 static inline void print_int(uint8_t de_type, int level, int n, struct frame *frm, uint16_t *psm, uint8_t *channel)
    270 {
    271 	uint64_t val, val2;
    272 
    273 	switch(de_type) {
    274 	case SDP_DE_UINT:
    275 		printf(" uint");
    276 		break;
    277 	case SDP_DE_INT:
    278 		printf(" int");
    279 		break;
    280 	case SDP_DE_BOOL:
    281 		printf(" bool");
    282 		break;
    283 	}
    284 
    285 	switch(n) {
    286 	case 1: /* 8-bit */
    287 		val = get_u8(frm);
    288 		if (channel && de_type == SDP_DE_UINT)
    289 			if (*channel == 0)
    290 				*channel = val;
    291 		break;
    292 	case 2: /* 16-bit */
    293 		val = get_u16(frm);
    294 		if (psm && de_type == SDP_DE_UINT)
    295 			if (*psm == 0)
    296 				*psm = val;
    297 		break;
    298 	case 4: /* 32-bit */
    299 		val = get_u32(frm);
    300 		break;
    301 	case 8: /* 64-bit */
    302 		val = get_u64(frm);
    303 		break;
    304 	case 16:/* 128-bit */
    305 		get_u128(frm, &val, &val2);
    306 		printf(" 0x%jx", val2);
    307 		if (val < 0x1000000000000000LL)
    308 			printf("0");
    309 		printf("%jx", val);
    310 		return;
    311 	default: /* syntax error */
    312 		printf(" err");
    313 		frm->ptr += n;
    314 		frm->len -= n;
    315 		return;
    316 	}
    317 
    318 	printf(" 0x%jx", val);
    319 }
    320 
    321 static inline void print_uuid(int n, struct frame *frm, uint16_t *psm, uint8_t *channel)
    322 {
    323 	uint32_t uuid = 0;
    324 	char* s;
    325 	int i;
    326 
    327 	switch(n) {
    328 	case 2: /* 16-bit UUID */
    329 		uuid = get_u16(frm);
    330 		s = "uuid-16";
    331 		break;
    332 	case 4: /* 32_bit UUID */
    333 		uuid = get_u32(frm);
    334 		s = "uuid-32";
    335 		break;
    336 	case 16: /* 128-bit UUID */
    337 		printf(" uuid-128 ");
    338 		for (i = 0; i < 16; i++) {
    339 			printf("%02x", ((unsigned char *) frm->ptr)[i]);
    340 			if (i == 3 || i == 5 || i == 7 || i == 9)
    341 				printf("-");
    342 		}
    343 		frm->ptr += 16;
    344 		frm->len -= 16;
    345 		return;
    346 	default: /* syntax error */
    347 		printf(" *err*");
    348 		frm->ptr += n;
    349 		frm->len -= n;
    350 		return;
    351 	}
    352 
    353 	if (psm && *psm > 0 && *psm != 0xffff) {
    354 		set_proto(frm->handle, *psm, 0, uuid);
    355 		*psm = 0xffff;
    356 	}
    357 
    358 	if (channel && *channel > 0 && *channel != 0xff) {
    359 		set_proto(frm->handle, *psm, *channel, uuid);
    360 		*channel = 0xff;
    361 	}
    362 
    363 	printf(" %s 0x%04x", s, uuid);
    364 	if ((s = get_uuid_name(uuid)))
    365 		printf(" (%s)", s);
    366 }
    367 
    368 static inline void print_string(int n, struct frame *frm, const char *name)
    369 {
    370 	int i, hex = 0;
    371 
    372 	for (i = 0; i < n; i++) {
    373 		if (i == (n - 1) && ((char *) frm->ptr)[i] == '\0')
    374 			break;
    375 
    376 		if (!isprint(((char *) frm->ptr)[i])) {
    377 			hex = 1;
    378 			break;
    379 		}
    380 	}
    381 
    382 	printf(" %s", name);
    383 	if (hex) {
    384 		for (i = 0; i < n; i++)
    385 			printf(" %02x", ((unsigned char *) frm->ptr)[i]);
    386 	} else {
    387 		printf(" \"");
    388 		for (i = 0; i < n; i++)
    389 			printf("%c", ((char *) frm->ptr)[i]);
    390 		printf("\"");
    391 	}
    392 
    393 	frm->ptr += n;
    394 	frm->len -= n;
    395 }
    396 
    397 static inline void print_de(int, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel);
    398 
    399 static inline void print_des(uint8_t de_type, int level, int n, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel)
    400 {
    401 	int len = frm->len;
    402 	while (len - frm->len < n && frm->len > 0)
    403 		print_de(level, frm, split, psm, channel);
    404 }
    405 
    406 static inline void print_de(int level, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel)
    407 {
    408 	int n = 0;
    409 	uint8_t de_type = parse_de_hdr(frm, &n);
    410 
    411 	switch (de_type) {
    412 	case SDP_DE_NULL:
    413 		printf(" null");
    414 		break;
    415 	case SDP_DE_UINT:
    416 	case SDP_DE_INT:
    417 	case SDP_DE_BOOL:
    418 		print_int(de_type, level, n, frm, psm, channel);
    419 		break;
    420 	case SDP_DE_UUID:
    421 		if (split) {
    422 			/* Split output by uuids.
    423 			 * Used for printing Protocol Desc List */
    424 			if (*split) {
    425 				printf("\n");
    426 				p_indent(level, NULL);
    427 			}
    428 			++*split;
    429 		}
    430 		print_uuid(n, frm, psm, channel);
    431 		break;
    432 	case SDP_DE_URL:
    433 	case SDP_DE_STRING:
    434 		print_string(n, frm, de_type == SDP_DE_URL? "url": "str");
    435 		break;
    436 	case SDP_DE_SEQ:
    437 		printf(" <");
    438 		print_des(de_type, level, n, frm, split, psm, channel);
    439 		printf(" >");
    440 		break;
    441 	case SDP_DE_ALT:
    442 		printf(" [");
    443 		print_des(de_type, level, n, frm, split, psm, channel);
    444 		printf(" ]");
    445 		break;
    446 	}
    447 }
    448 
    449 static inline void print_srv_srch_pat(int level, struct frame *frm)
    450 {
    451 	int len, n1 = 0, n2 = 0;
    452 
    453 	p_indent(level, frm);
    454 	printf("pat");
    455 
    456 	if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
    457 		len = frm->len;
    458 		while (len - frm->len < n1 && frm->len > 0) {
    459 			if (parse_de_hdr(frm, &n2) == SDP_DE_UUID) {
    460 				print_uuid(n2, frm, NULL, NULL);
    461 			} else {
    462 				printf("\nERROR: Unexpected syntax (UUID)\n");
    463 				raw_dump(level, frm);
    464 			}
    465 		}
    466 		printf("\n");
    467 	} else {
    468 		printf("\nERROR: Unexpected syntax (SEQ)\n");
    469 		raw_dump(level, frm);
    470 	}
    471 }
    472 
    473 static inline void print_attr_id_list(int level, struct frame *frm)
    474 {
    475 	uint16_t attr_id;
    476 	uint32_t attr_id_range;
    477 	int len, n1 = 0, n2 = 0;
    478 
    479 	p_indent(level, frm);
    480 	printf("aid(s)");
    481 
    482 	if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
    483 		len = frm->len;
    484 		while (len - frm->len < n1 && frm->len > 0) {
    485 			/* Print AttributeID */
    486 			if (parse_de_hdr(frm, &n2) == SDP_DE_UINT) {
    487 				char *name;
    488 				switch(n2) {
    489 				case 2:
    490 					attr_id = get_u16(frm);
    491 					name = get_attr_id_name(attr_id);
    492 					if (!name)
    493 						name = "unknown";
    494 					printf(" 0x%04x (%s)", attr_id, name);
    495 					break;
    496 				case 4:
    497 					attr_id_range = get_u32(frm);
    498 					printf(" 0x%04x - 0x%04x",
    499 							(attr_id_range >> 16),
    500 							(attr_id_range & 0xFFFF));
    501 					break;
    502 				}
    503 			} else {
    504 				printf("\nERROR: Unexpected syntax\n");
    505 				raw_dump(level, frm);
    506 			}
    507 		}
    508 		printf("\n");
    509 	} else {
    510 		printf("\nERROR: Unexpected syntax\n");
    511 		raw_dump(level, frm);
    512 	}
    513 }
    514 
    515 static inline void print_attr_list(int level, struct frame *frm)
    516 {
    517 	uint16_t attr_id, psm;
    518 	uint8_t channel;
    519 	int len, split, n1 = 0, n2 = 0;
    520 
    521 	if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
    522 		len = frm->len;
    523 		while (len - frm->len < n1 && frm->len > 0) {
    524 			/* Print AttributeID */
    525 			if (parse_de_hdr(frm, &n2) == SDP_DE_UINT && n2 == sizeof(attr_id)) {
    526 				char *name;
    527 				attr_id = get_u16(frm);
    528 				p_indent(level, 0);
    529 				name = get_attr_id_name(attr_id);
    530 				if (!name)
    531 					name = "unknown";
    532 				printf("aid 0x%04x (%s)\n", attr_id, name);
    533 				split = (attr_id != SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST);
    534 				psm = 0;
    535 				channel = 0;
    536 
    537 				/* Print AttributeValue */
    538 				p_indent(level + 1, 0);
    539 				print_de(level + 1, frm, split ? NULL: &split,
    540 					attr_id == SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST ? &psm : NULL,
    541 					attr_id == SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST ? &channel : NULL);
    542 				printf("\n");
    543 			} else {
    544 				printf("\nERROR: Unexpected syntax\n");
    545 				raw_dump(level, frm);
    546 				break;
    547 			}
    548 		}
    549 	} else {
    550 		printf("\nERROR: Unexpected syntax\n");
    551 		raw_dump(level, frm);
    552 	}
    553 }
    554 
    555 static inline void print_attr_lists(int level, struct frame *frm)
    556 {
    557 	int n = 0, cnt = 0;
    558 	int count = frm->len;
    559 
    560 	if (parse_de_hdr(frm, &n) == SDP_DE_SEQ) {
    561 		while (count - frm->len < n && frm->len > 0) {
    562 			p_indent(level, 0);
    563 			printf("record #%d\n", cnt++);
    564 			print_attr_list(level + 2, frm);
    565 		}
    566 	} else {
    567 		printf("\nERROR: Unexpected syntax\n");
    568 		raw_dump(level, frm);
    569 	}
    570 }
    571 
    572 static inline void print_cont_state(int level, unsigned char *buf)
    573 {
    574 	uint8_t cont = buf[0];
    575 	int i;
    576 
    577 	p_indent(level, 0);
    578 	printf("cont");
    579 	for (i = 0; i < cont + 1; i++)
    580 		printf(" %2.2X", buf[i]);
    581 	printf("\n");
    582 }
    583 
    584 static char *pid2str(uint8_t pid)
    585 {
    586 	switch (pid) {
    587 	case SDP_ERROR_RSP:
    588 		return "Error Rsp";
    589 	case SDP_SERVICE_SEARCH_REQ:
    590 		return "SS Req";
    591 	case SDP_SERVICE_SEARCH_RSP:
    592 		return "SS Rsp";
    593 	case SDP_SERVICE_ATTR_REQ:
    594 		return "SA Req";
    595 	case SDP_SERVICE_ATTR_RSP:
    596 		return "SA Rsp";
    597 	case SDP_SERVICE_SEARCH_ATTR_REQ:
    598 		return "SSA Req";
    599 	case SDP_SERVICE_SEARCH_ATTR_RSP:
    600 		return "SSA Rsp";
    601 	default:
    602 		return "Unknown";
    603 	}
    604 }
    605 
    606 #define FRAME_TABLE_SIZE 10
    607 
    608 static struct frame frame_table[FRAME_TABLE_SIZE];
    609 
    610 static int frame_add(struct frame *frm, int count)
    611 {
    612 	register struct frame *fr;
    613 	register unsigned char *data;
    614 	register int i, len = 0, pos = -1;
    615 
    616 	for (i = 0; i < FRAME_TABLE_SIZE; i++) {
    617 		if (frame_table[i].handle == frm->handle &&
    618 				frame_table[i].cid == frm->cid) {
    619 			pos = i;
    620 			len = frame_table[i].data_len;
    621 			break;
    622 		}
    623 		if (pos < 0 && !frame_table[i].handle)
    624 			pos = i;
    625 	}
    626 
    627 	if (pos < 0 || count <= 0)
    628 		return -EIO;
    629 
    630 	data = malloc(len + count);
    631 	if (!data)
    632 		return -ENOMEM;
    633 
    634 	fr = &frame_table[pos];
    635 
    636 	if (len > 0) {
    637 		memcpy(data, fr->data, len);
    638 		memcpy(data + len, frm->ptr, count);
    639 	} else
    640 		memcpy(data, frm->ptr, count);
    641 
    642 	if (fr->data)
    643 		free(fr->data);
    644 
    645 	fr->data       = data;
    646 	fr->data_len   = len + count;
    647 	fr->len        = fr->data_len;
    648 	fr->ptr        = fr->data;
    649 	fr->dev_id     = frm->dev_id;
    650 	fr->in         = frm->in;
    651 	fr->ts         = frm->ts;
    652 	fr->handle     = frm->handle;
    653 	fr->cid        = frm->cid;
    654 	fr->num        = frm->num;
    655 	fr->channel    = frm->channel;
    656 	fr->pppdump_fd = frm->pppdump_fd;
    657 	fr->audio_fd   = frm->audio_fd;
    658 
    659 	return pos;
    660 }
    661 
    662 static struct frame *frame_get(struct frame *frm, int count)
    663 {
    664 	register int pos;
    665 
    666 	pos = frame_add(frm, count);
    667 	if (pos < 0)
    668 		return frm;
    669 
    670 	frame_table[pos].handle = 0;
    671 
    672 	return &frame_table[pos];
    673 }
    674 
    675 void sdp_dump(int level, struct frame *frm)
    676 {
    677 	sdp_pdu_hdr *hdr = frm->ptr;
    678 	uint16_t tid = ntohs(hdr->tid);
    679 	uint16_t len = ntohs(hdr->len);
    680 	uint16_t total, count;
    681 	uint8_t cont;
    682 
    683 	frm->ptr += SDP_PDU_HDR_SIZE;
    684 	frm->len -= SDP_PDU_HDR_SIZE;
    685 
    686 	p_indent(level, frm);
    687 	printf("SDP %s: tid 0x%x len 0x%x\n", pid2str(hdr->pid), tid, len);
    688 
    689 	switch (hdr->pid) {
    690 	case SDP_ERROR_RSP:
    691 		p_indent(level + 1, frm);
    692 		printf("code 0x%x info ", get_u16(frm));
    693 		if (frm->len > 0)
    694 			hex_dump(0, frm, frm->len);
    695 		else
    696 			printf("none\n");
    697 		break;
    698 
    699 	case SDP_SERVICE_SEARCH_REQ:
    700 		/* Parse ServiceSearchPattern */
    701 		print_srv_srch_pat(level + 1, frm);
    702 
    703 		/* Parse MaximumServiceRecordCount */
    704 		p_indent(level + 1, frm);
    705 		printf("max %d\n", get_u16(frm));
    706 
    707 		/* Parse ContinuationState */
    708 		print_cont_state(level + 1, frm->ptr);
    709 		break;
    710 
    711 	case SDP_SERVICE_SEARCH_RSP:
    712 		/* Parse TotalServiceRecordCount */
    713 		total = get_u16(frm);
    714 
    715 		/* Parse CurrentServiceRecordCount */
    716 		count = get_u16(frm);
    717 		p_indent(level + 1, frm);
    718 		if (count < total)
    719 			printf("count %d of %d\n", count, total);
    720 		else
    721 			printf("count %d\n", count);
    722 
    723 		/* Parse service record handle(s) */
    724 		if (count > 0) {
    725 			int i;
    726 			p_indent(level + 1, frm);
    727 			printf("handle%s", count > 1 ? "s" : "");
    728 			for (i = 0; i < count; i++)
    729 				printf(" 0x%x", get_u32(frm));
    730 			printf("\n");
    731 		}
    732 
    733 		/* Parse ContinuationState */
    734 		print_cont_state(level + 1, frm->ptr);
    735 		break;
    736 
    737 	case SDP_SERVICE_ATTR_REQ:
    738 		/* Parse ServiceRecordHandle */
    739 		p_indent(level + 1, frm);
    740 		printf("handle 0x%x\n", get_u32(frm));
    741 
    742 		/* Parse MaximumAttributeByteCount */
    743 		p_indent(level + 1, frm);
    744 		printf("max %d\n", get_u16(frm));
    745 
    746 		/* Parse ServiceSearchPattern */
    747 		print_attr_id_list(level + 1, frm);
    748 
    749 		/* Parse ContinuationState */
    750 		print_cont_state(level + 1, frm->ptr);
    751 		break;
    752 
    753 	case SDP_SERVICE_ATTR_RSP:
    754 		/* Parse AttributeByteCount */
    755 		count = get_u16(frm);
    756 		p_indent(level + 1, frm);
    757 		printf("count %d\n", count);
    758 
    759 		/* Parse ContinuationState */
    760 		cont = *(unsigned char *)(frm->ptr + count);
    761 
    762 		if (cont == 0) {
    763 			/* Parse AttributeList */
    764 			print_attr_list(level + 1, frame_get(frm, count));
    765 		} else
    766 			frame_add(frm, count);
    767 
    768 		print_cont_state(level + 1, frm->ptr + count);
    769 		break;
    770 
    771 	case SDP_SERVICE_SEARCH_ATTR_REQ:
    772 		/* Parse ServiceSearchPattern */
    773 		print_srv_srch_pat(level + 1, frm);
    774 
    775 		/* Parse MaximumAttributeByteCount */
    776 		p_indent(level + 1, frm);
    777 		printf("max %d\n", get_u16(frm));
    778 
    779 		/* Parse AttributeList */
    780 		print_attr_id_list(level + 1, frm);
    781 
    782 		/* Parse ContinuationState */
    783 		print_cont_state(level + 1, frm->ptr);
    784 		break;
    785 
    786 	case SDP_SERVICE_SEARCH_ATTR_RSP:
    787 		/* Parse AttributeByteCount */
    788 		count = get_u16(frm);
    789 		p_indent(level + 1, frm);
    790 		printf("count %d\n", count);
    791 
    792 		/* Parse ContinuationState */
    793 		cont = *(unsigned char *)(frm->ptr + count);
    794 
    795 		if (cont == 0) {
    796 			/* Parse AttributeLists */
    797 			print_attr_lists(level + 1, frame_get(frm, count));
    798 		} else
    799 			frame_add(frm, count);
    800 
    801 		print_cont_state(level + 1, frm->ptr + count);
    802 		break;
    803 
    804 	default:
    805 		raw_dump(level + 1, frm);
    806 		break;
    807 	}
    808 }
    809