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