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