print.c revision 1.3 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