1121054Semax/*
2121054Semax * search.c
3121054Semax *
4121054Semax * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5121054Semax * All rights reserved.
6121054Semax *
7121054Semax * Redistribution and use in source and binary forms, with or without
8121054Semax * modification, are permitted provided that the following conditions
9121054Semax * are met:
10121054Semax * 1. Redistributions of source code must retain the above copyright
11121054Semax *    notice, this list of conditions and the following disclaimer.
12121054Semax * 2. Redistributions in binary form must reproduce the above copyright
13121054Semax *    notice, this list of conditions and the following disclaimer in the
14121054Semax *    documentation and/or other materials provided with the distribution.
15121054Semax *
16121054Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19121054Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26121054Semax * SUCH DAMAGE.
27121054Semax *
28121054Semax * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
29121054Semax * $FreeBSD$
30121054Semax */
31121054Semax
32146691Semax#include <netinet/in.h>
33121054Semax#include <bluetooth.h>
34121054Semax#include <ctype.h>
35121054Semax#include <sdp.h>
36121054Semax#include <stdio.h>
37121054Semax#include <stdlib.h>
38121054Semax#include "sdpcontrol.h"
39121054Semax
40121054Semax/* List of the attributes we are looking for */
41124317Semaxstatic uint32_t	attrs[] =
42121054Semax{
43121054Semax	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_RECORD_HANDLE,
44121054Semax			SDP_ATTR_SERVICE_RECORD_HANDLE),
45121054Semax	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_CLASS_ID_LIST,
46121054Semax			SDP_ATTR_SERVICE_CLASS_ID_LIST),
47121054Semax	SDP_ATTR_RANGE(	SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
48121054Semax			SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
49121054Semax	SDP_ATTR_RANGE(	SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
50121054Semax			SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
51121054Semax};
52121054Semax#define attrs_len	(sizeof(attrs)/sizeof(attrs[0]))
53121054Semax
54121054Semax/* Buffer for the attributes */
55121054Semax#define NRECS	25	/* request this much records from the SDP server */
56121054Semax#define	BSIZE	256	/* one attribute buffer size */
57124317Semaxstatic uint8_t		buffer[NRECS * attrs_len][BSIZE];
58121054Semax
59121054Semax/* SDP attributes */
60121054Semaxstatic sdp_attr_t	values[NRECS * attrs_len];
61121054Semax#define values_len	(sizeof(values)/sizeof(values[0]))
62121054Semax
63121054Semax/*
64121054Semax * Print Service Class ID List
65121054Semax *
66121054Semax * The ServiceClassIDList attribute consists of a data element sequence in
67121054Semax * which each data element is a UUID representing the service classes that
68121054Semax * a given service record conforms to. The UUIDs are listed in order from
69121054Semax * the most specific class to the most general class. The ServiceClassIDList
70121054Semax * must contain at least one service class UUID.
71121054Semax */
72121054Semax
73121054Semaxstatic void
74124317Semaxprint_service_class_id_list(uint8_t const *start, uint8_t const *end)
75121054Semax{
76124317Semax	uint32_t	type, len, value;
77121054Semax
78121054Semax	if (end - start < 2) {
79121054Semax		fprintf(stderr, "Invalid Service Class ID List. " \
80128076Semax				"Too short, len=%zd\n", end - start);
81121054Semax		return;
82121054Semax	}
83121054Semax
84121054Semax	SDP_GET8(type, start);
85121054Semax	switch (type) {
86121054Semax	case SDP_DATA_SEQ8:
87121054Semax		SDP_GET8(len, start);
88121054Semax		break;
89121054Semax
90121054Semax	case SDP_DATA_SEQ16:
91121054Semax		SDP_GET16(len, start);
92121054Semax		break;
93121054Semax
94121054Semax	case SDP_DATA_SEQ32:
95121054Semax		SDP_GET32(len, start);
96121054Semax		break;
97121054Semax
98121054Semax	default:
99121054Semax		fprintf(stderr, "Invalid Service Class ID List. " \
100121054Semax				"Not a sequence, type=%#x\n", type);
101121054Semax		return;
102121054Semax		/* NOT REACHED */
103121054Semax	}
104121054Semax
105290395Semax	if (len > (end - start)) {
106290395Semax		fprintf(stderr, "Invalid Service Class ID List. " \
107290395Semax				"Too long len=%d\n", len);
108290395Semax		return;
109290395Semax	}
110290395Semax
111121054Semax	while (start < end) {
112121054Semax		SDP_GET8(type, start);
113121054Semax		switch (type) {
114121054Semax		case SDP_DATA_UUID16:
115121054Semax			SDP_GET16(value, start);
116121054Semax			fprintf(stdout, "\t%s (%#4.4x)\n",
117121054Semax					sdp_uuid2desc(value), value);
118121054Semax			break;
119121054Semax
120121054Semax		case SDP_DATA_UUID32:
121121054Semax			SDP_GET32(value, start);
122121054Semax			fprintf(stdout, "\t%#8.8x\n", value);
123121054Semax			break;
124121054Semax
125121054Semax		case SDP_DATA_UUID128: {
126121054Semax			int128_t	uuid;
127121054Semax
128146691Semax			SDP_GET_UUID128(&uuid, start);
129121054Semax			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
130146691Semax					ntohl(*(uint32_t *)&uuid.b[0]),
131146691Semax					ntohs(*(uint16_t *)&uuid.b[4]),
132146691Semax					ntohs(*(uint16_t *)&uuid.b[6]),
133146691Semax					ntohs(*(uint16_t *)&uuid.b[8]),
134146691Semax					ntohs(*(uint16_t *)&uuid.b[10]),
135146691Semax					ntohl(*(uint32_t *)&uuid.b[12]));
136121054Semax			} break;
137121054Semax
138121054Semax		default:
139121054Semax			fprintf(stderr, "Invalid Service Class ID List. " \
140121054Semax					"Not a UUID, type=%#x\n", type);
141121054Semax			return;
142121054Semax			/* NOT REACHED */
143121054Semax		}
144121054Semax	}
145121054Semax} /* print_service_class_id_list */
146121054Semax
147121054Semax/*
148121054Semax * Print Protocol Descriptor List
149121054Semax *
150121054Semax * If the ProtocolDescriptorList describes a single stack, it takes the form
151121054Semax * of a data element sequence in which each element of the sequence is a
152121054Semax * protocol descriptor. Each protocol descriptor is, in turn, a data element
153121054Semax * sequence whose first element is a UUID identifying the protocol and whose
154121054Semax * successive elements are protocol-specific parameters. The protocol
155121054Semax * descriptors are listed in order from the lowest layer protocol to the
156121054Semax * highest layer protocol used to gain access to the service. If it is possible
157121054Semax * for more than one kind of protocol stack to be used to gain access to the
158121054Semax * service, the ProtocolDescriptorList takes the form of a data element
159121054Semax * alternative where each member is a data element sequence as described above.
160121054Semax */
161121054Semax
162121054Semaxstatic void
163124317Semaxprint_protocol_descriptor(uint8_t const *start, uint8_t const *end)
164121054Semax{
165121054Semax	union {
166121054Semax		uint8_t		uint8;
167121054Semax		uint16_t	uint16;
168121054Semax		uint32_t	uint32;
169121054Semax		uint64_t	uint64;
170121054Semax		int128_t	int128;
171121054Semax	}			value;
172124317Semax	uint32_t		type, len, param;
173121054Semax
174121054Semax	/* Get Protocol UUID */
175121054Semax	SDP_GET8(type, start);
176121054Semax	switch (type) {
177121054Semax	case SDP_DATA_UUID16:
178121054Semax		SDP_GET16(value.uint16, start);
179121054Semax		fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
180121054Semax				value.uint16);
181121054Semax		break;
182121054Semax
183121054Semax	case SDP_DATA_UUID32:
184121054Semax		SDP_GET32(value.uint32, start);
185121054Semax		fprintf(stdout, "\t%#8.8x\n", value.uint32);
186121054Semax		break;
187121054Semax
188121054Semax	case SDP_DATA_UUID128:
189146691Semax		SDP_GET_UUID128(&value.int128, start);
190121054Semax		fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
191146691Semax				ntohl(*(uint32_t *)&value.int128.b[0]),
192146691Semax				ntohs(*(uint16_t *)&value.int128.b[4]),
193146691Semax				ntohs(*(uint16_t *)&value.int128.b[6]),
194146691Semax				ntohs(*(uint16_t *)&value.int128.b[8]),
195146691Semax				ntohs(*(uint16_t *)&value.int128.b[10]),
196146691Semax				ntohl(*(uint32_t *)&value.int128.b[12]));
197121054Semax		break;
198121054Semax
199121054Semax	default:
200121054Semax		fprintf(stderr, "Invalid Protocol Descriptor. " \
201121054Semax				"Not a UUID, type=%#x\n", type);
202121054Semax		return;
203121054Semax		/* NOT REACHED */
204121054Semax	}
205121054Semax
206121054Semax	/* Protocol specific parameters */
207121054Semax	for (param = 1; start < end; param ++) {
208121054Semax		fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
209121054Semax
210121054Semax		SDP_GET8(type, start);
211121054Semax		switch (type) {
212121054Semax		case SDP_DATA_NIL:
213121054Semax			fprintf(stdout, "nil\n");
214121054Semax			break;
215121054Semax
216121054Semax		case SDP_DATA_UINT8:
217121054Semax		case SDP_DATA_INT8:
218121054Semax		case SDP_DATA_BOOL:
219121054Semax			SDP_GET8(value.uint8, start);
220121054Semax			fprintf(stdout, "u/int8/bool %u\n", value.uint8);
221121054Semax			break;
222121054Semax
223121054Semax		case SDP_DATA_UINT16:
224121054Semax		case SDP_DATA_INT16:
225121054Semax		case SDP_DATA_UUID16:
226121054Semax			SDP_GET16(value.uint16, start);
227121054Semax			fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
228121054Semax			break;
229121054Semax
230121054Semax		case SDP_DATA_UINT32:
231121054Semax		case SDP_DATA_INT32:
232121054Semax		case SDP_DATA_UUID32:
233121054Semax			SDP_GET32(value.uint32, start);
234121054Semax			fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
235121054Semax			break;
236121054Semax
237121054Semax		case SDP_DATA_UINT64:
238121054Semax		case SDP_DATA_INT64:
239121054Semax			SDP_GET64(value.uint64, start);
240128076Semax			fprintf(stdout, "u/int64 %ju\n", value.uint64);
241121054Semax			break;
242121054Semax
243121054Semax		case SDP_DATA_UINT128:
244121054Semax		case SDP_DATA_INT128:
245121054Semax			SDP_GET128(&value.int128, start);
246146691Semax			fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
247124317Semax				*(uint32_t *)&value.int128.b[0],
248146691Semax				*(uint32_t *)&value.int128.b[4],
249146691Semax				*(uint32_t *)&value.int128.b[8],
250124317Semax				*(uint32_t *)&value.int128.b[12]);
251121054Semax			break;
252121054Semax
253146691Semax		case SDP_DATA_UUID128:
254146691Semax			SDP_GET_UUID128(&value.int128, start);
255146691Semax			fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
256146691Semax				ntohl(*(uint32_t *)&value.int128.b[0]),
257146691Semax				ntohs(*(uint16_t *)&value.int128.b[4]),
258146691Semax				ntohs(*(uint16_t *)&value.int128.b[6]),
259146691Semax				ntohs(*(uint16_t *)&value.int128.b[8]),
260146691Semax				ntohs(*(uint16_t *)&value.int128.b[10]),
261146691Semax				ntohl(*(uint32_t *)&value.int128.b[12]));
262146691Semax			break;
263146691Semax
264121054Semax		case SDP_DATA_STR8:
265121054Semax		case SDP_DATA_URL8:
266121054Semax			SDP_GET8(len, start);
267290395Semax			for (; start < end && len > 0; start ++, len --)
268290395Semax				fprintf(stdout, "%c", *start);
269290395Semax			fprintf(stdout, "\n");
270121054Semax			break;
271121054Semax
272121054Semax		case SDP_DATA_STR16:
273121054Semax		case SDP_DATA_URL16:
274121054Semax			SDP_GET16(len, start);
275290395Semax			for (; start < end && len > 0; start ++, len --)
276290395Semax				fprintf(stdout, "%c", *start);
277290395Semax			fprintf(stdout, "\n");
278121054Semax			break;
279121054Semax
280121054Semax		case SDP_DATA_STR32:
281121054Semax		case SDP_DATA_URL32:
282121054Semax			SDP_GET32(len, start);
283290395Semax			for (; start < end && len > 0; start ++, len --)
284290395Semax				fprintf(stdout, "%c", *start);
285290395Semax			fprintf(stdout, "\n");
286121054Semax			break;
287121054Semax
288121054Semax		case SDP_DATA_SEQ8:
289121054Semax		case SDP_DATA_ALT8:
290121054Semax			SDP_GET8(len, start);
291290395Semax			for (; start < end && len > 0; start ++, len --)
292121054Semax				fprintf(stdout, "%#2.2x ", *start);
293121054Semax			fprintf(stdout, "\n");
294121054Semax			break;
295121054Semax
296121054Semax		case SDP_DATA_SEQ16:
297121054Semax		case SDP_DATA_ALT16:
298121054Semax			SDP_GET16(len, start);
299290395Semax			for (; start < end && len > 0; start ++, len --)
300121054Semax				fprintf(stdout, "%#2.2x ", *start);
301121054Semax			fprintf(stdout, "\n");
302121054Semax			break;
303121054Semax
304121054Semax		case SDP_DATA_SEQ32:
305121054Semax		case SDP_DATA_ALT32:
306121054Semax			SDP_GET32(len, start);
307290395Semax			for (; start < end && len > 0; start ++, len --)
308121054Semax				fprintf(stdout, "%#2.2x ", *start);
309121054Semax			fprintf(stdout, "\n");
310121054Semax			break;
311121054Semax
312121054Semax		default:
313121054Semax			fprintf(stderr, "Invalid Protocol Descriptor. " \
314121054Semax					"Unknown data type: %#02x\n", type);
315121054Semax			return;
316121054Semax			/* NOT REACHED */
317121054Semax		}
318121054Semax	}
319121054Semax} /* print_protocol_descriptor */
320121054Semax
321121054Semaxstatic void
322124317Semaxprint_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
323121054Semax{
324124317Semax	uint32_t	type, len;
325121054Semax
326121054Semax	if (end - start < 2) {
327121054Semax		fprintf(stderr, "Invalid Protocol Descriptor List. " \
328128076Semax				"Too short, len=%zd\n", end - start);
329121054Semax		return;
330121054Semax	}
331121054Semax
332121054Semax	SDP_GET8(type, start);
333121054Semax	switch (type) {
334121054Semax	case SDP_DATA_SEQ8:
335121054Semax		SDP_GET8(len, start);
336121054Semax		break;
337121054Semax
338121054Semax	case SDP_DATA_SEQ16:
339121054Semax		SDP_GET16(len, start);
340121054Semax		break;
341121054Semax
342121054Semax	case SDP_DATA_SEQ32:
343121054Semax		SDP_GET32(len, start);
344121054Semax		break;
345121054Semax
346121054Semax	default:
347121054Semax		fprintf(stderr, "Invalid Protocol Descriptor List. " \
348121054Semax				"Not a sequence, type=%#x\n", type);
349121054Semax		return;
350121054Semax		/* NOT REACHED */
351121054Semax	}
352121054Semax
353290395Semax	if (len > (end - start)) {
354290395Semax		fprintf(stderr, "Invalid Protocol Descriptor List. " \
355290395Semax				"Too long, len=%d\n", len);
356290395Semax		return;
357290395Semax	}
358290395Semax
359121054Semax	while (start < end) {
360121054Semax		SDP_GET8(type, start);
361121054Semax		switch (type) {
362121054Semax		case SDP_DATA_SEQ8:
363121054Semax			SDP_GET8(len, start);
364121054Semax			break;
365121054Semax
366121054Semax		case SDP_DATA_SEQ16:
367121054Semax			SDP_GET16(len, start);
368121054Semax			break;
369121054Semax
370121054Semax		case SDP_DATA_SEQ32:
371121054Semax			SDP_GET32(len, start);
372121054Semax			break;
373121054Semax
374121054Semax		default:
375121054Semax			fprintf(stderr, "Invalid Protocol Descriptor List. " \
376121054Semax					"Not a sequence, type=%#x\n", type);
377121054Semax			return;
378121054Semax			/* NOT REACHED */
379121054Semax		}
380121054Semax
381290395Semax		if (len > (end - start)) {
382290395Semax			fprintf(stderr, "Invalid Protocol Descriptor List. " \
383290395Semax					"Too long, len=%d\n", len);
384290395Semax			return;
385290395Semax		}
386290395Semax
387121054Semax		print_protocol_descriptor(start, start + len);
388121054Semax		start += len;
389121054Semax	}
390121054Semax} /* print_protocol_descriptor_list */
391121054Semax
392121054Semax/*
393121054Semax * Print Bluetooth Profile Descriptor List
394121054Semax *
395121054Semax * The BluetoothProfileDescriptorList attribute consists of a data element
396121054Semax * sequence in which each element is a profile descriptor that contains
397121054Semax * information about a Bluetooth profile to which the service represented by
398121054Semax * this service record conforms. Each profile descriptor is a data element
399121054Semax * sequence whose first element is the UUID assigned to the profile and whose
400121054Semax * second element is a 16-bit profile version number. Each version of a profile
401121054Semax * is assigned a 16-bit unsigned integer profile version number, which consists
402121054Semax * of two 8-bit fields. The higher-order 8 bits contain the major version
403121054Semax * number field and the lower-order 8 bits contain the minor version number
404121054Semax * field.
405121054Semax */
406121054Semax
407121054Semaxstatic void
408124317Semaxprint_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
409121054Semax{
410124317Semax	uint32_t	type, len, value;
411121054Semax
412121054Semax	if (end - start < 2) {
413121054Semax		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
414128076Semax				"Too short, len=%zd\n", end - start);
415121054Semax		return;
416121054Semax	}
417121054Semax
418121054Semax	SDP_GET8(type, start);
419121054Semax	switch (type) {
420121054Semax	case SDP_DATA_SEQ8:
421121054Semax		SDP_GET8(len, start);
422121054Semax		break;
423121054Semax
424121054Semax	case SDP_DATA_SEQ16:
425121054Semax		SDP_GET16(len, start);
426121054Semax		break;
427121054Semax
428121054Semax	case SDP_DATA_SEQ32:
429121054Semax		SDP_GET32(len, start);
430121054Semax		break;
431121054Semax
432121054Semax	default:
433121054Semax		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
434121054Semax				"Not a sequence, type=%#x\n", type);
435121054Semax		return;
436121054Semax		/* NOT REACHED */
437121054Semax	}
438121054Semax
439290395Semax	if (len > (end - start)) {
440290395Semax		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
441290395Semax				"Too long, len=%d\n", len);
442290395Semax		return;
443290395Semax	}
444290395Semax
445121054Semax	while (start < end) {
446121054Semax		SDP_GET8(type, start);
447121054Semax		switch (type) {
448121054Semax		case SDP_DATA_SEQ8:
449121054Semax			SDP_GET8(len, start);
450121054Semax			break;
451121054Semax
452121054Semax		case SDP_DATA_SEQ16:
453121054Semax			SDP_GET16(len, start);
454121054Semax			break;
455121054Semax
456121054Semax		case SDP_DATA_SEQ32:
457121054Semax			SDP_GET32(len, start);
458121054Semax			break;
459121054Semax
460121054Semax		default:
461121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
462121054Semax					"Descriptor List. " \
463121054Semax					"Not a sequence, type=%#x\n", type);
464121054Semax			return;
465121054Semax			/* NOT REACHED */
466121054Semax		}
467121054Semax
468290395Semax		if (len > (end - start)) {
469290395Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
470290395Semax					"Descriptor List. " \
471290395Semax					"Too long, len=%d\n", len);
472290395Semax			return;
473290395Semax		}
474290395Semax
475121054Semax		/* Get UUID */
476121054Semax		SDP_GET8(type, start);
477121054Semax		switch (type) {
478121054Semax		case SDP_DATA_UUID16:
479121054Semax			SDP_GET16(value, start);
480121054Semax			fprintf(stdout, "\t%s (%#4.4x) ",
481121054Semax					sdp_uuid2desc(value), value);
482121054Semax			break;
483121054Semax
484121054Semax		case SDP_DATA_UUID32:
485121054Semax			SDP_GET32(value, start);
486121054Semax			fprintf(stdout, "\t%#8.8x ", value);
487121054Semax			break;
488121054Semax
489121054Semax		case SDP_DATA_UUID128: {
490121054Semax			int128_t	uuid;
491121054Semax
492146691Semax			SDP_GET_UUID128(&uuid, start);
493121054Semax			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
494146691Semax					ntohl(*(uint32_t *)&uuid.b[0]),
495146691Semax					ntohs(*(uint16_t *)&uuid.b[4]),
496146691Semax					ntohs(*(uint16_t *)&uuid.b[6]),
497146691Semax					ntohs(*(uint16_t *)&uuid.b[8]),
498146691Semax					ntohs(*(uint16_t *)&uuid.b[10]),
499146691Semax					ntohl(*(uint32_t *)&uuid.b[12]));
500121054Semax			} break;
501121054Semax
502121054Semax		default:
503121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
504121054Semax					"Descriptor List. " \
505121054Semax					"Not a UUID, type=%#x\n", type);
506121054Semax			return;
507121054Semax			/* NOT REACHED */
508121054Semax		}
509121054Semax
510121054Semax		/* Get version */
511121054Semax		SDP_GET8(type, start);
512121054Semax		if (type != SDP_DATA_UINT16) {
513121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
514121054Semax					"Descriptor List. " \
515121054Semax					"Invalid version type=%#x\n", type);
516121054Semax			return;
517121054Semax		}
518121054Semax
519121054Semax		SDP_GET16(value, start);
520121054Semax		fprintf(stdout, "ver. %d.%d\n",
521121054Semax				(value >> 8) & 0xff, value & 0xff);
522121054Semax	}
523121054Semax} /* print_bluetooth_profile_descriptor_list */
524121054Semax
525121054Semax/* Perform SDP search command */
526121054Semaxstatic int
527121054Semaxdo_sdp_search(void *xs, int argc, char **argv)
528121054Semax{
529121054Semax	char		*ep = NULL;
530121054Semax	int32_t		 n, type, value;
531124317Semax	uint16_t	 service;
532121054Semax
533121054Semax	/* Parse command line arguments */
534121054Semax	switch (argc) {
535121054Semax	case 1:
536121054Semax		n = strtoul(argv[0], &ep, 16);
537121054Semax		if (*ep != 0) {
538121054Semax			switch (tolower(argv[0][0])) {
539121054Semax			case 'c': /* CIP/CTP */
540121054Semax				switch (tolower(argv[0][1])) {
541121054Semax				case 'i':
542121054Semax					service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
543121054Semax					break;
544121054Semax
545121054Semax				case 't':
546121054Semax					service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
547121054Semax					break;
548121054Semax
549121054Semax				default:
550121054Semax					return (USAGE);
551121054Semax					/* NOT REACHED */
552121054Semax				}
553121054Semax				break;
554121054Semax
555121054Semax			case 'd': /* DialUp Networking */
556121054Semax				service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
557121054Semax				break;
558121054Semax
559121054Semax			case 'f': /* Fax/OBEX File Transfer */
560121054Semax				switch (tolower(argv[0][1])) {
561121054Semax				case 'a':
562121054Semax					service = SDP_SERVICE_CLASS_FAX;
563121054Semax					break;
564121054Semax
565121054Semax				case 't':
566121054Semax					service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
567121054Semax					break;
568121054Semax
569121054Semax				default:
570121054Semax					return (USAGE);
571121054Semax					/* NOT REACHED */
572121054Semax				}
573121054Semax				break;
574121054Semax
575121054Semax			case 'g': /* GN */
576121054Semax				service = SDP_SERVICE_CLASS_GN;
577121054Semax				break;
578121054Semax
579121054Semax			case 'h': /* Headset/HID */
580121054Semax				switch (tolower(argv[0][1])) {
581121054Semax				case 'i':
582121054Semax					service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
583121054Semax					break;
584121054Semax
585121054Semax				case 's':
586121054Semax					service = SDP_SERVICE_CLASS_HEADSET;
587121054Semax					break;
588121054Semax
589121054Semax				default:
590121054Semax					return (USAGE);
591121054Semax					/* NOT REACHED */
592121054Semax				}
593121054Semax				break;
594121054Semax
595121054Semax			case 'l': /* LAN Access Using PPP */
596121054Semax				service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
597121054Semax				break;
598121054Semax
599121054Semax			case 'n': /* NAP */
600121054Semax				service = SDP_SERVICE_CLASS_NAP;
601121054Semax				break;
602121054Semax
603121054Semax			case 'o': /* OBEX Object Push */
604121054Semax				service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
605121054Semax				break;
606121054Semax
607121054Semax			case 's': /* Serial Port */
608121054Semax				service = SDP_SERVICE_CLASS_SERIAL_PORT;
609121054Semax				break;
610121054Semax
611121054Semax			default:
612121054Semax				return (USAGE);
613121054Semax				/* NOT REACHED */
614121054Semax			}
615121054Semax		} else
616124317Semax			service = (uint16_t) n;
617121054Semax		break;
618121054Semax
619121054Semax	default:
620121054Semax		return (USAGE);
621121054Semax	}
622121054Semax
623121054Semax	/* Initialize attribute values array */
624121054Semax	for (n = 0; n < values_len; n ++) {
625121054Semax		values[n].flags = SDP_ATTR_INVALID;
626121054Semax		values[n].attr = 0;
627121054Semax		values[n].vlen = BSIZE;
628121054Semax		values[n].value = buffer[n];
629121054Semax	}
630121054Semax
631121054Semax	/* Do SDP Service Search Attribute Request */
632121054Semax	n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
633121054Semax	if (n != 0)
634121054Semax		return (ERROR);
635121054Semax
636121054Semax	/* Print attributes values */
637121054Semax	for (n = 0; n < values_len; n ++) {
638121054Semax		if (values[n].flags != SDP_ATTR_OK)
639121054Semax			break;
640121054Semax
641121054Semax		switch (values[n].attr) {
642121054Semax		case SDP_ATTR_SERVICE_RECORD_HANDLE:
643121054Semax			fprintf(stdout, "\n");
644121054Semax			if (values[n].vlen == 5) {
645121054Semax				SDP_GET8(type, values[n].value);
646121054Semax				if (type == SDP_DATA_UINT32) {
647121054Semax					SDP_GET32(value, values[n].value);
648121054Semax					fprintf(stdout, "Record Handle: " \
649121054Semax							"%#8.8x\n", value);
650121054Semax				} else
651121054Semax					fprintf(stderr, "Invalid type=%#x " \
652121054Semax							"Record Handle " \
653121054Semax							"attribute!\n", type);
654121054Semax			} else
655121054Semax				fprintf(stderr, "Invalid size=%d for Record " \
656121054Semax						"Handle attribute\n",
657121054Semax						values[n].vlen);
658121054Semax			break;
659121054Semax
660121054Semax		case SDP_ATTR_SERVICE_CLASS_ID_LIST:
661121054Semax			fprintf(stdout, "Service Class ID List:\n");
662121054Semax			print_service_class_id_list(values[n].value,
663121054Semax					values[n].value + values[n].vlen);
664121054Semax			break;
665121054Semax
666121054Semax		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
667121054Semax			fprintf(stdout, "Protocol Descriptor List:\n");
668121054Semax			print_protocol_descriptor_list(values[n].value,
669121054Semax					values[n].value + values[n].vlen);
670121054Semax			break;
671121054Semax
672121054Semax		case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
673121054Semax			fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
674121054Semax			print_bluetooth_profile_descriptor_list(values[n].value,
675121054Semax					values[n].value + values[n].vlen);
676121054Semax			break;
677121054Semax
678121054Semax		default:
679121054Semax			fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
680121054Semax					values[n].attr);
681121054Semax			break;
682121054Semax		}
683121054Semax	}
684121054Semax
685121054Semax	return (OK);
686121054Semax} /* do_sdp_search */
687121054Semax
688121054Semax/* Perform SDP browse command */
689121054Semaxstatic int
690121054Semaxdo_sdp_browse(void *xs, int argc, char **argv)
691121054Semax{
692121054Semax#undef	_STR
693121054Semax#undef	STR
694121054Semax#define	_STR(x)	#x
695121054Semax#define	STR(x)	_STR(x)
696121054Semax
697121054Semax	static char const * const	av[] = {
698121054Semax		STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
699121054Semax		NULL
700121054Semax	};
701121054Semax
702121054Semax	switch (argc) {
703121054Semax	case 0:
704121054Semax		argc = 1;
705121054Semax		argv = (char **) av;
706121054Semax		/* FALL THROUGH */
707121054Semax	case 1:
708121054Semax		return (do_sdp_search(xs, argc, argv));
709121054Semax	}
710121054Semax
711121054Semax	return (USAGE);
712121054Semax} /* do_sdp_browse */
713121054Semax
714121054Semax/* List of SDP commands */
715121054Semaxstruct sdp_command	sdp_commands[] = {
716121054Semax{
717121054Semax"Browse [<Group>]",
718121054Semax"Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
719121054Semax"to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
720121054Semax"\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
721121054Semaxdo_sdp_browse
722121054Semax},
723121054Semax{
724121054Semax"Search <Service>",
725121054Semax"Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
726121054Semax"service to search for. For some services it is possible to use service name\n"\
727121054Semax"instead of service UUID\n\n" \
728121054Semax"\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
729121054Semax"\tKnown service names\n" \
730121054Semax"\t===================\n" \
731121054Semax"\tCIP   - Common ISDN Access\n" \
732121054Semax"\tCTP   - Cordless Telephony\n" \
733121054Semax"\tDUN   - DialUp Networking\n" \
734121054Semax"\tFAX   - Fax\n" \
735121054Semax"\tFTRN  - OBEX File Transfer\n" \
736121054Semax"\tGN    - GN\n" \
737121054Semax"\tHID   - Human Interface Device\n" \
738121054Semax"\tHSET  - Headset\n" \
739121054Semax"\tLAN   - LAN Access Using PPP\n" \
740121054Semax"\tNAP   - Network Access Point\n" \
741121054Semax"\tOPUSH - OBEX Object Push\n" \
742121054Semax"\tSP    - Serial Port\n",
743121054Semaxdo_sdp_search
744121054Semax},
745121054Semax{ NULL, NULL, NULL }
746121054Semax};
747121054Semax
748