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
105121054Semax	while (start < end) {
106121054Semax		SDP_GET8(type, start);
107121054Semax		switch (type) {
108121054Semax		case SDP_DATA_UUID16:
109121054Semax			SDP_GET16(value, start);
110121054Semax			fprintf(stdout, "\t%s (%#4.4x)\n",
111121054Semax					sdp_uuid2desc(value), value);
112121054Semax			break;
113121054Semax
114121054Semax		case SDP_DATA_UUID32:
115121054Semax			SDP_GET32(value, start);
116121054Semax			fprintf(stdout, "\t%#8.8x\n", value);
117121054Semax			break;
118121054Semax
119121054Semax		case SDP_DATA_UUID128: {
120121054Semax			int128_t	uuid;
121121054Semax
122146691Semax			SDP_GET_UUID128(&uuid, start);
123121054Semax			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
124146691Semax					ntohl(*(uint32_t *)&uuid.b[0]),
125146691Semax					ntohs(*(uint16_t *)&uuid.b[4]),
126146691Semax					ntohs(*(uint16_t *)&uuid.b[6]),
127146691Semax					ntohs(*(uint16_t *)&uuid.b[8]),
128146691Semax					ntohs(*(uint16_t *)&uuid.b[10]),
129146691Semax					ntohl(*(uint32_t *)&uuid.b[12]));
130121054Semax			} break;
131121054Semax
132121054Semax		default:
133121054Semax			fprintf(stderr, "Invalid Service Class ID List. " \
134121054Semax					"Not a UUID, type=%#x\n", type);
135121054Semax			return;
136121054Semax			/* NOT REACHED */
137121054Semax		}
138121054Semax	}
139121054Semax} /* print_service_class_id_list */
140121054Semax
141121054Semax/*
142121054Semax * Print Protocol Descriptor List
143121054Semax *
144121054Semax * If the ProtocolDescriptorList describes a single stack, it takes the form
145121054Semax * of a data element sequence in which each element of the sequence is a
146121054Semax * protocol descriptor. Each protocol descriptor is, in turn, a data element
147121054Semax * sequence whose first element is a UUID identifying the protocol and whose
148121054Semax * successive elements are protocol-specific parameters. The protocol
149121054Semax * descriptors are listed in order from the lowest layer protocol to the
150121054Semax * highest layer protocol used to gain access to the service. If it is possible
151121054Semax * for more than one kind of protocol stack to be used to gain access to the
152121054Semax * service, the ProtocolDescriptorList takes the form of a data element
153121054Semax * alternative where each member is a data element sequence as described above.
154121054Semax */
155121054Semax
156121054Semaxstatic void
157124317Semaxprint_protocol_descriptor(uint8_t const *start, uint8_t const *end)
158121054Semax{
159121054Semax	union {
160121054Semax		uint8_t		uint8;
161121054Semax		uint16_t	uint16;
162121054Semax		uint32_t	uint32;
163121054Semax		uint64_t	uint64;
164121054Semax		int128_t	int128;
165121054Semax	}			value;
166124317Semax	uint32_t		type, len, param;
167121054Semax
168121054Semax	/* Get Protocol UUID */
169121054Semax	SDP_GET8(type, start);
170121054Semax	switch (type) {
171121054Semax	case SDP_DATA_UUID16:
172121054Semax		SDP_GET16(value.uint16, start);
173121054Semax		fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
174121054Semax				value.uint16);
175121054Semax		break;
176121054Semax
177121054Semax	case SDP_DATA_UUID32:
178121054Semax		SDP_GET32(value.uint32, start);
179121054Semax		fprintf(stdout, "\t%#8.8x\n", value.uint32);
180121054Semax		break;
181121054Semax
182121054Semax	case SDP_DATA_UUID128:
183146691Semax		SDP_GET_UUID128(&value.int128, start);
184121054Semax		fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
185146691Semax				ntohl(*(uint32_t *)&value.int128.b[0]),
186146691Semax				ntohs(*(uint16_t *)&value.int128.b[4]),
187146691Semax				ntohs(*(uint16_t *)&value.int128.b[6]),
188146691Semax				ntohs(*(uint16_t *)&value.int128.b[8]),
189146691Semax				ntohs(*(uint16_t *)&value.int128.b[10]),
190146691Semax				ntohl(*(uint32_t *)&value.int128.b[12]));
191121054Semax		break;
192121054Semax
193121054Semax	default:
194121054Semax		fprintf(stderr, "Invalid Protocol Descriptor. " \
195121054Semax				"Not a UUID, type=%#x\n", type);
196121054Semax		return;
197121054Semax		/* NOT REACHED */
198121054Semax	}
199121054Semax
200121054Semax	/* Protocol specific parameters */
201121054Semax	for (param = 1; start < end; param ++) {
202121054Semax		fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
203121054Semax
204121054Semax		SDP_GET8(type, start);
205121054Semax		switch (type) {
206121054Semax		case SDP_DATA_NIL:
207121054Semax			fprintf(stdout, "nil\n");
208121054Semax			break;
209121054Semax
210121054Semax		case SDP_DATA_UINT8:
211121054Semax		case SDP_DATA_INT8:
212121054Semax		case SDP_DATA_BOOL:
213121054Semax			SDP_GET8(value.uint8, start);
214121054Semax			fprintf(stdout, "u/int8/bool %u\n", value.uint8);
215121054Semax			break;
216121054Semax
217121054Semax		case SDP_DATA_UINT16:
218121054Semax		case SDP_DATA_INT16:
219121054Semax		case SDP_DATA_UUID16:
220121054Semax			SDP_GET16(value.uint16, start);
221121054Semax			fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
222121054Semax			break;
223121054Semax
224121054Semax		case SDP_DATA_UINT32:
225121054Semax		case SDP_DATA_INT32:
226121054Semax		case SDP_DATA_UUID32:
227121054Semax			SDP_GET32(value.uint32, start);
228121054Semax			fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
229121054Semax			break;
230121054Semax
231121054Semax		case SDP_DATA_UINT64:
232121054Semax		case SDP_DATA_INT64:
233121054Semax			SDP_GET64(value.uint64, start);
234128076Semax			fprintf(stdout, "u/int64 %ju\n", value.uint64);
235121054Semax			break;
236121054Semax
237121054Semax		case SDP_DATA_UINT128:
238121054Semax		case SDP_DATA_INT128:
239121054Semax			SDP_GET128(&value.int128, start);
240146691Semax			fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
241124317Semax				*(uint32_t *)&value.int128.b[0],
242146691Semax				*(uint32_t *)&value.int128.b[4],
243146691Semax				*(uint32_t *)&value.int128.b[8],
244124317Semax				*(uint32_t *)&value.int128.b[12]);
245121054Semax			break;
246121054Semax
247146691Semax		case SDP_DATA_UUID128:
248146691Semax			SDP_GET_UUID128(&value.int128, start);
249146691Semax			fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
250146691Semax				ntohl(*(uint32_t *)&value.int128.b[0]),
251146691Semax				ntohs(*(uint16_t *)&value.int128.b[4]),
252146691Semax				ntohs(*(uint16_t *)&value.int128.b[6]),
253146691Semax				ntohs(*(uint16_t *)&value.int128.b[8]),
254146691Semax				ntohs(*(uint16_t *)&value.int128.b[10]),
255146691Semax				ntohl(*(uint32_t *)&value.int128.b[12]));
256146691Semax			break;
257146691Semax
258121054Semax		case SDP_DATA_STR8:
259121054Semax		case SDP_DATA_URL8:
260121054Semax			SDP_GET8(len, start);
261121054Semax			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
262121054Semax			start += len;
263121054Semax			break;
264121054Semax
265121054Semax		case SDP_DATA_STR16:
266121054Semax		case SDP_DATA_URL16:
267121054Semax			SDP_GET16(len, start);
268121054Semax			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
269121054Semax			start += len;
270121054Semax			break;
271121054Semax
272121054Semax		case SDP_DATA_STR32:
273121054Semax		case SDP_DATA_URL32:
274121054Semax			SDP_GET32(len, start);
275121054Semax			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
276121054Semax			start += len;
277121054Semax			break;
278121054Semax
279121054Semax		case SDP_DATA_SEQ8:
280121054Semax		case SDP_DATA_ALT8:
281121054Semax			SDP_GET8(len, start);
282121054Semax			for (; len > 0; start ++, len --)
283121054Semax				fprintf(stdout, "%#2.2x ", *start);
284121054Semax			fprintf(stdout, "\n");
285121054Semax			break;
286121054Semax
287121054Semax		case SDP_DATA_SEQ16:
288121054Semax		case SDP_DATA_ALT16:
289121054Semax			SDP_GET16(len, start);
290121054Semax			for (; len > 0; start ++, len --)
291121054Semax				fprintf(stdout, "%#2.2x ", *start);
292121054Semax			fprintf(stdout, "\n");
293121054Semax			break;
294121054Semax
295121054Semax		case SDP_DATA_SEQ32:
296121054Semax		case SDP_DATA_ALT32:
297121054Semax			SDP_GET32(len, start);
298121054Semax			for (; len > 0; start ++, len --)
299121054Semax				fprintf(stdout, "%#2.2x ", *start);
300121054Semax			fprintf(stdout, "\n");
301121054Semax			break;
302121054Semax
303121054Semax		default:
304121054Semax			fprintf(stderr, "Invalid Protocol Descriptor. " \
305121054Semax					"Unknown data type: %#02x\n", type);
306121054Semax			return;
307121054Semax			/* NOT REACHED */
308121054Semax		}
309121054Semax	}
310121054Semax} /* print_protocol_descriptor */
311121054Semax
312121054Semaxstatic void
313124317Semaxprint_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
314121054Semax{
315124317Semax	uint32_t	type, len;
316121054Semax
317121054Semax	if (end - start < 2) {
318121054Semax		fprintf(stderr, "Invalid Protocol Descriptor List. " \
319128076Semax				"Too short, len=%zd\n", end - start);
320121054Semax		return;
321121054Semax	}
322121054Semax
323121054Semax	SDP_GET8(type, start);
324121054Semax	switch (type) {
325121054Semax	case SDP_DATA_SEQ8:
326121054Semax		SDP_GET8(len, start);
327121054Semax		break;
328121054Semax
329121054Semax	case SDP_DATA_SEQ16:
330121054Semax		SDP_GET16(len, start);
331121054Semax		break;
332121054Semax
333121054Semax	case SDP_DATA_SEQ32:
334121054Semax		SDP_GET32(len, start);
335121054Semax		break;
336121054Semax
337121054Semax	default:
338121054Semax		fprintf(stderr, "Invalid Protocol Descriptor List. " \
339121054Semax				"Not a sequence, type=%#x\n", type);
340121054Semax		return;
341121054Semax		/* NOT REACHED */
342121054Semax	}
343121054Semax
344121054Semax	while (start < end) {
345121054Semax		SDP_GET8(type, start);
346121054Semax		switch (type) {
347121054Semax		case SDP_DATA_SEQ8:
348121054Semax			SDP_GET8(len, start);
349121054Semax			break;
350121054Semax
351121054Semax		case SDP_DATA_SEQ16:
352121054Semax			SDP_GET16(len, start);
353121054Semax			break;
354121054Semax
355121054Semax		case SDP_DATA_SEQ32:
356121054Semax			SDP_GET32(len, start);
357121054Semax			break;
358121054Semax
359121054Semax		default:
360121054Semax			fprintf(stderr, "Invalid Protocol Descriptor List. " \
361121054Semax					"Not a sequence, type=%#x\n", type);
362121054Semax			return;
363121054Semax			/* NOT REACHED */
364121054Semax		}
365121054Semax
366121054Semax		print_protocol_descriptor(start, start + len);
367121054Semax		start += len;
368121054Semax	}
369121054Semax} /* print_protocol_descriptor_list */
370121054Semax
371121054Semax/*
372121054Semax * Print Bluetooth Profile Descriptor List
373121054Semax *
374121054Semax * The BluetoothProfileDescriptorList attribute consists of a data element
375121054Semax * sequence in which each element is a profile descriptor that contains
376121054Semax * information about a Bluetooth profile to which the service represented by
377121054Semax * this service record conforms. Each profile descriptor is a data element
378121054Semax * sequence whose first element is the UUID assigned to the profile and whose
379121054Semax * second element is a 16-bit profile version number. Each version of a profile
380121054Semax * is assigned a 16-bit unsigned integer profile version number, which consists
381121054Semax * of two 8-bit fields. The higher-order 8 bits contain the major version
382121054Semax * number field and the lower-order 8 bits contain the minor version number
383121054Semax * field.
384121054Semax */
385121054Semax
386121054Semaxstatic void
387124317Semaxprint_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
388121054Semax{
389124317Semax	uint32_t	type, len, value;
390121054Semax
391121054Semax	if (end - start < 2) {
392121054Semax		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
393128076Semax				"Too short, len=%zd\n", end - start);
394121054Semax		return;
395121054Semax	}
396121054Semax
397121054Semax	SDP_GET8(type, start);
398121054Semax	switch (type) {
399121054Semax	case SDP_DATA_SEQ8:
400121054Semax		SDP_GET8(len, start);
401121054Semax		break;
402121054Semax
403121054Semax	case SDP_DATA_SEQ16:
404121054Semax		SDP_GET16(len, start);
405121054Semax		break;
406121054Semax
407121054Semax	case SDP_DATA_SEQ32:
408121054Semax		SDP_GET32(len, start);
409121054Semax		break;
410121054Semax
411121054Semax	default:
412121054Semax		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
413121054Semax				"Not a sequence, type=%#x\n", type);
414121054Semax		return;
415121054Semax		/* NOT REACHED */
416121054Semax	}
417121054Semax
418121054Semax	while (start < end) {
419121054Semax		SDP_GET8(type, start);
420121054Semax		switch (type) {
421121054Semax		case SDP_DATA_SEQ8:
422121054Semax			SDP_GET8(len, start);
423121054Semax			break;
424121054Semax
425121054Semax		case SDP_DATA_SEQ16:
426121054Semax			SDP_GET16(len, start);
427121054Semax			break;
428121054Semax
429121054Semax		case SDP_DATA_SEQ32:
430121054Semax			SDP_GET32(len, start);
431121054Semax			break;
432121054Semax
433121054Semax		default:
434121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
435121054Semax					"Descriptor List. " \
436121054Semax					"Not a sequence, type=%#x\n", type);
437121054Semax			return;
438121054Semax			/* NOT REACHED */
439121054Semax		}
440121054Semax
441121054Semax		/* Get UUID */
442121054Semax		SDP_GET8(type, start);
443121054Semax		switch (type) {
444121054Semax		case SDP_DATA_UUID16:
445121054Semax			SDP_GET16(value, start);
446121054Semax			fprintf(stdout, "\t%s (%#4.4x) ",
447121054Semax					sdp_uuid2desc(value), value);
448121054Semax			break;
449121054Semax
450121054Semax		case SDP_DATA_UUID32:
451121054Semax			SDP_GET32(value, start);
452121054Semax			fprintf(stdout, "\t%#8.8x ", value);
453121054Semax			break;
454121054Semax
455121054Semax		case SDP_DATA_UUID128: {
456121054Semax			int128_t	uuid;
457121054Semax
458146691Semax			SDP_GET_UUID128(&uuid, start);
459121054Semax			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
460146691Semax					ntohl(*(uint32_t *)&uuid.b[0]),
461146691Semax					ntohs(*(uint16_t *)&uuid.b[4]),
462146691Semax					ntohs(*(uint16_t *)&uuid.b[6]),
463146691Semax					ntohs(*(uint16_t *)&uuid.b[8]),
464146691Semax					ntohs(*(uint16_t *)&uuid.b[10]),
465146691Semax					ntohl(*(uint32_t *)&uuid.b[12]));
466121054Semax			} break;
467121054Semax
468121054Semax		default:
469121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
470121054Semax					"Descriptor List. " \
471121054Semax					"Not a UUID, type=%#x\n", type);
472121054Semax			return;
473121054Semax			/* NOT REACHED */
474121054Semax		}
475121054Semax
476121054Semax		/* Get version */
477121054Semax		SDP_GET8(type, start);
478121054Semax		if (type != SDP_DATA_UINT16) {
479121054Semax			fprintf(stderr, "Invalid Bluetooth Profile " \
480121054Semax					"Descriptor List. " \
481121054Semax					"Invalid version type=%#x\n", type);
482121054Semax			return;
483121054Semax		}
484121054Semax
485121054Semax		SDP_GET16(value, start);
486121054Semax		fprintf(stdout, "ver. %d.%d\n",
487121054Semax				(value >> 8) & 0xff, value & 0xff);
488121054Semax	}
489121054Semax} /* print_bluetooth_profile_descriptor_list */
490121054Semax
491121054Semax/* Perform SDP search command */
492121054Semaxstatic int
493121054Semaxdo_sdp_search(void *xs, int argc, char **argv)
494121054Semax{
495121054Semax	char		*ep = NULL;
496121054Semax	int32_t		 n, type, value;
497124317Semax	uint16_t	 service;
498121054Semax
499121054Semax	/* Parse command line arguments */
500121054Semax	switch (argc) {
501121054Semax	case 1:
502121054Semax		n = strtoul(argv[0], &ep, 16);
503121054Semax		if (*ep != 0) {
504121054Semax			switch (tolower(argv[0][0])) {
505121054Semax			case 'c': /* CIP/CTP */
506121054Semax				switch (tolower(argv[0][1])) {
507121054Semax				case 'i':
508121054Semax					service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
509121054Semax					break;
510121054Semax
511121054Semax				case 't':
512121054Semax					service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
513121054Semax					break;
514121054Semax
515121054Semax				default:
516121054Semax					return (USAGE);
517121054Semax					/* NOT REACHED */
518121054Semax				}
519121054Semax				break;
520121054Semax
521121054Semax			case 'd': /* DialUp Networking */
522121054Semax				service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
523121054Semax				break;
524121054Semax
525121054Semax			case 'f': /* Fax/OBEX File Transfer */
526121054Semax				switch (tolower(argv[0][1])) {
527121054Semax				case 'a':
528121054Semax					service = SDP_SERVICE_CLASS_FAX;
529121054Semax					break;
530121054Semax
531121054Semax				case 't':
532121054Semax					service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
533121054Semax					break;
534121054Semax
535121054Semax				default:
536121054Semax					return (USAGE);
537121054Semax					/* NOT REACHED */
538121054Semax				}
539121054Semax				break;
540121054Semax
541121054Semax			case 'g': /* GN */
542121054Semax				service = SDP_SERVICE_CLASS_GN;
543121054Semax				break;
544121054Semax
545121054Semax			case 'h': /* Headset/HID */
546121054Semax				switch (tolower(argv[0][1])) {
547121054Semax				case 'i':
548121054Semax					service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
549121054Semax					break;
550121054Semax
551121054Semax				case 's':
552121054Semax					service = SDP_SERVICE_CLASS_HEADSET;
553121054Semax					break;
554121054Semax
555121054Semax				default:
556121054Semax					return (USAGE);
557121054Semax					/* NOT REACHED */
558121054Semax				}
559121054Semax				break;
560121054Semax
561121054Semax			case 'l': /* LAN Access Using PPP */
562121054Semax				service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
563121054Semax				break;
564121054Semax
565121054Semax			case 'n': /* NAP */
566121054Semax				service = SDP_SERVICE_CLASS_NAP;
567121054Semax				break;
568121054Semax
569121054Semax			case 'o': /* OBEX Object Push */
570121054Semax				service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
571121054Semax				break;
572121054Semax
573121054Semax			case 's': /* Serial Port */
574121054Semax				service = SDP_SERVICE_CLASS_SERIAL_PORT;
575121054Semax				break;
576121054Semax
577121054Semax			default:
578121054Semax				return (USAGE);
579121054Semax				/* NOT REACHED */
580121054Semax			}
581121054Semax		} else
582124317Semax			service = (uint16_t) n;
583121054Semax		break;
584121054Semax
585121054Semax	default:
586121054Semax		return (USAGE);
587121054Semax	}
588121054Semax
589121054Semax	/* Initialize attribute values array */
590121054Semax	for (n = 0; n < values_len; n ++) {
591121054Semax		values[n].flags = SDP_ATTR_INVALID;
592121054Semax		values[n].attr = 0;
593121054Semax		values[n].vlen = BSIZE;
594121054Semax		values[n].value = buffer[n];
595121054Semax	}
596121054Semax
597121054Semax	/* Do SDP Service Search Attribute Request */
598121054Semax	n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
599121054Semax	if (n != 0)
600121054Semax		return (ERROR);
601121054Semax
602121054Semax	/* Print attributes values */
603121054Semax	for (n = 0; n < values_len; n ++) {
604121054Semax		if (values[n].flags != SDP_ATTR_OK)
605121054Semax			break;
606121054Semax
607121054Semax		switch (values[n].attr) {
608121054Semax		case SDP_ATTR_SERVICE_RECORD_HANDLE:
609121054Semax			fprintf(stdout, "\n");
610121054Semax			if (values[n].vlen == 5) {
611121054Semax				SDP_GET8(type, values[n].value);
612121054Semax				if (type == SDP_DATA_UINT32) {
613121054Semax					SDP_GET32(value, values[n].value);
614121054Semax					fprintf(stdout, "Record Handle: " \
615121054Semax							"%#8.8x\n", value);
616121054Semax				} else
617121054Semax					fprintf(stderr, "Invalid type=%#x " \
618121054Semax							"Record Handle " \
619121054Semax							"attribute!\n", type);
620121054Semax			} else
621121054Semax				fprintf(stderr, "Invalid size=%d for Record " \
622121054Semax						"Handle attribute\n",
623121054Semax						values[n].vlen);
624121054Semax			break;
625121054Semax
626121054Semax		case SDP_ATTR_SERVICE_CLASS_ID_LIST:
627121054Semax			fprintf(stdout, "Service Class ID List:\n");
628121054Semax			print_service_class_id_list(values[n].value,
629121054Semax					values[n].value + values[n].vlen);
630121054Semax			break;
631121054Semax
632121054Semax		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
633121054Semax			fprintf(stdout, "Protocol Descriptor List:\n");
634121054Semax			print_protocol_descriptor_list(values[n].value,
635121054Semax					values[n].value + values[n].vlen);
636121054Semax			break;
637121054Semax
638121054Semax		case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
639121054Semax			fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
640121054Semax			print_bluetooth_profile_descriptor_list(values[n].value,
641121054Semax					values[n].value + values[n].vlen);
642121054Semax			break;
643121054Semax
644121054Semax		default:
645121054Semax			fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
646121054Semax					values[n].attr);
647121054Semax			break;
648121054Semax		}
649121054Semax	}
650121054Semax
651121054Semax	return (OK);
652121054Semax} /* do_sdp_search */
653121054Semax
654121054Semax/* Perform SDP browse command */
655121054Semaxstatic int
656121054Semaxdo_sdp_browse(void *xs, int argc, char **argv)
657121054Semax{
658121054Semax#undef	_STR
659121054Semax#undef	STR
660121054Semax#define	_STR(x)	#x
661121054Semax#define	STR(x)	_STR(x)
662121054Semax
663121054Semax	static char const * const	av[] = {
664121054Semax		STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
665121054Semax		NULL
666121054Semax	};
667121054Semax
668121054Semax	switch (argc) {
669121054Semax	case 0:
670121054Semax		argc = 1;
671121054Semax		argv = (char **) av;
672121054Semax		/* FALL THROUGH */
673121054Semax	case 1:
674121054Semax		return (do_sdp_search(xs, argc, argv));
675121054Semax	}
676121054Semax
677121054Semax	return (USAGE);
678121054Semax} /* do_sdp_browse */
679121054Semax
680121054Semax/* List of SDP commands */
681121054Semaxstruct sdp_command	sdp_commands[] = {
682121054Semax{
683121054Semax"Browse [<Group>]",
684121054Semax"Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
685121054Semax"to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
686121054Semax"\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
687121054Semaxdo_sdp_browse
688121054Semax},
689121054Semax{
690121054Semax"Search <Service>",
691121054Semax"Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
692121054Semax"service to search for. For some services it is possible to use service name\n"\
693121054Semax"instead of service UUID\n\n" \
694121054Semax"\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
695121054Semax"\tKnown service names\n" \
696121054Semax"\t===================\n" \
697121054Semax"\tCIP   - Common ISDN Access\n" \
698121054Semax"\tCTP   - Cordless Telephony\n" \
699121054Semax"\tDUN   - DialUp Networking\n" \
700121054Semax"\tFAX   - Fax\n" \
701121054Semax"\tFTRN  - OBEX File Transfer\n" \
702121054Semax"\tGN    - GN\n" \
703121054Semax"\tHID   - Human Interface Device\n" \
704121054Semax"\tHSET  - Headset\n" \
705121054Semax"\tLAN   - LAN Access Using PPP\n" \
706121054Semax"\tNAP   - Network Access Point\n" \
707121054Semax"\tOPUSH - OBEX Object Push\n" \
708121054Semax"\tSP    - Serial Port\n",
709121054Semaxdo_sdp_search
710121054Semax},
711121054Semax{ NULL, NULL, NULL }
712121054Semax};
713121054Semax
714