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