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