1330449Seadler/*-
2121054Semax * search.c
3121054Semax *
4330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5330449Seadler *
6121054Semax * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7121054Semax * All rights reserved.
8121054Semax *
9121054Semax * Redistribution and use in source and binary forms, with or without
10121054Semax * modification, are permitted provided that the following conditions
11121054Semax * are met:
12121054Semax * 1. Redistributions of source code must retain the above copyright
13121054Semax *    notice, this list of conditions and the following disclaimer.
14121054Semax * 2. Redistributions in binary form must reproduce the above copyright
15121054Semax *    notice, this list of conditions and the following disclaimer in the
16121054Semax *    documentation and/or other materials provided with the distribution.
17121054Semax *
18121054Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21121054Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28121054Semax * SUCH DAMAGE.
29121054Semax *
30121054Semax * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
31121054Semax * $FreeBSD: stable/11/usr.sbin/bluetooth/sdpcontrol/search.c 330449 2018-03-05 07:26:05Z eadler $
32121054Semax */
33121054Semax
34146691Semax#include <netinet/in.h>
35281210Stakawata#define L2CAP_SOCKET_CHECKED
36121054Semax#include <bluetooth.h>
37121054Semax#include <ctype.h>
38121054Semax#include <sdp.h>
39121054Semax#include <stdio.h>
40121054Semax#include <stdlib.h>
41121054Semax#include "sdpcontrol.h"
42121054Semax
43121054Semax/* List of the attributes we are looking for */
44124317Semaxstatic uint32_t	attrs[] =
45121054Semax{
46121054Semax	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_RECORD_HANDLE,
47121054Semax			SDP_ATTR_SERVICE_RECORD_HANDLE),
48121054Semax	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_CLASS_ID_LIST,
49121054Semax			SDP_ATTR_SERVICE_CLASS_ID_LIST),
50121054Semax	SDP_ATTR_RANGE(	SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
51121054Semax			SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
52121054Semax	SDP_ATTR_RANGE(	SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
53121054Semax			SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
54121054Semax};
55121054Semax#define attrs_len	(sizeof(attrs)/sizeof(attrs[0]))
56121054Semax
57121054Semax/* Buffer for the attributes */
58121054Semax#define NRECS	25	/* request this much records from the SDP server */
59121054Semax#define	BSIZE	256	/* one attribute buffer size */
60124317Semaxstatic uint8_t		buffer[NRECS * attrs_len][BSIZE];
61121054Semax
62121054Semax/* SDP attributes */
63121054Semaxstatic sdp_attr_t	values[NRECS * attrs_len];
64121054Semax#define values_len	(sizeof(values)/sizeof(values[0]))
65121054Semax
66121054Semax/*
67121054Semax * Print Service Class ID List
68121054Semax *
69121054Semax * The ServiceClassIDList attribute consists of a data element sequence in
70121054Semax * which each data element is a UUID representing the service classes that
71121054Semax * a given service record conforms to. The UUIDs are listed in order from
72121054Semax * the most specific class to the most general class. The ServiceClassIDList
73121054Semax * must contain at least one service class UUID.
74121054Semax */
75121054Semax
76121054Semaxstatic void
77124317Semaxprint_service_class_id_list(uint8_t const *start, uint8_t const *end)
78121054Semax{
79124317Semax	uint32_t	type, len, value;
80121054Semax
81121054Semax	if (end - start < 2) {
82121054Semax		fprintf(stderr, "Invalid Service Class ID List. " \
83128076Semax				"Too short, len=%zd\n", end - start);
84121054Semax		return;
85121054Semax	}
86121054Semax
87121054Semax	SDP_GET8(type, start);
88121054Semax	switch (type) {
89121054Semax	case SDP_DATA_SEQ8:
90121054Semax		SDP_GET8(len, start);
91121054Semax		break;
92121054Semax
93121054Semax	case SDP_DATA_SEQ16:
94121054Semax		SDP_GET16(len, start);
95121054Semax		break;
96121054Semax
97121054Semax	case SDP_DATA_SEQ32:
98121054Semax		SDP_GET32(len, start);
99121054Semax		break;
100121054Semax
101121054Semax	default:
102121054Semax		fprintf(stderr, "Invalid Service Class ID List. " \
103121054Semax				"Not a sequence, type=%#x\n", type);
104121054Semax		return;
105121054Semax		/* NOT REACHED */
106121054Semax	}
107121054Semax
108289637Semax	if (len > (end - start)) {
109289637Semax		fprintf(stderr, "Invalid Service Class ID List. " \
110289637Semax				"Too long len=%d\n", len);
111289637Semax		return;
112289637Semax	}
113289637Semax
114121054Semax	while (start < end) {
115121054Semax		SDP_GET8(type, start);
116121054Semax		switch (type) {
117121054Semax		case SDP_DATA_UUID16:
118121054Semax			SDP_GET16(value, start);
119121054Semax			fprintf(stdout, "\t%s (%#4.4x)\n",
120121054Semax					sdp_uuid2desc(value), value);
121121054Semax			break;
122121054Semax
123121054Semax		case SDP_DATA_UUID32:
124121054Semax			SDP_GET32(value, start);
125121054Semax			fprintf(stdout, "\t%#8.8x\n", value);
126121054Semax			break;
127121054Semax
128121054Semax		case SDP_DATA_UUID128: {
129121054Semax			int128_t	uuid;
130121054Semax
131146691Semax			SDP_GET_UUID128(&uuid, start);
132121054Semax			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
133146691Semax					ntohl(*(uint32_t *)&uuid.b[0]),
134146691Semax					ntohs(*(uint16_t *)&uuid.b[4]),
135146691Semax					ntohs(*(uint16_t *)&uuid.b[6]),
136146691Semax					ntohs(*(uint16_t *)&uuid.b[8]),
137146691Semax					ntohs(*(uint16_t *)&uuid.b[10]),
138146691Semax					ntohl(*(uint32_t *)&uuid.b[12]));
139121054Semax			} break;
140121054Semax
141121054Semax		default:
142121054Semax			fprintf(stderr, "Invalid Service Class ID List. " \
143121054Semax					"Not a UUID, type=%#x\n", type);
144121054Semax			return;
145121054Semax			/* NOT REACHED */
146121054Semax		}
147121054Semax	}
148121054Semax} /* print_service_class_id_list */
149121054Semax
150121054Semax/*
151121054Semax * Print Protocol Descriptor List
152121054Semax *
153121054Semax * If the ProtocolDescriptorList describes a single stack, it takes the form
154121054Semax * of a data element sequence in which each element of the sequence is a
155121054Semax * protocol descriptor. Each protocol descriptor is, in turn, a data element
156121054Semax * sequence whose first element is a UUID identifying the protocol and whose
157121054Semax * successive elements are protocol-specific parameters. The protocol
158121054Semax * descriptors are listed in order from the lowest layer protocol to the
159121054Semax * highest layer protocol used to gain access to the service. If it is possible
160121054Semax * for more than one kind of protocol stack to be used to gain access to the
161121054Semax * service, the ProtocolDescriptorList takes the form of a data element
162121054Semax * alternative where each member is a data element sequence as described above.
163121054Semax */
164121054Semax
165121054Semaxstatic void
166124317Semaxprint_protocol_descriptor(uint8_t const *start, uint8_t const *end)
167121054Semax{
168121054Semax	union {
169121054Semax		uint8_t		uint8;
170121054Semax		uint16_t	uint16;
171121054Semax		uint32_t	uint32;
172121054Semax		uint64_t	uint64;
173121054Semax		int128_t	int128;
174121054Semax	}			value;
175124317Semax	uint32_t		type, len, param;
176121054Semax
177121054Semax	/* Get Protocol UUID */
178121054Semax	SDP_GET8(type, start);
179121054Semax	switch (type) {
180121054Semax	case SDP_DATA_UUID16:
181121054Semax		SDP_GET16(value.uint16, start);
182121054Semax		fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
183121054Semax				value.uint16);
184121054Semax		break;
185121054Semax
186121054Semax	case SDP_DATA_UUID32:
187121054Semax		SDP_GET32(value.uint32, start);
188121054Semax		fprintf(stdout, "\t%#8.8x\n", value.uint32);
189121054Semax		break;
190121054Semax
191121054Semax	case SDP_DATA_UUID128:
192146691Semax		SDP_GET_UUID128(&value.int128, start);
193121054Semax		fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
194146691Semax				ntohl(*(uint32_t *)&value.int128.b[0]),
195146691Semax				ntohs(*(uint16_t *)&value.int128.b[4]),
196146691Semax				ntohs(*(uint16_t *)&value.int128.b[6]),
197146691Semax				ntohs(*(uint16_t *)&value.int128.b[8]),
198146691Semax				ntohs(*(uint16_t *)&value.int128.b[10]),
199146691Semax				ntohl(*(uint32_t *)&value.int128.b[12]));
200121054Semax		break;
201121054Semax
202121054Semax	default:
203121054Semax		fprintf(stderr, "Invalid Protocol Descriptor. " \
204121054Semax				"Not a UUID, type=%#x\n", type);
205121054Semax		return;
206121054Semax		/* NOT REACHED */
207121054Semax	}
208121054Semax
209121054Semax	/* Protocol specific parameters */
210121054Semax	for (param = 1; start < end; param ++) {
211121054Semax		fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
212121054Semax
213121054Semax		SDP_GET8(type, start);
214121054Semax		switch (type) {
215121054Semax		case SDP_DATA_NIL:
216121054Semax			fprintf(stdout, "nil\n");
217121054Semax			break;
218121054Semax
219121054Semax		case SDP_DATA_UINT8:
220121054Semax		case SDP_DATA_INT8:
221121054Semax		case SDP_DATA_BOOL:
222121054Semax			SDP_GET8(value.uint8, start);
223121054Semax			fprintf(stdout, "u/int8/bool %u\n", value.uint8);
224121054Semax			break;
225121054Semax
226121054Semax		case SDP_DATA_UINT16:
227121054Semax		case SDP_DATA_INT16:
228121054Semax		case SDP_DATA_UUID16:
229121054Semax			SDP_GET16(value.uint16, start);
230121054Semax			fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
231121054Semax			break;
232121054Semax
233121054Semax		case SDP_DATA_UINT32:
234121054Semax		case SDP_DATA_INT32:
235121054Semax		case SDP_DATA_UUID32:
236121054Semax			SDP_GET32(value.uint32, start);
237121054Semax			fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
238121054Semax			break;
239121054Semax
240121054Semax		case SDP_DATA_UINT64:
241121054Semax		case SDP_DATA_INT64:
242121054Semax			SDP_GET64(value.uint64, start);
243128076Semax			fprintf(stdout, "u/int64 %ju\n", value.uint64);
244121054Semax			break;
245121054Semax
246121054Semax		case SDP_DATA_UINT128:
247121054Semax		case SDP_DATA_INT128:
248121054Semax			SDP_GET128(&value.int128, start);
249146691Semax			fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
250124317Semax				*(uint32_t *)&value.int128.b[0],
251146691Semax				*(uint32_t *)&value.int128.b[4],
252146691Semax				*(uint32_t *)&value.int128.b[8],
253124317Semax				*(uint32_t *)&value.int128.b[12]);
254121054Semax			break;
255121054Semax
256146691Semax		case SDP_DATA_UUID128:
257146691Semax			SDP_GET_UUID128(&value.int128, start);
258146691Semax			fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
259146691Semax				ntohl(*(uint32_t *)&value.int128.b[0]),
260146691Semax				ntohs(*(uint16_t *)&value.int128.b[4]),
261146691Semax				ntohs(*(uint16_t *)&value.int128.b[6]),
262146691Semax				ntohs(*(uint16_t *)&value.int128.b[8]),
263146691Semax				ntohs(*(uint16_t *)&value.int128.b[10]),
264146691Semax				ntohl(*(uint32_t *)&value.int128.b[12]));
265146691Semax			break;
266146691Semax
267121054Semax		case SDP_DATA_STR8:
268121054Semax		case SDP_DATA_URL8:
269121054Semax			SDP_GET8(len, start);
270289637Semax			for (; start < end && len > 0; start ++, len --)
271289637Semax				fprintf(stdout, "%c", *start);
272289637Semax			fprintf(stdout, "\n");
273121054Semax			break;
274121054Semax
275121054Semax		case SDP_DATA_STR16:
276121054Semax		case SDP_DATA_URL16:
277121054Semax			SDP_GET16(len, start);
278289637Semax			for (; start < end && len > 0; start ++, len --)
279289637Semax				fprintf(stdout, "%c", *start);
280289637Semax			fprintf(stdout, "\n");
281121054Semax			break;
282121054Semax
283121054Semax		case SDP_DATA_STR32:
284121054Semax		case SDP_DATA_URL32:
285121054Semax			SDP_GET32(len, start);
286289637Semax			for (; start < end && len > 0; start ++, len --)
287289637Semax				fprintf(stdout, "%c", *start);
288289637Semax			fprintf(stdout, "\n");
289121054Semax			break;
290121054Semax
291121054Semax		case SDP_DATA_SEQ8:
292121054Semax		case SDP_DATA_ALT8:
293121054Semax			SDP_GET8(len, start);
294289637Semax			for (; start < end && len > 0; start ++, len --)
295121054Semax				fprintf(stdout, "%#2.2x ", *start);
296121054Semax			fprintf(stdout, "\n");
297121054Semax			break;
298121054Semax
299121054Semax		case SDP_DATA_SEQ16:
300121054Semax		case SDP_DATA_ALT16:
301121054Semax			SDP_GET16(len, start);
302289637Semax			for (; start < end && len > 0; start ++, len --)
303121054Semax				fprintf(stdout, "%#2.2x ", *start);
304121054Semax			fprintf(stdout, "\n");
305121054Semax			break;
306121054Semax
307121054Semax		case SDP_DATA_SEQ32:
308121054Semax		case SDP_DATA_ALT32:
309121054Semax			SDP_GET32(len, start);
310289637Semax			for (; start < end && len > 0; start ++, len --)
311121054Semax				fprintf(stdout, "%#2.2x ", *start);
312121054Semax			fprintf(stdout, "\n");
313121054Semax			break;
314121054Semax
315121054Semax		default:
316121054Semax			fprintf(stderr, "Invalid Protocol Descriptor. " \
317121054Semax					"Unknown data type: %#02x\n", type);
318121054Semax			return;
319121054Semax			/* NOT REACHED */
320121054Semax		}
321121054Semax	}
322121054Semax} /* print_protocol_descriptor */
323121054Semax
324121054Semaxstatic void
325124317Semaxprint_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
326121054Semax{
327124317Semax	uint32_t	type, len;
328121054Semax
329121054Semax	if (end - start < 2) {
330121054Semax		fprintf(stderr, "Invalid Protocol Descriptor List. " \
331128076Semax				"Too short, len=%zd\n", end - start);
332121054Semax		return;
333121054Semax	}
334121054Semax
335121054Semax	SDP_GET8(type, start);
336121054Semax	switch (type) {
337121054Semax	case SDP_DATA_SEQ8:
338121054Semax		SDP_GET8(len, start);
339121054Semax		break;
340121054Semax
341121054Semax	case SDP_DATA_SEQ16:
342121054Semax		SDP_GET16(len, start);
343121054Semax		break;
344121054Semax
345121054Semax	case SDP_DATA_SEQ32:
346121054Semax		SDP_GET32(len, start);
347121054Semax		break;
348121054Semax
349121054Semax	default:
350121054Semax		fprintf(stderr, "Invalid Protocol Descriptor List. " \
351121054Semax				"Not a sequence, type=%#x\n", type);
352121054Semax		return;
353121054Semax		/* NOT REACHED */
354121054Semax	}
355121054Semax
356289637Semax	if (len > (end - start)) {
357289637Semax		fprintf(stderr, "Invalid Protocol Descriptor List. " \
358289637Semax				"Too long, len=%d\n", len);
359289637Semax		return;
360289637Semax	}
361289637Semax
362121054Semax	while (start < end) {
363121054Semax		SDP_GET8(type, start);
364121054Semax		switch (type) {
365121054Semax		case SDP_DATA_SEQ8:
366121054Semax			SDP_GET8(len, start);
367121054Semax			break;
368121054Semax
369121054Semax		case SDP_DATA_SEQ16:
370121054Semax			SDP_GET16(len, start);
371121054Semax			break;
372121054Semax
373121054Semax		case SDP_DATA_SEQ32:
374121054Semax			SDP_GET32(len, start);
375121054Semax			break;
376121054Semax
377121054Semax		default:
378121054Semax			fprintf(stderr, "Invalid Protocol Descriptor List. " \
379121054Semax					"Not a sequence, type=%#x\n", type);
380121054Semax			return;
381121054Semax			/* NOT REACHED */
382121054Semax		}
383121054Semax
384289637Semax		if (len > (end - start)) {
385289637Semax			fprintf(stderr, "Invalid Protocol Descriptor List. " \
386289637Semax					"Too long, len=%d\n", len);
387289637Semax			return;
388289637Semax		}
389289637Semax
390121054Semax		print_protocol_descriptor(start, start + len);
391121054Semax		start += len;
392121054Semax	}
393121054Semax} /* print_protocol_descriptor_list */
394121054Semax
395121054Semax/*
396121054Semax * Print Bluetooth Profile Descriptor List
397121054Semax *
398121054Semax * The BluetoothProfileDescriptorList attribute consists of a data element
399121054Semax * sequence in which each element is a profile descriptor that contains
400121054Semax * information about a Bluetooth profile to which the service represented by
401121054Semax * this service record conforms. Each profile descriptor is a data element
402121054Semax * sequence whose first element is the UUID assigned to the profile and whose
403121054Semax * second element is a 16-bit profile version number. Each version of a profile
404121054Semax * is assigned a 16-bit unsigned integer profile version number, which consists
405121054Semax * of two 8-bit fields. The higher-order 8 bits contain the major version
406121054Semax * number field and the lower-order 8 bits contain the minor version number
407121054Semax * field.
408121054Semax */
409121054Semax
410121054Semaxstatic void
411124317Semaxprint_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
412121054Semax{
413124317Semax	uint32_t	type, len, value;
414121054Semax
415121054Semax	if (end - start < 2) {
416121054Semax		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
417128076Semax				"Too short, len=%zd\n", end - start);
418121054Semax		return;
419121054Semax	}
420121054Semax
421121054Semax	SDP_GET8(type, start);
422121054Semax	switch (type) {
423121054Semax	case SDP_DATA_SEQ8:
424121054Semax		SDP_GET8(len, start);
425121054Semax		break;
426121054Semax
427121054Semax	case SDP_DATA_SEQ16:
428121054Semax		SDP_GET16(len, start);
429121054Semax		break;
430121054Semax
431121054Semax	case SDP_DATA_SEQ32:
432121054Semax		SDP_GET32(len, start);
433121054Semax		break;
434121054Semax
435121054Semax	default:
436121054Semax		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
437121054Semax				"Not a sequence, type=%#x\n", type);
438121054Semax		return;
439121054Semax		/* NOT REACHED */
440121054Semax	}
441121054Semax
442289637Semax	if (len > (end - start)) {
443289637Semax		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
444289637Semax				"Too long, len=%d\n", len);
445289637Semax		return;
446289637Semax	}
447289637Semax
448121054Semax	while (start < end) {
449121054Semax		SDP_GET8(type, start);
450121054Semax		switch (type) {
451121054Semax		case SDP_DATA_SEQ8:
452121054Semax			SDP_GET8(len, start);
453121054Semax			break;
454121054Semax
455121054Semax		case SDP_DATA_SEQ16:
456121054Semax			SDP_GET16(len, start);
457121054Semax			break;
458121054Semax
459121054Semax		case SDP_DATA_SEQ32:
460121054Semax			SDP_GET32(len, start);
461121054Semax			break;
462121054Semax
463121054Semax		default:
464121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
465121054Semax					"Descriptor List. " \
466121054Semax					"Not a sequence, type=%#x\n", type);
467121054Semax			return;
468121054Semax			/* NOT REACHED */
469121054Semax		}
470121054Semax
471289637Semax		if (len > (end - start)) {
472289637Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
473289637Semax					"Descriptor List. " \
474289637Semax					"Too long, len=%d\n", len);
475289637Semax			return;
476289637Semax		}
477289637Semax
478121054Semax		/* Get UUID */
479121054Semax		SDP_GET8(type, start);
480121054Semax		switch (type) {
481121054Semax		case SDP_DATA_UUID16:
482121054Semax			SDP_GET16(value, start);
483121054Semax			fprintf(stdout, "\t%s (%#4.4x) ",
484121054Semax					sdp_uuid2desc(value), value);
485121054Semax			break;
486121054Semax
487121054Semax		case SDP_DATA_UUID32:
488121054Semax			SDP_GET32(value, start);
489121054Semax			fprintf(stdout, "\t%#8.8x ", value);
490121054Semax			break;
491121054Semax
492121054Semax		case SDP_DATA_UUID128: {
493121054Semax			int128_t	uuid;
494121054Semax
495146691Semax			SDP_GET_UUID128(&uuid, start);
496121054Semax			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
497146691Semax					ntohl(*(uint32_t *)&uuid.b[0]),
498146691Semax					ntohs(*(uint16_t *)&uuid.b[4]),
499146691Semax					ntohs(*(uint16_t *)&uuid.b[6]),
500146691Semax					ntohs(*(uint16_t *)&uuid.b[8]),
501146691Semax					ntohs(*(uint16_t *)&uuid.b[10]),
502146691Semax					ntohl(*(uint32_t *)&uuid.b[12]));
503121054Semax			} break;
504121054Semax
505121054Semax		default:
506121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
507121054Semax					"Descriptor List. " \
508121054Semax					"Not a UUID, type=%#x\n", type);
509121054Semax			return;
510121054Semax			/* NOT REACHED */
511121054Semax		}
512121054Semax
513121054Semax		/* Get version */
514121054Semax		SDP_GET8(type, start);
515121054Semax		if (type != SDP_DATA_UINT16) {
516121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
517121054Semax					"Descriptor List. " \
518121054Semax					"Invalid version type=%#x\n", type);
519121054Semax			return;
520121054Semax		}
521121054Semax
522121054Semax		SDP_GET16(value, start);
523121054Semax		fprintf(stdout, "ver. %d.%d\n",
524121054Semax				(value >> 8) & 0xff, value & 0xff);
525121054Semax	}
526121054Semax} /* print_bluetooth_profile_descriptor_list */
527121054Semax
528121054Semax/* Perform SDP search command */
529121054Semaxstatic int
530121054Semaxdo_sdp_search(void *xs, int argc, char **argv)
531121054Semax{
532121054Semax	char		*ep = NULL;
533121054Semax	int32_t		 n, type, value;
534124317Semax	uint16_t	 service;
535121054Semax
536121054Semax	/* Parse command line arguments */
537121054Semax	switch (argc) {
538121054Semax	case 1:
539121054Semax		n = strtoul(argv[0], &ep, 16);
540121054Semax		if (*ep != 0) {
541121054Semax			switch (tolower(argv[0][0])) {
542121054Semax			case 'c': /* CIP/CTP */
543121054Semax				switch (tolower(argv[0][1])) {
544121054Semax				case 'i':
545121054Semax					service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
546121054Semax					break;
547121054Semax
548121054Semax				case 't':
549121054Semax					service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
550121054Semax					break;
551121054Semax
552121054Semax				default:
553121054Semax					return (USAGE);
554121054Semax					/* NOT REACHED */
555121054Semax				}
556121054Semax				break;
557121054Semax
558121054Semax			case 'd': /* DialUp Networking */
559121054Semax				service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
560121054Semax				break;
561121054Semax
562121054Semax			case 'f': /* Fax/OBEX File Transfer */
563121054Semax				switch (tolower(argv[0][1])) {
564121054Semax				case 'a':
565121054Semax					service = SDP_SERVICE_CLASS_FAX;
566121054Semax					break;
567121054Semax
568121054Semax				case 't':
569121054Semax					service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
570121054Semax					break;
571121054Semax
572121054Semax				default:
573121054Semax					return (USAGE);
574121054Semax					/* NOT REACHED */
575121054Semax				}
576121054Semax				break;
577121054Semax
578121054Semax			case 'g': /* GN */
579121054Semax				service = SDP_SERVICE_CLASS_GN;
580121054Semax				break;
581121054Semax
582121054Semax			case 'h': /* Headset/HID */
583121054Semax				switch (tolower(argv[0][1])) {
584121054Semax				case 'i':
585121054Semax					service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
586121054Semax					break;
587121054Semax
588121054Semax				case 's':
589121054Semax					service = SDP_SERVICE_CLASS_HEADSET;
590121054Semax					break;
591121054Semax
592121054Semax				default:
593121054Semax					return (USAGE);
594121054Semax					/* NOT REACHED */
595121054Semax				}
596121054Semax				break;
597121054Semax
598121054Semax			case 'l': /* LAN Access Using PPP */
599121054Semax				service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
600121054Semax				break;
601121054Semax
602121054Semax			case 'n': /* NAP */
603121054Semax				service = SDP_SERVICE_CLASS_NAP;
604121054Semax				break;
605121054Semax
606121054Semax			case 'o': /* OBEX Object Push */
607121054Semax				service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
608121054Semax				break;
609121054Semax
610121054Semax			case 's': /* Serial Port */
611121054Semax				service = SDP_SERVICE_CLASS_SERIAL_PORT;
612121054Semax				break;
613121054Semax
614121054Semax			default:
615121054Semax				return (USAGE);
616121054Semax				/* NOT REACHED */
617121054Semax			}
618121054Semax		} else
619124317Semax			service = (uint16_t) n;
620121054Semax		break;
621121054Semax
622121054Semax	default:
623121054Semax		return (USAGE);
624121054Semax	}
625121054Semax
626121054Semax	/* Initialize attribute values array */
627121054Semax	for (n = 0; n < values_len; n ++) {
628121054Semax		values[n].flags = SDP_ATTR_INVALID;
629121054Semax		values[n].attr = 0;
630121054Semax		values[n].vlen = BSIZE;
631121054Semax		values[n].value = buffer[n];
632121054Semax	}
633121054Semax
634121054Semax	/* Do SDP Service Search Attribute Request */
635121054Semax	n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
636121054Semax	if (n != 0)
637121054Semax		return (ERROR);
638121054Semax
639121054Semax	/* Print attributes values */
640121054Semax	for (n = 0; n < values_len; n ++) {
641121054Semax		if (values[n].flags != SDP_ATTR_OK)
642121054Semax			break;
643121054Semax
644121054Semax		switch (values[n].attr) {
645121054Semax		case SDP_ATTR_SERVICE_RECORD_HANDLE:
646121054Semax			fprintf(stdout, "\n");
647121054Semax			if (values[n].vlen == 5) {
648121054Semax				SDP_GET8(type, values[n].value);
649121054Semax				if (type == SDP_DATA_UINT32) {
650121054Semax					SDP_GET32(value, values[n].value);
651121054Semax					fprintf(stdout, "Record Handle: " \
652121054Semax							"%#8.8x\n", value);
653121054Semax				} else
654121054Semax					fprintf(stderr, "Invalid type=%#x " \
655121054Semax							"Record Handle " \
656121054Semax							"attribute!\n", type);
657121054Semax			} else
658121054Semax				fprintf(stderr, "Invalid size=%d for Record " \
659121054Semax						"Handle attribute\n",
660121054Semax						values[n].vlen);
661121054Semax			break;
662121054Semax
663121054Semax		case SDP_ATTR_SERVICE_CLASS_ID_LIST:
664121054Semax			fprintf(stdout, "Service Class ID List:\n");
665121054Semax			print_service_class_id_list(values[n].value,
666121054Semax					values[n].value + values[n].vlen);
667121054Semax			break;
668121054Semax
669121054Semax		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
670121054Semax			fprintf(stdout, "Protocol Descriptor List:\n");
671121054Semax			print_protocol_descriptor_list(values[n].value,
672121054Semax					values[n].value + values[n].vlen);
673121054Semax			break;
674121054Semax
675121054Semax		case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
676121054Semax			fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
677121054Semax			print_bluetooth_profile_descriptor_list(values[n].value,
678121054Semax					values[n].value + values[n].vlen);
679121054Semax			break;
680121054Semax
681121054Semax		default:
682121054Semax			fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
683121054Semax					values[n].attr);
684121054Semax			break;
685121054Semax		}
686121054Semax	}
687121054Semax
688121054Semax	return (OK);
689121054Semax} /* do_sdp_search */
690121054Semax
691121054Semax/* Perform SDP browse command */
692121054Semaxstatic int
693121054Semaxdo_sdp_browse(void *xs, int argc, char **argv)
694121054Semax{
695121054Semax#undef	_STR
696121054Semax#undef	STR
697121054Semax#define	_STR(x)	#x
698121054Semax#define	STR(x)	_STR(x)
699121054Semax
700121054Semax	static char const * const	av[] = {
701121054Semax		STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
702121054Semax		NULL
703121054Semax	};
704121054Semax
705121054Semax	switch (argc) {
706121054Semax	case 0:
707121054Semax		argc = 1;
708121054Semax		argv = (char **) av;
709121054Semax		/* FALL THROUGH */
710121054Semax	case 1:
711121054Semax		return (do_sdp_search(xs, argc, argv));
712121054Semax	}
713121054Semax
714121054Semax	return (USAGE);
715121054Semax} /* do_sdp_browse */
716121054Semax
717121054Semax/* List of SDP commands */
718121054Semaxstruct sdp_command	sdp_commands[] = {
719121054Semax{
720121054Semax"Browse [<Group>]",
721121054Semax"Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
722121054Semax"to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
723121054Semax"\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
724121054Semaxdo_sdp_browse
725121054Semax},
726121054Semax{
727121054Semax"Search <Service>",
728121054Semax"Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
729121054Semax"service to search for. For some services it is possible to use service name\n"\
730121054Semax"instead of service UUID\n\n" \
731121054Semax"\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
732121054Semax"\tKnown service names\n" \
733121054Semax"\t===================\n" \
734121054Semax"\tCIP   - Common ISDN Access\n" \
735121054Semax"\tCTP   - Cordless Telephony\n" \
736121054Semax"\tDUN   - DialUp Networking\n" \
737121054Semax"\tFAX   - Fax\n" \
738121054Semax"\tFTRN  - OBEX File Transfer\n" \
739121054Semax"\tGN    - GN\n" \
740121054Semax"\tHID   - Human Interface Device\n" \
741121054Semax"\tHSET  - Headset\n" \
742121054Semax"\tLAN   - LAN Access Using PPP\n" \
743121054Semax"\tNAP   - Network Access Point\n" \
744121054Semax"\tOPUSH - OBEX Object Push\n" \
745121054Semax"\tSP    - Serial Port\n",
746121054Semaxdo_sdp_search
747121054Semax},
748121054Semax{ NULL, NULL, NULL }
749121054Semax};
750121054Semax
751