1 /*        $NetBSD: print.c,v 1.24 2021/08/27 17:41:39 rillig Exp $    */
2 
3 /*-
4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Iain Hibbert.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: print.c,v 1.24 2021/08/27 17:41:39 rillig Exp $");
34 
35 #include <ctype.h>
36 #include <iconv.h>
37 #include <langinfo.h>
38 #include <sdp.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <uuid.h>
44 #include <vis.h>
45 
46 #include "sdpquery.h"
47 
48 typedef struct {
49           uint16_t  id;
50           const char *        desc;
51           void                (*print)(sdp_data_t *);
52 } attr_t;
53 
54 typedef struct {
55           uint16_t  class;
56           const char *        desc;
57           attr_t *  attrs;
58           size_t              nattr;
59 } service_t;
60 
61 typedef struct {
62           uint16_t  base;
63           const char *        codeset;
64 } language_t;
65 
66 static const char *string_uuid(uuid_t *);
67 static const char *string_vis(const char *, size_t);
68 
69 static void print_hexdump(const char *, const uint8_t *, size_t);
70 static bool print_attribute(uint16_t, sdp_data_t *, attr_t *, size_t);
71 static bool print_universal_attribute(uint16_t, sdp_data_t *);
72 static bool print_language_attribute(uint16_t, sdp_data_t *);
73 static bool print_service_attribute(uint16_t, sdp_data_t *);
74 
75 static void print_bool(sdp_data_t *);
76 static void print_uint8d(sdp_data_t *);
77 static void print_uint8x(sdp_data_t *);
78 static void print_uint16d(sdp_data_t *);
79 static void print_uint16x(sdp_data_t *);
80 static void print_uint32d(sdp_data_t *);
81 static void print_uint32x(sdp_data_t *);
82 static void print_uuid(sdp_data_t *);
83 static void print_uuid_list(sdp_data_t *);
84 static void print_string(sdp_data_t *);
85 static void print_string_list(sdp_data_t *);
86 static void print_url(sdp_data_t *);
87 static void print_profile_version(sdp_data_t *);
88 static void print_codeset_string(const char *, size_t, const char *);
89 static void print_language_string(sdp_data_t *);
90 static void print_utf8_string(sdp_data_t *);
91 
92 static void print_service_class_id_list(sdp_data_t *);
93 static void print_protocol_descriptor(sdp_data_t *);
94 static void print_protocol_descriptor_list(sdp_data_t *);
95 static void print_language_base_attribute_id_list(sdp_data_t *);
96 static void print_service_availability(sdp_data_t *);
97 static void print_bluetooth_profile_descriptor_list(sdp_data_t *);
98 static void print_additional_protocol_descriptor_lists(sdp_data_t *);
99 static void print_sds_version_number_list(sdp_data_t *);
100 static void print_ct_network(sdp_data_t *);
101 static void print_asrc_features(sdp_data_t *);
102 static void print_asink_features(sdp_data_t *);
103 static void print_avrcp_features(sdp_data_t *);
104 static void print_supported_data_stores(sdp_data_t *);
105 static void print_supported_formats(sdp_data_t *);
106 static void print_wap_addr(sdp_data_t *);
107 static void print_wap_gateway(sdp_data_t *);
108 static void print_wap_type(sdp_data_t *);
109 static void print_hid_version(sdp_data_t *);
110 static void print_hid_device_subclass(sdp_data_t *);
111 static void print_hid_descriptor_list(sdp_data_t *);
112 static void print_hid_langid_base_list(sdp_data_t *);
113 static void print_security_description(sdp_data_t *);
114 static void print_hf_features(sdp_data_t *);
115 static void print_hfag_network(sdp_data_t *);
116 static void print_hfag_features(sdp_data_t *);
117 static void print_net_access_type(sdp_data_t *);
118 static void print_pnp_source(sdp_data_t *);
119 static void print_mas_types(sdp_data_t *);
120 static void print_map_features(sdp_data_t *);
121 static void print_pse_repositories(sdp_data_t *);
122 static void print_pse_features(sdp_data_t *);
123 static void print_hdp_features(sdp_data_t *);
124 static void print_hdp_specification(sdp_data_t *);
125 static void print_mcap_procedures(sdp_data_t *);
126 static void print_character_repertoires(sdp_data_t *);
127 static void print_bip_capabilities(sdp_data_t *);
128 static void print_bip_features(sdp_data_t *);
129 static void print_bip_functions(sdp_data_t *);
130 static void print_bip_capacity(sdp_data_t *);
131 static void print_1284id(sdp_data_t *);
132 static void print_ctn_features(sdp_data_t *);
133 
134 static void print_rfcomm(sdp_data_t *);
135 static void print_att(sdp_data_t *);
136 static void print_bnep(sdp_data_t *);
137 static void print_avctp(sdp_data_t *);
138 static void print_avdtp(sdp_data_t *);
139 static void print_l2cap(sdp_data_t *);
140 
141 attr_t protocol_list[] = {
142           { 0x0001, "SDP",                                  NULL },
143           { 0x0002, "UDP",                                  NULL },
144           { 0x0003, "RFCOMM",                               print_rfcomm },
145           { 0x0004, "TCP",                                  NULL },
146           { 0x0005, "TCS_BIN",                                        NULL },
147           { 0x0006, "TCS_AT",                               NULL },
148           { 0x0007, "ATT",                                  print_att },
149           { 0x0008, "OBEX",                                 NULL },
150           { 0x0009, "IP",                                             NULL },
151           { 0x000a, "FTP",                                  NULL },
152           { 0x000c, "HTTP",                                 NULL },
153           { 0x000e, "WSP",                                  NULL },
154           { 0x000f, "BNEP",                                 print_bnep },
155           { 0x0010, "UPNP",                                 NULL },
156           { 0x0011, "HIDP",                                 NULL },
157           { 0x0012, "HARDCOPY_CONTROL_CHANNEL",             NULL },
158           { 0x0014, "HARDCOPY_DATA_CHANNEL",                NULL },
159           { 0x0016, "HARDCOPY_NOTIFICATION",                NULL },
160           { 0x0017, "AVCTP",                                print_avctp },
161           { 0x0019, "AVDTP",                                print_avdtp },
162           { 0x001b, "CMTP",                                 NULL },
163           { 0x001d, "UDI_C_PLANE",                          NULL },
164           { 0x001e, "MCAP_CONTROL_CHANNEL",                 NULL },
165           { 0x001f, "MCAP_DATA_CHANNEL",                              NULL },
166           { 0x0100, "L2CAP",                                print_l2cap },
167 };
168 
169 attr_t universal_attrs[] = {
170           { 0x0000, "ServiceRecordHandle",                  print_uint32x },
171           { 0x0001, "ServiceClassIDList",                             print_service_class_id_list },
172           { 0x0002, "ServiceRecordState",                             print_uint32x },
173           { 0x0003, "ServiceID",                                      print_uuid },
174           { 0x0004, "ProtocolDescriptorList",               print_protocol_descriptor_list },
175           { 0x0005, "BrowseGroupList",                      print_uuid_list },
176           { 0x0006, "LanguageBaseAttributeIDList",          print_language_base_attribute_id_list },
177           { 0x0007, "ServiceInfoTimeToLive",                print_uint32d },
178           { 0x0008, "ServiceAvailability",                  print_service_availability },
179           { 0x0009, "BluetoothProfileDescriptorList",       print_bluetooth_profile_descriptor_list },
180           { 0x000a, "DocumentationURL",                     print_url },
181           { 0x000b, "ClientExecutableURL",                  print_url },
182           { 0x000c, "IconURL",                                        print_url },
183           { 0x000d, "AdditionalProtocolDescriptorLists",    print_additional_protocol_descriptor_lists },
184 };
185 
186 attr_t language_attrs[] = { /* Language Attribute Offsets */
187           { 0x0000, "ServiceName",                          print_language_string },
188           { 0x0001, "ServiceDescription",                             print_language_string },
189           { 0x0002, "ProviderName",                         print_language_string },
190 };
191 
192 attr_t sds_attrs[] = {        /* Service Discovery Server */
193           { 0x0200, "VersionNumberList",                              print_sds_version_number_list },
194           { 0x0201, "ServiceDatabaseState",                 print_uint32x },
195 };
196 
197 attr_t bgd_attrs[] = {        /* Browse Group Descriptor */
198           { 0x0200, "GroupID",                                        print_uuid },
199 };
200 
201 attr_t ct_attrs[] = { /* Cordless Telephony */
202           { 0x0301, "ExternalNetwork",                      print_ct_network },
203 };
204 
205 attr_t asrc_attrs[] = { /* Audio Source */
206           { 0x0311, "SupportedFeatures",                              print_asrc_features },
207 };
208 
209 attr_t asink_attrs[] = { /* Audio Sink */
210           { 0x0311, "SupportedFeatures",                              print_asink_features },
211 };
212 
213 attr_t avrcp_attrs[] = { /* Audio Video Remote Control Profile */
214           { 0x0311, "SupportedFeatures",                              print_avrcp_features },
215 };
216 
217 attr_t lan_attrs[] = {        /* LAN Access Using PPP */
218           { 0x0200, "IPSubnet",                                       print_string },
219 };
220 
221 attr_t dun_attrs[] = {        /* Dialup Networking */
222           { 0x0305, "AudioFeedbackSupport",                 print_bool },
223 };
224 
225 attr_t irmc_sync_attrs[] = { /* IrMC Sync */
226           { 0x0301, "SupportedDataStoresList",              print_supported_data_stores },
227 };
228 
229 attr_t opush_attrs[] = { /* Object Push */
230           { 0x0200, "GeopL2capPSM",                         print_uint16x },
231           { 0x0303, "SupportedFormatsList",                 print_supported_formats },
232 };
233 
234 attr_t ft_attrs[] = { /* File Transfer */
235           { 0x0200, "GeopL2capPSM",                         print_uint16x },
236 };
237 
238 attr_t hset_attrs[] = {       /* Headset */
239           { 0x0302, "RemoteAudioVolumeControl",             print_bool },
240 };
241 
242 attr_t fax_attrs[] = {        /* Fax */
243           { 0x0302, "FAXClass1",                                      print_bool },
244           { 0x0303, "FAXClass2.0",                          print_bool },
245           { 0x0304, "FAXClass2",                                      print_bool },
246           { 0x0305, "AudioFeedbackSupport",                 print_bool },
247 };
248 
249 attr_t wap_attrs[] = {        /* WAP Bearer */
250           { 0x0306, "NetworkAddress",                       print_wap_addr },
251           { 0x0307, "WAPGateway",                                     print_wap_gateway },
252           { 0x0308, "HomePageURL",                          print_url },
253           { 0x0309, "WAPStackType",                         print_wap_type },
254 };
255 
256 attr_t panu_attrs[] = {       /* Personal Area Networking User */
257           { 0x0200, "IpSubnet",                                       print_string },
258           { 0x030a, "SecurityDescription",                  print_security_description },
259 };
260 
261 attr_t nap_attrs[] = {        /* Network Access Point */
262           { 0x0200, "IpSubnet",                                       print_string },
263           { 0x030a, "SecurityDescription",                  print_security_description },
264           { 0x030b, "NetAccessType",                        print_net_access_type },
265           { 0x030c, "MaxNetAccessRate",                     print_uint32d },
266           { 0x030d, "IPv4Subnet",                                     print_string },
267           { 0x030e, "IPv6Subnet",                                     print_string },
268 };
269 
270 attr_t gn_attrs[] = {         /* Group Network */
271           { 0x0200, "IpSubnet",                                       print_string },
272           { 0x030a, "SecurityDescription",                  print_security_description },
273           { 0x030d, "IPv4Subnet",                                     print_string },
274           { 0x030e, "IPv6Subnet",                                     print_string },
275 };
276 
277 attr_t bp_attrs[] = {         /* Basic Printing */
278           { 0x0350, "DocumentFormatsSupported",             print_string_list },
279           { 0x0352, "CharacterRepertoiresSupported",        print_character_repertoires },
280           { 0x0354, "XHTML-PrintImageFormatsSupported",     print_string_list },
281           { 0x0356, "ColorSupported",                       print_bool },
282           { 0x0358, "1284ID",                               print_1284id },
283           { 0x035a, "PrinterName",                          print_utf8_string },
284           { 0x035c, "PrinterLocation",                      print_utf8_string },
285           { 0x035e, "DuplexSupported",                      print_bool },
286           { 0x0360, "MediaTypesSupported",                  print_string_list },
287           { 0x0362, "MaxMediaWidth",                        print_uint16d },
288           { 0x0364, "MaxMediaLength",                       print_uint16d },
289           { 0x0366, "EnhancedLayoutSupport",                print_bool },
290           { 0x0368, "RUIFormatsSupported",                  print_string_list },
291           { 0x0370, "ReferencePrintingRUISupported",        print_bool },
292           { 0x0372, "DirectPrintingRUISupported",           print_bool },
293           { 0x0374, "ReferencePrintingTopURL",              print_url },
294           { 0x0376, "DirectPrintingTopURL",                 print_url },
295           { 0x037a, "DeviceName",                                     print_utf8_string },
296 };
297 
298 attr_t bi_attrs[] = {         /* Basic Imaging */
299           { 0x0200, "GeopL2capPSM",                         print_uint16x },
300           { 0x0310, "SupportedCapabilities",                print_bip_capabilities },
301           { 0x0311, "SupportedFeatures",                              print_bip_features },
302           { 0x0312, "SupportedFunctions",                             print_bip_functions },
303           { 0x0313, "TotalImagingDataCapacity",             print_bip_capacity },
304 };
305 
306 attr_t hf_attrs[] = {         /* Handsfree */
307           { 0x0311, "SupportedFeatures",                              print_hf_features },
308 };
309 
310 attr_t hfag_attrs[] = {       /* Handsfree Audio Gateway */
311           { 0x0301, "Network",                                        print_hfag_network },
312           { 0x0311, "SupportedFeatures",                              print_hfag_features },
313 };
314 
315 attr_t rui_attrs[] = {        /* Reflected User Interface */
316           { 0x0368, "RUIFormatsSupported",                  print_string_list },
317           { 0x0378, "PrinterAdminRUITopURL",                print_url },
318 };
319 
320 attr_t hid_attrs[] = {        /* Human Interface Device */
321           { 0x0200, "HIDDeviceReleaseNumber",               print_hid_version },
322           { 0x0201, "HIDParserVersion",                     print_hid_version },
323           { 0x0202, "HIDDeviceSubClass",                              print_hid_device_subclass },
324           { 0x0203, "HIDCountryCode",                       print_uint8x },
325           { 0x0204, "HIDVirtualCable",                      print_bool },
326           { 0x0205, "HIDReconnectInitiate",                 print_bool },
327           { 0x0206, "HIDDescriptorList",                              print_hid_descriptor_list },
328           { 0x0207, "HIDLANGIDBaseList",                              print_hid_langid_base_list },
329           { 0x0208, "HIDSDPDisable",                        print_bool },
330           { 0x0209, "HIDBatteryPower",                      print_bool },
331           { 0x020a, "HIDRemoteWake",                        print_bool },
332           { 0x020b, "HIDProfileVersion",                              print_profile_version },
333           { 0x020c, "HIDSupervisionTimeout",                print_uint16d },
334           { 0x020d, "HIDNormallyConnectable",               print_bool },
335           { 0x020e, "HIDBootDevice",                        print_bool },
336           { 0x020f, "HIDHostMaxLatency",                              print_uint16d },
337           { 0x0210, "HIDHostMinTimeout",                              print_uint16d },
338 };
339 
340 attr_t hcr_attrs[] = {        /* Hardcopy Cable Replacement */
341           { 0x0300, "1284ID",                               print_1284id },
342           { 0x0302, "DeviceName",                                     print_utf8_string },
343           { 0x0304, "FriendlyName",                         print_utf8_string },
344           { 0x0306, "DeviceLocation",                       print_utf8_string },
345 };
346 
347 attr_t mps_attrs[] = {        /* Multi-Profile Specification */
348           { 0x0200, "SingleDeviceSupportedScenarios",       NULL },
349           { 0x0201, "MultiDeviceSupportedScenarios",        NULL },
350           { 0x0202, "SupportedProfileAndProtocolDependencies", print_uint16x },
351 };
352 
353 attr_t cas_attrs[] = { /* Calendar, Tasks & Notes Access */
354           { 0x0315, "InstanceID",                                     print_uint8d },
355           { 0x0317, "SupportedFeatures",                              print_ctn_features },
356 };
357 
358 attr_t cns_attrs[] = { /* Calendar, Tasks & Notes Notification */
359           { 0x0317, "SupportedFeatures",                              print_ctn_features },
360 };
361 
362 attr_t pnp_attrs[] = {        /* Device ID */
363           { 0x0200, "SpecificationID",                      print_profile_version },
364           { 0x0201, "VendorID",                                       print_uint16x },
365           { 0x0202, "ProductID",                                      print_uint16x },
366           { 0x0203, "Version",                                        print_hid_version },
367           { 0x0204, "PrimaryRecord",                        print_bool },
368           { 0x0205, "VendorIDSource",                       print_pnp_source },
369 };
370 
371 attr_t mas_attrs[] = {        /* Message Access Server */
372           { 0x0200, "GeopL2capPSM",                         print_uint16x },
373           { 0x0315, "InstanceID",                                     print_uint8d },
374           { 0x0316, "SupportedMessageTypes",                print_mas_types },
375           { 0x0317, "SupportedFeatures",                              print_map_features },
376 };
377 
378 attr_t mns_attrs[] = {        /* Message Notification Server */
379           { 0x0200, "GeopL2capPSM",                         print_uint16x },
380           { 0x0317, "SupportedFeatures",                              print_map_features },
381 };
382 
383 attr_t gnss_attrs[] = {       /* Global Navigation Satellite System Server */
384           { 0x0200, "SupportedFeatures",                              print_uint16x },
385 };
386 
387 attr_t pse_attrs[] = {        /* Phonebook Access Server */
388           { 0x0200, "GeopL2capPSM",                         print_uint16x },
389           { 0x0314, "SupportedRepositories",                print_pse_repositories },
390           { 0x0317, "SupportedFeatures",                              print_pse_features },
391 };
392 
393 attr_t hdp_attrs[] = {        /* Health Device Profile */
394           { 0x0200, "SupportedFeaturesList",                print_hdp_features },
395           { 0x0301, "DataExchangeSpecification",            print_hdp_specification },
396           { 0x0302, "MCAPSupportedProcedures",              print_mcap_procedures },
397 };
398 
399 #define A(a)        a, __arraycount(a)
400 service_t service_list[] = {
401           { 0x1000, "Service Discovery Server",             A(sds_attrs) },
402           { 0x1001, "Browse Group Descriptor",              A(bgd_attrs) },
403           { 0x1002, "Public Browse Root",                             NULL, 0 },
404           { 0x1101, "Serial Port",                          NULL, 0 },
405           { 0x1102, "LAN Access Using PPP",                 A(lan_attrs) },
406           { 0x1103, "Dialup Networking",                              A(dun_attrs) },
407           { 0x1104, "IrMC Sync",                                      A(irmc_sync_attrs) },
408           { 0x1105, "Object Push",                          A(opush_attrs) },
409           { 0x1106, "File Transfer",                        A(ft_attrs) },
410           { 0x1107, "IrMC Sync Command",                              NULL, 0 },
411           { 0x1108, "Headset",                                        A(hset_attrs) },
412           { 0x1109, "Cordless Telephony",                             A(ct_attrs) },
413           { 0x110a, "Audio Source",                         A(asrc_attrs) },
414           { 0x110b, "Audio Sink",                                     A(asink_attrs) },
415           { 0x110c, "A/V Remote Control Target",            A(avrcp_attrs) },
416           { 0x110d, "Advanced Audio Distribution",          NULL, 0 },
417           { 0x110e, "A/V Remote Control",                             A(avrcp_attrs) },
418           { 0x110f, "Video Conferencing",                             NULL, 0 },
419           { 0x1110, "Intercom",                                       NULL, 0 },
420           { 0x1111, "Fax",                                  A(fax_attrs) },
421           { 0x1112, "Headset Audio Gateway",                NULL, 0 },
422           { 0x1113, "WAP",                                  A(wap_attrs) },
423           { 0x1114, "WAP Client",                                     NULL, 0 },
424           { 0x1115, "Personal Area Networking User",        A(panu_attrs) },
425           { 0x1116, "Network Access Point",                 A(nap_attrs) },
426           { 0x1117, "Group Network",                        A(gn_attrs) },
427           { 0x1118, "Direct Printing",                      A(bp_attrs) },
428           { 0x1119, "Reference Printing",                             A(bp_attrs) },
429           { 0x111a, "Imaging",                                        NULL, 0 },
430           { 0x111b, "Imaging Responder",                              A(bi_attrs) },
431           { 0x111c, "Imaging Automatic Archive",            A(bi_attrs) },
432           { 0x111d, "Imaging Referenced Objects",           A(bi_attrs) },
433           { 0x111e, "Handsfree",                                      A(hf_attrs) },
434           { 0x111f, "Handsfree Audio Gateway",              A(hfag_attrs) },
435           { 0x1120, "Direct Printing Reference Objects",    NULL, 0 },
436           { 0x1121, "Reflected User Interface",             A(rui_attrs) },
437           { 0x1122, "Basic Printing",                       NULL, 0 },
438           { 0x1123, "Printing Status",                      A(bp_attrs) },
439           { 0x1124, "Human Interface Device",               A(hid_attrs) },
440           { 0x1125, "Hardcopy Cable Replacement",           NULL, 0 },
441           { 0x1126, "Hardcopy Cable Replacement Print",     A(hcr_attrs) },
442           { 0x1127, "Hardcopy Cable Replacement Scan",      A(hcr_attrs) },
443           { 0x1128, "Common ISDN Access",                             NULL, 0 },
444           { 0x1129, "Video Conferencing GW",                NULL, 0 },
445           { 0x112a, "UDI MT",                               NULL, 0 },
446           { 0x112b, "UDI TA",                               NULL, 0 },
447           { 0x112c, "Audio/Video",                          NULL, 0 },
448           { 0x112d, "SIM Access",                                     NULL, 0 },
449           { 0x112e, "Phonebook Access Client",              NULL, 0 },
450           { 0x112f, "Phonebook Access Server",              A(pse_attrs) },
451           { 0x1130, "Phonebook Access",                     NULL, 0 },
452           { 0x1131, "Headset HS",                                     NULL, 0 },
453           { 0x1132, "Message Access Server",                A(mas_attrs) },
454           { 0x1133, "Message Notification Server",          A(mns_attrs) },
455           { 0x1134, "Message Access Profile",               NULL, 0 },
456           { 0x1135, "Global Navigation Satellite System Profile", NULL, 0 },
457           { 0x1136, "Global Navigation Satellite System Server", A(gnss_attrs) },
458           { 0x1137, "3D Display",                                     NULL, 0 },
459           { 0x1138, "3D Glasses",                                     NULL, 0 },
460           { 0x1139, "3D Synchronization",                             NULL, 0 },
461           { 0x113a, "Multi-Profile Specification Profile",NULL, 0 },
462           { 0x113b, "Multi-Profile Specification Server", A(mps_attrs) },
463           { 0x113c, "Calendar, Tasks & Notes Access",       A(cas_attrs) },
464           { 0x113d, "Calendar, Tasks & Notes Notification",A(cns_attrs) },
465           { 0x113e, "Calendar, Tasks & Notes Profile",      NULL, 0 },
466           { 0x1200, "PNP Information",                      A(pnp_attrs) },
467           { 0x1201, "Generic Networking",                             NULL, 0 },
468           { 0x1202, "Generic File Transfer",                NULL, 0 },
469           { 0x1203, "Generic Audio",                        NULL, 0 },
470           { 0x1204, "Generic Telephony",                              NULL, 0 },
471           { 0x1205, "UPNP",                                 NULL, 0 },
472           { 0x1206, "UPNP IP",                                        NULL, 0 },
473           { 0x1300, "UPNP IP PAN",                          NULL, 0 },
474           { 0x1301, "UPNP IP LAP",                          NULL, 0 },
475           { 0x1302, "UPNP IP L2CAP",                        NULL, 0 },
476           { 0x1303, "Video Source",                         NULL, 0 },
477           { 0x1304, "Video Sink",                                     NULL, 0 },
478           { 0x1305, "Video Distribution",                             NULL, 0 },
479           { 0x1400, "HDP",                                  NULL, 0 },
480           { 0x1401, "HDP Source",                                     A(hdp_attrs) },
481           { 0x1402, "HDP Sink",                                       A(hdp_attrs) },
482           { 0x1800, "Generic Access Profile",               NULL, 0 },
483           { 0x1801, "Generic Attribute Server",             NULL, 0 },
484 };
485 #undef A
486 
487 /* extracted Service Class ID List */
488 #define MAX_SERVICES                    16
489 static size_t nservices;
490 static uint16_t service_class[MAX_SERVICES];
491 
492 /* extracted Language Base Attribute ID List */
493 #define MAX_LANGUAGES                   16
494 static int nlanguages;
495 static language_t language[MAX_LANGUAGES];
496 static int current;
497 
498 static bool
sdp_get_uint8(sdp_data_t * d,uint8_t * vp)499 sdp_get_uint8(sdp_data_t *d, uint8_t *vp)
500 {
501           uintmax_t v;
502 
503           if (sdp_data_type(d) != SDP_DATA_UINT8
504               || !sdp_get_uint(d, &v))
505                     return false;
506 
507           *vp = (uint8_t)v;
508           return true;
509 }
510 
511 static bool
sdp_get_uint16(sdp_data_t * d,uint16_t * vp)512 sdp_get_uint16(sdp_data_t *d, uint16_t *vp)
513 {
514           uintmax_t v;
515 
516           if (sdp_data_type(d) != SDP_DATA_UINT16
517               || !sdp_get_uint(d, &v))
518                     return false;
519 
520           *vp = (uint16_t)v;
521           return true;
522 }
523 
524 static bool
sdp_get_uint32(sdp_data_t * d,uint32_t * vp)525 sdp_get_uint32(sdp_data_t *d, uint32_t *vp)
526 {
527           uintmax_t v;
528 
529           if (sdp_data_type(d) != SDP_DATA_UINT32
530               || !sdp_get_uint(d, &v))
531                     return false;
532 
533           *vp = (uint32_t)v;
534           return true;
535 }
536 
537 static bool
sdp_get_uint64(sdp_data_t * d,uint64_t * vp)538 sdp_get_uint64(sdp_data_t *d, uint64_t *vp)
539 {
540           uintmax_t v;
541 
542           if (sdp_data_type(d) != SDP_DATA_UINT64
543               || !sdp_get_uint(d, &v))
544                     return false;
545 
546           *vp = (uint64_t)v;
547           return true;
548 }
549 
550 void
print_record(sdp_data_t * rec)551 print_record(sdp_data_t *rec)
552 {
553           sdp_data_t value;
554           uint16_t id;
555 
556           nservices = 0;
557           nlanguages = 0;
558           current = -1;
559 
560           while (sdp_get_attr(rec, &id, &value)) {
561                     if (Xflag) {
562                               printf("AttributeID 0x%04x:\n", id);
563                               print_hexdump("     ", value.next,
564                                   (size_t)(value.end - value.next));
565                     } else if (Rflag) {
566                               printf("AttributeID 0x%04x:\n", id);
567                               sdp_data_print(&value, 4);
568                     } else if (print_universal_attribute(id, &value)
569                         || print_language_attribute(id, &value)
570                         || print_service_attribute(id, &value)) {
571                               if (value.next != value.end)
572                                   printf("    [additional data ignored]\n");
573                     } else {
574                               printf("AttributeID 0x%04x:\n", id);
575                               sdp_data_print(&value, 4);
576                     }
577           }
578 }
579 
580 static const char *
string_uuid(uuid_t * uuid)581 string_uuid(uuid_t *uuid)
582 {
583           static char buf[64];
584           const char *desc;
585           uuid_t u;
586           size_t i;
587 
588           u = *uuid;
589           u.time_low = 0;
590           if (!uuid_equal(&u, &BLUETOOTH_BASE_UUID, NULL)) {
591                     snprintf(buf, sizeof(buf),
592                         "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
593                         uuid->time_low, uuid->time_mid, uuid->time_hi_and_version,
594                         uuid->clock_seq_hi_and_reserved, uuid->clock_seq_low,
595                         uuid->node[0], uuid->node[1], uuid->node[2],
596                         uuid->node[3], uuid->node[4], uuid->node[5]);
597 
598                     return buf;
599           }
600 
601           desc = NULL;
602           for (i = 0; i < __arraycount(service_list); i++) {
603                     if (uuid->time_low == service_list[i].class) {
604                               desc = service_list[i].desc;
605                               break;
606                     }
607           }
608 
609           for (i = 0; i < __arraycount(protocol_list); i++) {
610                     if (uuid->time_low == protocol_list[i].id) {
611                               desc = protocol_list[i].desc;
612                               break;
613                     }
614           }
615 
616           if (!Nflag && desc) {
617                     snprintf(buf, sizeof(buf), "%s", desc);
618                     return buf;
619           }
620 
621           snprintf(buf, sizeof(buf), "%s%s(0x%*.*x)",
622               (desc == NULL ? "" : desc),
623               (desc == NULL ? "" : " "),
624               (uuid->time_low > UINT16_MAX ? 8 : 4),
625               (uuid->time_low > UINT16_MAX ? 8 : 4),
626               uuid->time_low);
627 
628           return buf;
629 }
630 
631 static const char *
string_vis(const char * src,size_t len)632 string_vis(const char *src, size_t len)
633 {
634           static char buf[50];
635           char *dst = buf;
636           int style;
637 
638           buf[0] = '\0';
639           style = VIS_CSTYLE | VIS_NL;
640           while (len > 0 && (dst + 5) < (buf + sizeof(buf))) {
641                     dst = vis(dst, src[0], style, (len > 1 ? src[1] : 0));
642                     src++;
643                     len--;
644           }
645 
646           return buf;
647 }
648 
649 static void
print_hexdump(const char * title,const uint8_t * data,size_t len)650 print_hexdump(const char *title, const uint8_t *data, size_t len)
651 {
652           int n, i;
653 
654           i = 0;
655           n = printf("%s", title);
656 
657           while (len-- > 0) {
658                     if (++i > 8) {
659                               printf("\n%*s", n, "");
660                               i = 1;
661                     }
662 
663                     printf(" 0x%02x", *data++);
664           }
665 
666           printf("\n");
667 }
668 
669 static bool
print_attribute(uint16_t id,sdp_data_t * value,attr_t * attr,size_t count)670 print_attribute(uint16_t id, sdp_data_t *value, attr_t *attr, size_t count)
671 {
672           size_t i;
673 
674           for (i = 0; i < count; i++) {
675                     if (id == attr[i].id) {
676                               printf("%s", attr[i].desc);
677 
678                               if (Nflag) {
679                                         printf(" (");
680 
681                                         if (current != -1)
682                                                   printf("0x%04x + ", language[current].base);
683 
684                                         printf("0x%04x)", id);
685                               }
686 
687                               printf(": ");
688 
689                               if (attr[i].print == NULL) {
690                                         printf("\n");
691                                         sdp_data_print(value, 4);
692                                         value->next = value->end;
693                               } else {
694                                         (attr[i].print)(value);
695                               }
696 
697                               return true;
698                     }
699           }
700 
701           return false;
702 }
703 
704 static bool
print_universal_attribute(uint16_t id,sdp_data_t * value)705 print_universal_attribute(uint16_t id, sdp_data_t *value)
706 {
707 
708           return print_attribute(id, value,
709               universal_attrs, __arraycount(universal_attrs));
710 }
711 
712 static bool
print_language_attribute(uint16_t id,sdp_data_t * value)713 print_language_attribute(uint16_t id, sdp_data_t *value)
714 {
715           bool done = false;
716 
717           for (current = 0; current < nlanguages && !done; current++)
718                     done = print_attribute(id - language[current].base, value,
719                         language_attrs, __arraycount(language_attrs));
720 
721           current = -1;
722           return done;
723 }
724 
725 static bool
print_service_attribute(uint16_t id,sdp_data_t * value)726 print_service_attribute(uint16_t id, sdp_data_t *value)
727 {
728           size_t i, j;
729 
730           for (i = 0; i < nservices; i++) {
731                     for (j = 0; j < __arraycount(service_list); j++) {
732                               if (service_class[i] == service_list[j].class
733                                   && print_attribute(id, value,
734                                   service_list[j].attrs, service_list[j].nattr))
735                                         return true;
736                     }
737           }
738 
739           return false;
740 }
741 
742 static void
print_bool(sdp_data_t * data)743 print_bool(sdp_data_t *data)
744 {
745           bool v;
746 
747           if (!sdp_get_bool(data, &v))
748                     return;
749 
750           printf("%s\n", (v ? "true" : "false"));
751 }
752 
753 static void
print_uint8d(sdp_data_t * data)754 print_uint8d(sdp_data_t *data)
755 {
756           uint8_t v;
757 
758           if (!sdp_get_uint8(data, &v))
759                     return;
760 
761           printf("%d\n", v);
762 }
763 
764 static void
print_uint8x(sdp_data_t * data)765 print_uint8x(sdp_data_t *data)
766 {
767           uint8_t v;
768 
769           if (!sdp_get_uint8(data, &v))
770                     return;
771 
772           printf("0x%02x\n", v);
773 }
774 
775 static void
print_uint16d(sdp_data_t * data)776 print_uint16d(sdp_data_t *data)
777 {
778           uint16_t v;
779 
780           if (!sdp_get_uint16(data, &v))
781                     return;
782 
783           printf("%d\n", v);
784 }
785 
786 static void
print_uint16x(sdp_data_t * data)787 print_uint16x(sdp_data_t *data)
788 {
789           uint16_t v;
790 
791           if (!sdp_get_uint16(data, &v))
792                     return;
793 
794           printf("0x%04x\n", v);
795 }
796 
797 static void
print_uint32x(sdp_data_t * data)798 print_uint32x(sdp_data_t *data)
799 {
800           uint32_t v;
801 
802           if (!sdp_get_uint32(data, &v))
803                     return;
804 
805           printf("0x%08x\n", v);
806 }
807 
808 static void
print_uint32d(sdp_data_t * data)809 print_uint32d(sdp_data_t *data)
810 {
811           uint32_t v;
812 
813           if (!sdp_get_uint32(data, &v))
814                     return;
815 
816           printf("%d\n", v);
817 }
818 
819 static void
print_uuid(sdp_data_t * data)820 print_uuid(sdp_data_t *data)
821 {
822           uuid_t uuid;
823 
824           if (!sdp_get_uuid(data, &uuid))
825                     return;
826 
827           printf("%s\n", string_uuid(&uuid));
828 }
829 
830 static void
print_uuid_list(sdp_data_t * data)831 print_uuid_list(sdp_data_t *data)
832 {
833           sdp_data_t seq;
834           uuid_t uuid;
835 
836           if (!sdp_get_seq(data, &seq))
837                     return;
838 
839           printf("\n");
840           while (sdp_get_uuid(&seq, &uuid))
841                     printf("    %s\n", string_uuid(&uuid));
842 
843           if (seq.next != seq.end)
844                     printf("    [additional data]\n");
845 }
846 
847 static void
print_string(sdp_data_t * data)848 print_string(sdp_data_t *data)
849 {
850           char *str;
851           size_t len;
852 
853           if (!sdp_get_str(data, &str, &len))
854                     return;
855 
856           printf("\"%s\"\n", string_vis(str, len));
857 }
858 
859 static void
print_string_list(sdp_data_t * data)860 print_string_list(sdp_data_t *data)
861 {
862           char *str, *ep;
863           size_t len, l;
864 
865           if (!sdp_get_str(data, &str, &len))
866                     return;
867 
868           printf("\n");
869           while (len > 0) {
870                     ep = memchr(str, (int)',', len);
871                     if (ep == NULL) {
872                               l = len;
873                               len = 0;
874                     } else {
875                               l = (size_t)(ep - str);
876                               len -= l + 1;
877                               ep++;
878                     }
879                     printf("    %s\n", string_vis(str, l));
880                     str = ep;
881           }
882 }
883 
884 static void
print_url(sdp_data_t * data)885 print_url(sdp_data_t *data)
886 {
887           char *url;
888           size_t len;
889 
890           if (!sdp_get_url(data, &url, &len))
891                     return;
892 
893           printf("\"%s\"\n", string_vis(url, len));
894 }
895 
896 static void
print_profile_version(sdp_data_t * data)897 print_profile_version(sdp_data_t *data)
898 {
899           uint16_t v;
900 
901           if (!sdp_get_uint16(data, &v))
902                     return;
903 
904           printf("v%d.%d\n", (v >> 8), (v & 0xff));
905 }
906 
907 static void
print_codeset_string(const char * src,size_t srclen,const char * codeset)908 print_codeset_string(const char *src, size_t srclen, const char *codeset)
909 {
910           char buf[50], *dst;
911           iconv_t ih;
912           size_t dstlen;
913 
914           dst = buf;
915           dstlen = sizeof(buf);
916 
917           ih = iconv_open(nl_langinfo(CODESET), codeset);
918           if (ih == (iconv_t)-1) {
919                     printf("Can't convert %s string\n", codeset);
920                     return;
921           }
922 
923           (void)iconv(ih, __UNCONST(&src), &srclen, &dst, &dstlen);
924 
925           iconv_close(ih);
926 
927           printf("\"%.*s%s\n", (int)(sizeof(buf) - dstlen), buf,
928               (srclen > 0 ? " ..." : "\""));
929 }
930 
931 /*
932  * This should only be called through print_language_attribute() which
933  * sets codeset of the string to be printed.
934  */
935 static void
print_language_string(sdp_data_t * data)936 print_language_string(sdp_data_t *data)
937 {
938           char *str;
939           size_t len;
940 
941           if (!sdp_get_str(data, &str, &len))
942                     return;
943 
944           print_codeset_string(str, len, language[current].codeset);
945 }
946 
947 
948 static void
print_utf8_string(sdp_data_t * data)949 print_utf8_string(sdp_data_t *data)
950 {
951           char *str;
952           size_t len;
953 
954           if (!sdp_get_str(data, &str, &len))
955                     return;
956 
957           print_codeset_string(str, len, "UTF-8");
958 }
959 
960 static void
print_service_class_id_list(sdp_data_t * data)961 print_service_class_id_list(sdp_data_t *data)
962 {
963           sdp_data_t seq;
964           uuid_t uuid;
965 
966           if (!sdp_get_seq(data, &seq))
967                     return;
968 
969           printf("\n");
970           while (sdp_get_uuid(&seq, &uuid)) {
971                     printf("    %s\n", string_uuid(&uuid));
972 
973                     if (nservices < MAX_SERVICES) {
974                               service_class[nservices] = uuid.time_low;
975                               uuid.time_low = 0;
976                               if (uuid_equal(&uuid, &BLUETOOTH_BASE_UUID, NULL))
977                                         nservices++;
978                     }
979           }
980 
981           if (seq.next != seq.end)
982                     printf("    [additional data]\n");
983 }
984 
985 static void
print_protocol_descriptor(sdp_data_t * data)986 print_protocol_descriptor(sdp_data_t *data)
987 {
988           uuid_t u0, uuid;
989           size_t i;
990 
991           if (!sdp_get_uuid(data, &uuid))
992                     return;
993 
994           u0 = uuid;
995           u0.time_low = 0;
996           if (uuid_equal(&u0, &BLUETOOTH_BASE_UUID, NULL)) {
997                     for (i = 0; i < __arraycount(protocol_list); i++) {
998                               if (uuid.time_low == protocol_list[i].id) {
999                                         printf("    %s", protocol_list[i].desc);
1000 
1001                                         if (Nflag)
1002                                                   printf(" (0x%04x)", protocol_list[i].id);
1003 
1004                                         if (protocol_list[i].print)
1005                                                   (protocol_list[i].print)(data);
1006 
1007                                         if (data->next != data->end)
1008                                                   printf(" [additional data]");
1009 
1010                                         printf("\n");
1011                                         return;
1012                               }
1013                     }
1014           }
1015 
1016           printf("    %s\n", string_uuid(&uuid));
1017           sdp_data_print(data, 4);
1018           data->next = data->end;
1019 }
1020 
1021 static void
print_protocol_descriptor_list(sdp_data_t * data)1022 print_protocol_descriptor_list(sdp_data_t *data)
1023 {
1024           sdp_data_t seq, proto;
1025 
1026           printf("\n");
1027           sdp_get_alt(data, data);      /* strip [optional] alt header */
1028 
1029           while (sdp_get_seq(data, &seq)) {
1030                     while (sdp_get_seq(&seq, &proto))
1031                               print_protocol_descriptor(&proto);
1032 
1033                     if (seq.next != seq.end)
1034                               printf("    [additional protocol data]\n");
1035           }
1036 
1037           if (data->next != data->end)
1038                     printf("    [additional data]\n");
1039 }
1040 
1041 static void
print_language_base_attribute_id_list(sdp_data_t * data)1042 print_language_base_attribute_id_list(sdp_data_t *data)
1043 {
1044           sdp_data_t list;
1045           uint16_t v;
1046           const char *codeset;
1047           char lang[2];
1048 
1049           if (!sdp_get_seq(data, &list))
1050                     return;
1051 
1052           printf("\n");
1053           while (list.next < list.end) {
1054                     /*
1055                      * ISO-639-1 natural language values are published at
1056                      *        http://www.loc.gov/standards/iso639-2/php/code-list.php
1057                      */
1058                     if (!sdp_get_uint16(&list, &v))
1059                               break;
1060 
1061                     be16enc(lang, v);
1062                     if (!islower((unsigned char)lang[0]) ||
1063                         !islower((unsigned char)lang[1]))
1064                               break;
1065 
1066                     /*
1067                      * MIBenum values are published at
1068                      *        http://www.iana.org/assignments/character-sets
1069                      */
1070                     if (!sdp_get_uint16(&list, &v))
1071                               break;
1072 
1073                     switch(v) {
1074                     case 3:             codeset = "US-ASCII";                   break;
1075                     case 4:             codeset = "ISO-8859-1";                 break;
1076                     case 5:             codeset = "ISO-8859-2";                 break;
1077                     case 106: codeset = "UTF-8";            break;
1078                     case 1013:          codeset = "UTF-16BE";                   break;
1079                     case 1014:          codeset = "UTF-16LE";                   break;
1080                     default:  codeset = "Unknown";                    break;
1081                     }
1082 
1083                     if (!sdp_get_uint16(&list, &v))
1084                               break;
1085 
1086                     printf("    %.2s.%s base 0x%04x\n", lang, codeset, v);
1087 
1088                     if (nlanguages < MAX_LANGUAGES) {
1089                               language[nlanguages].base = v;
1090                               language[nlanguages].codeset = codeset;
1091                               nlanguages++;
1092                     }
1093           }
1094 
1095           if (list.next != list.end)
1096                     printf("    [additional data]\n");
1097 }
1098 
1099 static void
print_service_availability(sdp_data_t * data)1100 print_service_availability(sdp_data_t *data)
1101 {
1102           uint8_t v;
1103 
1104           if (!sdp_get_uint8(data, &v))
1105                     return;
1106 
1107           printf("%d/%d\n", v, UINT8_MAX);
1108 }
1109 
1110 static void
print_bluetooth_profile_descriptor_list(sdp_data_t * data)1111 print_bluetooth_profile_descriptor_list(sdp_data_t *data)
1112 {
1113           sdp_data_t seq, profile;
1114           uuid_t uuid;
1115           uint16_t v;
1116 
1117           if (!sdp_get_seq(data, &seq))
1118                     return;
1119 
1120           printf("\n");
1121           while (seq.next < seq.end) {
1122                     if (!sdp_get_seq(&seq, &profile)
1123                         || !sdp_get_uuid(&profile, &uuid)
1124                         || !sdp_get_uint16(&profile, &v))
1125                               break;
1126 
1127                     printf("    %s, v%d.%d", string_uuid(&uuid),
1128                         (v >> 8), (v & 0xff));
1129 
1130                     if (profile.next != profile.end)
1131                               printf(" [additional profile data]");
1132 
1133                     printf("\n");
1134           }
1135 
1136           if (seq.next != seq.end)
1137                     printf("    [additional data]\n");
1138 }
1139 
1140 static void
print_additional_protocol_descriptor_lists(sdp_data_t * data)1141 print_additional_protocol_descriptor_lists(sdp_data_t *data)
1142 {
1143           sdp_data_t seq, stack, proto;
1144 
1145           printf("\n");
1146           sdp_get_seq(data, &seq);
1147 
1148           while (sdp_get_seq(&seq, &stack))
1149                     while (sdp_get_seq(&stack, &proto))
1150                               print_protocol_descriptor(&proto);
1151 
1152           if (seq.next != seq.end)
1153                     printf("    [additional data]\n");
1154 }
1155 
1156 static void
print_sds_version_number_list(sdp_data_t * data)1157 print_sds_version_number_list(sdp_data_t *data)
1158 {
1159           sdp_data_t list;
1160           const char *sep;
1161           uint16_t v;
1162 
1163           if (!sdp_get_seq(data, &list))
1164                     return;
1165 
1166           sep = "";
1167           while (sdp_get_uint16(&list, &v)) {
1168                     printf("%sv%d.%d", sep, (v >> 8), (v & 0xff));
1169                     sep = ", ";
1170           }
1171 
1172           if (list.next != list.end)
1173                     printf(" [additional data]");
1174 
1175           printf("\n");
1176 }
1177 
1178 static void
print_ct_network(sdp_data_t * data)1179 print_ct_network(sdp_data_t *data)
1180 {
1181           uint8_t v;
1182 
1183           if (!sdp_get_uint8(data, &v))
1184                     return;
1185 
1186           switch (v) {
1187           case 0x01:          printf("PSTN");                         break;
1188           case 0x02:          printf("ISDN");                         break;
1189           case 0x03:          printf("GSM");                          break;
1190           case 0x04:          printf("CDMA");                         break;
1191           case 0x05:          printf("Analogue Cellular");  break;
1192           case 0x06:          printf("Packet Switched");    break;
1193           case 0x07:          printf("Other");              break;
1194           default:  printf("0x%02x", v);                    break;
1195           }
1196 
1197           printf("\n");
1198 }
1199 
1200 static void
print_asrc_features(sdp_data_t * data)1201 print_asrc_features(sdp_data_t *data)
1202 {
1203           uint16_t v;
1204 
1205           if (!sdp_get_uint16(data, &v))
1206                     return;
1207 
1208           if (Nflag)
1209                     printf("(0x%04x)", v);
1210 
1211           printf("\n");
1212           if (v & (1<<0))     printf("    Player\n");
1213           if (v & (1<<1))     printf("    Microphone\n");
1214           if (v & (1<<2))     printf("    Tuner\n");
1215           if (v & (1<<3))     printf("    Mixer\n");
1216 }
1217 
1218 static void
print_asink_features(sdp_data_t * data)1219 print_asink_features(sdp_data_t *data)
1220 {
1221           uint16_t v;
1222 
1223           if (!sdp_get_uint16(data, &v))
1224                     return;
1225 
1226           if (Nflag)
1227                     printf("(0x%04x)", v);
1228 
1229           printf("\n");
1230           if (v & (1<<0))     printf("    Headphone\n");
1231           if (v & (1<<1))     printf("    Speaker\n");
1232           if (v & (1<<2))     printf("    Recorder\n");
1233           if (v & (1<<3))     printf("    Amplifier\n");
1234 }
1235 
1236 static void
print_avrcp_features(sdp_data_t * data)1237 print_avrcp_features(sdp_data_t *data)
1238 {
1239           uint16_t v;
1240 
1241           if (!sdp_get_uint16(data, &v))
1242                     return;
1243 
1244           if (Nflag)
1245                     printf("(0x%04x)", v);
1246 
1247           printf("\n");
1248           if (v & (1<<0))     printf("    Category 1\n");
1249           if (v & (1<<1))     printf("    Category 2\n");
1250           if (v & (1<<2))     printf("    Category 3\n");
1251           if (v & (1<<3))     printf("    Category 4\n");
1252 }
1253 
1254 static void
print_supported_data_stores(sdp_data_t * data)1255 print_supported_data_stores(sdp_data_t *data)
1256 {
1257           sdp_data_t list;
1258           const char *sep;
1259           uint8_t v;
1260 
1261           if (!sdp_get_seq(data, &list))
1262                     return;
1263 
1264           sep = "\n    ";
1265           while (sdp_get_uint8(&list, &v)) {
1266                     printf("%s", sep);
1267                     sep = ", ";
1268 
1269                     switch(v) {
1270                     case 0x01:          printf("Phonebook");          break;
1271                     case 0x03:          printf("Calendar"); break;
1272                     case 0x05:          printf("Notes");    break;
1273                     case 0x06:          printf("Messages"); break;
1274                     default:  printf("0x%02x", v);          break;
1275                     }
1276           }
1277 
1278           if (list.next != list.end)
1279                     printf("   [additional data]");
1280 
1281           printf("\n");
1282 }
1283 
1284 static void
print_supported_formats(sdp_data_t * data)1285 print_supported_formats(sdp_data_t *data)
1286 {
1287           sdp_data_t list;
1288           const char *sep;
1289           uint8_t v;
1290 
1291           if (!sdp_get_seq(data, &list))
1292                     return;
1293 
1294           sep = "\n    ";
1295           while (sdp_get_uint8(&list, &v)) {
1296                     printf("%s", sep);
1297                     sep = ", ";
1298 
1299                     switch(v) {
1300                     case 0x01:          printf("vCard 2.1");          break;
1301                     case 0x02:          printf("vCard 3.0");          break;
1302                     case 0x03:          printf("vCal 1.0"); break;
1303                     case 0x04:          printf("iCal 2.0"); break;
1304                     case 0x05:          printf("vNote");    break;
1305                     case 0x06:          printf("vMessage"); break;
1306                     case 0xff:          printf("Any");                break;
1307                     default:  printf("0x%02x", v);          break;
1308                     }
1309           }
1310 
1311           if (list.next != list.end)
1312                     printf("   [additional data]");
1313 
1314           printf("\n");
1315 }
1316 
1317 static void
print_wap_addr(sdp_data_t * data)1318 print_wap_addr(sdp_data_t *data)
1319 {
1320           uint32_t v;
1321 
1322           if (!sdp_get_uint32(data, &v))
1323                     return;
1324 
1325           printf("%d.%d.%d.%d\n",
1326               ((v & 0xff000000) >> 24), ((v & 0x00ff0000) >> 16),
1327               ((v & 0x0000ff00) >> 8), (v & 0x000000ff));
1328 }
1329 
1330 static void
print_wap_gateway(sdp_data_t * data)1331 print_wap_gateway(sdp_data_t *data)
1332 {
1333           uint8_t v;
1334 
1335           if (!sdp_get_uint8(data, &v))
1336                     return;
1337 
1338           switch(v) {
1339           case 0x01:          printf("Origin Server\n");    break;
1340           case 0x02:          printf("Proxy\n");            break;
1341           default:  printf("0x%02x\n", v);                  break;
1342           }
1343 }
1344 
1345 static void
print_wap_type(sdp_data_t * data)1346 print_wap_type(sdp_data_t *data)
1347 {
1348           uint8_t v;
1349 
1350           if (!sdp_get_uint8(data, &v))
1351                     return;
1352 
1353           switch(v) {
1354           case 0x01:          printf("Connectionless\n");   break;
1355           case 0x02:          printf("Connection Oriented\n");break;
1356           case 0x03:          printf("Both\n");             break;
1357           default:  printf("0x%02x\n", v);                  break;
1358           }
1359 }
1360 
1361 static void
print_hid_version(sdp_data_t * data)1362 print_hid_version(sdp_data_t *data)
1363 {
1364           uint16_t v;
1365 
1366           if (!sdp_get_uint16(data, &v))
1367                     return;
1368 
1369           printf("v%d.%d.%d\n",
1370               ((v & 0xff00) >> 8), ((v & 0x00f0) >> 4), (v & 0x000f));
1371 }
1372 
1373 static void
print_hid_device_subclass(sdp_data_t * data)1374 print_hid_device_subclass(sdp_data_t *data)
1375 {
1376           uint8_t v;
1377 
1378           if (!sdp_get_uint8(data, &v))
1379                     return;
1380 
1381           switch ((v & 0x3c) >> 2) {
1382           case 1:             printf("Joystick");           break;
1383           case 2:             printf("Gamepad");            break;
1384           case 3:             printf("Remote Control");     break;
1385           case 4:             printf("Sensing Device");     break;
1386           case 5:             printf("Digitiser Tablet");   break;
1387           case 6:             printf("Card Reader");                  break;
1388           default:  printf("Peripheral");                   break;
1389           }
1390 
1391           if (v & 0x40)       printf(" <Keyboard>");
1392           if (v & 0x80)       printf(" <Mouse>");
1393 
1394           printf("\n");
1395 }
1396 
1397 static void
print_hid_descriptor_list(sdp_data_t * data)1398 print_hid_descriptor_list(sdp_data_t *data)
1399 {
1400           sdp_data_t list, seq;
1401           uint8_t type;
1402           const char *name;
1403           char *str;
1404           size_t len;
1405 
1406           if (!sdp_get_seq(data, &list))
1407                     return;
1408 
1409           printf("\n");
1410           while (list.next < list.end) {
1411                     if (!sdp_get_seq(&list, &seq)
1412                         || !sdp_get_uint8(&seq, &type)
1413                         || !sdp_get_str(&seq, &str, &len))
1414                               return;
1415 
1416                     switch (type) {
1417                     case 0x22:          name = "Report";              break;
1418                     case 0x23:          name = "Physical Descriptor"; break;
1419                     default:  name = "";                              break;
1420                     }
1421 
1422                     printf("    Type 0x%02x: %s\n", type, name);
1423                     print_hexdump("    Data", (uint8_t *)str, len);
1424 
1425                     if (seq.next != seq.end)
1426                               printf("    [additional data]\n");
1427           }
1428 }
1429 
1430 static void
print_hid_langid_base_list(sdp_data_t * data)1431 print_hid_langid_base_list(sdp_data_t *data)
1432 {
1433           sdp_data_t list, seq;
1434           uint16_t lang, base;
1435 
1436           if (!sdp_get_seq(data, &list))
1437                     return;
1438 
1439           while (list.next < list.end) {
1440                     if (!sdp_get_seq(&list, &seq)
1441                         || !sdp_get_uint16(&seq, &lang)
1442                         || !sdp_get_uint16(&seq, &base))
1443                               return;
1444 
1445                     printf("\n    ");
1446                     /*
1447                      * The language is encoded according to the
1448                      *   "Universal Serial Bus Language Identifiers (LANGIDs)"
1449                      * specification. It does not seem worth listing them all
1450                      * here, but feel free to add if you notice any being used.
1451                      */
1452                     switch (lang) {
1453                     case 0x0409:        printf("English (US)");                 break;
1454                     case 0x0809:        printf("English (UK)");                 break;
1455                     default:  printf("0x%04x", lang);                 break;
1456                     }
1457 
1458                     printf(" base 0x%04x%s\n", base,
1459                         (seq.next == seq.end ? "" : " [additional data]"));
1460           }
1461 }
1462 
1463 static void
print_security_description(sdp_data_t * data)1464 print_security_description(sdp_data_t *data)
1465 {
1466           uint16_t v;
1467 
1468           if (!sdp_get_uint16(data, &v))
1469                     return;
1470 
1471           switch (v) {
1472           case 0x0000:        printf("None");                                   break;
1473           case 0x0001:        printf("Service-level Security");       break;
1474           case 0x0002:        printf("802.1x Security");              break;
1475           default:  printf("0x%04x", v);                              break;
1476           }
1477 
1478           printf("\n");
1479 }
1480 
1481 static void
print_hf_features(sdp_data_t * data)1482 print_hf_features(sdp_data_t *data)
1483 {
1484           uint16_t v;
1485 
1486           if (!sdp_get_uint16(data, &v))
1487                     return;
1488 
1489           if (Nflag)
1490                     printf("(0x%04x)", v);
1491 
1492           printf("\n");
1493           if (v & (1<<0))     printf("    Echo Cancellation/Noise Reduction\n");
1494           if (v & (1<<1))     printf("    Call Waiting\n");
1495           if (v & (1<<2))     printf("    Caller Line Identification\n");
1496           if (v & (1<<3))     printf("    Voice Recognition\n");
1497           if (v & (1<<4))     printf("    Volume Control\n");
1498 }
1499 
1500 static void
print_hfag_network(sdp_data_t * data)1501 print_hfag_network(sdp_data_t *data)
1502 {
1503           uint8_t v;
1504 
1505           if (!sdp_get_uint8(data, &v))
1506                     return;
1507 
1508           switch (v) {
1509           case 0x01:          printf("Ability to reject a call");     break;
1510           case 0x02:          printf("No ability to reject a call");  break;
1511           default:  printf("0x%02x", v);                              break;
1512           }
1513 
1514           printf("\n");
1515 }
1516 
1517 static void
print_hfag_features(sdp_data_t * data)1518 print_hfag_features(sdp_data_t *data)
1519 {
1520           uint16_t v;
1521 
1522           if (!sdp_get_uint16(data, &v))
1523                     return;
1524 
1525           if (Nflag)
1526                     printf("(0x%04x)", v);
1527 
1528           printf("\n");
1529           if (v & (1<<0))     printf("    3 Way Calling\n");
1530           if (v & (1<<1))     printf("    Echo Cancellation/Noise Reduction\n");
1531           if (v & (1<<2))     printf("    Voice Recognition\n");
1532           if (v & (1<<3))     printf("    In-band Ring Tone\n");
1533           if (v & (1<<4))     printf("    Voice Tags\n");
1534 }
1535 
1536 static void
print_net_access_type(sdp_data_t * data)1537 print_net_access_type(sdp_data_t *data)
1538 {
1539           uint16_t v;
1540 
1541           if (!sdp_get_uint16(data, &v))
1542                     return;
1543 
1544           switch(v) {
1545           case 0x0000:        printf("PSTN");                         break;
1546           case 0x0001:        printf("ISDN");                         break;
1547           case 0x0002:        printf("DSL");                          break;
1548           case 0x0003:        printf("Cable Modem");                  break;
1549           case 0x0004:        printf("10Mb Ethernet");      break;
1550           case 0x0005:        printf("100Mb Ethernet");     break;
1551           case 0x0006:        printf("4Mb Token Ring");     break;
1552           case 0x0007:        printf("16Mb Token Ring");    break;
1553           case 0x0008:        printf("100Mb Token Ring");   break;
1554           case 0x0009:        printf("FDDI");                         break;
1555           case 0x000a:        printf("GSM");                          break;
1556           case 0x000b:        printf("CDMA");                         break;
1557           case 0x000c:        printf("GPRS");                         break;
1558           case 0x000d:        printf("3G Cellular");                  break;
1559           case 0xfffe:        printf("other");              break;
1560           default:  printf("0x%04x", v);                    break;
1561           }
1562 
1563           printf("\n");
1564 }
1565 
1566 static void
print_pnp_source(sdp_data_t * data)1567 print_pnp_source(sdp_data_t *data)
1568 {
1569           uint16_t v;
1570 
1571           if (!sdp_get_uint16(data, &v))
1572                     return;
1573 
1574           switch (v) {
1575           case 0x0001:        printf("Bluetooth SIG");                break;
1576           case 0x0002:        printf("USB Implementers Forum");       break;
1577           default:  printf("0x%04x", v);                              break;
1578           }
1579 
1580           printf("\n");
1581 }
1582 
1583 static void
print_mas_types(sdp_data_t * data)1584 print_mas_types(sdp_data_t *data)
1585 {
1586           uint8_t v;
1587 
1588           if (!sdp_get_uint8(data, &v))
1589                     return;
1590 
1591           if (Nflag)
1592                     printf("(0x%02x)", v);
1593 
1594           printf("\n");
1595           if (v & (1<<0))     printf("    EMAIL\n");
1596           if (v & (1<<1))     printf("    SMS_GSM\n");
1597           if (v & (1<<2))     printf("    SMS_CDMA\n");
1598           if (v & (1<<3))     printf("    MMS\n");
1599 }
1600 
1601 static void
print_map_features(sdp_data_t * data)1602 print_map_features(sdp_data_t *data)
1603 {
1604           uint32_t v;
1605 
1606           if (!sdp_get_uint32(data, &v))
1607                     return;
1608 
1609           if (Nflag)
1610                     printf("(0x%08x)", v);
1611 
1612           printf("\n");
1613           if (v & (1<<0))     printf("    Notification Registration\n");
1614           if (v & (1<<1))     printf("    Notification\n");
1615           if (v & (1<<2))     printf("    Browsing\n");
1616           if (v & (1<<3))     printf("    Uploading\n");
1617           if (v & (1<<4))     printf("    Delete\n");
1618           if (v & (1<<5))     printf("    Instance Information\n");
1619           if (v & (1<<6))     printf("    Extended Event Report 1.1\n");
1620 }
1621 
1622 static void
print_pse_repositories(sdp_data_t * data)1623 print_pse_repositories(sdp_data_t *data)
1624 {
1625           uint8_t v;
1626 
1627           if (!sdp_get_uint8(data, &v))
1628                     return;
1629 
1630           if (Nflag)
1631                     printf("(0x%02x)", v);
1632 
1633           printf("\n");
1634           if (v & (1<<0))     printf("    Local Phonebook\n");
1635           if (v & (1<<1))     printf("    SIM Card\n");
1636           if (v & (1<<2))     printf("    Speed Dial\n");
1637           if (v & (1<<3))     printf("    Favorites\n");
1638 }
1639 
1640 static void
print_pse_features(sdp_data_t * data)1641 print_pse_features(sdp_data_t *data)
1642 {
1643           uint32_t v;
1644 
1645           if (!sdp_get_uint32(data, &v))
1646                     return;
1647 
1648           if (Nflag)
1649                     printf("(0x%08x)", v);
1650 
1651           printf("\n");
1652           if (v & (1<<0))     printf("    Download\n");
1653           if (v & (1<<1))     printf("    Browsing\n");
1654           if (v & (1<<2))     printf("    Database Identifier\n");
1655           if (v & (1<<3))     printf("    Folder Version Counters\n");
1656           if (v & (1<<4))     printf("    vCard Selecting\n");
1657           if (v & (1<<5))     printf("    Enhanced Missed Calls\n");
1658           if (v & (1<<6))     printf("    X-BT-UCI vCard Property\n");
1659           if (v & (1<<7))     printf("    X-BT-UID vCard Property\n");
1660           if (v & (1<<8))     printf("    Contact Referencing\n");
1661           if (v & (1<<9))     printf("    Default Contact Image Format\n");
1662 }
1663 
1664 static void
print_hdp_features(sdp_data_t * data)1665 print_hdp_features(sdp_data_t *data)
1666 {
1667           sdp_data_t seq, feature;
1668           char *str;
1669           size_t len;
1670           uint16_t type;
1671           uint8_t id, role;
1672 
1673           if (!sdp_get_seq(data, &seq))
1674                     return;
1675 
1676           printf("\n");
1677           while (sdp_get_seq(&seq, &feature)) {
1678                     if (!sdp_get_uint8(&feature, &id)
1679                         || !sdp_get_uint16(&feature, &type)
1680                         || !sdp_get_uint8(&feature, &role))
1681                               break;
1682 
1683                     printf("    # %d: ", id);
1684 
1685                     switch(type) {
1686                     case 0x1004:        printf("Pulse Oximeter"); break;
1687                     case 0x1006:        printf("Basic ECG"); break;
1688                     case 0x1007:        printf("Blood Pressure Monitor"); break;
1689                     case 0x1008:        printf("Body Thermometer"); break;
1690                     case 0x100F:        printf("Body Weight Scale"); break;
1691                     case 0x1011:        printf("Glucose Meter"); break;
1692                     case 0x1012:        printf("International Normalized Ratio Monitor"); break;
1693                     case 0x1014:        printf("Body Composition Analyzer"); break;
1694                     case 0x1015:        printf("Peak Flow Monitor"); break;
1695                     case 0x1029:        printf("Cardiovascular Fitness and Activity Monitor"); break;
1696                     case 0x1068:        printf("Step Counter"); break;
1697                     case 0x102A:        printf("Strength Fitness Equipment"); break;
1698                     case 0x1047:        printf("Independent Living Activity Hub"); break;
1699                     case 0x1075:        printf("Fall Sensor"); break;
1700                     case 0x1076:        printf("Personal Emergency Response Sensor"); break;
1701                     case 0x1077:        printf("Smoke Sensor"); break;
1702                     case 0x1078:        printf("Carbon Monoxide Sensor"); break;
1703                     case 0x1079:        printf("Water Sensor"); break;
1704                     case 0x107A:        printf("Gas Sensor"); break;
1705                     case 0x107B:        printf("Motion Sensor"); break;
1706                     case 0x107C:        printf("Property Exit Sensor"); break;
1707                     case 0x107D:        printf("Enuresis Sensor"); break;
1708                     case 0x107E:        printf("Contact Closure Sensor"); break;
1709                     case 0x107F:        printf("Usage Sensor"); break;
1710                     case 0x1080:        printf("Switch Sensor"); break;
1711                     case 0x1081:        printf("Medication Dosing Sensor"); break;
1712                     case 0x1082:        printf("Temperature Sensor"); break;
1713                     case 0x1048:        printf("Medication monitor"); break;
1714                     default:  printf("Type 0x%04x", type);  break;
1715                     }
1716 
1717                     switch(role) {
1718                     case 0x00:          printf(" [Source]");                    break;
1719                     case 0x01:          printf(" [Sink]");            break;
1720                     default:  printf(" [Role 0x%02x]", role);         break;
1721                     }
1722 
1723                     printf("\n");
1724 
1725                     if (sdp_get_str(&feature, &str, &len)) {
1726                               int n;
1727 
1728                               /* This optional human-readable description should
1729                                * be in the primary language encoding, which ought
1730                                * to have a base of 0x0100 or if there isn't one,
1731                                * use the first encoding listed
1732                                */
1733                               for (n = 0; n < nlanguages; n++) {
1734                                         if (language[n].base == 0x0100)
1735                                                   break;
1736                               }
1737 
1738                               printf("    # %d: ", id);
1739                               if (n < nlanguages)
1740                                         print_codeset_string(str, len, language[n].codeset);
1741                               else if (n > 0)
1742                                         print_codeset_string(str, len, language[0].codeset);
1743                               else
1744                                         printf("%s", string_vis(str, len));
1745 
1746                               printf("\n");
1747                     }
1748 
1749                     if (feature.next != feature.end)
1750                               printf("    [additional data in feature]\n");
1751           }
1752 
1753           if (seq.next != seq.end)
1754                     printf("    [additional data]\n");
1755 }
1756 
1757 static void
print_hdp_specification(sdp_data_t * data)1758 print_hdp_specification(sdp_data_t *data)
1759 {
1760           uint8_t v;
1761 
1762           if (!sdp_get_uint8(data, &v))
1763                     return;
1764 
1765           switch(v) {
1766           case 0x01:          printf("ISO/IEEE 11073-20601\n");       break;
1767           default:  printf("0x%02x\n", v);                            break;
1768           }
1769 }
1770 
1771 static void
print_mcap_procedures(sdp_data_t * data)1772 print_mcap_procedures(sdp_data_t *data)
1773 {
1774           uint8_t v;
1775 
1776           if (!sdp_get_uint8(data, &v))
1777                     return;
1778 
1779           if (Nflag)
1780                     printf("(0x%02x)", v);
1781 
1782           printf("\n");
1783           if (v & (1<<1))     printf("    Reconnect Initiation\n");
1784           if (v & (1<<2))     printf("    Reconnect Acceptance\n");
1785           if (v & (1<<3))     printf("    Clock Synchronization Protocol\n");
1786           if (v & (1<<4))     printf("    Sync-Master Role\n");
1787 }
1788 
1789 static void
print_character_repertoires(sdp_data_t * data)1790 print_character_repertoires(sdp_data_t *data)
1791 {
1792           uintmax_t v;
1793 
1794           /*
1795            * we have no uint128 type so use uintmax as only
1796            * only 17-bits are currently defined, and if the
1797            * value is out of bounds it will be printed anyway
1798            */
1799           if (sdp_data_type(data) != SDP_DATA_UINT128
1800               || !sdp_get_uint(data, &v))
1801                     return;
1802 
1803           if (Nflag)
1804                     printf("(0x%016jx)", v);
1805 
1806           printf("\n");
1807           if (v & (1<< 0)) printf("    ISO-8859-1\n");
1808           if (v & (1<< 1)) printf("    ISO-8859-2\n");
1809           if (v & (1<< 2)) printf("    ISO-8859-3\n");
1810           if (v & (1<< 3)) printf("    ISO-8859-4\n");
1811           if (v & (1<< 4)) printf("    ISO-8859-5\n");
1812           if (v & (1<< 5)) printf("    ISO-8859-6\n");
1813           if (v & (1<< 6)) printf("    ISO-8859-7\n");
1814           if (v & (1<< 7)) printf("    ISO-8859-8\n");
1815           if (v & (1<< 8)) printf("    ISO-8859-9\n");
1816           if (v & (1<< 9)) printf("    ISO-8859-10\n");
1817           if (v & (1<<10)) printf("    ISO-8859-13\n");
1818           if (v & (1<<11)) printf("    ISO-8859-14\n");
1819           if (v & (1<<12)) printf("    ISO-8859-15\n");
1820           if (v & (1<<13)) printf("    GB18030\n");
1821           if (v & (1<<14)) printf("    JIS X0208-1990, JIS X0201-1976\n");
1822           if (v & (1<<15)) printf("    KSC 5601-1992\n");
1823           if (v & (1<<16)) printf("    Big5\n");
1824           if (v & (1<<17)) printf("    TIS-620\n");
1825 }
1826 
1827 static void
print_bip_capabilities(sdp_data_t * data)1828 print_bip_capabilities(sdp_data_t *data)
1829 {
1830           uint8_t v;
1831 
1832           if (!sdp_get_uint8(data, &v))
1833                     return;
1834 
1835           if (Nflag)
1836                     printf("(0x%02x)", v);
1837 
1838           printf("\n");
1839           if (v & (1<< 0)) printf("    Generic imaging\n");
1840           if (v & (1<< 1)) printf("    Capturing\n");
1841           if (v & (1<< 2)) printf("    Printing\n");
1842           if (v & (1<< 3)) printf("    Displaying\n");
1843 }
1844 
1845 static void
print_bip_features(sdp_data_t * data)1846 print_bip_features(sdp_data_t *data)
1847 {
1848           uint16_t v;
1849 
1850           if (!sdp_get_uint16(data, &v))
1851                     return;
1852 
1853           if (Nflag)
1854                     printf("(0x%04x)", v);
1855 
1856           printf("\n");
1857           if (v & (1<<0))     printf("    ImagePush\n");
1858           if (v & (1<<1))     printf("    ImagePush-Store\n");
1859           if (v & (1<<2))     printf("    ImagePush-Print\n");
1860           if (v & (1<<3))     printf("    ImagePush-Display\n");
1861           if (v & (1<<4))     printf("    ImagePull\n");
1862           if (v & (1<<5))     printf("    AdvancedImagePrinting\n");
1863           if (v & (1<<6))     printf("    AutomaticArchive\n");
1864           if (v & (1<<7))     printf("    RemoteCamera\n");
1865           if (v & (1<<8))     printf("    RemoteDisplay\n");
1866 }
1867 
1868 static void
print_bip_functions(sdp_data_t * data)1869 print_bip_functions(sdp_data_t *data)
1870 {
1871           uint32_t v;
1872 
1873           if (!sdp_get_uint32(data, &v))
1874                     return;
1875 
1876           if (Nflag)
1877                     printf("(0x%08x)", v);
1878 
1879           printf("\n");
1880           if (v & (1<< 0)) printf("    GetCapabilities\n");
1881           if (v & (1<< 1)) printf("    PutImage\n");
1882           if (v & (1<< 2)) printf("    PutLinkedAttachment\n");
1883           if (v & (1<< 3)) printf("    PutLinkedThumbnail\n");
1884           if (v & (1<< 4)) printf("    RemoteDisplay\n");
1885           if (v & (1<< 5)) printf("    GetImagesList\n");
1886           if (v & (1<< 6)) printf("    GetImageProperties\n");
1887           if (v & (1<< 7)) printf("    GetImage\n");
1888           if (v & (1<< 8)) printf("    GetLinkedThumbnail\n");
1889           if (v & (1<< 9)) printf("    GetLinkedAttachment\n");
1890           if (v & (1<<10)) printf("    DeleteImage\n");
1891           if (v & (1<<11)) printf("    StartPrint\n");
1892           if (v & (1<<12)) printf("    GetPartialImage\n");
1893           if (v & (1<<13)) printf("    StartArchive\n");
1894           if (v & (1<<14)) printf("    GetMonitoringImage\n");
1895           if (v & (1<<16)) printf("    GetStatus\n");
1896 }
1897 
1898 static void
print_bip_capacity(sdp_data_t * data)1899 print_bip_capacity(sdp_data_t *data)
1900 {
1901           char buf[9];
1902           uint64_t v;
1903 
1904           if (!sdp_get_uint64(data, &v))
1905                     return;
1906 
1907           if (v > INT64_MAX) {
1908                     printf("more than ");
1909                     v = INT64_MAX;
1910           }
1911 
1912           (void)humanize_number(buf, sizeof(buf), (int64_t)v,
1913               "bytes", HN_AUTOSCALE, HN_NOSPACE);
1914 
1915           printf("%s\n", buf);
1916 }
1917 
1918 static void
print_1284id(sdp_data_t * data)1919 print_1284id(sdp_data_t *data)
1920 {
1921           char *str, *ep;
1922           size_t len, l;
1923 
1924           if (!sdp_get_str(data, &str, &len))
1925                     return;
1926 
1927           if (len < 2 || len != be16dec(str)) {
1928                     printf("[invalid IEEE 1284 Device ID]\n");
1929                     return;
1930           }
1931 
1932           str += 2;
1933           len -= 2;
1934 
1935           printf("\n");
1936           while (len > 0) {
1937                     ep = memchr(str, (int)';', len);
1938                     if (ep == NULL) {
1939                               printf("[invalid IEEE 1284 Device ID]\n");
1940                               return;
1941                     }
1942 
1943                     l = (size_t)(ep - str + 1);
1944                     printf("    %s\n", string_vis(str, l));
1945                     str += l;
1946                     len -= l;
1947           }
1948 }
1949 
1950 static void
print_ctn_features(sdp_data_t * data)1951 print_ctn_features(sdp_data_t *data)
1952 {
1953           uint32_t v;
1954 
1955           if (!sdp_get_uint32(data, &v))
1956                     return;
1957 
1958           if (Nflag)
1959                     printf("(0x%08x)", v);
1960 
1961           printf("\n");
1962           if (v & (1<<0))     printf("    Account Management\n");
1963           if (v & (1<<1))     printf("    Notification\n");
1964           if (v & (1<<2))     printf("    Browsing\n");
1965           if (v & (1<<3))     printf("    Downloading\n");
1966           if (v & (1<<4))     printf("    Uploading\n");
1967           if (v & (1<<5))     printf("    Delete\n");
1968           if (v & (1<<6))     printf("    Forward\n");
1969 }
1970 
1971 static void
print_rfcomm(sdp_data_t * data)1972 print_rfcomm(sdp_data_t *data)
1973 {
1974           uint8_t v;
1975 
1976           if (sdp_get_uint8(data, &v))
1977                     printf(" (channel %d)", v);
1978 }
1979 
1980 static void
print_att(sdp_data_t * data)1981 print_att(sdp_data_t *data)
1982 {
1983           uint16_t s, e;
1984 
1985           if (sdp_get_uint16(data, &s) && sdp_get_uint16(data, &e))
1986                     printf(" (0x%04x .. 0x%04x)", s, e);
1987 }
1988 
1989 static void
print_bnep(sdp_data_t * data)1990 print_bnep(sdp_data_t *data)
1991 {
1992           sdp_data_t seq;
1993           uint16_t v;
1994           const char *sep;
1995 
1996           if (!sdp_get_uint16(data, &v)
1997               || !sdp_get_seq(data, &seq))
1998                     return;
1999 
2000           printf(" (v%d.%d", (v >> 8), (v & 0xff));
2001           sep = "; ";
2002           while (sdp_get_uint16(&seq, &v)) {
2003                     printf("%s", sep);
2004                     sep = ", ";
2005 
2006                     switch (v) {
2007                     case 0x0800:        printf("IPv4");               break;
2008                     case 0x0806:        printf("ARP");                break;
2009                     case 0x8100:        printf("802.1Q");   break;
2010                     case 0x86dd:        printf("IPv6");               break;
2011                     default:  printf("0x%04x", v);          break;
2012                     }
2013           }
2014           printf(")");
2015 
2016           if (seq.next != seq.end)
2017                     printf(" [additional data]");
2018 }
2019 
2020 static void
print_avctp(sdp_data_t * data)2021 print_avctp(sdp_data_t *data)
2022 {
2023           uint16_t v;
2024 
2025           if (sdp_get_uint16(data, &v))
2026                     printf(" (v%d.%d)", (v >> 8), (v & 0xff));
2027 }
2028 
2029 static void
print_avdtp(sdp_data_t * data)2030 print_avdtp(sdp_data_t *data)
2031 {
2032           uint16_t v;
2033 
2034           if (sdp_get_uint16(data, &v))
2035                     printf(" (v%d.%d)", (v >> 8), (v & 0xff));
2036 }
2037 
2038 static void
print_l2cap(sdp_data_t * data)2039 print_l2cap(sdp_data_t *data)
2040 {
2041           uint16_t v;
2042 
2043           if (sdp_get_uint16(data, &v))
2044                     printf(" (PSM 0x%04x)", v);
2045 }
2046