xref: /netbsd-src/usr.bin/sdpquery/print.c (revision 9f6b0b0b98d9a0c03b08197211dfa8c988e55b96)
1*9f6b0b0bSrillig /*	$NetBSD: print.c,v 1.24 2021/08/27 17:41:39 rillig Exp $	*/
2384153c1Splunky 
3384153c1Splunky /*-
4384153c1Splunky  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5384153c1Splunky  * All rights reserved.
6384153c1Splunky  *
7384153c1Splunky  * This code is derived from software contributed to The NetBSD Foundation
8384153c1Splunky  * by Iain Hibbert.
9384153c1Splunky  *
10384153c1Splunky  * Redistribution and use in source and binary forms, with or without
11384153c1Splunky  * modification, are permitted provided that the following conditions
12384153c1Splunky  * are met:
13384153c1Splunky  * 1. Redistributions of source code must retain the above copyright
14384153c1Splunky  *    notice, this list of conditions and the following disclaimer.
15384153c1Splunky  * 2. Redistributions in binary form must reproduce the above copyright
16384153c1Splunky  *    notice, this list of conditions and the following disclaimer in the
17384153c1Splunky  *    documentation and/or other materials provided with the distribution.
18384153c1Splunky  *
19384153c1Splunky  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20384153c1Splunky  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21384153c1Splunky  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22384153c1Splunky  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23384153c1Splunky  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24384153c1Splunky  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25384153c1Splunky  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26384153c1Splunky  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27384153c1Splunky  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28384153c1Splunky  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29384153c1Splunky  * POSSIBILITY OF SUCH DAMAGE.
30384153c1Splunky  */
31384153c1Splunky 
32384153c1Splunky #include <sys/cdefs.h>
33*9f6b0b0bSrillig __RCSID("$NetBSD: print.c,v 1.24 2021/08/27 17:41:39 rillig Exp $");
34384153c1Splunky 
35384153c1Splunky #include <ctype.h>
36384153c1Splunky #include <iconv.h>
37384153c1Splunky #include <langinfo.h>
38384153c1Splunky #include <sdp.h>
39384153c1Splunky #include <stdbool.h>
40384153c1Splunky #include <stdio.h>
41384153c1Splunky #include <stdlib.h>
42384153c1Splunky #include <string.h>
43384153c1Splunky #include <uuid.h>
44384153c1Splunky #include <vis.h>
45384153c1Splunky 
46384153c1Splunky #include "sdpquery.h"
47384153c1Splunky 
48384153c1Splunky typedef struct {
49384153c1Splunky 	uint16_t	id;
50384153c1Splunky 	const char *	desc;
51384153c1Splunky 	void		(*print)(sdp_data_t *);
52384153c1Splunky } attr_t;
53384153c1Splunky 
54384153c1Splunky typedef struct {
55384153c1Splunky 	uint16_t	class;
56384153c1Splunky 	const char *	desc;
57384153c1Splunky 	attr_t *	attrs;
58384153c1Splunky 	size_t		nattr;
59384153c1Splunky } service_t;
60384153c1Splunky 
61384153c1Splunky typedef struct {
62384153c1Splunky 	uint16_t	base;
63384153c1Splunky 	const char *	codeset;
64384153c1Splunky } language_t;
65384153c1Splunky 
66384153c1Splunky static const char *string_uuid(uuid_t *);
671803dc4bSplunky static const char *string_vis(const char *, size_t);
68384153c1Splunky 
69384153c1Splunky static void print_hexdump(const char *, const uint8_t *, size_t);
702424b4a6Splunky static bool print_attribute(uint16_t, sdp_data_t *, attr_t *, size_t);
71384153c1Splunky static bool print_universal_attribute(uint16_t, sdp_data_t *);
72384153c1Splunky static bool print_language_attribute(uint16_t, sdp_data_t *);
73384153c1Splunky static bool print_service_attribute(uint16_t, sdp_data_t *);
74384153c1Splunky 
75384153c1Splunky static void print_bool(sdp_data_t *);
76018ad52aSplunky static void print_uint8d(sdp_data_t *);
77384153c1Splunky static void print_uint8x(sdp_data_t *);
78384153c1Splunky static void print_uint16d(sdp_data_t *);
79447afe8dSplunky static void print_uint16x(sdp_data_t *);
80384153c1Splunky static void print_uint32d(sdp_data_t *);
8112d25979Splunky static void print_uint32x(sdp_data_t *);
82384153c1Splunky static void print_uuid(sdp_data_t *);
83384153c1Splunky static void print_uuid_list(sdp_data_t *);
84384153c1Splunky static void print_string(sdp_data_t *);
859a6467a3Splunky static void print_string_list(sdp_data_t *);
86384153c1Splunky static void print_url(sdp_data_t *);
87384153c1Splunky static void print_profile_version(sdp_data_t *);
88a54eea1cSplunky static void print_codeset_string(const char *, size_t, const char *);
89384153c1Splunky static void print_language_string(sdp_data_t *);
90a54eea1cSplunky static void print_utf8_string(sdp_data_t *);
91384153c1Splunky 
92384153c1Splunky static void print_service_class_id_list(sdp_data_t *);
93384153c1Splunky static void print_protocol_descriptor(sdp_data_t *);
94384153c1Splunky static void print_protocol_descriptor_list(sdp_data_t *);
95384153c1Splunky static void print_language_base_attribute_id_list(sdp_data_t *);
96384153c1Splunky static void print_service_availability(sdp_data_t *);
97384153c1Splunky static void print_bluetooth_profile_descriptor_list(sdp_data_t *);
98384153c1Splunky static void print_additional_protocol_descriptor_lists(sdp_data_t *);
99384153c1Splunky static void print_sds_version_number_list(sdp_data_t *);
100384153c1Splunky static void print_ct_network(sdp_data_t *);
101384153c1Splunky static void print_asrc_features(sdp_data_t *);
102384153c1Splunky static void print_asink_features(sdp_data_t *);
103384153c1Splunky static void print_avrcp_features(sdp_data_t *);
104384153c1Splunky static void print_supported_data_stores(sdp_data_t *);
105384153c1Splunky static void print_supported_formats(sdp_data_t *);
106d82c7103Splunky static void print_wap_addr(sdp_data_t *);
107d82c7103Splunky static void print_wap_gateway(sdp_data_t *);
108d82c7103Splunky static void print_wap_type(sdp_data_t *);
109384153c1Splunky static void print_hid_version(sdp_data_t *);
110384153c1Splunky static void print_hid_device_subclass(sdp_data_t *);
111384153c1Splunky static void print_hid_descriptor_list(sdp_data_t *);
112e8fd30ebSplunky static void print_hid_langid_base_list(sdp_data_t *);
113384153c1Splunky static void print_security_description(sdp_data_t *);
114384153c1Splunky static void print_hf_features(sdp_data_t *);
115384153c1Splunky static void print_hfag_network(sdp_data_t *);
116384153c1Splunky static void print_hfag_features(sdp_data_t *);
117384153c1Splunky static void print_net_access_type(sdp_data_t *);
118447afe8dSplunky static void print_pnp_source(sdp_data_t *);
119018ad52aSplunky static void print_mas_types(sdp_data_t *);
120d82c7103Splunky static void print_map_features(sdp_data_t *);
121d82c7103Splunky static void print_pse_repositories(sdp_data_t *);
122d82c7103Splunky static void print_pse_features(sdp_data_t *);
123d82c7103Splunky static void print_hdp_features(sdp_data_t *);
124d82c7103Splunky static void print_hdp_specification(sdp_data_t *);
125d82c7103Splunky static void print_mcap_procedures(sdp_data_t *);
126c7407d62Splunky static void print_character_repertoires(sdp_data_t *);
12712d25979Splunky static void print_bip_capabilities(sdp_data_t *);
12812d25979Splunky static void print_bip_features(sdp_data_t *);
12912d25979Splunky static void print_bip_functions(sdp_data_t *);
13012d25979Splunky static void print_bip_capacity(sdp_data_t *);
131f88159b8Splunky static void print_1284id(sdp_data_t *);
132d82c7103Splunky static void print_ctn_features(sdp_data_t *);
133384153c1Splunky 
134384153c1Splunky static void print_rfcomm(sdp_data_t *);
135d82c7103Splunky static void print_att(sdp_data_t *);
136384153c1Splunky static void print_bnep(sdp_data_t *);
137384153c1Splunky static void print_avctp(sdp_data_t *);
138384153c1Splunky static void print_avdtp(sdp_data_t *);
139384153c1Splunky static void print_l2cap(sdp_data_t *);
140384153c1Splunky 
141384153c1Splunky attr_t protocol_list[] = {
142384153c1Splunky 	{ 0x0001, "SDP",				NULL },
143384153c1Splunky 	{ 0x0002, "UDP",				NULL },
144384153c1Splunky 	{ 0x0003, "RFCOMM",				print_rfcomm },
145384153c1Splunky 	{ 0x0004, "TCP",				NULL },
146384153c1Splunky 	{ 0x0005, "TCS_BIN",				NULL },
147384153c1Splunky 	{ 0x0006, "TCS_AT",				NULL },
148d82c7103Splunky 	{ 0x0007, "ATT",				print_att },
149384153c1Splunky 	{ 0x0008, "OBEX",				NULL },
150384153c1Splunky 	{ 0x0009, "IP",					NULL },
151384153c1Splunky 	{ 0x000a, "FTP",				NULL },
152384153c1Splunky 	{ 0x000c, "HTTP",				NULL },
153384153c1Splunky 	{ 0x000e, "WSP",				NULL },
154384153c1Splunky 	{ 0x000f, "BNEP",				print_bnep },
155384153c1Splunky 	{ 0x0010, "UPNP",				NULL },
156384153c1Splunky 	{ 0x0011, "HIDP",				NULL },
157384153c1Splunky 	{ 0x0012, "HARDCOPY_CONTROL_CHANNEL",		NULL },
158384153c1Splunky 	{ 0x0014, "HARDCOPY_DATA_CHANNEL",		NULL },
159384153c1Splunky 	{ 0x0016, "HARDCOPY_NOTIFICATION",		NULL },
160384153c1Splunky 	{ 0x0017, "AVCTP",				print_avctp },
161384153c1Splunky 	{ 0x0019, "AVDTP",				print_avdtp },
162384153c1Splunky 	{ 0x001b, "CMTP",				NULL },
163384153c1Splunky 	{ 0x001d, "UDI_C_PLANE",			NULL },
164018ad52aSplunky 	{ 0x001e, "MCAP_CONTROL_CHANNEL",		NULL },
165018ad52aSplunky 	{ 0x001f, "MCAP_DATA_CHANNEL",			NULL },
166384153c1Splunky 	{ 0x0100, "L2CAP",				print_l2cap },
167384153c1Splunky };
168384153c1Splunky 
169384153c1Splunky attr_t universal_attrs[] = {
170384153c1Splunky 	{ 0x0000, "ServiceRecordHandle",		print_uint32x },
171384153c1Splunky 	{ 0x0001, "ServiceClassIDList",			print_service_class_id_list },
172384153c1Splunky 	{ 0x0002, "ServiceRecordState",			print_uint32x },
173384153c1Splunky 	{ 0x0003, "ServiceID",				print_uuid },
174384153c1Splunky 	{ 0x0004, "ProtocolDescriptorList",		print_protocol_descriptor_list },
175384153c1Splunky 	{ 0x0005, "BrowseGroupList",			print_uuid_list },
176384153c1Splunky 	{ 0x0006, "LanguageBaseAttributeIDList",	print_language_base_attribute_id_list },
177384153c1Splunky 	{ 0x0007, "ServiceInfoTimeToLive",		print_uint32d },
178384153c1Splunky 	{ 0x0008, "ServiceAvailability",		print_service_availability },
179384153c1Splunky 	{ 0x0009, "BluetoothProfileDescriptorList",	print_bluetooth_profile_descriptor_list },
180384153c1Splunky 	{ 0x000a, "DocumentationURL",			print_url },
181384153c1Splunky 	{ 0x000b, "ClientExecutableURL",		print_url },
182384153c1Splunky 	{ 0x000c, "IconURL",				print_url },
183384153c1Splunky 	{ 0x000d, "AdditionalProtocolDescriptorLists",	print_additional_protocol_descriptor_lists },
184384153c1Splunky };
185384153c1Splunky 
186384153c1Splunky attr_t language_attrs[] = { /* Language Attribute Offsets */
187384153c1Splunky 	{ 0x0000, "ServiceName",			print_language_string },
188384153c1Splunky 	{ 0x0001, "ServiceDescription",			print_language_string },
189384153c1Splunky 	{ 0x0002, "ProviderName",			print_language_string },
190384153c1Splunky };
191384153c1Splunky 
192384153c1Splunky attr_t sds_attrs[] = {	/* Service Discovery Server */
193384153c1Splunky 	{ 0x0200, "VersionNumberList",			print_sds_version_number_list },
194384153c1Splunky 	{ 0x0201, "ServiceDatabaseState",		print_uint32x },
195384153c1Splunky };
196384153c1Splunky 
197384153c1Splunky attr_t bgd_attrs[] = {	/* Browse Group Descriptor */
198384153c1Splunky 	{ 0x0200, "GroupID",				print_uuid },
199384153c1Splunky };
200384153c1Splunky 
201384153c1Splunky attr_t ct_attrs[] = { /* Cordless Telephony */
202384153c1Splunky 	{ 0x0301, "ExternalNetwork",			print_ct_network },
203384153c1Splunky };
204384153c1Splunky 
205384153c1Splunky attr_t asrc_attrs[] = { /* Audio Source */
206384153c1Splunky 	{ 0x0311, "SupportedFeatures",			print_asrc_features },
207384153c1Splunky };
208384153c1Splunky 
209384153c1Splunky attr_t asink_attrs[] = { /* Audio Sink */
210384153c1Splunky 	{ 0x0311, "SupportedFeatures",			print_asink_features },
211384153c1Splunky };
212384153c1Splunky 
213384153c1Splunky attr_t avrcp_attrs[] = { /* Audio Video Remote Control Profile */
214384153c1Splunky 	{ 0x0311, "SupportedFeatures",			print_avrcp_features },
215384153c1Splunky };
216384153c1Splunky 
217384153c1Splunky attr_t lan_attrs[] = {	/* LAN Access Using PPP */
218384153c1Splunky 	{ 0x0200, "IPSubnet",				print_string },
219384153c1Splunky };
220384153c1Splunky 
221384153c1Splunky attr_t dun_attrs[] = {	/* Dialup Networking */
222384153c1Splunky 	{ 0x0305, "AudioFeedbackSupport",		print_bool },
223384153c1Splunky };
224384153c1Splunky 
225384153c1Splunky attr_t irmc_sync_attrs[] = { /* IrMC Sync */
226384153c1Splunky 	{ 0x0301, "SupportedDataStoresList",		print_supported_data_stores },
227384153c1Splunky };
228384153c1Splunky 
229384153c1Splunky attr_t opush_attrs[] = { /* Object Push */
230d82c7103Splunky 	{ 0x0200, "GeopL2capPSM",			print_uint16x },
231384153c1Splunky 	{ 0x0303, "SupportedFormatsList",		print_supported_formats },
232384153c1Splunky };
233384153c1Splunky 
234d82c7103Splunky attr_t ft_attrs[] = { /* File Transfer */
235d82c7103Splunky 	{ 0x0200, "GeopL2capPSM",			print_uint16x },
236d82c7103Splunky };
237d82c7103Splunky 
238384153c1Splunky attr_t hset_attrs[] = {	/* Headset */
239384153c1Splunky 	{ 0x0302, "RemoteAudioVolumeControl",		print_bool },
240384153c1Splunky };
241384153c1Splunky 
242384153c1Splunky attr_t fax_attrs[] = {	/* Fax */
243384153c1Splunky 	{ 0x0302, "FAXClass1",				print_bool },
244384153c1Splunky 	{ 0x0303, "FAXClass2.0",			print_bool },
245384153c1Splunky 	{ 0x0304, "FAXClass2",				print_bool },
246384153c1Splunky 	{ 0x0305, "AudioFeedbackSupport",		print_bool },
247384153c1Splunky };
248384153c1Splunky 
249d82c7103Splunky attr_t wap_attrs[] = {	/* WAP Bearer */
250d82c7103Splunky 	{ 0x0306, "NetworkAddress",			print_wap_addr },
251d82c7103Splunky 	{ 0x0307, "WAPGateway",				print_wap_gateway },
252d82c7103Splunky 	{ 0x0308, "HomePageURL",			print_url },
253d82c7103Splunky 	{ 0x0309, "WAPStackType",			print_wap_type },
254d82c7103Splunky };
255d82c7103Splunky 
256384153c1Splunky attr_t panu_attrs[] = {	/* Personal Area Networking User */
257d82c7103Splunky 	{ 0x0200, "IpSubnet",				print_string },
258384153c1Splunky 	{ 0x030a, "SecurityDescription",		print_security_description },
259384153c1Splunky };
260384153c1Splunky 
261384153c1Splunky attr_t nap_attrs[] = {	/* Network Access Point */
262d82c7103Splunky 	{ 0x0200, "IpSubnet",				print_string },
263384153c1Splunky 	{ 0x030a, "SecurityDescription",		print_security_description },
264384153c1Splunky 	{ 0x030b, "NetAccessType",			print_net_access_type },
265384153c1Splunky 	{ 0x030c, "MaxNetAccessRate",			print_uint32d },
266384153c1Splunky 	{ 0x030d, "IPv4Subnet",				print_string },
267384153c1Splunky 	{ 0x030e, "IPv6Subnet",				print_string },
268384153c1Splunky };
269384153c1Splunky 
270384153c1Splunky attr_t gn_attrs[] = {	/* Group Network */
271d82c7103Splunky 	{ 0x0200, "IpSubnet",				print_string },
272384153c1Splunky 	{ 0x030a, "SecurityDescription",		print_security_description },
273384153c1Splunky 	{ 0x030d, "IPv4Subnet",				print_string },
274384153c1Splunky 	{ 0x030e, "IPv6Subnet",				print_string },
275384153c1Splunky };
276384153c1Splunky 
277c7407d62Splunky attr_t bp_attrs[] = {	/* Basic Printing */
2789a6467a3Splunky 	{ 0x0350, "DocumentFormatsSupported",		print_string_list },
279c7407d62Splunky 	{ 0x0352, "CharacterRepertoiresSupported",	print_character_repertoires },
2809a6467a3Splunky 	{ 0x0354, "XHTML-PrintImageFormatsSupported",	print_string_list },
281c7407d62Splunky 	{ 0x0356, "ColorSupported",			print_bool },
282f88159b8Splunky 	{ 0x0358, "1284ID",				print_1284id },
283a54eea1cSplunky 	{ 0x035a, "PrinterName",			print_utf8_string },
284a54eea1cSplunky 	{ 0x035c, "PrinterLocation",			print_utf8_string },
285c7407d62Splunky 	{ 0x035e, "DuplexSupported",			print_bool },
2869a6467a3Splunky 	{ 0x0360, "MediaTypesSupported",		print_string_list },
287c7407d62Splunky 	{ 0x0362, "MaxMediaWidth",			print_uint16d },
288c7407d62Splunky 	{ 0x0364, "MaxMediaLength",			print_uint16d },
289c7407d62Splunky 	{ 0x0366, "EnhancedLayoutSupport",		print_bool },
2909a6467a3Splunky 	{ 0x0368, "RUIFormatsSupported",		print_string_list },
291c7407d62Splunky 	{ 0x0370, "ReferencePrintingRUISupported",	print_bool },
292c7407d62Splunky 	{ 0x0372, "DirectPrintingRUISupported",		print_bool },
293c7407d62Splunky 	{ 0x0374, "ReferencePrintingTopURL",		print_url },
294c7407d62Splunky 	{ 0x0376, "DirectPrintingTopURL",		print_url },
295a54eea1cSplunky 	{ 0x037a, "DeviceName",				print_utf8_string },
296c7407d62Splunky };
297c7407d62Splunky 
29812d25979Splunky attr_t bi_attrs[] = {	/* Basic Imaging */
299d82c7103Splunky 	{ 0x0200, "GeopL2capPSM",			print_uint16x },
30012d25979Splunky 	{ 0x0310, "SupportedCapabilities",		print_bip_capabilities },
30112d25979Splunky 	{ 0x0311, "SupportedFeatures",			print_bip_features },
30212d25979Splunky 	{ 0x0312, "SupportedFunctions",			print_bip_functions },
30312d25979Splunky 	{ 0x0313, "TotalImagingDataCapacity",		print_bip_capacity },
30412d25979Splunky };
30512d25979Splunky 
306384153c1Splunky attr_t hf_attrs[] = {	/* Handsfree */
307384153c1Splunky 	{ 0x0311, "SupportedFeatures",			print_hf_features },
308384153c1Splunky };
309384153c1Splunky 
310384153c1Splunky attr_t hfag_attrs[] = {	/* Handsfree Audio Gateway */
311384153c1Splunky 	{ 0x0301, "Network",				print_hfag_network },
312384153c1Splunky 	{ 0x0311, "SupportedFeatures",			print_hfag_features },
313384153c1Splunky };
314384153c1Splunky 
315c7407d62Splunky attr_t rui_attrs[] = {	/* Reflected User Interface */
3169a6467a3Splunky 	{ 0x0368, "RUIFormatsSupported",		print_string_list },
317c7407d62Splunky 	{ 0x0378, "PrinterAdminRUITopURL",		print_url },
318c7407d62Splunky };
319c7407d62Splunky 
320384153c1Splunky attr_t hid_attrs[] = {	/* Human Interface Device */
321384153c1Splunky 	{ 0x0200, "HIDDeviceReleaseNumber",		print_hid_version },
322384153c1Splunky 	{ 0x0201, "HIDParserVersion",			print_hid_version },
323384153c1Splunky 	{ 0x0202, "HIDDeviceSubClass",			print_hid_device_subclass },
324384153c1Splunky 	{ 0x0203, "HIDCountryCode",			print_uint8x },
325384153c1Splunky 	{ 0x0204, "HIDVirtualCable",			print_bool },
326384153c1Splunky 	{ 0x0205, "HIDReconnectInitiate",		print_bool },
327384153c1Splunky 	{ 0x0206, "HIDDescriptorList",			print_hid_descriptor_list },
328e8fd30ebSplunky 	{ 0x0207, "HIDLANGIDBaseList",			print_hid_langid_base_list },
329384153c1Splunky 	{ 0x0208, "HIDSDPDisable",			print_bool },
330384153c1Splunky 	{ 0x0209, "HIDBatteryPower",			print_bool },
331384153c1Splunky 	{ 0x020a, "HIDRemoteWake",			print_bool },
332384153c1Splunky 	{ 0x020b, "HIDProfileVersion",			print_profile_version },
333384153c1Splunky 	{ 0x020c, "HIDSupervisionTimeout",		print_uint16d },
334384153c1Splunky 	{ 0x020d, "HIDNormallyConnectable",		print_bool },
335384153c1Splunky 	{ 0x020e, "HIDBootDevice",			print_bool },
336d82c7103Splunky 	{ 0x020f, "HIDHostMaxLatency",			print_uint16d },
337d82c7103Splunky 	{ 0x0210, "HIDHostMinTimeout",			print_uint16d },
338384153c1Splunky };
339384153c1Splunky 
34010d720dbSplunky attr_t hcr_attrs[] = {	/* Hardcopy Cable Replacement */
341f88159b8Splunky 	{ 0x0300, "1284ID",				print_1284id },
342a54eea1cSplunky 	{ 0x0302, "DeviceName",				print_utf8_string },
343a54eea1cSplunky 	{ 0x0304, "FriendlyName",			print_utf8_string },
344a54eea1cSplunky 	{ 0x0306, "DeviceLocation",			print_utf8_string },
34510d720dbSplunky };
34610d720dbSplunky 
347d82c7103Splunky attr_t mps_attrs[] = {	/* Multi-Profile Specification */
348d82c7103Splunky 	{ 0x0200, "SingleDeviceSupportedScenarios",	NULL },
349d82c7103Splunky 	{ 0x0201, "MultiDeviceSupportedScenarios",	NULL },
350d82c7103Splunky 	{ 0x0202, "SupportedProfileAndProtocolDependencies", print_uint16x },
351d82c7103Splunky };
352d82c7103Splunky 
353d82c7103Splunky attr_t cas_attrs[] = { /* Calendar, Tasks & Notes Access */
354d82c7103Splunky 	{ 0x0315, "InstanceID",				print_uint8d },
355d82c7103Splunky 	{ 0x0317, "SupportedFeatures",			print_ctn_features },
356d82c7103Splunky };
357d82c7103Splunky 
358d82c7103Splunky attr_t cns_attrs[] = { /* Calendar, Tasks & Notes Notification */
359d82c7103Splunky 	{ 0x0317, "SupportedFeatures",			print_ctn_features },
360d82c7103Splunky };
361d82c7103Splunky 
362447afe8dSplunky attr_t pnp_attrs[] = {	/* Device ID */
363447afe8dSplunky 	{ 0x0200, "SpecificationID",			print_profile_version },
364447afe8dSplunky 	{ 0x0201, "VendorID",				print_uint16x },
365447afe8dSplunky 	{ 0x0202, "ProductID",				print_uint16x },
366447afe8dSplunky 	{ 0x0203, "Version",				print_hid_version },
367447afe8dSplunky 	{ 0x0204, "PrimaryRecord",			print_bool },
368447afe8dSplunky 	{ 0x0205, "VendorIDSource",			print_pnp_source },
369447afe8dSplunky };
370447afe8dSplunky 
371018ad52aSplunky attr_t mas_attrs[] = {	/* Message Access Server */
372d82c7103Splunky 	{ 0x0200, "GeopL2capPSM",			print_uint16x },
373018ad52aSplunky 	{ 0x0315, "InstanceID",				print_uint8d },
374018ad52aSplunky 	{ 0x0316, "SupportedMessageTypes",		print_mas_types },
375d82c7103Splunky 	{ 0x0317, "SupportedFeatures",			print_map_features },
376d82c7103Splunky };
377d82c7103Splunky 
378d82c7103Splunky attr_t mns_attrs[] = {	/* Message Notification Server */
379d82c7103Splunky 	{ 0x0200, "GeopL2capPSM",			print_uint16x },
380d82c7103Splunky 	{ 0x0317, "SupportedFeatures",			print_map_features },
381d82c7103Splunky };
382d82c7103Splunky 
383d82c7103Splunky attr_t gnss_attrs[] = {	/* Global Navigation Satellite System Server */
384d82c7103Splunky 	{ 0x0200, "SupportedFeatures",			print_uint16x },
385018ad52aSplunky };
386018ad52aSplunky 
38746834460Splunky attr_t pse_attrs[] = {	/* Phonebook Access Server */
388d82c7103Splunky 	{ 0x0200, "GeopL2capPSM",			print_uint16x },
389d82c7103Splunky 	{ 0x0314, "SupportedRepositories",		print_pse_repositories },
390d82c7103Splunky 	{ 0x0317, "SupportedFeatures",			print_pse_features },
391d82c7103Splunky };
392d82c7103Splunky 
393d82c7103Splunky attr_t hdp_attrs[] = {	/* Health Device Profile */
394d82c7103Splunky 	{ 0x0200, "SupportedFeaturesList",		print_hdp_features },
395d82c7103Splunky 	{ 0x0301, "DataExchangeSpecification",		print_hdp_specification },
396d82c7103Splunky 	{ 0x0302, "MCAPSupportedProcedures",		print_mcap_procedures },
39746834460Splunky };
39846834460Splunky 
399384153c1Splunky #define A(a)	a, __arraycount(a)
400384153c1Splunky service_t service_list[] = {
401384153c1Splunky 	{ 0x1000, "Service Discovery Server",		A(sds_attrs) },
402384153c1Splunky 	{ 0x1001, "Browse Group Descriptor",		A(bgd_attrs) },
403384153c1Splunky 	{ 0x1002, "Public Browse Root",			NULL, 0 },
404384153c1Splunky 	{ 0x1101, "Serial Port",			NULL, 0 },
405384153c1Splunky 	{ 0x1102, "LAN Access Using PPP",		A(lan_attrs) },
406384153c1Splunky 	{ 0x1103, "Dialup Networking",			A(dun_attrs) },
407384153c1Splunky 	{ 0x1104, "IrMC Sync",				A(irmc_sync_attrs) },
408384153c1Splunky 	{ 0x1105, "Object Push",			A(opush_attrs) },
409d82c7103Splunky 	{ 0x1106, "File Transfer",			A(ft_attrs) },
410384153c1Splunky 	{ 0x1107, "IrMC Sync Command",			NULL, 0 },
411384153c1Splunky 	{ 0x1108, "Headset",				A(hset_attrs) },
412384153c1Splunky 	{ 0x1109, "Cordless Telephony",			A(ct_attrs) },
413384153c1Splunky 	{ 0x110a, "Audio Source",			A(asrc_attrs) },
414384153c1Splunky 	{ 0x110b, "Audio Sink",				A(asink_attrs) },
415384153c1Splunky 	{ 0x110c, "A/V Remote Control Target",		A(avrcp_attrs) },
416384153c1Splunky 	{ 0x110d, "Advanced Audio Distribution",	NULL, 0 },
417384153c1Splunky 	{ 0x110e, "A/V Remote Control",			A(avrcp_attrs) },
418384153c1Splunky 	{ 0x110f, "Video Conferencing",			NULL, 0 },
419384153c1Splunky 	{ 0x1110, "Intercom",				NULL, 0 },
420384153c1Splunky 	{ 0x1111, "Fax",				A(fax_attrs) },
421384153c1Splunky 	{ 0x1112, "Headset Audio Gateway",		NULL, 0 },
422d82c7103Splunky 	{ 0x1113, "WAP",				A(wap_attrs) },
423384153c1Splunky 	{ 0x1114, "WAP Client",				NULL, 0 },
424384153c1Splunky 	{ 0x1115, "Personal Area Networking User",	A(panu_attrs) },
425384153c1Splunky 	{ 0x1116, "Network Access Point",		A(nap_attrs) },
426384153c1Splunky 	{ 0x1117, "Group Network",			A(gn_attrs) },
427b0e371d8Splunky 	{ 0x1118, "Direct Printing",			A(bp_attrs) },
428c7407d62Splunky 	{ 0x1119, "Reference Printing",			A(bp_attrs) },
429384153c1Splunky 	{ 0x111a, "Imaging",				NULL, 0 },
43012d25979Splunky 	{ 0x111b, "Imaging Responder",			A(bi_attrs) },
43112d25979Splunky 	{ 0x111c, "Imaging Automatic Archive",		A(bi_attrs) },
43212d25979Splunky 	{ 0x111d, "Imaging Referenced Objects",		A(bi_attrs) },
433384153c1Splunky 	{ 0x111e, "Handsfree",				A(hf_attrs) },
434384153c1Splunky 	{ 0x111f, "Handsfree Audio Gateway",		A(hfag_attrs) },
435384153c1Splunky 	{ 0x1120, "Direct Printing Reference Objects",	NULL, 0 },
436c7407d62Splunky 	{ 0x1121, "Reflected User Interface",		A(rui_attrs) },
437384153c1Splunky 	{ 0x1122, "Basic Printing",			NULL, 0 },
438b0e371d8Splunky 	{ 0x1123, "Printing Status",			A(bp_attrs) },
439384153c1Splunky 	{ 0x1124, "Human Interface Device",		A(hid_attrs) },
440384153c1Splunky 	{ 0x1125, "Hardcopy Cable Replacement",		NULL, 0 },
44110d720dbSplunky 	{ 0x1126, "Hardcopy Cable Replacement Print",	A(hcr_attrs) },
44210d720dbSplunky 	{ 0x1127, "Hardcopy Cable Replacement Scan",	A(hcr_attrs) },
443384153c1Splunky 	{ 0x1128, "Common ISDN Access",			NULL, 0 },
444384153c1Splunky 	{ 0x1129, "Video Conferencing GW",		NULL, 0 },
445384153c1Splunky 	{ 0x112a, "UDI MT",				NULL, 0 },
446384153c1Splunky 	{ 0x112b, "UDI TA",				NULL, 0 },
447384153c1Splunky 	{ 0x112c, "Audio/Video",			NULL, 0 },
448384153c1Splunky 	{ 0x112d, "SIM Access",				NULL, 0 },
44946834460Splunky 	{ 0x112e, "Phonebook Access Client",		NULL, 0 },
45046834460Splunky 	{ 0x112f, "Phonebook Access Server",		A(pse_attrs) },
451018ad52aSplunky 	{ 0x1130, "Phonebook Access",			NULL, 0 },
452018ad52aSplunky 	{ 0x1131, "Headset HS",				NULL, 0 },
453018ad52aSplunky 	{ 0x1132, "Message Access Server",		A(mas_attrs) },
454d82c7103Splunky 	{ 0x1133, "Message Notification Server",	A(mns_attrs) },
455018ad52aSplunky 	{ 0x1134, "Message Access Profile",		NULL, 0 },
456d82c7103Splunky 	{ 0x1135, "Global Navigation Satellite System Profile", NULL, 0 },
457d82c7103Splunky 	{ 0x1136, "Global Navigation Satellite System Server", A(gnss_attrs) },
458d82c7103Splunky 	{ 0x1137, "3D Display",				NULL, 0 },
459d82c7103Splunky 	{ 0x1138, "3D Glasses",				NULL, 0 },
460d82c7103Splunky 	{ 0x1139, "3D Synchronization",			NULL, 0 },
461d82c7103Splunky 	{ 0x113a, "Multi-Profile Specification Profile",NULL, 0 },
462d82c7103Splunky 	{ 0x113b, "Multi-Profile Specification Server", A(mps_attrs) },
463d82c7103Splunky 	{ 0x113c, "Calendar, Tasks & Notes Access",	A(cas_attrs) },
464d82c7103Splunky 	{ 0x113d, "Calendar, Tasks & Notes Notification",A(cns_attrs) },
465d82c7103Splunky 	{ 0x113e, "Calendar, Tasks & Notes Profile",	NULL, 0 },
466447afe8dSplunky 	{ 0x1200, "PNP Information",			A(pnp_attrs) },
467384153c1Splunky 	{ 0x1201, "Generic Networking",			NULL, 0 },
468384153c1Splunky 	{ 0x1202, "Generic File Transfer",		NULL, 0 },
469384153c1Splunky 	{ 0x1203, "Generic Audio",			NULL, 0 },
470384153c1Splunky 	{ 0x1204, "Generic Telephony",			NULL, 0 },
471384153c1Splunky 	{ 0x1205, "UPNP",				NULL, 0 },
472384153c1Splunky 	{ 0x1206, "UPNP IP",				NULL, 0 },
473384153c1Splunky 	{ 0x1300, "UPNP IP PAN",			NULL, 0 },
474384153c1Splunky 	{ 0x1301, "UPNP IP LAP",			NULL, 0 },
475384153c1Splunky 	{ 0x1302, "UPNP IP L2CAP",			NULL, 0 },
476018ad52aSplunky 	{ 0x1303, "Video Source",			NULL, 0 },
477018ad52aSplunky 	{ 0x1304, "Video Sink",				NULL, 0 },
478018ad52aSplunky 	{ 0x1305, "Video Distribution",			NULL, 0 },
479018ad52aSplunky 	{ 0x1400, "HDP",				NULL, 0 },
480d82c7103Splunky 	{ 0x1401, "HDP Source",				A(hdp_attrs) },
481d82c7103Splunky 	{ 0x1402, "HDP Sink",				A(hdp_attrs) },
482d82c7103Splunky 	{ 0x1800, "Generic Access Profile",		NULL, 0 },
483d82c7103Splunky 	{ 0x1801, "Generic Attribute Server",		NULL, 0 },
484384153c1Splunky };
485384153c1Splunky #undef A
486384153c1Splunky 
487384153c1Splunky /* extracted Service Class ID List */
488384153c1Splunky #define MAX_SERVICES		16
489384153c1Splunky static size_t nservices;
490384153c1Splunky static uint16_t service_class[MAX_SERVICES];
491384153c1Splunky 
492384153c1Splunky /* extracted Language Base Attribute ID List */
493384153c1Splunky #define MAX_LANGUAGES		16
494384153c1Splunky static int nlanguages;
495384153c1Splunky static language_t language[MAX_LANGUAGES];
496384153c1Splunky static int current;
497384153c1Splunky 
498384153c1Splunky static bool
sdp_get_uint8(sdp_data_t * d,uint8_t * vp)499384153c1Splunky sdp_get_uint8(sdp_data_t *d, uint8_t *vp)
500384153c1Splunky {
501384153c1Splunky 	uintmax_t v;
502384153c1Splunky 
503384153c1Splunky 	if (sdp_data_type(d) != SDP_DATA_UINT8
504384153c1Splunky 	    || !sdp_get_uint(d, &v))
505384153c1Splunky 		return false;
506384153c1Splunky 
507384153c1Splunky 	*vp = (uint8_t)v;
508384153c1Splunky 	return true;
509384153c1Splunky }
510384153c1Splunky 
511384153c1Splunky static bool
sdp_get_uint16(sdp_data_t * d,uint16_t * vp)512384153c1Splunky sdp_get_uint16(sdp_data_t *d, uint16_t *vp)
513384153c1Splunky {
514384153c1Splunky 	uintmax_t v;
515384153c1Splunky 
516384153c1Splunky 	if (sdp_data_type(d) != SDP_DATA_UINT16
517384153c1Splunky 	    || !sdp_get_uint(d, &v))
518384153c1Splunky 		return false;
519384153c1Splunky 
520384153c1Splunky 	*vp = (uint16_t)v;
521384153c1Splunky 	return true;
522384153c1Splunky }
523384153c1Splunky 
524384153c1Splunky static bool
sdp_get_uint32(sdp_data_t * d,uint32_t * vp)525384153c1Splunky sdp_get_uint32(sdp_data_t *d, uint32_t *vp)
526384153c1Splunky {
527384153c1Splunky 	uintmax_t v;
528384153c1Splunky 
529384153c1Splunky 	if (sdp_data_type(d) != SDP_DATA_UINT32
530384153c1Splunky 	    || !sdp_get_uint(d, &v))
531384153c1Splunky 		return false;
532384153c1Splunky 
533384153c1Splunky 	*vp = (uint32_t)v;
534384153c1Splunky 	return true;
535384153c1Splunky }
536384153c1Splunky 
53712d25979Splunky static bool
sdp_get_uint64(sdp_data_t * d,uint64_t * vp)53812d25979Splunky sdp_get_uint64(sdp_data_t *d, uint64_t *vp)
53912d25979Splunky {
54012d25979Splunky 	uintmax_t v;
54112d25979Splunky 
54212d25979Splunky 	if (sdp_data_type(d) != SDP_DATA_UINT64
54312d25979Splunky 	    || !sdp_get_uint(d, &v))
54412d25979Splunky 		return false;
54512d25979Splunky 
54612d25979Splunky 	*vp = (uint64_t)v;
54712d25979Splunky 	return true;
54812d25979Splunky }
54912d25979Splunky 
550384153c1Splunky void
print_record(sdp_data_t * rec)551384153c1Splunky print_record(sdp_data_t *rec)
552384153c1Splunky {
553384153c1Splunky 	sdp_data_t value;
554384153c1Splunky 	uint16_t id;
555384153c1Splunky 
556384153c1Splunky 	nservices = 0;
557384153c1Splunky 	nlanguages = 0;
558384153c1Splunky 	current = -1;
559384153c1Splunky 
560384153c1Splunky 	while (sdp_get_attr(rec, &id, &value)) {
561384153c1Splunky 		if (Xflag) {
562384153c1Splunky 			printf("AttributeID 0x%04x:\n", id);
5632424b4a6Splunky 			print_hexdump("     ", value.next,
5642424b4a6Splunky 			    (size_t)(value.end - value.next));
565384153c1Splunky 		} else if (Rflag) {
566384153c1Splunky 			printf("AttributeID 0x%04x:\n", id);
567384153c1Splunky 			sdp_data_print(&value, 4);
568384153c1Splunky 		} else if (print_universal_attribute(id, &value)
569384153c1Splunky 		    || print_language_attribute(id, &value)
570384153c1Splunky 		    || print_service_attribute(id, &value)) {
571384153c1Splunky 			if (value.next != value.end)
572384153c1Splunky 			    printf("    [additional data ignored]\n");
573384153c1Splunky 		} else {
574384153c1Splunky 			printf("AttributeID 0x%04x:\n", id);
575384153c1Splunky 			sdp_data_print(&value, 4);
576384153c1Splunky 		}
577384153c1Splunky 	}
578384153c1Splunky }
579384153c1Splunky 
580384153c1Splunky static const char *
string_uuid(uuid_t * uuid)581384153c1Splunky string_uuid(uuid_t *uuid)
582384153c1Splunky {
583384153c1Splunky 	static char buf[64];
584384153c1Splunky 	const char *desc;
585384153c1Splunky 	uuid_t u;
586384153c1Splunky 	size_t i;
587384153c1Splunky 
588384153c1Splunky 	u = *uuid;
589384153c1Splunky 	u.time_low = 0;
590384153c1Splunky 	if (!uuid_equal(&u, &BLUETOOTH_BASE_UUID, NULL)) {
591384153c1Splunky 		snprintf(buf, sizeof(buf),
592384153c1Splunky 		    "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
593384153c1Splunky 		    uuid->time_low, uuid->time_mid, uuid->time_hi_and_version,
594384153c1Splunky 		    uuid->clock_seq_hi_and_reserved, uuid->clock_seq_low,
595384153c1Splunky 		    uuid->node[0], uuid->node[1], uuid->node[2],
596384153c1Splunky 		    uuid->node[3], uuid->node[4], uuid->node[5]);
597384153c1Splunky 
598384153c1Splunky 		return buf;
599384153c1Splunky 	}
600384153c1Splunky 
601384153c1Splunky 	desc = NULL;
602384153c1Splunky 	for (i = 0; i < __arraycount(service_list); i++) {
603384153c1Splunky 		if (uuid->time_low == service_list[i].class) {
604384153c1Splunky 			desc = service_list[i].desc;
605384153c1Splunky 			break;
606384153c1Splunky 		}
607384153c1Splunky 	}
608384153c1Splunky 
609384153c1Splunky 	for (i = 0; i < __arraycount(protocol_list); i++) {
610384153c1Splunky 		if (uuid->time_low == protocol_list[i].id) {
611384153c1Splunky 			desc = protocol_list[i].desc;
612384153c1Splunky 			break;
613384153c1Splunky 		}
614384153c1Splunky 	}
615384153c1Splunky 
616384153c1Splunky 	if (!Nflag && desc) {
617384153c1Splunky 		snprintf(buf, sizeof(buf), "%s", desc);
618384153c1Splunky 		return buf;
619384153c1Splunky 	}
620384153c1Splunky 
621384153c1Splunky 	snprintf(buf, sizeof(buf), "%s%s(0x%*.*x)",
622384153c1Splunky 	    (desc == NULL ? "" : desc),
623384153c1Splunky 	    (desc == NULL ? "" : " "),
624384153c1Splunky 	    (uuid->time_low > UINT16_MAX ? 8 : 4),
625384153c1Splunky 	    (uuid->time_low > UINT16_MAX ? 8 : 4),
626384153c1Splunky 	    uuid->time_low);
627384153c1Splunky 
628384153c1Splunky 	return buf;
629384153c1Splunky }
630384153c1Splunky 
631384153c1Splunky static const char *
string_vis(const char * src,size_t len)6321803dc4bSplunky string_vis(const char *src, size_t len)
633384153c1Splunky {
634384153c1Splunky 	static char buf[50];
635384153c1Splunky 	char *dst = buf;
6361803dc4bSplunky 	int style;
637384153c1Splunky 
638cc676302Splunky 	buf[0] = '\0';
6391803dc4bSplunky 	style = VIS_CSTYLE | VIS_NL;
640384153c1Splunky 	while (len > 0 && (dst + 5) < (buf + sizeof(buf))) {
641384153c1Splunky 		dst = vis(dst, src[0], style, (len > 1 ? src[1] : 0));
642384153c1Splunky 		src++;
643384153c1Splunky 		len--;
644384153c1Splunky 	}
645384153c1Splunky 
646384153c1Splunky 	return buf;
647384153c1Splunky }
648384153c1Splunky 
649384153c1Splunky static void
print_hexdump(const char * title,const uint8_t * data,size_t len)650384153c1Splunky print_hexdump(const char *title, const uint8_t *data, size_t len)
651384153c1Splunky {
652384153c1Splunky 	int n, i;
653384153c1Splunky 
654384153c1Splunky 	i = 0;
655384153c1Splunky 	n = printf("%s", title);
656384153c1Splunky 
657384153c1Splunky 	while (len-- > 0) {
658384153c1Splunky 		if (++i > 8) {
659384153c1Splunky 			printf("\n%*s", n, "");
660384153c1Splunky 			i = 1;
661384153c1Splunky 		}
662384153c1Splunky 
663384153c1Splunky 		printf(" 0x%02x", *data++);
664384153c1Splunky 	}
665384153c1Splunky 
666384153c1Splunky 	printf("\n");
667384153c1Splunky }
668384153c1Splunky 
669384153c1Splunky static bool
print_attribute(uint16_t id,sdp_data_t * value,attr_t * attr,size_t count)6702424b4a6Splunky print_attribute(uint16_t id, sdp_data_t *value, attr_t *attr, size_t count)
671384153c1Splunky {
6722424b4a6Splunky 	size_t i;
673384153c1Splunky 
674384153c1Splunky 	for (i = 0; i < count; i++) {
675384153c1Splunky 		if (id == attr[i].id) {
676384153c1Splunky 			printf("%s", attr[i].desc);
677384153c1Splunky 
678384153c1Splunky 			if (Nflag) {
679384153c1Splunky 				printf(" (");
680384153c1Splunky 
681384153c1Splunky 				if (current != -1)
682384153c1Splunky 					printf("0x%04x + ", language[current].base);
683384153c1Splunky 
684384153c1Splunky 				printf("0x%04x)", id);
685384153c1Splunky 			}
686384153c1Splunky 
687384153c1Splunky 			printf(": ");
688384153c1Splunky 
689384153c1Splunky 			if (attr[i].print == NULL) {
690384153c1Splunky 				printf("\n");
691384153c1Splunky 				sdp_data_print(value, 4);
692384153c1Splunky 				value->next = value->end;
693384153c1Splunky 			} else {
694384153c1Splunky 				(attr[i].print)(value);
695384153c1Splunky 			}
696384153c1Splunky 
697384153c1Splunky 			return true;
698384153c1Splunky 		}
699384153c1Splunky 	}
700384153c1Splunky 
701384153c1Splunky 	return false;
702384153c1Splunky }
703384153c1Splunky 
704384153c1Splunky static bool
print_universal_attribute(uint16_t id,sdp_data_t * value)705384153c1Splunky print_universal_attribute(uint16_t id, sdp_data_t *value)
706384153c1Splunky {
707384153c1Splunky 
708384153c1Splunky 	return print_attribute(id, value,
709384153c1Splunky 	    universal_attrs, __arraycount(universal_attrs));
710384153c1Splunky }
711384153c1Splunky 
712384153c1Splunky static bool
print_language_attribute(uint16_t id,sdp_data_t * value)713384153c1Splunky print_language_attribute(uint16_t id, sdp_data_t *value)
714384153c1Splunky {
715384153c1Splunky 	bool done = false;
716384153c1Splunky 
717384153c1Splunky 	for (current = 0; current < nlanguages && !done; current++)
718384153c1Splunky 		done = print_attribute(id - language[current].base, value,
719384153c1Splunky 		    language_attrs, __arraycount(language_attrs));
720384153c1Splunky 
721384153c1Splunky 	current = -1;
722384153c1Splunky 	return done;
723384153c1Splunky }
724384153c1Splunky 
725384153c1Splunky static bool
print_service_attribute(uint16_t id,sdp_data_t * value)726384153c1Splunky print_service_attribute(uint16_t id, sdp_data_t *value)
727384153c1Splunky {
728384153c1Splunky 	size_t i, j;
729384153c1Splunky 
730384153c1Splunky 	for (i = 0; i < nservices; i++) {
731384153c1Splunky 		for (j = 0; j < __arraycount(service_list); j++) {
73245c72a01Splunky 			if (service_class[i] == service_list[j].class
73345c72a01Splunky 			    && print_attribute(id, value,
73445c72a01Splunky 			    service_list[j].attrs, service_list[j].nattr))
73545c72a01Splunky 				return true;
736384153c1Splunky 		}
737384153c1Splunky 	}
738384153c1Splunky 
739384153c1Splunky 	return false;
740384153c1Splunky }
741384153c1Splunky 
742384153c1Splunky static void
print_bool(sdp_data_t * data)743384153c1Splunky print_bool(sdp_data_t *data)
744384153c1Splunky {
745384153c1Splunky 	bool v;
746384153c1Splunky 
747384153c1Splunky 	if (!sdp_get_bool(data, &v))
748384153c1Splunky 		return;
749384153c1Splunky 
750384153c1Splunky 	printf("%s\n", (v ? "true" : "false"));
751384153c1Splunky }
752384153c1Splunky 
753384153c1Splunky static void
print_uint8d(sdp_data_t * data)754018ad52aSplunky print_uint8d(sdp_data_t *data)
755018ad52aSplunky {
756018ad52aSplunky 	uint8_t v;
757018ad52aSplunky 
758018ad52aSplunky 	if (!sdp_get_uint8(data, &v))
759018ad52aSplunky 		return;
760018ad52aSplunky 
761018ad52aSplunky 	printf("%d\n", v);
762018ad52aSplunky }
763018ad52aSplunky 
764018ad52aSplunky static void
print_uint8x(sdp_data_t * data)765384153c1Splunky print_uint8x(sdp_data_t *data)
766384153c1Splunky {
767384153c1Splunky 	uint8_t v;
768384153c1Splunky 
769384153c1Splunky 	if (!sdp_get_uint8(data, &v))
770384153c1Splunky 		return;
771384153c1Splunky 
772384153c1Splunky 	printf("0x%02x\n", v);
773384153c1Splunky }
774384153c1Splunky 
775384153c1Splunky static void
print_uint16d(sdp_data_t * data)776384153c1Splunky print_uint16d(sdp_data_t *data)
777384153c1Splunky {
778384153c1Splunky 	uint16_t v;
779384153c1Splunky 
780384153c1Splunky 	if (!sdp_get_uint16(data, &v))
781384153c1Splunky 		return;
782384153c1Splunky 
783384153c1Splunky 	printf("%d\n", v);
784384153c1Splunky }
785384153c1Splunky 
786384153c1Splunky static void
print_uint16x(sdp_data_t * data)787447afe8dSplunky print_uint16x(sdp_data_t *data)
788447afe8dSplunky {
789447afe8dSplunky 	uint16_t v;
790447afe8dSplunky 
791447afe8dSplunky 	if (!sdp_get_uint16(data, &v))
792447afe8dSplunky 		return;
793447afe8dSplunky 
794447afe8dSplunky 	printf("0x%04x\n", v);
795447afe8dSplunky }
796447afe8dSplunky 
797447afe8dSplunky static void
print_uint32x(sdp_data_t * data)798384153c1Splunky print_uint32x(sdp_data_t *data)
799384153c1Splunky {
800384153c1Splunky 	uint32_t v;
801384153c1Splunky 
802384153c1Splunky 	if (!sdp_get_uint32(data, &v))
803384153c1Splunky 		return;
804384153c1Splunky 
805384153c1Splunky 	printf("0x%08x\n", v);
806384153c1Splunky }
807384153c1Splunky 
808384153c1Splunky static void
print_uint32d(sdp_data_t * data)809384153c1Splunky print_uint32d(sdp_data_t *data)
810384153c1Splunky {
811384153c1Splunky 	uint32_t v;
812384153c1Splunky 
813384153c1Splunky 	if (!sdp_get_uint32(data, &v))
814384153c1Splunky 		return;
815384153c1Splunky 
816384153c1Splunky 	printf("%d\n", v);
817384153c1Splunky }
818384153c1Splunky 
819384153c1Splunky static void
print_uuid(sdp_data_t * data)820384153c1Splunky print_uuid(sdp_data_t *data)
821384153c1Splunky {
822384153c1Splunky 	uuid_t uuid;
823384153c1Splunky 
824384153c1Splunky 	if (!sdp_get_uuid(data, &uuid))
825384153c1Splunky 		return;
826384153c1Splunky 
827384153c1Splunky 	printf("%s\n", string_uuid(&uuid));
828384153c1Splunky }
829384153c1Splunky 
830384153c1Splunky static void
print_uuid_list(sdp_data_t * data)831384153c1Splunky print_uuid_list(sdp_data_t *data)
832384153c1Splunky {
833384153c1Splunky 	sdp_data_t seq;
834384153c1Splunky 	uuid_t uuid;
835384153c1Splunky 
836384153c1Splunky 	if (!sdp_get_seq(data, &seq))
837384153c1Splunky 		return;
838384153c1Splunky 
839384153c1Splunky 	printf("\n");
840384153c1Splunky 	while (sdp_get_uuid(&seq, &uuid))
841384153c1Splunky 		printf("    %s\n", string_uuid(&uuid));
842384153c1Splunky 
843384153c1Splunky 	if (seq.next != seq.end)
844384153c1Splunky 		printf("    [additional data]\n");
845384153c1Splunky }
846384153c1Splunky 
847384153c1Splunky static void
print_string(sdp_data_t * data)848384153c1Splunky print_string(sdp_data_t *data)
849384153c1Splunky {
850384153c1Splunky 	char *str;
851384153c1Splunky 	size_t len;
852384153c1Splunky 
853384153c1Splunky 	if (!sdp_get_str(data, &str, &len))
854384153c1Splunky 		return;
855384153c1Splunky 
8561803dc4bSplunky 	printf("\"%s\"\n", string_vis(str, len));
857384153c1Splunky }
858384153c1Splunky 
859384153c1Splunky static void
print_string_list(sdp_data_t * data)8609a6467a3Splunky print_string_list(sdp_data_t *data)
8619a6467a3Splunky {
8629a6467a3Splunky 	char *str, *ep;
8639a6467a3Splunky 	size_t len, l;
8649a6467a3Splunky 
8659a6467a3Splunky 	if (!sdp_get_str(data, &str, &len))
8669a6467a3Splunky 		return;
8679a6467a3Splunky 
8689a6467a3Splunky 	printf("\n");
8699a6467a3Splunky 	while (len > 0) {
8709a6467a3Splunky 		ep = memchr(str, (int)',', len);
8719a6467a3Splunky 		if (ep == NULL) {
8729a6467a3Splunky 			l = len;
8739a6467a3Splunky 			len = 0;
8749a6467a3Splunky 		} else {
8759a6467a3Splunky 			l = (size_t)(ep - str);
8769a6467a3Splunky 			len -= l + 1;
8779a6467a3Splunky 			ep++;
8789a6467a3Splunky 		}
8791803dc4bSplunky 		printf("    %s\n", string_vis(str, l));
8809a6467a3Splunky 		str = ep;
8819a6467a3Splunky 	}
8829a6467a3Splunky }
8839a6467a3Splunky 
8849a6467a3Splunky static void
print_url(sdp_data_t * data)885384153c1Splunky print_url(sdp_data_t *data)
886384153c1Splunky {
887384153c1Splunky 	char *url;
888384153c1Splunky 	size_t len;
889384153c1Splunky 
890384153c1Splunky 	if (!sdp_get_url(data, &url, &len))
891384153c1Splunky 		return;
892384153c1Splunky 
8931803dc4bSplunky 	printf("\"%s\"\n", string_vis(url, len));
894384153c1Splunky }
895384153c1Splunky 
896384153c1Splunky static void
print_profile_version(sdp_data_t * data)897384153c1Splunky print_profile_version(sdp_data_t *data)
898384153c1Splunky {
899384153c1Splunky 	uint16_t v;
900384153c1Splunky 
901384153c1Splunky 	if (!sdp_get_uint16(data, &v))
902384153c1Splunky 		return;
903384153c1Splunky 
904384153c1Splunky 	printf("v%d.%d\n", (v >> 8), (v & 0xff));
905384153c1Splunky }
906384153c1Splunky 
907a54eea1cSplunky static void
print_codeset_string(const char * src,size_t srclen,const char * codeset)908a54eea1cSplunky print_codeset_string(const char *src, size_t srclen, const char *codeset)
909a54eea1cSplunky {
910a54eea1cSplunky 	char buf[50], *dst;
911a54eea1cSplunky 	iconv_t ih;
9126e28978dSchristos 	size_t dstlen;
913a54eea1cSplunky 
914a54eea1cSplunky 	dst = buf;
915a54eea1cSplunky 	dstlen = sizeof(buf);
916a54eea1cSplunky 
917a54eea1cSplunky 	ih = iconv_open(nl_langinfo(CODESET), codeset);
918a54eea1cSplunky 	if (ih == (iconv_t)-1) {
919a54eea1cSplunky 		printf("Can't convert %s string\n", codeset);
920a54eea1cSplunky 		return;
921a54eea1cSplunky 	}
922a54eea1cSplunky 
92377a1ad5fSkamil 	(void)iconv(ih, __UNCONST(&src), &srclen, &dst, &dstlen);
924a54eea1cSplunky 
925a54eea1cSplunky 	iconv_close(ih);
926a54eea1cSplunky 
927a54eea1cSplunky 	printf("\"%.*s%s\n", (int)(sizeof(buf) - dstlen), buf,
928a54eea1cSplunky 	    (srclen > 0 ? " ..." : "\""));
929a54eea1cSplunky }
930a54eea1cSplunky 
931384153c1Splunky /*
932384153c1Splunky  * This should only be called through print_language_attribute() which
933384153c1Splunky  * sets codeset of the string to be printed.
934384153c1Splunky  */
935384153c1Splunky static void
print_language_string(sdp_data_t * data)936384153c1Splunky print_language_string(sdp_data_t *data)
937384153c1Splunky {
938a54eea1cSplunky 	char *str;
939a54eea1cSplunky 	size_t len;
940384153c1Splunky 
941a54eea1cSplunky 	if (!sdp_get_str(data, &str, &len))
942384153c1Splunky 		return;
943384153c1Splunky 
944a54eea1cSplunky 	print_codeset_string(str, len, language[current].codeset);
945384153c1Splunky }
946384153c1Splunky 
947384153c1Splunky 
948a54eea1cSplunky static void
print_utf8_string(sdp_data_t * data)949a54eea1cSplunky print_utf8_string(sdp_data_t *data)
950a54eea1cSplunky {
951a54eea1cSplunky 	char *str;
952a54eea1cSplunky 	size_t len;
953384153c1Splunky 
954a54eea1cSplunky 	if (!sdp_get_str(data, &str, &len))
955a54eea1cSplunky 		return;
956384153c1Splunky 
957a54eea1cSplunky 	print_codeset_string(str, len, "UTF-8");
958384153c1Splunky }
959384153c1Splunky 
960384153c1Splunky static void
print_service_class_id_list(sdp_data_t * data)961384153c1Splunky print_service_class_id_list(sdp_data_t *data)
962384153c1Splunky {
963384153c1Splunky 	sdp_data_t seq;
964384153c1Splunky 	uuid_t uuid;
965384153c1Splunky 
966384153c1Splunky 	if (!sdp_get_seq(data, &seq))
967384153c1Splunky 		return;
968384153c1Splunky 
969384153c1Splunky 	printf("\n");
970384153c1Splunky 	while (sdp_get_uuid(&seq, &uuid)) {
971384153c1Splunky 		printf("    %s\n", string_uuid(&uuid));
972384153c1Splunky 
973384153c1Splunky 		if (nservices < MAX_SERVICES) {
974384153c1Splunky 			service_class[nservices] = uuid.time_low;
975384153c1Splunky 			uuid.time_low = 0;
976384153c1Splunky 			if (uuid_equal(&uuid, &BLUETOOTH_BASE_UUID, NULL))
977384153c1Splunky 				nservices++;
978384153c1Splunky 		}
979384153c1Splunky 	}
980384153c1Splunky 
981384153c1Splunky 	if (seq.next != seq.end)
982384153c1Splunky 		printf("    [additional data]\n");
983384153c1Splunky }
984384153c1Splunky 
985384153c1Splunky static void
print_protocol_descriptor(sdp_data_t * data)986384153c1Splunky print_protocol_descriptor(sdp_data_t *data)
987384153c1Splunky {
988384153c1Splunky 	uuid_t u0, uuid;
989384153c1Splunky 	size_t i;
990384153c1Splunky 
991384153c1Splunky 	if (!sdp_get_uuid(data, &uuid))
992384153c1Splunky 		return;
993384153c1Splunky 
994384153c1Splunky 	u0 = uuid;
995384153c1Splunky 	u0.time_low = 0;
996384153c1Splunky 	if (uuid_equal(&u0, &BLUETOOTH_BASE_UUID, NULL)) {
997384153c1Splunky 		for (i = 0; i < __arraycount(protocol_list); i++) {
998384153c1Splunky 			if (uuid.time_low == protocol_list[i].id) {
999384153c1Splunky 				printf("    %s", protocol_list[i].desc);
1000384153c1Splunky 
1001384153c1Splunky 				if (Nflag)
1002384153c1Splunky 					printf(" (0x%04x)", protocol_list[i].id);
1003384153c1Splunky 
1004384153c1Splunky 				if (protocol_list[i].print)
1005384153c1Splunky 					(protocol_list[i].print)(data);
1006384153c1Splunky 
1007384153c1Splunky 				if (data->next != data->end)
1008d82c7103Splunky 					printf(" [additional data]");
1009384153c1Splunky 
1010384153c1Splunky 				printf("\n");
1011384153c1Splunky 				return;
1012384153c1Splunky 			}
1013384153c1Splunky 		}
1014384153c1Splunky 	}
1015384153c1Splunky 
1016384153c1Splunky 	printf("    %s\n", string_uuid(&uuid));
1017384153c1Splunky 	sdp_data_print(data, 4);
1018384153c1Splunky 	data->next = data->end;
1019384153c1Splunky }
1020384153c1Splunky 
1021384153c1Splunky static void
print_protocol_descriptor_list(sdp_data_t * data)1022384153c1Splunky print_protocol_descriptor_list(sdp_data_t *data)
1023384153c1Splunky {
1024384153c1Splunky 	sdp_data_t seq, proto;
1025384153c1Splunky 
1026384153c1Splunky 	printf("\n");
1027384153c1Splunky 	sdp_get_alt(data, data);	/* strip [optional] alt header */
1028384153c1Splunky 
1029d82c7103Splunky 	while (sdp_get_seq(data, &seq)) {
1030384153c1Splunky 		while (sdp_get_seq(&seq, &proto))
1031384153c1Splunky 			print_protocol_descriptor(&proto);
1032d82c7103Splunky 
1033d82c7103Splunky 		if (seq.next != seq.end)
1034d82c7103Splunky 			printf("    [additional protocol data]\n");
1035d82c7103Splunky 	}
1036d82c7103Splunky 
1037d82c7103Splunky 	if (data->next != data->end)
1038d82c7103Splunky 		printf("    [additional data]\n");
1039384153c1Splunky }
1040384153c1Splunky 
1041384153c1Splunky static void
print_language_base_attribute_id_list(sdp_data_t * data)1042384153c1Splunky print_language_base_attribute_id_list(sdp_data_t *data)
1043384153c1Splunky {
1044384153c1Splunky 	sdp_data_t list;
1045384153c1Splunky 	uint16_t v;
1046384153c1Splunky 	const char *codeset;
1047384153c1Splunky 	char lang[2];
1048384153c1Splunky 
1049384153c1Splunky 	if (!sdp_get_seq(data, &list))
1050384153c1Splunky 		return;
1051384153c1Splunky 
1052384153c1Splunky 	printf("\n");
1053384153c1Splunky 	while (list.next < list.end) {
1054384153c1Splunky 		/*
1055384153c1Splunky 		 * ISO-639-1 natural language values are published at
1056384153c1Splunky 		 *	http://www.loc.gov/standards/iso639-2/php/code-list.php
1057384153c1Splunky 		 */
1058384153c1Splunky 		if (!sdp_get_uint16(&list, &v))
1059384153c1Splunky 			break;
1060384153c1Splunky 
1061384153c1Splunky 		be16enc(lang, v);
1062*9f6b0b0bSrillig 		if (!islower((unsigned char)lang[0]) ||
1063*9f6b0b0bSrillig 		    !islower((unsigned char)lang[1]))
1064384153c1Splunky 			break;
1065384153c1Splunky 
1066384153c1Splunky 		/*
1067384153c1Splunky 		 * MIBenum values are published at
1068384153c1Splunky 		 *	http://www.iana.org/assignments/character-sets
1069384153c1Splunky 		 */
1070384153c1Splunky 		if (!sdp_get_uint16(&list, &v))
1071384153c1Splunky 			break;
1072384153c1Splunky 
1073384153c1Splunky 		switch(v) {
1074384153c1Splunky 		case 3:		codeset = "US-ASCII";		break;
1075384153c1Splunky 		case 4:		codeset = "ISO-8859-1";		break;
1076384153c1Splunky 		case 5:		codeset = "ISO-8859-2";		break;
1077384153c1Splunky 		case 106:	codeset = "UTF-8";		break;
1078384153c1Splunky 		case 1013:	codeset = "UTF-16BE";		break;
1079384153c1Splunky 		case 1014:	codeset = "UTF-16LE";		break;
1080384153c1Splunky 		default:	codeset = "Unknown";		break;
1081384153c1Splunky 		}
1082384153c1Splunky 
1083384153c1Splunky 		if (!sdp_get_uint16(&list, &v))
1084384153c1Splunky 			break;
1085384153c1Splunky 
1086384153c1Splunky 		printf("    %.2s.%s base 0x%04x\n", lang, codeset, v);
1087384153c1Splunky 
1088384153c1Splunky 		if (nlanguages < MAX_LANGUAGES) {
1089384153c1Splunky 			language[nlanguages].base = v;
1090384153c1Splunky 			language[nlanguages].codeset = codeset;
1091384153c1Splunky 			nlanguages++;
1092384153c1Splunky 		}
1093384153c1Splunky 	}
1094384153c1Splunky 
1095384153c1Splunky 	if (list.next != list.end)
1096384153c1Splunky 		printf("    [additional data]\n");
1097384153c1Splunky }
1098384153c1Splunky 
1099384153c1Splunky static void
print_service_availability(sdp_data_t * data)1100384153c1Splunky print_service_availability(sdp_data_t *data)
1101384153c1Splunky {
1102384153c1Splunky 	uint8_t v;
1103384153c1Splunky 
1104384153c1Splunky 	if (!sdp_get_uint8(data, &v))
1105384153c1Splunky 		return;
1106384153c1Splunky 
1107384153c1Splunky 	printf("%d/%d\n", v, UINT8_MAX);
1108384153c1Splunky }
1109384153c1Splunky 
1110384153c1Splunky static void
print_bluetooth_profile_descriptor_list(sdp_data_t * data)1111384153c1Splunky print_bluetooth_profile_descriptor_list(sdp_data_t *data)
1112384153c1Splunky {
1113384153c1Splunky 	sdp_data_t seq, profile;
1114384153c1Splunky 	uuid_t uuid;
1115384153c1Splunky 	uint16_t v;
1116384153c1Splunky 
1117384153c1Splunky 	if (!sdp_get_seq(data, &seq))
1118384153c1Splunky 		return;
1119384153c1Splunky 
1120384153c1Splunky 	printf("\n");
1121384153c1Splunky 	while (seq.next < seq.end) {
1122384153c1Splunky 		if (!sdp_get_seq(&seq, &profile)
1123384153c1Splunky 		    || !sdp_get_uuid(&profile, &uuid)
1124384153c1Splunky 		    || !sdp_get_uint16(&profile, &v))
1125384153c1Splunky 			break;
1126384153c1Splunky 
1127384153c1Splunky 		printf("    %s, v%d.%d", string_uuid(&uuid),
1128384153c1Splunky 		    (v >> 8), (v & 0xff));
1129384153c1Splunky 
1130384153c1Splunky 		if (profile.next != profile.end)
1131384153c1Splunky 			printf(" [additional profile data]");
1132384153c1Splunky 
1133384153c1Splunky 		printf("\n");
1134384153c1Splunky 	}
1135384153c1Splunky 
1136384153c1Splunky 	if (seq.next != seq.end)
1137384153c1Splunky 		printf("    [additional data]\n");
1138384153c1Splunky }
1139384153c1Splunky 
1140384153c1Splunky static void
print_additional_protocol_descriptor_lists(sdp_data_t * data)1141384153c1Splunky print_additional_protocol_descriptor_lists(sdp_data_t *data)
1142384153c1Splunky {
1143384153c1Splunky 	sdp_data_t seq, stack, proto;
1144384153c1Splunky 
1145384153c1Splunky 	printf("\n");
1146384153c1Splunky 	sdp_get_seq(data, &seq);
1147384153c1Splunky 
1148384153c1Splunky 	while (sdp_get_seq(&seq, &stack))
1149384153c1Splunky 		while (sdp_get_seq(&stack, &proto))
1150384153c1Splunky 			print_protocol_descriptor(&proto);
1151384153c1Splunky 
1152384153c1Splunky 	if (seq.next != seq.end)
1153384153c1Splunky 		printf("    [additional data]\n");
1154384153c1Splunky }
1155384153c1Splunky 
1156384153c1Splunky static void
print_sds_version_number_list(sdp_data_t * data)1157384153c1Splunky print_sds_version_number_list(sdp_data_t *data)
1158384153c1Splunky {
1159384153c1Splunky 	sdp_data_t list;
1160384153c1Splunky 	const char *sep;
1161384153c1Splunky 	uint16_t v;
1162384153c1Splunky 
1163384153c1Splunky 	if (!sdp_get_seq(data, &list))
1164384153c1Splunky 		return;
1165384153c1Splunky 
1166384153c1Splunky 	sep = "";
1167384153c1Splunky 	while (sdp_get_uint16(&list, &v)) {
1168384153c1Splunky 		printf("%sv%d.%d", sep, (v >> 8), (v & 0xff));
1169384153c1Splunky 		sep = ", ";
1170384153c1Splunky 	}
1171384153c1Splunky 
1172384153c1Splunky 	if (list.next != list.end)
1173384153c1Splunky 		printf(" [additional data]");
1174384153c1Splunky 
1175384153c1Splunky 	printf("\n");
1176384153c1Splunky }
1177384153c1Splunky 
1178384153c1Splunky static void
print_ct_network(sdp_data_t * data)1179384153c1Splunky print_ct_network(sdp_data_t *data)
1180384153c1Splunky {
1181384153c1Splunky 	uint8_t v;
1182384153c1Splunky 
1183384153c1Splunky 	if (!sdp_get_uint8(data, &v))
1184384153c1Splunky 		return;
1185384153c1Splunky 
1186384153c1Splunky 	switch (v) {
1187384153c1Splunky 	case 0x01:	printf("PSTN");			break;
1188384153c1Splunky 	case 0x02:	printf("ISDN");			break;
1189384153c1Splunky 	case 0x03:	printf("GSM");			break;
1190384153c1Splunky 	case 0x04:	printf("CDMA");			break;
1191384153c1Splunky 	case 0x05:	printf("Analogue Cellular");	break;
1192384153c1Splunky 	case 0x06:	printf("Packet Switched");	break;
1193384153c1Splunky 	case 0x07:	printf("Other");		break;
1194384153c1Splunky 	default:	printf("0x%02x", v);		break;
1195384153c1Splunky 	}
1196384153c1Splunky 
1197384153c1Splunky 	printf("\n");
1198384153c1Splunky }
1199384153c1Splunky 
1200384153c1Splunky static void
print_asrc_features(sdp_data_t * data)1201384153c1Splunky print_asrc_features(sdp_data_t *data)
1202384153c1Splunky {
1203384153c1Splunky 	uint16_t v;
1204384153c1Splunky 
1205384153c1Splunky 	if (!sdp_get_uint16(data, &v))
1206384153c1Splunky 		return;
1207384153c1Splunky 
1208384153c1Splunky 	if (Nflag)
1209384153c1Splunky 		printf("(0x%04x)", v);
1210384153c1Splunky 
1211384153c1Splunky 	printf("\n");
1212384153c1Splunky 	if (v & (1<<0))	printf("    Player\n");
1213384153c1Splunky 	if (v & (1<<1))	printf("    Microphone\n");
1214384153c1Splunky 	if (v & (1<<2))	printf("    Tuner\n");
1215384153c1Splunky 	if (v & (1<<3))	printf("    Mixer\n");
1216384153c1Splunky }
1217384153c1Splunky 
1218384153c1Splunky static void
print_asink_features(sdp_data_t * data)1219384153c1Splunky print_asink_features(sdp_data_t *data)
1220384153c1Splunky {
1221384153c1Splunky 	uint16_t v;
1222384153c1Splunky 
1223384153c1Splunky 	if (!sdp_get_uint16(data, &v))
1224384153c1Splunky 		return;
1225384153c1Splunky 
1226384153c1Splunky 	if (Nflag)
1227384153c1Splunky 		printf("(0x%04x)", v);
1228384153c1Splunky 
1229384153c1Splunky 	printf("\n");
1230384153c1Splunky 	if (v & (1<<0))	printf("    Headphone\n");
1231384153c1Splunky 	if (v & (1<<1))	printf("    Speaker\n");
1232384153c1Splunky 	if (v & (1<<2))	printf("    Recorder\n");
1233384153c1Splunky 	if (v & (1<<3))	printf("    Amplifier\n");
1234384153c1Splunky }
1235384153c1Splunky 
1236384153c1Splunky static void
print_avrcp_features(sdp_data_t * data)1237384153c1Splunky print_avrcp_features(sdp_data_t *data)
1238384153c1Splunky {
1239384153c1Splunky 	uint16_t v;
1240384153c1Splunky 
1241384153c1Splunky 	if (!sdp_get_uint16(data, &v))
1242384153c1Splunky 		return;
1243384153c1Splunky 
1244384153c1Splunky 	if (Nflag)
1245384153c1Splunky 		printf("(0x%04x)", v);
1246384153c1Splunky 
1247384153c1Splunky 	printf("\n");
1248384153c1Splunky 	if (v & (1<<0))	printf("    Category 1\n");
1249384153c1Splunky 	if (v & (1<<1))	printf("    Category 2\n");
1250384153c1Splunky 	if (v & (1<<2))	printf("    Category 3\n");
1251384153c1Splunky 	if (v & (1<<3))	printf("    Category 4\n");
1252384153c1Splunky }
1253384153c1Splunky 
1254384153c1Splunky static void
print_supported_data_stores(sdp_data_t * data)1255384153c1Splunky print_supported_data_stores(sdp_data_t *data)
1256384153c1Splunky {
1257384153c1Splunky 	sdp_data_t list;
1258384153c1Splunky 	const char *sep;
1259384153c1Splunky 	uint8_t v;
1260384153c1Splunky 
1261384153c1Splunky 	if (!sdp_get_seq(data, &list))
1262384153c1Splunky 		return;
1263384153c1Splunky 
1264384153c1Splunky 	sep = "\n    ";
1265384153c1Splunky 	while (sdp_get_uint8(&list, &v)) {
12669f52716dSjoerg 		printf("%s", sep);
1267384153c1Splunky 		sep = ", ";
1268384153c1Splunky 
1269384153c1Splunky 		switch(v) {
1270384153c1Splunky 		case 0x01:	printf("Phonebook");	break;
1271384153c1Splunky 		case 0x03:	printf("Calendar");	break;
1272384153c1Splunky 		case 0x05:	printf("Notes");	break;
1273384153c1Splunky 		case 0x06:	printf("Messages");	break;
1274384153c1Splunky 		default:	printf("0x%02x", v);	break;
1275384153c1Splunky 		}
1276384153c1Splunky 	}
1277384153c1Splunky 
1278384153c1Splunky 	if (list.next != list.end)
1279384153c1Splunky 		printf("   [additional data]");
1280384153c1Splunky 
1281384153c1Splunky 	printf("\n");
1282384153c1Splunky }
1283384153c1Splunky 
1284384153c1Splunky static void
print_supported_formats(sdp_data_t * data)1285384153c1Splunky print_supported_formats(sdp_data_t *data)
1286384153c1Splunky {
1287384153c1Splunky 	sdp_data_t list;
1288384153c1Splunky 	const char *sep;
1289384153c1Splunky 	uint8_t v;
1290384153c1Splunky 
1291384153c1Splunky 	if (!sdp_get_seq(data, &list))
1292384153c1Splunky 		return;
1293384153c1Splunky 
1294384153c1Splunky 	sep = "\n    ";
1295384153c1Splunky 	while (sdp_get_uint8(&list, &v)) {
12969f52716dSjoerg 		printf("%s", sep);
1297384153c1Splunky 		sep = ", ";
1298384153c1Splunky 
1299384153c1Splunky 		switch(v) {
1300384153c1Splunky 		case 0x01:	printf("vCard 2.1");	break;
1301384153c1Splunky 		case 0x02:	printf("vCard 3.0");	break;
1302384153c1Splunky 		case 0x03:	printf("vCal 1.0");	break;
1303384153c1Splunky 		case 0x04:	printf("iCal 2.0");	break;
1304384153c1Splunky 		case 0x05:	printf("vNote");	break;
1305384153c1Splunky 		case 0x06:	printf("vMessage");	break;
1306384153c1Splunky 		case 0xff:	printf("Any");		break;
1307384153c1Splunky 		default:	printf("0x%02x", v);	break;
1308384153c1Splunky 		}
1309384153c1Splunky 	}
1310384153c1Splunky 
1311384153c1Splunky 	if (list.next != list.end)
1312384153c1Splunky 		printf("   [additional data]");
1313384153c1Splunky 
1314384153c1Splunky 	printf("\n");
1315384153c1Splunky }
1316384153c1Splunky 
1317384153c1Splunky static void
print_wap_addr(sdp_data_t * data)1318d82c7103Splunky print_wap_addr(sdp_data_t *data)
1319d82c7103Splunky {
1320d82c7103Splunky 	uint32_t v;
1321d82c7103Splunky 
1322d82c7103Splunky 	if (!sdp_get_uint32(data, &v))
1323d82c7103Splunky 		return;
1324d82c7103Splunky 
1325d82c7103Splunky 	printf("%d.%d.%d.%d\n",
1326d82c7103Splunky 	    ((v & 0xff000000) >> 24), ((v & 0x00ff0000) >> 16),
1327d82c7103Splunky 	    ((v & 0x0000ff00) >> 8), (v & 0x000000ff));
1328d82c7103Splunky }
1329d82c7103Splunky 
1330d82c7103Splunky static void
print_wap_gateway(sdp_data_t * data)1331d82c7103Splunky print_wap_gateway(sdp_data_t *data)
1332d82c7103Splunky {
1333d82c7103Splunky 	uint8_t v;
1334d82c7103Splunky 
1335d82c7103Splunky 	if (!sdp_get_uint8(data, &v))
1336d82c7103Splunky 		return;
1337d82c7103Splunky 
1338d82c7103Splunky 	switch(v) {
1339d82c7103Splunky 	case 0x01:	printf("Origin Server\n");	break;
1340d82c7103Splunky 	case 0x02:	printf("Proxy\n");		break;
1341d82c7103Splunky 	default:	printf("0x%02x\n", v);		break;
1342d82c7103Splunky 	}
1343d82c7103Splunky }
1344d82c7103Splunky 
1345d82c7103Splunky static void
print_wap_type(sdp_data_t * data)1346d82c7103Splunky print_wap_type(sdp_data_t *data)
1347d82c7103Splunky {
1348d82c7103Splunky 	uint8_t v;
1349d82c7103Splunky 
1350d82c7103Splunky 	if (!sdp_get_uint8(data, &v))
1351d82c7103Splunky 		return;
1352d82c7103Splunky 
1353d82c7103Splunky 	switch(v) {
1354d82c7103Splunky 	case 0x01:	printf("Connectionless\n");	break;
1355d82c7103Splunky 	case 0x02:	printf("Connection Oriented\n");break;
1356d82c7103Splunky 	case 0x03:	printf("Both\n");		break;
1357d82c7103Splunky 	default:	printf("0x%02x\n", v);		break;
1358d82c7103Splunky 	}
1359d82c7103Splunky }
1360d82c7103Splunky 
1361d82c7103Splunky static void
print_hid_version(sdp_data_t * data)1362384153c1Splunky print_hid_version(sdp_data_t *data)
1363384153c1Splunky {
1364384153c1Splunky 	uint16_t v;
1365384153c1Splunky 
1366384153c1Splunky 	if (!sdp_get_uint16(data, &v))
1367384153c1Splunky 		return;
1368384153c1Splunky 
1369384153c1Splunky 	printf("v%d.%d.%d\n",
1370384153c1Splunky 	    ((v & 0xff00) >> 8), ((v & 0x00f0) >> 4), (v & 0x000f));
1371384153c1Splunky }
1372384153c1Splunky 
1373384153c1Splunky static void
print_hid_device_subclass(sdp_data_t * data)1374384153c1Splunky print_hid_device_subclass(sdp_data_t *data)
1375384153c1Splunky {
1376384153c1Splunky 	uint8_t v;
1377384153c1Splunky 
1378384153c1Splunky 	if (!sdp_get_uint8(data, &v))
1379384153c1Splunky 		return;
1380384153c1Splunky 
1381384153c1Splunky 	switch ((v & 0x3c) >> 2) {
1382384153c1Splunky 	case 1:		printf("Joystick");		break;
1383384153c1Splunky 	case 2:		printf("Gamepad");		break;
1384384153c1Splunky 	case 3:		printf("Remote Control");	break;
1385384153c1Splunky 	case 4:		printf("Sensing Device");	break;
1386384153c1Splunky 	case 5:		printf("Digitiser Tablet");	break;
1387384153c1Splunky 	case 6:		printf("Card Reader");		break;
1388384153c1Splunky 	default:	printf("Peripheral");		break;
1389384153c1Splunky 	}
1390384153c1Splunky 
1391384153c1Splunky 	if (v & 0x40)	printf(" <Keyboard>");
1392384153c1Splunky 	if (v & 0x80)	printf(" <Mouse>");
1393384153c1Splunky 
1394384153c1Splunky 	printf("\n");
1395384153c1Splunky }
1396384153c1Splunky 
1397384153c1Splunky static void
print_hid_descriptor_list(sdp_data_t * data)1398384153c1Splunky print_hid_descriptor_list(sdp_data_t *data)
1399384153c1Splunky {
1400384153c1Splunky 	sdp_data_t list, seq;
1401384153c1Splunky 	uint8_t type;
1402384153c1Splunky 	const char *name;
1403384153c1Splunky 	char *str;
1404384153c1Splunky 	size_t len;
1405384153c1Splunky 
1406384153c1Splunky 	if (!sdp_get_seq(data, &list))
1407384153c1Splunky 		return;
1408384153c1Splunky 
1409384153c1Splunky 	printf("\n");
1410384153c1Splunky 	while (list.next < list.end) {
1411384153c1Splunky 		if (!sdp_get_seq(&list, &seq)
1412384153c1Splunky 		    || !sdp_get_uint8(&seq, &type)
1413384153c1Splunky 		    || !sdp_get_str(&seq, &str, &len))
1414384153c1Splunky 			return;
1415384153c1Splunky 
1416384153c1Splunky 		switch (type) {
1417384153c1Splunky 		case 0x22:	name = "Report";		break;
1418384153c1Splunky 		case 0x23:	name = "Physical Descriptor";	break;
1419384153c1Splunky 		default:	name = "";			break;
1420384153c1Splunky 		}
1421384153c1Splunky 
1422384153c1Splunky 		printf("    Type 0x%02x: %s\n", type, name);
1423384153c1Splunky 		print_hexdump("    Data", (uint8_t *)str, len);
1424384153c1Splunky 
1425384153c1Splunky 		if (seq.next != seq.end)
1426384153c1Splunky 			printf("    [additional data]\n");
1427384153c1Splunky 	}
1428384153c1Splunky }
1429384153c1Splunky 
1430384153c1Splunky static void
print_hid_langid_base_list(sdp_data_t * data)1431e8fd30ebSplunky print_hid_langid_base_list(sdp_data_t *data)
1432e8fd30ebSplunky {
1433e8fd30ebSplunky 	sdp_data_t list, seq;
1434e8fd30ebSplunky 	uint16_t lang, base;
1435e8fd30ebSplunky 
1436e8fd30ebSplunky 	if (!sdp_get_seq(data, &list))
1437e8fd30ebSplunky 		return;
1438e8fd30ebSplunky 
1439e8fd30ebSplunky 	while (list.next < list.end) {
1440e8fd30ebSplunky 		if (!sdp_get_seq(&list, &seq)
1441e8fd30ebSplunky 		    || !sdp_get_uint16(&seq, &lang)
1442e8fd30ebSplunky 		    || !sdp_get_uint16(&seq, &base))
1443e8fd30ebSplunky 			return;
1444e8fd30ebSplunky 
1445e8fd30ebSplunky 		printf("\n    ");
1446e8fd30ebSplunky 		/*
1447e8fd30ebSplunky 		 * The language is encoded according to the
1448e8fd30ebSplunky 		 *   "Universal Serial Bus Language Identifiers (LANGIDs)"
1449e8fd30ebSplunky 		 * specification. It does not seem worth listing them all
1450e8fd30ebSplunky 		 * here, but feel free to add if you notice any being used.
1451e8fd30ebSplunky 		 */
1452e8fd30ebSplunky 		switch (lang) {
1453e8fd30ebSplunky 		case 0x0409:	printf("English (US)");		break;
1454e8fd30ebSplunky 		case 0x0809:	printf("English (UK)");		break;
1455e8fd30ebSplunky 		default:	printf("0x%04x", lang);		break;
1456e8fd30ebSplunky 		}
1457e8fd30ebSplunky 
1458d82c7103Splunky 		printf(" base 0x%04x%s\n", base,
1459d82c7103Splunky 		    (seq.next == seq.end ? "" : " [additional data]"));
1460e8fd30ebSplunky 	}
1461e8fd30ebSplunky }
1462e8fd30ebSplunky 
1463e8fd30ebSplunky static void
print_security_description(sdp_data_t * data)1464384153c1Splunky print_security_description(sdp_data_t *data)
1465384153c1Splunky {
1466384153c1Splunky 	uint16_t v;
1467384153c1Splunky 
1468384153c1Splunky 	if (!sdp_get_uint16(data, &v))
1469384153c1Splunky 		return;
1470384153c1Splunky 
1471384153c1Splunky 	switch (v) {
1472384153c1Splunky 	case 0x0000:	printf("None");				break;
1473384153c1Splunky 	case 0x0001:	printf("Service-level Security");	break;
1474384153c1Splunky 	case 0x0002:	printf("802.1x Security");		break;
1475384153c1Splunky 	default:	printf("0x%04x", v);			break;
1476384153c1Splunky 	}
1477384153c1Splunky 
1478384153c1Splunky 	printf("\n");
1479384153c1Splunky }
1480384153c1Splunky 
1481384153c1Splunky static void
print_hf_features(sdp_data_t * data)1482384153c1Splunky print_hf_features(sdp_data_t *data)
1483384153c1Splunky {
1484384153c1Splunky 	uint16_t v;
1485384153c1Splunky 
1486384153c1Splunky 	if (!sdp_get_uint16(data, &v))
1487384153c1Splunky 		return;
1488384153c1Splunky 
1489384153c1Splunky 	if (Nflag)
1490384153c1Splunky 		printf("(0x%04x)", v);
1491384153c1Splunky 
1492384153c1Splunky 	printf("\n");
1493384153c1Splunky 	if (v & (1<<0))	printf("    Echo Cancellation/Noise Reduction\n");
1494384153c1Splunky 	if (v & (1<<1))	printf("    Call Waiting\n");
1495384153c1Splunky 	if (v & (1<<2))	printf("    Caller Line Identification\n");
1496384153c1Splunky 	if (v & (1<<3))	printf("    Voice Recognition\n");
1497384153c1Splunky 	if (v & (1<<4))	printf("    Volume Control\n");
1498384153c1Splunky }
1499384153c1Splunky 
1500384153c1Splunky static void
print_hfag_network(sdp_data_t * data)1501384153c1Splunky print_hfag_network(sdp_data_t *data)
1502384153c1Splunky {
1503384153c1Splunky 	uint8_t v;
1504384153c1Splunky 
1505384153c1Splunky 	if (!sdp_get_uint8(data, &v))
1506384153c1Splunky 		return;
1507384153c1Splunky 
1508384153c1Splunky 	switch (v) {
1509384153c1Splunky 	case 0x01:	printf("Ability to reject a call");	break;
1510384153c1Splunky 	case 0x02:	printf("No ability to reject a call");	break;
1511384153c1Splunky 	default:	printf("0x%02x", v);			break;
1512384153c1Splunky 	}
1513384153c1Splunky 
1514384153c1Splunky 	printf("\n");
1515384153c1Splunky }
1516384153c1Splunky 
1517384153c1Splunky static void
print_hfag_features(sdp_data_t * data)1518384153c1Splunky print_hfag_features(sdp_data_t *data)
1519384153c1Splunky {
1520384153c1Splunky 	uint16_t v;
1521384153c1Splunky 
1522384153c1Splunky 	if (!sdp_get_uint16(data, &v))
1523384153c1Splunky 		return;
1524384153c1Splunky 
1525384153c1Splunky 	if (Nflag)
1526384153c1Splunky 		printf("(0x%04x)", v);
1527384153c1Splunky 
1528384153c1Splunky 	printf("\n");
1529384153c1Splunky 	if (v & (1<<0))	printf("    3 Way Calling\n");
1530384153c1Splunky 	if (v & (1<<1))	printf("    Echo Cancellation/Noise Reduction\n");
1531384153c1Splunky 	if (v & (1<<2))	printf("    Voice Recognition\n");
1532384153c1Splunky 	if (v & (1<<3))	printf("    In-band Ring Tone\n");
1533384153c1Splunky 	if (v & (1<<4))	printf("    Voice Tags\n");
1534384153c1Splunky }
1535384153c1Splunky 
1536384153c1Splunky static void
print_net_access_type(sdp_data_t * data)1537384153c1Splunky print_net_access_type(sdp_data_t *data)
1538384153c1Splunky {
1539384153c1Splunky 	uint16_t v;
1540384153c1Splunky 
1541384153c1Splunky 	if (!sdp_get_uint16(data, &v))
1542384153c1Splunky 		return;
1543384153c1Splunky 
1544384153c1Splunky 	switch(v) {
1545384153c1Splunky 	case 0x0000:	printf("PSTN");			break;
1546384153c1Splunky 	case 0x0001:	printf("ISDN");			break;
1547384153c1Splunky 	case 0x0002:	printf("DSL");			break;
1548384153c1Splunky 	case 0x0003:	printf("Cable Modem");		break;
1549384153c1Splunky 	case 0x0004:	printf("10Mb Ethernet");	break;
1550384153c1Splunky 	case 0x0005:	printf("100Mb Ethernet");	break;
1551384153c1Splunky 	case 0x0006:	printf("4Mb Token Ring");	break;
1552384153c1Splunky 	case 0x0007:	printf("16Mb Token Ring");	break;
1553384153c1Splunky 	case 0x0008:	printf("100Mb Token Ring");	break;
1554384153c1Splunky 	case 0x0009:	printf("FDDI");			break;
1555384153c1Splunky 	case 0x000a:	printf("GSM");			break;
1556384153c1Splunky 	case 0x000b:	printf("CDMA");			break;
1557384153c1Splunky 	case 0x000c:	printf("GPRS");			break;
1558384153c1Splunky 	case 0x000d:	printf("3G Cellular");		break;
1559384153c1Splunky 	case 0xfffe:	printf("other");		break;
1560384153c1Splunky 	default:	printf("0x%04x", v);		break;
1561384153c1Splunky 	}
1562384153c1Splunky 
1563384153c1Splunky 	printf("\n");
1564384153c1Splunky }
1565384153c1Splunky 
1566384153c1Splunky static void
print_pnp_source(sdp_data_t * data)1567447afe8dSplunky print_pnp_source(sdp_data_t *data)
1568447afe8dSplunky {
1569447afe8dSplunky 	uint16_t v;
1570447afe8dSplunky 
1571447afe8dSplunky 	if (!sdp_get_uint16(data, &v))
1572447afe8dSplunky 		return;
1573447afe8dSplunky 
1574447afe8dSplunky 	switch (v) {
1575447afe8dSplunky 	case 0x0001:	printf("Bluetooth SIG");		break;
1576447afe8dSplunky 	case 0x0002:	printf("USB Implementers Forum");	break;
1577447afe8dSplunky 	default:	printf("0x%04x", v);			break;
1578447afe8dSplunky 	}
1579447afe8dSplunky 
1580447afe8dSplunky 	printf("\n");
1581447afe8dSplunky }
1582447afe8dSplunky 
1583447afe8dSplunky static void
print_mas_types(sdp_data_t * data)1584018ad52aSplunky print_mas_types(sdp_data_t *data)
1585018ad52aSplunky {
1586018ad52aSplunky 	uint8_t v;
1587018ad52aSplunky 
1588018ad52aSplunky 	if (!sdp_get_uint8(data, &v))
1589018ad52aSplunky 		return;
1590018ad52aSplunky 
1591018ad52aSplunky 	if (Nflag)
1592018ad52aSplunky 		printf("(0x%02x)", v);
1593018ad52aSplunky 
1594018ad52aSplunky 	printf("\n");
1595018ad52aSplunky 	if (v & (1<<0))	printf("    EMAIL\n");
1596018ad52aSplunky 	if (v & (1<<1))	printf("    SMS_GSM\n");
1597018ad52aSplunky 	if (v & (1<<2))	printf("    SMS_CDMA\n");
1598018ad52aSplunky 	if (v & (1<<3))	printf("    MMS\n");
1599018ad52aSplunky }
1600018ad52aSplunky 
1601018ad52aSplunky static void
print_map_features(sdp_data_t * data)1602d82c7103Splunky print_map_features(sdp_data_t *data)
1603d82c7103Splunky {
1604d82c7103Splunky 	uint32_t v;
1605d82c7103Splunky 
1606d82c7103Splunky 	if (!sdp_get_uint32(data, &v))
1607d82c7103Splunky 		return;
1608d82c7103Splunky 
1609d82c7103Splunky 	if (Nflag)
1610d82c7103Splunky 		printf("(0x%08x)", v);
1611d82c7103Splunky 
1612d82c7103Splunky 	printf("\n");
1613d82c7103Splunky 	if (v & (1<<0))	printf("    Notification Registration\n");
1614d82c7103Splunky 	if (v & (1<<1))	printf("    Notification\n");
1615d82c7103Splunky 	if (v & (1<<2))	printf("    Browsing\n");
1616d82c7103Splunky 	if (v & (1<<3))	printf("    Uploading\n");
1617d82c7103Splunky 	if (v & (1<<4))	printf("    Delete\n");
1618d82c7103Splunky 	if (v & (1<<5))	printf("    Instance Information\n");
1619d82c7103Splunky 	if (v & (1<<6))	printf("    Extended Event Report 1.1\n");
1620d82c7103Splunky }
1621d82c7103Splunky 
1622d82c7103Splunky static void
print_pse_repositories(sdp_data_t * data)1623d82c7103Splunky print_pse_repositories(sdp_data_t *data)
162446834460Splunky {
162546834460Splunky 	uint8_t v;
162646834460Splunky 
162746834460Splunky 	if (!sdp_get_uint8(data, &v))
162846834460Splunky 		return;
162946834460Splunky 
163046834460Splunky 	if (Nflag)
163146834460Splunky 		printf("(0x%02x)", v);
163246834460Splunky 
163346834460Splunky 	printf("\n");
163446834460Splunky 	if (v & (1<<0))	printf("    Local Phonebook\n");
163546834460Splunky 	if (v & (1<<1))	printf("    SIM Card\n");
1636d82c7103Splunky 	if (v & (1<<2))	printf("    Speed Dial\n");
1637d82c7103Splunky 	if (v & (1<<3))	printf("    Favorites\n");
1638d82c7103Splunky }
1639d82c7103Splunky 
1640d82c7103Splunky static void
print_pse_features(sdp_data_t * data)1641d82c7103Splunky print_pse_features(sdp_data_t *data)
1642d82c7103Splunky {
1643d82c7103Splunky 	uint32_t v;
1644d82c7103Splunky 
1645d82c7103Splunky 	if (!sdp_get_uint32(data, &v))
1646d82c7103Splunky 		return;
1647d82c7103Splunky 
1648d82c7103Splunky 	if (Nflag)
1649d82c7103Splunky 		printf("(0x%08x)", v);
1650d82c7103Splunky 
1651d82c7103Splunky 	printf("\n");
1652d82c7103Splunky 	if (v & (1<<0))	printf("    Download\n");
1653d82c7103Splunky 	if (v & (1<<1))	printf("    Browsing\n");
1654d82c7103Splunky 	if (v & (1<<2))	printf("    Database Identifier\n");
1655d82c7103Splunky 	if (v & (1<<3))	printf("    Folder Version Counters\n");
1656d82c7103Splunky 	if (v & (1<<4))	printf("    vCard Selecting\n");
1657d82c7103Splunky 	if (v & (1<<5))	printf("    Enhanced Missed Calls\n");
1658d82c7103Splunky 	if (v & (1<<6))	printf("    X-BT-UCI vCard Property\n");
1659d82c7103Splunky 	if (v & (1<<7))	printf("    X-BT-UID vCard Property\n");
1660d82c7103Splunky 	if (v & (1<<8))	printf("    Contact Referencing\n");
1661d82c7103Splunky 	if (v & (1<<9))	printf("    Default Contact Image Format\n");
1662d82c7103Splunky }
1663d82c7103Splunky 
1664d82c7103Splunky static void
print_hdp_features(sdp_data_t * data)1665d82c7103Splunky print_hdp_features(sdp_data_t *data)
1666d82c7103Splunky {
1667d82c7103Splunky 	sdp_data_t seq, feature;
1668d82c7103Splunky 	char *str;
1669d82c7103Splunky 	size_t len;
1670d82c7103Splunky 	uint16_t type;
1671d82c7103Splunky 	uint8_t id, role;
1672d82c7103Splunky 
1673d82c7103Splunky 	if (!sdp_get_seq(data, &seq))
1674d82c7103Splunky 		return;
1675d82c7103Splunky 
1676d82c7103Splunky 	printf("\n");
1677d82c7103Splunky 	while (sdp_get_seq(&seq, &feature)) {
1678d82c7103Splunky 		if (!sdp_get_uint8(&feature, &id)
1679d82c7103Splunky 		    || !sdp_get_uint16(&feature, &type)
1680d82c7103Splunky 		    || !sdp_get_uint8(&feature, &role))
1681d82c7103Splunky 			break;
1682d82c7103Splunky 
1683d82c7103Splunky 		printf("    # %d: ", id);
1684d82c7103Splunky 
1685d82c7103Splunky 		switch(type) {
1686d82c7103Splunky 		case 0x1004:	printf("Pulse Oximeter"); break;
1687d82c7103Splunky 		case 0x1006:	printf("Basic ECG"); break;
1688d82c7103Splunky 		case 0x1007:	printf("Blood Pressure Monitor"); break;
1689d82c7103Splunky 		case 0x1008:	printf("Body Thermometer"); break;
1690d82c7103Splunky 		case 0x100F:	printf("Body Weight Scale"); break;
1691d82c7103Splunky 		case 0x1011:	printf("Glucose Meter"); break;
1692d82c7103Splunky 		case 0x1012:	printf("International Normalized Ratio Monitor"); break;
1693d82c7103Splunky 		case 0x1014:	printf("Body Composition Analyzer"); break;
1694d82c7103Splunky 		case 0x1015:	printf("Peak Flow Monitor"); break;
1695d82c7103Splunky 		case 0x1029:	printf("Cardiovascular Fitness and Activity Monitor"); break;
1696d82c7103Splunky 		case 0x1068:	printf("Step Counter"); break;
1697d82c7103Splunky 		case 0x102A:	printf("Strength Fitness Equipment"); break;
1698d82c7103Splunky 		case 0x1047:	printf("Independent Living Activity Hub"); break;
1699d82c7103Splunky 		case 0x1075:	printf("Fall Sensor"); break;
1700d82c7103Splunky 		case 0x1076:	printf("Personal Emergency Response Sensor"); break;
1701d82c7103Splunky 		case 0x1077:	printf("Smoke Sensor"); break;
1702d82c7103Splunky 		case 0x1078:	printf("Carbon Monoxide Sensor"); break;
1703d82c7103Splunky 		case 0x1079:	printf("Water Sensor"); break;
1704d82c7103Splunky 		case 0x107A:	printf("Gas Sensor"); break;
1705d82c7103Splunky 		case 0x107B:	printf("Motion Sensor"); break;
1706d82c7103Splunky 		case 0x107C:	printf("Property Exit Sensor"); break;
1707d82c7103Splunky 		case 0x107D:	printf("Enuresis Sensor"); break;
1708d82c7103Splunky 		case 0x107E:	printf("Contact Closure Sensor"); break;
1709d82c7103Splunky 		case 0x107F:	printf("Usage Sensor"); break;
1710d82c7103Splunky 		case 0x1080:	printf("Switch Sensor"); break;
1711d82c7103Splunky 		case 0x1081:	printf("Medication Dosing Sensor"); break;
1712d82c7103Splunky 		case 0x1082:	printf("Temperature Sensor"); break;
1713d82c7103Splunky 		case 0x1048:	printf("Medication monitor"); break;
1714d82c7103Splunky 		default:	printf("Type 0x%04x", type);	break;
1715d82c7103Splunky 		}
1716d82c7103Splunky 
1717d82c7103Splunky 		switch(role) {
1718d82c7103Splunky 		case 0x00:	printf(" [Source]");		break;
1719d82c7103Splunky 		case 0x01:	printf(" [Sink]");		break;
1720d82c7103Splunky 		default:	printf(" [Role 0x%02x]", role);	break;
1721d82c7103Splunky 		}
1722d82c7103Splunky 
1723d82c7103Splunky 		printf("\n");
1724d82c7103Splunky 
1725d82c7103Splunky 		if (sdp_get_str(&feature, &str, &len)) {
1726d82c7103Splunky 			int n;
1727d82c7103Splunky 
1728d82c7103Splunky 			/* This optional human-readable description should
1729d82c7103Splunky 			 * be in the primary language encoding, which ought
1730d82c7103Splunky 			 * to have a base of 0x0100 or if there isn't one,
1731d82c7103Splunky 			 * use the first encoding listed
1732d82c7103Splunky 			 */
1733d82c7103Splunky 			for (n = 0; n < nlanguages; n++) {
1734d82c7103Splunky 				if (language[n].base == 0x0100)
1735d82c7103Splunky 					break;
1736d82c7103Splunky 			}
1737d82c7103Splunky 
1738d82c7103Splunky 			printf("    # %d: ", id);
1739d82c7103Splunky 			if (n < nlanguages)
1740d82c7103Splunky 				print_codeset_string(str, len, language[n].codeset);
1741d82c7103Splunky 			else if (n > 0)
1742d82c7103Splunky 				print_codeset_string(str, len, language[0].codeset);
1743d82c7103Splunky 			else
1744d82c7103Splunky 				printf("%s", string_vis(str, len));
1745d82c7103Splunky 
1746d82c7103Splunky 			printf("\n");
1747d82c7103Splunky 		}
1748d82c7103Splunky 
1749d82c7103Splunky 		if (feature.next != feature.end)
1750d82c7103Splunky 			printf("    [additional data in feature]\n");
1751d82c7103Splunky 	}
1752d82c7103Splunky 
1753d82c7103Splunky 	if (seq.next != seq.end)
1754d82c7103Splunky 		printf("    [additional data]\n");
1755d82c7103Splunky }
1756d82c7103Splunky 
1757d82c7103Splunky static void
print_hdp_specification(sdp_data_t * data)1758d82c7103Splunky print_hdp_specification(sdp_data_t *data)
1759d82c7103Splunky {
1760d82c7103Splunky 	uint8_t v;
1761d82c7103Splunky 
1762d82c7103Splunky 	if (!sdp_get_uint8(data, &v))
1763d82c7103Splunky 		return;
1764d82c7103Splunky 
1765d82c7103Splunky 	switch(v) {
1766d82c7103Splunky 	case 0x01:	printf("ISO/IEEE 11073-20601\n");	break;
1767d82c7103Splunky 	default:	printf("0x%02x\n", v);			break;
1768d82c7103Splunky 	}
1769d82c7103Splunky }
1770d82c7103Splunky 
1771d82c7103Splunky static void
print_mcap_procedures(sdp_data_t * data)1772d82c7103Splunky print_mcap_procedures(sdp_data_t *data)
1773d82c7103Splunky {
1774d82c7103Splunky 	uint8_t v;
1775d82c7103Splunky 
1776d82c7103Splunky 	if (!sdp_get_uint8(data, &v))
1777d82c7103Splunky 		return;
1778d82c7103Splunky 
1779d82c7103Splunky 	if (Nflag)
1780d82c7103Splunky 		printf("(0x%02x)", v);
1781d82c7103Splunky 
1782d82c7103Splunky 	printf("\n");
1783d82c7103Splunky 	if (v & (1<<1))	printf("    Reconnect Initiation\n");
1784d82c7103Splunky 	if (v & (1<<2))	printf("    Reconnect Acceptance\n");
1785d82c7103Splunky 	if (v & (1<<3))	printf("    Clock Synchronization Protocol\n");
1786d82c7103Splunky 	if (v & (1<<4))	printf("    Sync-Master Role\n");
178746834460Splunky }
178846834460Splunky 
178946834460Splunky static void
print_character_repertoires(sdp_data_t * data)1790c7407d62Splunky print_character_repertoires(sdp_data_t *data)
1791c7407d62Splunky {
1792a8cbf485Splunky 	uintmax_t v;
1793c7407d62Splunky 
1794c7407d62Splunky 	/*
1795a8cbf485Splunky 	 * we have no uint128 type so use uintmax as only
1796a8cbf485Splunky 	 * only 17-bits are currently defined, and if the
1797a8cbf485Splunky 	 * value is out of bounds it will be printed anyway
1798c7407d62Splunky 	 */
1799a8cbf485Splunky 	if (sdp_data_type(data) != SDP_DATA_UINT128
1800a8cbf485Splunky 	    || !sdp_get_uint(data, &v))
1801c7407d62Splunky 		return;
1802c7407d62Splunky 
1803c7407d62Splunky 	if (Nflag)
1804a8cbf485Splunky 		printf("(0x%016jx)", v);
1805c7407d62Splunky 
1806c7407d62Splunky 	printf("\n");
1807a8cbf485Splunky 	if (v & (1<< 0)) printf("    ISO-8859-1\n");
1808a8cbf485Splunky 	if (v & (1<< 1)) printf("    ISO-8859-2\n");
1809a8cbf485Splunky 	if (v & (1<< 2)) printf("    ISO-8859-3\n");
1810a8cbf485Splunky 	if (v & (1<< 3)) printf("    ISO-8859-4\n");
1811a8cbf485Splunky 	if (v & (1<< 4)) printf("    ISO-8859-5\n");
1812a8cbf485Splunky 	if (v & (1<< 5)) printf("    ISO-8859-6\n");
1813a8cbf485Splunky 	if (v & (1<< 6)) printf("    ISO-8859-7\n");
1814a8cbf485Splunky 	if (v & (1<< 7)) printf("    ISO-8859-8\n");
1815a8cbf485Splunky 	if (v & (1<< 8)) printf("    ISO-8859-9\n");
1816a8cbf485Splunky 	if (v & (1<< 9)) printf("    ISO-8859-10\n");
1817a8cbf485Splunky 	if (v & (1<<10)) printf("    ISO-8859-13\n");
1818a8cbf485Splunky 	if (v & (1<<11)) printf("    ISO-8859-14\n");
1819a8cbf485Splunky 	if (v & (1<<12)) printf("    ISO-8859-15\n");
1820a8cbf485Splunky 	if (v & (1<<13)) printf("    GB18030\n");
1821a8cbf485Splunky 	if (v & (1<<14)) printf("    JIS X0208-1990, JIS X0201-1976\n");
1822a8cbf485Splunky 	if (v & (1<<15)) printf("    KSC 5601-1992\n");
1823a8cbf485Splunky 	if (v & (1<<16)) printf("    Big5\n");
1824a8cbf485Splunky 	if (v & (1<<17)) printf("    TIS-620\n");
1825c7407d62Splunky }
1826c7407d62Splunky 
1827c7407d62Splunky static void
print_bip_capabilities(sdp_data_t * data)182812d25979Splunky print_bip_capabilities(sdp_data_t *data)
182912d25979Splunky {
183012d25979Splunky 	uint8_t v;
183112d25979Splunky 
183212d25979Splunky 	if (!sdp_get_uint8(data, &v))
183312d25979Splunky 		return;
183412d25979Splunky 
183512d25979Splunky 	if (Nflag)
183612d25979Splunky 		printf("(0x%02x)", v);
183712d25979Splunky 
183812d25979Splunky 	printf("\n");
183912d25979Splunky 	if (v & (1<< 0)) printf("    Generic imaging\n");
184012d25979Splunky 	if (v & (1<< 1)) printf("    Capturing\n");
184112d25979Splunky 	if (v & (1<< 2)) printf("    Printing\n");
184212d25979Splunky 	if (v & (1<< 3)) printf("    Displaying\n");
184312d25979Splunky }
184412d25979Splunky 
184512d25979Splunky static void
print_bip_features(sdp_data_t * data)184612d25979Splunky print_bip_features(sdp_data_t *data)
184712d25979Splunky {
184812d25979Splunky 	uint16_t v;
184912d25979Splunky 
185012d25979Splunky 	if (!sdp_get_uint16(data, &v))
185112d25979Splunky 		return;
185212d25979Splunky 
185312d25979Splunky 	if (Nflag)
185412d25979Splunky 		printf("(0x%04x)", v);
185512d25979Splunky 
185612d25979Splunky 	printf("\n");
185712d25979Splunky 	if (v & (1<<0))	printf("    ImagePush\n");
185812d25979Splunky 	if (v & (1<<1))	printf("    ImagePush-Store\n");
185912d25979Splunky 	if (v & (1<<2))	printf("    ImagePush-Print\n");
186012d25979Splunky 	if (v & (1<<3))	printf("    ImagePush-Display\n");
186112d25979Splunky 	if (v & (1<<4))	printf("    ImagePull\n");
186212d25979Splunky 	if (v & (1<<5))	printf("    AdvancedImagePrinting\n");
186312d25979Splunky 	if (v & (1<<6))	printf("    AutomaticArchive\n");
186412d25979Splunky 	if (v & (1<<7))	printf("    RemoteCamera\n");
186512d25979Splunky 	if (v & (1<<8))	printf("    RemoteDisplay\n");
186612d25979Splunky }
186712d25979Splunky 
186812d25979Splunky static void
print_bip_functions(sdp_data_t * data)186912d25979Splunky print_bip_functions(sdp_data_t *data)
187012d25979Splunky {
187112d25979Splunky 	uint32_t v;
187212d25979Splunky 
187312d25979Splunky 	if (!sdp_get_uint32(data, &v))
187412d25979Splunky 		return;
187512d25979Splunky 
187612d25979Splunky 	if (Nflag)
187712d25979Splunky 		printf("(0x%08x)", v);
187812d25979Splunky 
187912d25979Splunky 	printf("\n");
188012d25979Splunky 	if (v & (1<< 0)) printf("    GetCapabilities\n");
188112d25979Splunky 	if (v & (1<< 1)) printf("    PutImage\n");
188212d25979Splunky 	if (v & (1<< 2)) printf("    PutLinkedAttachment\n");
188312d25979Splunky 	if (v & (1<< 3)) printf("    PutLinkedThumbnail\n");
188412d25979Splunky 	if (v & (1<< 4)) printf("    RemoteDisplay\n");
188512d25979Splunky 	if (v & (1<< 5)) printf("    GetImagesList\n");
188612d25979Splunky 	if (v & (1<< 6)) printf("    GetImageProperties\n");
188712d25979Splunky 	if (v & (1<< 7)) printf("    GetImage\n");
188812d25979Splunky 	if (v & (1<< 8)) printf("    GetLinkedThumbnail\n");
188912d25979Splunky 	if (v & (1<< 9)) printf("    GetLinkedAttachment\n");
189012d25979Splunky 	if (v & (1<<10)) printf("    DeleteImage\n");
189112d25979Splunky 	if (v & (1<<11)) printf("    StartPrint\n");
189212d25979Splunky 	if (v & (1<<12)) printf("    GetPartialImage\n");
189312d25979Splunky 	if (v & (1<<13)) printf("    StartArchive\n");
189412d25979Splunky 	if (v & (1<<14)) printf("    GetMonitoringImage\n");
189512d25979Splunky 	if (v & (1<<16)) printf("    GetStatus\n");
189612d25979Splunky }
189712d25979Splunky 
189812d25979Splunky static void
print_bip_capacity(sdp_data_t * data)189912d25979Splunky print_bip_capacity(sdp_data_t *data)
190012d25979Splunky {
190112d25979Splunky 	char buf[9];
190212d25979Splunky 	uint64_t v;
190312d25979Splunky 
190412d25979Splunky 	if (!sdp_get_uint64(data, &v))
190512d25979Splunky 		return;
190612d25979Splunky 
190712d25979Splunky 	if (v > INT64_MAX) {
190812d25979Splunky 		printf("more than ");
190912d25979Splunky 		v = INT64_MAX;
191012d25979Splunky 	}
191112d25979Splunky 
191212d25979Splunky 	(void)humanize_number(buf, sizeof(buf), (int64_t)v,
191312d25979Splunky 	    "bytes", HN_AUTOSCALE, HN_NOSPACE);
191412d25979Splunky 
191512d25979Splunky 	printf("%s\n", buf);
191612d25979Splunky }
191712d25979Splunky 
191812d25979Splunky static void
print_1284id(sdp_data_t * data)1919f88159b8Splunky print_1284id(sdp_data_t *data)
1920f88159b8Splunky {
1921f88159b8Splunky 	char *str, *ep;
1922f88159b8Splunky 	size_t len, l;
1923f88159b8Splunky 
1924f88159b8Splunky 	if (!sdp_get_str(data, &str, &len))
1925f88159b8Splunky 		return;
1926f88159b8Splunky 
1927f88159b8Splunky 	if (len < 2 || len != be16dec(str)) {
1928f88159b8Splunky 		printf("[invalid IEEE 1284 Device ID]\n");
1929f88159b8Splunky 		return;
1930f88159b8Splunky 	}
1931f88159b8Splunky 
1932f88159b8Splunky 	str += 2;
1933f88159b8Splunky 	len -= 2;
1934f88159b8Splunky 
1935f88159b8Splunky 	printf("\n");
1936f88159b8Splunky 	while (len > 0) {
1937f88159b8Splunky 		ep = memchr(str, (int)';', len);
1938f88159b8Splunky 		if (ep == NULL) {
1939f88159b8Splunky 			printf("[invalid IEEE 1284 Device ID]\n");
1940f88159b8Splunky 			return;
1941f88159b8Splunky 		}
1942f88159b8Splunky 
1943f88159b8Splunky 		l = (size_t)(ep - str + 1);
19441803dc4bSplunky 		printf("    %s\n", string_vis(str, l));
1945f88159b8Splunky 		str += l;
1946f88159b8Splunky 		len -= l;
1947f88159b8Splunky 	}
1948f88159b8Splunky }
1949f88159b8Splunky 
1950f88159b8Splunky static void
print_ctn_features(sdp_data_t * data)1951d82c7103Splunky print_ctn_features(sdp_data_t *data)
1952d82c7103Splunky {
1953d82c7103Splunky 	uint32_t v;
1954d82c7103Splunky 
1955d82c7103Splunky 	if (!sdp_get_uint32(data, &v))
1956d82c7103Splunky 		return;
1957d82c7103Splunky 
1958d82c7103Splunky 	if (Nflag)
1959d82c7103Splunky 		printf("(0x%08x)", v);
1960d82c7103Splunky 
1961d82c7103Splunky 	printf("\n");
1962d82c7103Splunky 	if (v & (1<<0))	printf("    Account Management\n");
1963d82c7103Splunky 	if (v & (1<<1))	printf("    Notification\n");
1964d82c7103Splunky 	if (v & (1<<2))	printf("    Browsing\n");
1965d82c7103Splunky 	if (v & (1<<3))	printf("    Downloading\n");
1966d82c7103Splunky 	if (v & (1<<4))	printf("    Uploading\n");
1967d82c7103Splunky 	if (v & (1<<5))	printf("    Delete\n");
1968d82c7103Splunky 	if (v & (1<<6))	printf("    Forward\n");
1969d82c7103Splunky }
1970d82c7103Splunky 
1971d82c7103Splunky static void
print_rfcomm(sdp_data_t * data)1972384153c1Splunky print_rfcomm(sdp_data_t *data)
1973384153c1Splunky {
1974384153c1Splunky 	uint8_t v;
1975384153c1Splunky 
1976384153c1Splunky 	if (sdp_get_uint8(data, &v))
1977384153c1Splunky 		printf(" (channel %d)", v);
1978384153c1Splunky }
1979384153c1Splunky 
1980384153c1Splunky static void
print_att(sdp_data_t * data)1981d82c7103Splunky print_att(sdp_data_t *data)
1982d82c7103Splunky {
1983d82c7103Splunky 	uint16_t s, e;
1984d82c7103Splunky 
1985d82c7103Splunky 	if (sdp_get_uint16(data, &s) && sdp_get_uint16(data, &e))
1986d82c7103Splunky 		printf(" (0x%04x .. 0x%04x)", s, e);
1987d82c7103Splunky }
1988d82c7103Splunky 
1989d82c7103Splunky static void
print_bnep(sdp_data_t * data)1990384153c1Splunky print_bnep(sdp_data_t *data)
1991384153c1Splunky {
1992384153c1Splunky 	sdp_data_t seq;
1993384153c1Splunky 	uint16_t v;
1994384153c1Splunky 	const char *sep;
1995384153c1Splunky 
1996384153c1Splunky 	if (!sdp_get_uint16(data, &v)
1997384153c1Splunky 	    || !sdp_get_seq(data, &seq))
1998384153c1Splunky 		return;
1999384153c1Splunky 
2000384153c1Splunky 	printf(" (v%d.%d", (v >> 8), (v & 0xff));
2001384153c1Splunky 	sep = "; ";
2002384153c1Splunky 	while (sdp_get_uint16(&seq, &v)) {
20039f52716dSjoerg 		printf("%s", sep);
2004384153c1Splunky 		sep = ", ";
2005384153c1Splunky 
2006384153c1Splunky 		switch (v) {
2007384153c1Splunky 		case 0x0800:	printf("IPv4");		break;
2008384153c1Splunky 		case 0x0806:	printf("ARP");		break;
200960e7a7b1Splunky 		case 0x8100:	printf("802.1Q");	break;
2010384153c1Splunky 		case 0x86dd:	printf("IPv6");		break;
2011384153c1Splunky 		default:	printf("0x%04x", v);	break;
2012384153c1Splunky 		}
2013384153c1Splunky 	}
2014384153c1Splunky 	printf(")");
2015384153c1Splunky 
2016384153c1Splunky 	if (seq.next != seq.end)
2017384153c1Splunky 		printf(" [additional data]");
2018384153c1Splunky }
2019384153c1Splunky 
2020384153c1Splunky static void
print_avctp(sdp_data_t * data)2021384153c1Splunky print_avctp(sdp_data_t *data)
2022384153c1Splunky {
2023384153c1Splunky 	uint16_t v;
2024384153c1Splunky 
2025384153c1Splunky 	if (sdp_get_uint16(data, &v))
2026384153c1Splunky 		printf(" (v%d.%d)", (v >> 8), (v & 0xff));
2027384153c1Splunky }
2028384153c1Splunky 
2029384153c1Splunky static void
print_avdtp(sdp_data_t * data)2030384153c1Splunky print_avdtp(sdp_data_t *data)
2031384153c1Splunky {
2032384153c1Splunky 	uint16_t v;
2033384153c1Splunky 
2034384153c1Splunky 	if (sdp_get_uint16(data, &v))
2035384153c1Splunky 		printf(" (v%d.%d)", (v >> 8), (v & 0xff));
2036384153c1Splunky }
2037384153c1Splunky 
2038384153c1Splunky static void
print_l2cap(sdp_data_t * data)2039384153c1Splunky print_l2cap(sdp_data_t *data)
2040384153c1Splunky {
2041384153c1Splunky 	uint16_t v;
2042384153c1Splunky 
2043384153c1Splunky 	if (sdp_get_uint16(data, &v))
2044384153c1Splunky 		printf(" (PSM 0x%04x)", v);
2045384153c1Splunky }
2046