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