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