1 /* $NetBSD: print.c,v 1.1 2009/05/12 18:37:50 plunky Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Iain Hibbert. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: print.c,v 1.1 2009/05/12 18:37:50 plunky Exp $"); 34 35 #include <ctype.h> 36 #include <iconv.h> 37 #include <langinfo.h> 38 #include <sdp.h> 39 #include <stdbool.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <uuid.h> 44 #include <vis.h> 45 46 #include "sdpquery.h" 47 48 typedef struct { 49 uint16_t id; 50 const char * desc; 51 void (*print)(sdp_data_t *); 52 } attr_t; 53 54 typedef struct { 55 uint16_t class; 56 const char * desc; 57 attr_t * attrs; 58 size_t nattr; 59 } service_t; 60 61 typedef struct { 62 uint16_t base; 63 const char * codeset; 64 } language_t; 65 66 static const char *string_uuid(uuid_t *); 67 static const char *string_vis(int, const char *, size_t); 68 69 static void print_hexdump(const char *, const uint8_t *, size_t); 70 static bool print_attribute(uint16_t, sdp_data_t *, attr_t *, int); 71 static bool print_universal_attribute(uint16_t, sdp_data_t *); 72 static bool print_language_attribute(uint16_t, sdp_data_t *); 73 static bool print_service_attribute(uint16_t, sdp_data_t *); 74 75 static void print_bool(sdp_data_t *); 76 static void print_uint8x(sdp_data_t *); 77 static void print_uint16d(sdp_data_t *); 78 static void print_uint32x(sdp_data_t *); 79 static void print_uint32d(sdp_data_t *); 80 static void print_uuid(sdp_data_t *); 81 static void print_uuid_list(sdp_data_t *); 82 static void print_string(sdp_data_t *); 83 static void print_url(sdp_data_t *); 84 static void print_profile_version(sdp_data_t *); 85 static void print_language_string(sdp_data_t *); 86 87 static void print_service_class_id_list(sdp_data_t *); 88 static void print_protocol_descriptor(sdp_data_t *); 89 static void print_protocol_descriptor_list(sdp_data_t *); 90 static void print_language_base_attribute_id_list(sdp_data_t *); 91 static void print_service_availability(sdp_data_t *); 92 static void print_bluetooth_profile_descriptor_list(sdp_data_t *); 93 static void print_additional_protocol_descriptor_lists(sdp_data_t *); 94 static void print_sds_version_number_list(sdp_data_t *); 95 static void print_ct_network(sdp_data_t *); 96 static void print_asrc_features(sdp_data_t *); 97 static void print_asink_features(sdp_data_t *); 98 static void print_avrcp_features(sdp_data_t *); 99 static void print_supported_data_stores(sdp_data_t *); 100 static void print_supported_formats(sdp_data_t *); 101 static void print_hid_version(sdp_data_t *); 102 static void print_hid_device_subclass(sdp_data_t *); 103 static void print_hid_descriptor_list(sdp_data_t *); 104 static void print_security_description(sdp_data_t *); 105 static void print_hf_features(sdp_data_t *); 106 static void print_hfag_network(sdp_data_t *); 107 static void print_hfag_features(sdp_data_t *); 108 static void print_net_access_type(sdp_data_t *); 109 110 static void print_rfcomm(sdp_data_t *); 111 static void print_bnep(sdp_data_t *); 112 static void print_avctp(sdp_data_t *); 113 static void print_avdtp(sdp_data_t *); 114 static void print_l2cap(sdp_data_t *); 115 116 attr_t protocol_list[] = { 117 { 0x0001, "SDP", NULL }, 118 { 0x0002, "UDP", NULL }, 119 { 0x0003, "RFCOMM", print_rfcomm }, 120 { 0x0004, "TCP", NULL }, 121 { 0x0005, "TCS_BIN", NULL }, 122 { 0x0006, "TCS_AT", NULL }, 123 { 0x0008, "OBEX", NULL }, 124 { 0x0009, "IP", NULL }, 125 { 0x000a, "FTP", NULL }, 126 { 0x000c, "HTTP", NULL }, 127 { 0x000e, "WSP", NULL }, 128 { 0x000f, "BNEP", print_bnep }, 129 { 0x0010, "UPNP", NULL }, 130 { 0x0011, "HIDP", NULL }, 131 { 0x0012, "HARDCOPY_CONTROL_CHANNEL", NULL }, 132 { 0x0014, "HARDCOPY_DATA_CHANNEL", NULL }, 133 { 0x0016, "HARDCOPY_NOTIFICATION", NULL }, 134 { 0x0017, "AVCTP", print_avctp }, 135 { 0x0019, "AVDTP", print_avdtp }, 136 { 0x001b, "CMTP", NULL }, 137 { 0x001d, "UDI_C_PLANE", NULL }, 138 { 0x0100, "L2CAP", print_l2cap }, 139 }; 140 141 attr_t universal_attrs[] = { 142 { 0x0000, "ServiceRecordHandle", print_uint32x }, 143 { 0x0001, "ServiceClassIDList", print_service_class_id_list }, 144 { 0x0002, "ServiceRecordState", print_uint32x }, 145 { 0x0003, "ServiceID", print_uuid }, 146 { 0x0004, "ProtocolDescriptorList", print_protocol_descriptor_list }, 147 { 0x0005, "BrowseGroupList", print_uuid_list }, 148 { 0x0006, "LanguageBaseAttributeIDList", print_language_base_attribute_id_list }, 149 { 0x0007, "ServiceInfoTimeToLive", print_uint32d }, 150 { 0x0008, "ServiceAvailability", print_service_availability }, 151 { 0x0009, "BluetoothProfileDescriptorList", print_bluetooth_profile_descriptor_list }, 152 { 0x000a, "DocumentationURL", print_url }, 153 { 0x000b, "ClientExecutableURL", print_url }, 154 { 0x000c, "IconURL", print_url }, 155 { 0x000d, "AdditionalProtocolDescriptorLists", print_additional_protocol_descriptor_lists }, 156 }; 157 158 attr_t language_attrs[] = { /* Language Attribute Offsets */ 159 { 0x0000, "ServiceName", print_language_string }, 160 { 0x0001, "ServiceDescription", print_language_string }, 161 { 0x0002, "ProviderName", print_language_string }, 162 }; 163 164 attr_t sds_attrs[] = { /* Service Discovery Server */ 165 { 0x0200, "VersionNumberList", print_sds_version_number_list }, 166 { 0x0201, "ServiceDatabaseState", print_uint32x }, 167 }; 168 169 attr_t bgd_attrs[] = { /* Browse Group Descriptor */ 170 { 0x0200, "GroupID", print_uuid }, 171 }; 172 173 attr_t ct_attrs[] = { /* Cordless Telephony */ 174 { 0x0301, "ExternalNetwork", print_ct_network }, 175 }; 176 177 attr_t asrc_attrs[] = { /* Audio Source */ 178 { 0x0311, "SupportedFeatures", print_asrc_features }, 179 }; 180 181 attr_t asink_attrs[] = { /* Audio Sink */ 182 { 0x0311, "SupportedFeatures", print_asink_features }, 183 }; 184 185 attr_t avrcp_attrs[] = { /* Audio Video Remote Control Profile */ 186 { 0x0311, "SupportedFeatures", print_avrcp_features }, 187 }; 188 189 attr_t lan_attrs[] = { /* LAN Access Using PPP */ 190 { 0x0200, "IPSubnet", print_string }, 191 }; 192 193 attr_t dun_attrs[] = { /* Dialup Networking */ 194 { 0x0305, "AudioFeedbackSupport", print_bool }, 195 }; 196 197 attr_t irmc_sync_attrs[] = { /* IrMC Sync */ 198 { 0x0301, "SupportedDataStoresList", print_supported_data_stores }, 199 }; 200 201 attr_t opush_attrs[] = { /* Object Push */ 202 { 0x0303, "SupportedFormatsList", print_supported_formats }, 203 }; 204 205 attr_t hset_attrs[] = { /* Headset */ 206 { 0x0302, "RemoteAudioVolumeControl", print_bool }, 207 }; 208 209 attr_t fax_attrs[] = { /* Fax */ 210 { 0x0302, "FAXClass1", print_bool }, 211 { 0x0303, "FAXClass2.0", print_bool }, 212 { 0x0304, "FAXClass2", print_bool }, 213 { 0x0305, "AudioFeedbackSupport", print_bool }, 214 }; 215 216 attr_t panu_attrs[] = { /* Personal Area Networking User */ 217 { 0x030a, "SecurityDescription", print_security_description }, 218 }; 219 220 attr_t nap_attrs[] = { /* Network Access Point */ 221 { 0x030a, "SecurityDescription", print_security_description }, 222 { 0x030b, "NetAccessType", print_net_access_type }, 223 { 0x030c, "MaxNetAccessRate", print_uint32d }, 224 { 0x030d, "IPv4Subnet", print_string }, 225 { 0x030e, "IPv6Subnet", print_string }, 226 }; 227 228 attr_t gn_attrs[] = { /* Group Network */ 229 { 0x030a, "SecurityDescription", print_security_description }, 230 { 0x030d, "IPv4Subnet", print_string }, 231 { 0x030e, "IPv6Subnet", print_string }, 232 }; 233 234 attr_t hf_attrs[] = { /* Handsfree */ 235 { 0x0311, "SupportedFeatures", print_hf_features }, 236 }; 237 238 attr_t hfag_attrs[] = { /* Handsfree Audio Gateway */ 239 { 0x0301, "Network", print_hfag_network }, 240 { 0x0311, "SupportedFeatures", print_hfag_features }, 241 }; 242 243 attr_t hid_attrs[] = { /* Human Interface Device */ 244 { 0x0200, "HIDDeviceReleaseNumber", print_hid_version }, 245 { 0x0201, "HIDParserVersion", print_hid_version }, 246 { 0x0202, "HIDDeviceSubClass", print_hid_device_subclass }, 247 { 0x0203, "HIDCountryCode", print_uint8x }, 248 { 0x0204, "HIDVirtualCable", print_bool }, 249 { 0x0205, "HIDReconnectInitiate", print_bool }, 250 { 0x0206, "HIDDescriptorList", print_hid_descriptor_list }, 251 { 0x0207, "HIDLANGIDBaseList", NULL }, 252 { 0x0208, "HIDSDPDisable", print_bool }, 253 { 0x0209, "HIDBatteryPower", print_bool }, 254 { 0x020a, "HIDRemoteWake", print_bool }, 255 { 0x020b, "HIDProfileVersion", print_profile_version }, 256 { 0x020c, "HIDSupervisionTimeout", print_uint16d }, 257 { 0x020d, "HIDNormallyConnectable", print_bool }, 258 { 0x020e, "HIDBootDevice", print_bool }, 259 }; 260 261 #define A(a) a, __arraycount(a) 262 service_t service_list[] = { 263 { 0x1000, "Service Discovery Server", A(sds_attrs) }, 264 { 0x1001, "Browse Group Descriptor", A(bgd_attrs) }, 265 { 0x1002, "Public Browse Root", NULL, 0 }, 266 { 0x1101, "Serial Port", NULL, 0 }, 267 { 0x1102, "LAN Access Using PPP", A(lan_attrs) }, 268 { 0x1103, "Dialup Networking", A(dun_attrs) }, 269 { 0x1104, "IrMC Sync", A(irmc_sync_attrs) }, 270 { 0x1105, "Object Push", A(opush_attrs) }, 271 { 0x1106, "File Transfer", NULL, 0 }, 272 { 0x1107, "IrMC Sync Command", NULL, 0 }, 273 { 0x1108, "Headset", A(hset_attrs) }, 274 { 0x1109, "Cordless Telephony", A(ct_attrs) }, 275 { 0x110a, "Audio Source", A(asrc_attrs) }, 276 { 0x110b, "Audio Sink", A(asink_attrs) }, 277 { 0x110c, "A/V Remote Control Target", A(avrcp_attrs) }, 278 { 0x110d, "Advanced Audio Distribution", NULL, 0 }, 279 { 0x110e, "A/V Remote Control", A(avrcp_attrs) }, 280 { 0x110f, "Video Conferencing", NULL, 0 }, 281 { 0x1110, "Intercom", NULL, 0 }, 282 { 0x1111, "Fax", A(fax_attrs) }, 283 { 0x1112, "Headset Audio Gateway", NULL, 0 }, 284 { 0x1113, "WAP", NULL, 0 }, 285 { 0x1114, "WAP Client", NULL, 0 }, 286 { 0x1115, "Personal Area Networking User", A(panu_attrs) }, 287 { 0x1116, "Network Access Point", A(nap_attrs) }, 288 { 0x1117, "Group Network", A(gn_attrs) }, 289 { 0x1118, "Direct Printing", NULL, 0 }, 290 { 0x1119, "Reference Printing", NULL, 0 }, 291 { 0x111a, "Imaging", NULL, 0 }, 292 { 0x111b, "Imaging Responder", NULL, 0 }, 293 { 0x111c, "Imaging Automatic Archive", NULL, 0 }, 294 { 0x111d, "Imaging Referenced Objects", NULL, 0 }, 295 { 0x111e, "Handsfree", A(hf_attrs) }, 296 { 0x111f, "Handsfree Audio Gateway", A(hfag_attrs) }, 297 { 0x1120, "Direct Printing Reference Objects", NULL, 0 }, 298 { 0x1121, "Reflected User Interface", NULL, 0 }, 299 { 0x1122, "Basic Printing", NULL, 0 }, 300 { 0x1123, "Printing Status", NULL, 0 }, 301 { 0x1124, "Human Interface Device", A(hid_attrs) }, 302 { 0x1125, "Hardcopy Cable Replacement", NULL, 0 }, 303 { 0x1126, "Hardcopy Cable Replacement Print", NULL, 0 }, 304 { 0x1127, "Hardcopy Cable Replacement Scan", NULL, 0 }, 305 { 0x1128, "Common ISDN Access", NULL, 0 }, 306 { 0x1129, "Video Conferencing GW", NULL, 0 }, 307 { 0x112a, "UDI MT", NULL, 0 }, 308 { 0x112b, "UDI TA", NULL, 0 }, 309 { 0x112c, "Audio/Video", NULL, 0 }, 310 { 0x112d, "SIM Access", NULL, 0 }, 311 { 0x1200, "PNP Information", NULL, 0 }, 312 { 0x1201, "Generic Networking", NULL, 0 }, 313 { 0x1202, "Generic File Transfer", NULL, 0 }, 314 { 0x1203, "Generic Audio", NULL, 0 }, 315 { 0x1204, "Generic Telephony", NULL, 0 }, 316 { 0x1205, "UPNP", NULL, 0 }, 317 { 0x1206, "UPNP IP", NULL, 0 }, 318 { 0x1300, "UPNP IP PAN", NULL, 0 }, 319 { 0x1301, "UPNP IP LAP", NULL, 0 }, 320 { 0x1302, "UPNP IP L2CAP", NULL, 0 }, 321 }; 322 #undef A 323 324 /* extracted Service Class ID List */ 325 #define MAX_SERVICES 16 326 static size_t nservices; 327 static uint16_t service_class[MAX_SERVICES]; 328 329 /* extracted Language Base Attribute ID List */ 330 #define MAX_LANGUAGES 16 331 static int nlanguages; 332 static language_t language[MAX_LANGUAGES]; 333 static int current; 334 335 static bool 336 sdp_get_uint8(sdp_data_t *d, uint8_t *vp) 337 { 338 uintmax_t v; 339 340 if (sdp_data_type(d) != SDP_DATA_UINT8 341 || !sdp_get_uint(d, &v)) 342 return false; 343 344 *vp = (uint8_t)v; 345 return true; 346 } 347 348 static bool 349 sdp_get_uint16(sdp_data_t *d, uint16_t *vp) 350 { 351 uintmax_t v; 352 353 if (sdp_data_type(d) != SDP_DATA_UINT16 354 || !sdp_get_uint(d, &v)) 355 return false; 356 357 *vp = (uint16_t)v; 358 return true; 359 } 360 361 static bool 362 sdp_get_uint32(sdp_data_t *d, uint32_t *vp) 363 { 364 uintmax_t v; 365 366 if (sdp_data_type(d) != SDP_DATA_UINT32 367 || !sdp_get_uint(d, &v)) 368 return false; 369 370 *vp = (uint32_t)v; 371 return true; 372 } 373 374 void 375 print_record(sdp_data_t *rec) 376 { 377 sdp_data_t value; 378 uint16_t id; 379 380 nservices = 0; 381 nlanguages = 0; 382 current = -1; 383 384 while (sdp_get_attr(rec, &id, &value)) { 385 if (Xflag) { 386 printf("AttributeID 0x%04x:\n", id); 387 print_hexdump(" ", value.next, value.end - value.next); 388 } else if (Rflag) { 389 printf("AttributeID 0x%04x:\n", id); 390 sdp_data_print(&value, 4); 391 } else if (print_universal_attribute(id, &value) 392 || print_language_attribute(id, &value) 393 || print_service_attribute(id, &value)) { 394 if (value.next != value.end) 395 printf(" [additional data ignored]\n"); 396 } else { 397 printf("AttributeID 0x%04x:\n", id); 398 sdp_data_print(&value, 4); 399 } 400 } 401 } 402 403 static const char * 404 string_uuid(uuid_t *uuid) 405 { 406 static char buf[64]; 407 const char *desc; 408 uuid_t u; 409 size_t i; 410 411 u = *uuid; 412 u.time_low = 0; 413 if (!uuid_equal(&u, &BLUETOOTH_BASE_UUID, NULL)) { 414 snprintf(buf, sizeof(buf), 415 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 416 uuid->time_low, uuid->time_mid, uuid->time_hi_and_version, 417 uuid->clock_seq_hi_and_reserved, uuid->clock_seq_low, 418 uuid->node[0], uuid->node[1], uuid->node[2], 419 uuid->node[3], uuid->node[4], uuid->node[5]); 420 421 return buf; 422 } 423 424 desc = NULL; 425 for (i = 0; i < __arraycount(service_list); i++) { 426 if (uuid->time_low == service_list[i].class) { 427 desc = service_list[i].desc; 428 break; 429 } 430 } 431 432 for (i = 0; i < __arraycount(protocol_list); i++) { 433 if (uuid->time_low == protocol_list[i].id) { 434 desc = protocol_list[i].desc; 435 break; 436 } 437 } 438 439 if (!Nflag && desc) { 440 snprintf(buf, sizeof(buf), "%s", desc); 441 return buf; 442 } 443 444 snprintf(buf, sizeof(buf), "%s%s(0x%*.*x)", 445 (desc == NULL ? "" : desc), 446 (desc == NULL ? "" : " "), 447 (uuid->time_low > UINT16_MAX ? 8 : 4), 448 (uuid->time_low > UINT16_MAX ? 8 : 4), 449 uuid->time_low); 450 451 return buf; 452 } 453 454 static const char * 455 string_vis(int style, const char *src, size_t len) 456 { 457 static char buf[50]; 458 char *dst = buf; 459 460 style |= VIS_NL; 461 while (len > 0 && (dst + 5) < (buf + sizeof(buf))) { 462 dst = vis(dst, src[0], style, (len > 1 ? src[1] : 0)); 463 src++; 464 len--; 465 } 466 467 return buf; 468 } 469 470 static void 471 print_hexdump(const char *title, const uint8_t *data, size_t len) 472 { 473 int n, i; 474 475 i = 0; 476 n = printf("%s", title); 477 478 while (len-- > 0) { 479 if (++i > 8) { 480 printf("\n%*s", n, ""); 481 i = 1; 482 } 483 484 printf(" 0x%02x", *data++); 485 } 486 487 printf("\n"); 488 } 489 490 static bool 491 print_attribute(uint16_t id, sdp_data_t *value, attr_t *attr, int count) 492 { 493 int i; 494 495 for (i = 0; i < count; i++) { 496 if (id == attr[i].id) { 497 printf("%s", attr[i].desc); 498 499 if (Nflag) { 500 printf(" ("); 501 502 if (current != -1) 503 printf("0x%04x + ", language[current].base); 504 505 printf("0x%04x)", id); 506 } 507 508 printf(": "); 509 510 if (attr[i].print == NULL) { 511 printf("\n"); 512 sdp_data_print(value, 4); 513 value->next = value->end; 514 } else { 515 (attr[i].print)(value); 516 } 517 518 return true; 519 } 520 } 521 522 return false; 523 } 524 525 static bool 526 print_universal_attribute(uint16_t id, sdp_data_t *value) 527 { 528 529 return print_attribute(id, value, 530 universal_attrs, __arraycount(universal_attrs)); 531 } 532 533 static bool 534 print_language_attribute(uint16_t id, sdp_data_t *value) 535 { 536 bool done = false; 537 538 for (current = 0; current < nlanguages && !done; current++) 539 done = print_attribute(id - language[current].base, value, 540 language_attrs, __arraycount(language_attrs)); 541 542 current = -1; 543 return done; 544 } 545 546 static bool 547 print_service_attribute(uint16_t id, sdp_data_t *value) 548 { 549 size_t i, j; 550 551 for (i = 0; i < nservices; i++) { 552 for (j = 0; j < __arraycount(service_list); j++) { 553 if (service_class[i] == service_list[j].class) 554 return print_attribute(id, value, 555 service_list[j].attrs, 556 service_list[j].nattr); 557 } 558 } 559 560 return false; 561 } 562 563 static void 564 print_bool(sdp_data_t *data) 565 { 566 bool v; 567 568 if (!sdp_get_bool(data, &v)) 569 return; 570 571 printf("%s\n", (v ? "true" : "false")); 572 } 573 574 static void 575 print_uint8x(sdp_data_t *data) 576 { 577 uint8_t v; 578 579 if (!sdp_get_uint8(data, &v)) 580 return; 581 582 printf("0x%02x\n", v); 583 } 584 585 static void 586 print_uint16d(sdp_data_t *data) 587 { 588 uint16_t v; 589 590 if (!sdp_get_uint16(data, &v)) 591 return; 592 593 printf("%d\n", v); 594 } 595 596 static void 597 print_uint32x(sdp_data_t *data) 598 { 599 uint32_t v; 600 601 if (!sdp_get_uint32(data, &v)) 602 return; 603 604 printf("0x%08x\n", v); 605 } 606 607 static void 608 print_uint32d(sdp_data_t *data) 609 { 610 uint32_t v; 611 612 if (!sdp_get_uint32(data, &v)) 613 return; 614 615 printf("%d\n", v); 616 } 617 618 static void 619 print_uuid(sdp_data_t *data) 620 { 621 uuid_t uuid; 622 623 if (!sdp_get_uuid(data, &uuid)) 624 return; 625 626 printf("%s\n", string_uuid(&uuid)); 627 } 628 629 static void 630 print_uuid_list(sdp_data_t *data) 631 { 632 sdp_data_t seq; 633 uuid_t uuid; 634 635 if (!sdp_get_seq(data, &seq)) 636 return; 637 638 printf("\n"); 639 while (sdp_get_uuid(&seq, &uuid)) 640 printf(" %s\n", string_uuid(&uuid)); 641 642 if (seq.next != seq.end) 643 printf(" [additional data]\n"); 644 } 645 646 static void 647 print_string(sdp_data_t *data) 648 { 649 char *str; 650 size_t len; 651 652 if (!sdp_get_str(data, &str, &len)) 653 return; 654 655 printf("\"%s\"\n", string_vis(VIS_CSTYLE, str, len)); 656 } 657 658 static void 659 print_url(sdp_data_t *data) 660 { 661 char *url; 662 size_t len; 663 664 if (!sdp_get_url(data, &url, &len)) 665 return; 666 667 printf("\"%s\"\n", string_vis(VIS_HTTPSTYLE, url, len)); 668 } 669 670 static void 671 print_profile_version(sdp_data_t *data) 672 { 673 uint16_t v; 674 675 if (!sdp_get_uint16(data, &v)) 676 return; 677 678 printf("v%d.%d\n", (v >> 8), (v & 0xff)); 679 } 680 681 /* 682 * This should only be called through print_language_attribute() which 683 * sets codeset of the string to be printed. 684 */ 685 static void 686 print_language_string(sdp_data_t *data) 687 { 688 char buf[50], *dst, *src; 689 iconv_t ih; 690 size_t n, srcleft, dstleft; 691 692 if (!sdp_get_str(data, &src, &srcleft)) 693 return; 694 695 dst = buf; 696 dstleft = sizeof(buf); 697 698 ih = iconv_open(nl_langinfo(CODESET), language[current].codeset); 699 if (ih == (iconv_t)-1) { 700 printf("Can't convert %s string\n", language[current].codeset); 701 return; 702 } 703 704 n = iconv(ih, (const char **)&src, &srcleft, &dst, &dstleft); 705 706 iconv_close(ih); 707 708 if (Nflag || n > 0) 709 printf("(%s) ", language[current].codeset); 710 711 printf("\"%.*s%s\n", (int)(sizeof(buf) - dstleft), buf, 712 (srcleft > 0 ? " ..." : "\"")); 713 } 714 715 static void 716 print_service_class_id_list(sdp_data_t *data) 717 { 718 sdp_data_t seq; 719 uuid_t uuid; 720 721 if (!sdp_get_seq(data, &seq)) 722 return; 723 724 printf("\n"); 725 while (sdp_get_uuid(&seq, &uuid)) { 726 printf(" %s\n", string_uuid(&uuid)); 727 728 if (nservices < MAX_SERVICES) { 729 service_class[nservices] = uuid.time_low; 730 uuid.time_low = 0; 731 if (uuid_equal(&uuid, &BLUETOOTH_BASE_UUID, NULL)) 732 nservices++; 733 } 734 } 735 736 if (seq.next != seq.end) 737 printf(" [additional data]\n"); 738 } 739 740 static void 741 print_protocol_descriptor(sdp_data_t *data) 742 { 743 uuid_t u0, uuid; 744 size_t i; 745 746 if (!sdp_get_uuid(data, &uuid)) 747 return; 748 749 u0 = uuid; 750 u0.time_low = 0; 751 if (uuid_equal(&u0, &BLUETOOTH_BASE_UUID, NULL)) { 752 for (i = 0; i < __arraycount(protocol_list); i++) { 753 if (uuid.time_low == protocol_list[i].id) { 754 printf(" %s", protocol_list[i].desc); 755 756 if (Nflag) 757 printf(" (0x%04x)", protocol_list[i].id); 758 759 if (protocol_list[i].print) 760 (protocol_list[i].print)(data); 761 762 if (data->next != data->end) 763 printf(" [additional data ignored]"); 764 765 printf("\n"); 766 return; 767 } 768 } 769 } 770 771 printf(" %s\n", string_uuid(&uuid)); 772 sdp_data_print(data, 4); 773 data->next = data->end; 774 } 775 776 static void 777 print_protocol_descriptor_list(sdp_data_t *data) 778 { 779 sdp_data_t seq, proto; 780 781 printf("\n"); 782 sdp_get_alt(data, data); /* strip [optional] alt header */ 783 784 while (sdp_get_seq(data, &seq)) 785 while (sdp_get_seq(&seq, &proto)) 786 print_protocol_descriptor(&proto); 787 } 788 789 static void 790 print_language_base_attribute_id_list(sdp_data_t *data) 791 { 792 sdp_data_t list; 793 uint16_t v; 794 const char *codeset; 795 char lang[2]; 796 797 if (!sdp_get_seq(data, &list)) 798 return; 799 800 printf("\n"); 801 while (list.next < list.end) { 802 /* 803 * ISO-639-1 natural language values are published at 804 * http://www.loc.gov/standards/iso639-2/php/code-list.php 805 */ 806 if (!sdp_get_uint16(&list, &v)) 807 break; 808 809 be16enc(lang, v); 810 if (!islower((int)lang[0]) || !islower((int)lang[1])) 811 break; 812 813 /* 814 * MIBenum values are published at 815 * http://www.iana.org/assignments/character-sets 816 */ 817 if (!sdp_get_uint16(&list, &v)) 818 break; 819 820 switch(v) { 821 case 3: codeset = "US-ASCII"; break; 822 case 4: codeset = "ISO-8859-1"; break; 823 case 5: codeset = "ISO-8859-2"; break; 824 case 106: codeset = "UTF-8"; break; 825 case 1013: codeset = "UTF-16BE"; break; 826 case 1014: codeset = "UTF-16LE"; break; 827 default: codeset = "Unknown"; break; 828 } 829 830 if (!sdp_get_uint16(&list, &v)) 831 break; 832 833 printf(" %.2s.%s base 0x%04x\n", lang, codeset, v); 834 835 if (nlanguages < MAX_LANGUAGES) { 836 language[nlanguages].base = v; 837 language[nlanguages].codeset = codeset; 838 nlanguages++; 839 } 840 } 841 842 if (list.next != list.end) 843 printf(" [additional data]\n"); 844 } 845 846 static void 847 print_service_availability(sdp_data_t *data) 848 { 849 uint8_t v; 850 851 if (!sdp_get_uint8(data, &v)) 852 return; 853 854 printf("%d/%d\n", v, UINT8_MAX); 855 } 856 857 static void 858 print_bluetooth_profile_descriptor_list(sdp_data_t *data) 859 { 860 sdp_data_t seq, profile; 861 uuid_t uuid; 862 uint16_t v; 863 864 if (!sdp_get_seq(data, &seq)) 865 return; 866 867 printf("\n"); 868 while (seq.next < seq.end) { 869 if (!sdp_get_seq(&seq, &profile) 870 || !sdp_get_uuid(&profile, &uuid) 871 || !sdp_get_uint16(&profile, &v)) 872 break; 873 874 printf(" %s, v%d.%d", string_uuid(&uuid), 875 (v >> 8), (v & 0xff)); 876 877 if (profile.next != profile.end) 878 printf(" [additional profile data]"); 879 880 printf("\n"); 881 } 882 883 if (seq.next != seq.end) 884 printf(" [additional data]\n"); 885 } 886 887 static void 888 print_additional_protocol_descriptor_lists(sdp_data_t *data) 889 { 890 sdp_data_t seq, stack, proto; 891 892 printf("\n"); 893 sdp_get_seq(data, &seq); 894 895 while (sdp_get_seq(&seq, &stack)) 896 while (sdp_get_seq(&stack, &proto)) 897 print_protocol_descriptor(&proto); 898 899 if (seq.next != seq.end) 900 printf(" [additional data]\n"); 901 } 902 903 static void 904 print_sds_version_number_list(sdp_data_t *data) 905 { 906 sdp_data_t list; 907 const char *sep; 908 uint16_t v; 909 910 if (!sdp_get_seq(data, &list)) 911 return; 912 913 sep = ""; 914 while (sdp_get_uint16(&list, &v)) { 915 printf("%sv%d.%d", sep, (v >> 8), (v & 0xff)); 916 sep = ", "; 917 } 918 919 if (list.next != list.end) 920 printf(" [additional data]"); 921 922 printf("\n"); 923 } 924 925 static void 926 print_ct_network(sdp_data_t *data) 927 { 928 uint8_t v; 929 930 if (!sdp_get_uint8(data, &v)) 931 return; 932 933 switch (v) { 934 case 0x01: printf("PSTN"); break; 935 case 0x02: printf("ISDN"); break; 936 case 0x03: printf("GSM"); break; 937 case 0x04: printf("CDMA"); break; 938 case 0x05: printf("Analogue Cellular"); break; 939 case 0x06: printf("Packet Switched"); break; 940 case 0x07: printf("Other"); break; 941 default: printf("0x%02x", v); break; 942 } 943 944 printf("\n"); 945 } 946 947 static void 948 print_asrc_features(sdp_data_t *data) 949 { 950 uint16_t v; 951 952 if (!sdp_get_uint16(data, &v)) 953 return; 954 955 if (Nflag) 956 printf("(0x%04x)", v); 957 958 printf("\n"); 959 if (v & (1<<0)) printf(" Player\n"); 960 if (v & (1<<1)) printf(" Microphone\n"); 961 if (v & (1<<2)) printf(" Tuner\n"); 962 if (v & (1<<3)) printf(" Mixer\n"); 963 } 964 965 static void 966 print_asink_features(sdp_data_t *data) 967 { 968 uint16_t v; 969 970 if (!sdp_get_uint16(data, &v)) 971 return; 972 973 if (Nflag) 974 printf("(0x%04x)", v); 975 976 printf("\n"); 977 if (v & (1<<0)) printf(" Headphone\n"); 978 if (v & (1<<1)) printf(" Speaker\n"); 979 if (v & (1<<2)) printf(" Recorder\n"); 980 if (v & (1<<3)) printf(" Amplifier\n"); 981 } 982 983 static void 984 print_avrcp_features(sdp_data_t *data) 985 { 986 uint16_t v; 987 988 if (!sdp_get_uint16(data, &v)) 989 return; 990 991 if (Nflag) 992 printf("(0x%04x)", v); 993 994 printf("\n"); 995 if (v & (1<<0)) printf(" Category 1\n"); 996 if (v & (1<<1)) printf(" Category 2\n"); 997 if (v & (1<<2)) printf(" Category 3\n"); 998 if (v & (1<<3)) printf(" Category 4\n"); 999 } 1000 1001 static void 1002 print_supported_data_stores(sdp_data_t *data) 1003 { 1004 sdp_data_t list; 1005 const char *sep; 1006 uint8_t v; 1007 1008 if (!sdp_get_seq(data, &list)) 1009 return; 1010 1011 sep = "\n "; 1012 while (sdp_get_uint8(&list, &v)) { 1013 printf(sep); 1014 sep = ", "; 1015 1016 switch(v) { 1017 case 0x01: printf("Phonebook"); break; 1018 case 0x03: printf("Calendar"); break; 1019 case 0x05: printf("Notes"); break; 1020 case 0x06: printf("Messages"); break; 1021 default: printf("0x%02x", v); break; 1022 } 1023 } 1024 1025 if (list.next != list.end) 1026 printf(" [additional data]"); 1027 1028 printf("\n"); 1029 } 1030 1031 static void 1032 print_supported_formats(sdp_data_t *data) 1033 { 1034 sdp_data_t list; 1035 const char *sep; 1036 uint8_t v; 1037 1038 if (!sdp_get_seq(data, &list)) 1039 return; 1040 1041 sep = "\n "; 1042 while (sdp_get_uint8(&list, &v)) { 1043 printf(sep); 1044 sep = ", "; 1045 1046 switch(v) { 1047 case 0x01: printf("vCard 2.1"); break; 1048 case 0x02: printf("vCard 3.0"); break; 1049 case 0x03: printf("vCal 1.0"); break; 1050 case 0x04: printf("iCal 2.0"); break; 1051 case 0x05: printf("vNote"); break; 1052 case 0x06: printf("vMessage"); break; 1053 case 0xff: printf("Any"); break; 1054 default: printf("0x%02x", v); break; 1055 } 1056 } 1057 1058 if (list.next != list.end) 1059 printf(" [additional data]"); 1060 1061 printf("\n"); 1062 } 1063 1064 static void 1065 print_hid_version(sdp_data_t *data) 1066 { 1067 uint16_t v; 1068 1069 if (!sdp_get_uint16(data, &v)) 1070 return; 1071 1072 printf("v%d.%d.%d\n", 1073 ((v & 0xff00) >> 8), ((v & 0x00f0) >> 4), (v & 0x000f)); 1074 } 1075 1076 static void 1077 print_hid_device_subclass(sdp_data_t *data) 1078 { 1079 uint8_t v; 1080 1081 if (!sdp_get_uint8(data, &v)) 1082 return; 1083 1084 switch ((v & 0x3c) >> 2) { 1085 case 1: printf("Joystick"); break; 1086 case 2: printf("Gamepad"); break; 1087 case 3: printf("Remote Control"); break; 1088 case 4: printf("Sensing Device"); break; 1089 case 5: printf("Digitiser Tablet"); break; 1090 case 6: printf("Card Reader"); break; 1091 default: printf("Peripheral"); break; 1092 } 1093 1094 if (v & 0x40) printf(" <Keyboard>"); 1095 if (v & 0x80) printf(" <Mouse>"); 1096 1097 printf("\n"); 1098 } 1099 1100 static void 1101 print_hid_descriptor_list(sdp_data_t *data) 1102 { 1103 sdp_data_t list, seq; 1104 uint8_t type; 1105 const char *name; 1106 char *str; 1107 size_t len; 1108 1109 1110 if (!sdp_get_seq(data, &list)) 1111 return; 1112 1113 printf("\n"); 1114 while (list.next < list.end) { 1115 if (!sdp_get_seq(&list, &seq) 1116 || !sdp_get_uint8(&seq, &type) 1117 || !sdp_get_str(&seq, &str, &len)) 1118 return; 1119 1120 switch (type) { 1121 case 0x22: name = "Report"; break; 1122 case 0x23: name = "Physical Descriptor"; break; 1123 default: name = ""; break; 1124 } 1125 1126 printf(" Type 0x%02x: %s\n", type, name); 1127 print_hexdump(" Data", (uint8_t *)str, len); 1128 1129 if (seq.next != seq.end) 1130 printf(" [additional data]\n"); 1131 } 1132 } 1133 1134 static void 1135 print_security_description(sdp_data_t *data) 1136 { 1137 uint16_t v; 1138 1139 if (!sdp_get_uint16(data, &v)) 1140 return; 1141 1142 switch (v) { 1143 case 0x0000: printf("None"); break; 1144 case 0x0001: printf("Service-level Security"); break; 1145 case 0x0002: printf("802.1x Security"); break; 1146 default: printf("0x%04x", v); break; 1147 } 1148 1149 printf("\n"); 1150 } 1151 1152 static void 1153 print_hf_features(sdp_data_t *data) 1154 { 1155 uint16_t v; 1156 1157 if (!sdp_get_uint16(data, &v)) 1158 return; 1159 1160 if (Nflag) 1161 printf("(0x%04x)", v); 1162 1163 printf("\n"); 1164 if (v & (1<<0)) printf(" Echo Cancellation/Noise Reduction\n"); 1165 if (v & (1<<1)) printf(" Call Waiting\n"); 1166 if (v & (1<<2)) printf(" Caller Line Identification\n"); 1167 if (v & (1<<3)) printf(" Voice Recognition\n"); 1168 if (v & (1<<4)) printf(" Volume Control\n"); 1169 } 1170 1171 static void 1172 print_hfag_network(sdp_data_t *data) 1173 { 1174 uint8_t v; 1175 1176 if (!sdp_get_uint8(data, &v)) 1177 return; 1178 1179 switch (v) { 1180 case 0x01: printf("Ability to reject a call"); break; 1181 case 0x02: printf("No ability to reject a call"); break; 1182 default: printf("0x%02x", v); break; 1183 } 1184 1185 printf("\n"); 1186 } 1187 1188 static void 1189 print_hfag_features(sdp_data_t *data) 1190 { 1191 uint16_t v; 1192 1193 if (!sdp_get_uint16(data, &v)) 1194 return; 1195 1196 if (Nflag) 1197 printf("(0x%04x)", v); 1198 1199 printf("\n"); 1200 if (v & (1<<0)) printf(" 3 Way Calling\n"); 1201 if (v & (1<<1)) printf(" Echo Cancellation/Noise Reduction\n"); 1202 if (v & (1<<2)) printf(" Voice Recognition\n"); 1203 if (v & (1<<3)) printf(" In-band Ring Tone\n"); 1204 if (v & (1<<4)) printf(" Voice Tags\n"); 1205 } 1206 1207 static void 1208 print_net_access_type(sdp_data_t *data) 1209 { 1210 uint16_t v; 1211 1212 if (!sdp_get_uint16(data, &v)) 1213 return; 1214 1215 switch(v) { 1216 case 0x0000: printf("PSTN"); break; 1217 case 0x0001: printf("ISDN"); break; 1218 case 0x0002: printf("DSL"); break; 1219 case 0x0003: printf("Cable Modem"); break; 1220 case 0x0004: printf("10Mb Ethernet"); break; 1221 case 0x0005: printf("100Mb Ethernet"); break; 1222 case 0x0006: printf("4Mb Token Ring"); break; 1223 case 0x0007: printf("16Mb Token Ring"); break; 1224 case 0x0008: printf("100Mb Token Ring"); break; 1225 case 0x0009: printf("FDDI"); break; 1226 case 0x000a: printf("GSM"); break; 1227 case 0x000b: printf("CDMA"); break; 1228 case 0x000c: printf("GPRS"); break; 1229 case 0x000d: printf("3G Cellular"); break; 1230 case 0xfffe: printf("other"); break; 1231 default: printf("0x%04x", v); break; 1232 } 1233 1234 printf("\n"); 1235 } 1236 1237 static void 1238 print_rfcomm(sdp_data_t *data) 1239 { 1240 uint8_t v; 1241 1242 if (sdp_get_uint8(data, &v)) 1243 printf(" (channel %d)", v); 1244 } 1245 1246 static void 1247 print_bnep(sdp_data_t *data) 1248 { 1249 sdp_data_t seq; 1250 uint16_t v; 1251 const char *sep; 1252 1253 if (!sdp_get_uint16(data, &v) 1254 || !sdp_get_seq(data, &seq)) 1255 return; 1256 1257 printf(" (v%d.%d", (v >> 8), (v & 0xff)); 1258 sep = "; "; 1259 while (sdp_get_uint16(&seq, &v)) { 1260 printf(sep); 1261 sep = ", "; 1262 1263 switch (v) { 1264 case 0x0800: printf("IPv4"); break; 1265 case 0x0806: printf("ARP"); break; 1266 case 0x86dd: printf("IPv6"); break; 1267 default: printf("0x%04x", v); break; 1268 } 1269 } 1270 printf(")"); 1271 1272 if (seq.next != seq.end) 1273 printf(" [additional data]"); 1274 } 1275 1276 static void 1277 print_avctp(sdp_data_t *data) 1278 { 1279 uint16_t v; 1280 1281 if (sdp_get_uint16(data, &v)) 1282 printf(" (v%d.%d)", (v >> 8), (v & 0xff)); 1283 } 1284 1285 static void 1286 print_avdtp(sdp_data_t *data) 1287 { 1288 uint16_t v; 1289 1290 if (sdp_get_uint16(data, &v)) 1291 printf(" (v%d.%d)", (v >> 8), (v & 0xff)); 1292 } 1293 1294 static void 1295 print_l2cap(sdp_data_t *data) 1296 { 1297 uint16_t v; 1298 1299 if (sdp_get_uint16(data, &v)) 1300 printf(" (PSM 0x%04x)", v); 1301 } 1302