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