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