search.c revision 124317
1193326Sed/*
2193326Sed * search.c
3193326Sed *
4193326Sed * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5193326Sed * All rights reserved.
6193326Sed *
7193326Sed * Redistribution and use in source and binary forms, with or without
8193326Sed * modification, are permitted provided that the following conditions
9193326Sed * are met:
10193326Sed * 1. Redistributions of source code must retain the above copyright
11193326Sed *    notice, this list of conditions and the following disclaimer.
12193326Sed * 2. Redistributions in binary form must reproduce the above copyright
13193326Sed *    notice, this list of conditions and the following disclaimer in the
14193326Sed *    documentation and/or other materials provided with the distribution.
15193326Sed *
16193326Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17219077Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18193326Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19193326Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20219077Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21239462Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24193326Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25193326Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26193326Sed * SUCH DAMAGE.
27193326Sed *
28218893Sdim * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
29193326Sed * $FreeBSD: head/usr.sbin/bluetooth/sdpcontrol/search.c 124317 2004-01-09 22:44:28Z emax $
30193326Sed */
31193326Sed
32193326Sed#include <bluetooth.h>
33276479Sdim#include <ctype.h>
34198092Srdivacky#include <sdp.h>
35193326Sed#include <stdio.h>
36193326Sed#include <stdlib.h>
37239462Sdim#include "sdpcontrol.h"
38239462Sdim
39193326Sed/* List of the attributes we are looking for */
40193326Sedstatic uint32_t	attrs[] =
41193326Sed{
42193326Sed	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_RECORD_HANDLE,
43193326Sed			SDP_ATTR_SERVICE_RECORD_HANDLE),
44193326Sed	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_CLASS_ID_LIST,
45193326Sed			SDP_ATTR_SERVICE_CLASS_ID_LIST),
46218893Sdim	SDP_ATTR_RANGE(	SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
47218893Sdim			SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
48193326Sed	SDP_ATTR_RANGE(	SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
49198092Srdivacky			SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
50193326Sed};
51193326Sed#define attrs_len	(sizeof(attrs)/sizeof(attrs[0]))
52193326Sed
53219077Sdim/* Buffer for the attributes */
54193326Sed#define NRECS	25	/* request this much records from the SDP server */
55193326Sed#define	BSIZE	256	/* one attribute buffer size */
56193326Sedstatic uint8_t		buffer[NRECS * attrs_len][BSIZE];
57193326Sed
58193326Sed/* SDP attributes */
59218893Sdimstatic sdp_attr_t	values[NRECS * attrs_len];
60249423Sdim#define values_len	(sizeof(values)/sizeof(values[0]))
61249423Sdim
62193326Sed/*
63198092Srdivacky * Print Service Class ID List
64276479Sdim *
65276479Sdim * The ServiceClassIDList attribute consists of a data element sequence in
66193326Sed * which each data element is a UUID representing the service classes that
67193326Sed * a given service record conforms to. The UUIDs are listed in order from
68193326Sed * the most specific class to the most general class. The ServiceClassIDList
69280031Sdim * must contain at least one service class UUID.
70249423Sdim */
71193326Sed
72193326Sedstatic void
73193326Sedprint_service_class_id_list(uint8_t const *start, uint8_t const *end)
74193326Sed{
75218893Sdim	uint32_t	type, len, value;
76219077Sdim
77219077Sdim	if (end - start < 2) {
78219077Sdim		fprintf(stderr, "Invalid Service Class ID List. " \
79219077Sdim				"Too short, len=%d\n", end - start);
80276479Sdim		return;
81276479Sdim	}
82219077Sdim
83219077Sdim	SDP_GET8(type, start);
84219077Sdim	switch (type) {
85280031Sdim	case SDP_DATA_SEQ8:
86219077Sdim		SDP_GET8(len, start);
87219077Sdim		break;
88219077Sdim
89219077Sdim	case SDP_DATA_SEQ16:
90219077Sdim		SDP_GET16(len, start);
91219077Sdim		break;
92218893Sdim
93218893Sdim	case SDP_DATA_SEQ32:
94193326Sed		SDP_GET32(len, start);
95193326Sed		break;
96193326Sed
97219077Sdim	default:
98218893Sdim		fprintf(stderr, "Invalid Service Class ID List. " \
99193326Sed				"Not a sequence, type=%#x\n", type);
100193326Sed		return;
101198092Srdivacky		/* NOT REACHED */
102198092Srdivacky	}
103218893Sdim
104198092Srdivacky	while (start < end) {
105198092Srdivacky		SDP_GET8(type, start);
106276479Sdim		switch (type) {
107219077Sdim		case SDP_DATA_UUID16:
108198092Srdivacky			SDP_GET16(value, start);
109198092Srdivacky			fprintf(stdout, "\t%s (%#4.4x)\n",
110198092Srdivacky					sdp_uuid2desc(value), value);
111198092Srdivacky			break;
112218893Sdim
113218893Sdim		case SDP_DATA_UUID32:
114193326Sed			SDP_GET32(value, start);
115239462Sdim			fprintf(stdout, "\t%#8.8x\n", value);
116239462Sdim			break;
117239462Sdim
118193326Sed		case SDP_DATA_UUID128: {
119193326Sed			int128_t	uuid;
120193326Sed
121280031Sdim			SDP_GET128(&uuid, start);
122280031Sdim			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
123280031Sdim					*(uint32_t *)&uuid.b[0],
124280031Sdim					*(uint16_t *)&uuid.b[4],
125280031Sdim					*(uint16_t *)&uuid.b[6],
126280031Sdim					*(uint16_t *)&uuid.b[8],
127280031Sdim					*(uint16_t *)&uuid.b[10],
128280031Sdim					*(uint32_t *)&uuid.b[12]);
129280031Sdim			} break;
130280031Sdim
131219077Sdim		default:
132276479Sdim			fprintf(stderr, "Invalid Service Class ID List. " \
133219077Sdim					"Not a UUID, type=%#x\n", type);
134219077Sdim			return;
135219077Sdim			/* NOT REACHED */
136219077Sdim		}
137219077Sdim	}
138219077Sdim} /* print_service_class_id_list */
139280031Sdim
140280031Sdim/*
141280031Sdim * Print Protocol Descriptor List
142280031Sdim *
143280031Sdim * If the ProtocolDescriptorList describes a single stack, it takes the form
144280031Sdim * of a data element sequence in which each element of the sequence is a
145219077Sdim * protocol descriptor. Each protocol descriptor is, in turn, a data element
146219077Sdim * sequence whose first element is a UUID identifying the protocol and whose
147219077Sdim * successive elements are protocol-specific parameters. The protocol
148219077Sdim * descriptors are listed in order from the lowest layer protocol to the
149219077Sdim * highest layer protocol used to gain access to the service. If it is possible
150219077Sdim * for more than one kind of protocol stack to be used to gain access to the
151219077Sdim * service, the ProtocolDescriptorList takes the form of a data element
152219077Sdim * alternative where each member is a data element sequence as described above.
153234353Sdim */
154219077Sdim
155219077Sdimstatic void
156280031Sdimprint_protocol_descriptor(uint8_t const *start, uint8_t const *end)
157219077Sdim{
158280031Sdim	union {
159219077Sdim		uint8_t		uint8;
160219077Sdim		uint16_t	uint16;
161276479Sdim		uint32_t	uint32;
162219077Sdim		uint64_t	uint64;
163219077Sdim		int128_t	int128;
164280031Sdim	}			value;
165219077Sdim	uint32_t		type, len, param;
166280031Sdim
167219077Sdim	/* Get Protocol UUID */
168219077Sdim	SDP_GET8(type, start);
169276479Sdim	switch (type) {
170219077Sdim	case SDP_DATA_UUID16:
171219077Sdim		SDP_GET16(value.uint16, start);
172280031Sdim		fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
173280031Sdim				value.uint16);
174280031Sdim		break;
175280031Sdim
176219077Sdim	case SDP_DATA_UUID32:
177280031Sdim		SDP_GET32(value.uint32, start);
178280031Sdim		fprintf(stdout, "\t%#8.8x\n", value.uint32);
179280031Sdim		break;
180193326Sed
181193326Sed	case SDP_DATA_UUID128:
182193326Sed		SDP_GET128(&value.int128, start);
183193326Sed		fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
184193326Sed				*(uint32_t *)&value.int128.b[0],
185193326Sed				*(uint16_t *)&value.int128.b[4],
186193326Sed				*(uint16_t *)&value.int128.b[6],
187193326Sed				*(uint16_t *)&value.int128.b[8],
188193326Sed				*(uint16_t *)&value.int128.b[10],
189219077Sdim				*(uint32_t *)&value.int128.b[12]);
190193326Sed		break;
191193326Sed
192193326Sed	default:
193280031Sdim		fprintf(stderr, "Invalid Protocol Descriptor. " \
194280031Sdim				"Not a UUID, type=%#x\n", type);
195280031Sdim		return;
196280031Sdim		/* NOT REACHED */
197280031Sdim	}
198280031Sdim
199280031Sdim	/* Protocol specific parameters */
200280031Sdim	for (param = 1; start < end; param ++) {
201280031Sdim		fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
202193326Sed
203193326Sed		SDP_GET8(type, start);
204193326Sed		switch (type) {
205193326Sed		case SDP_DATA_NIL:
206193326Sed			fprintf(stdout, "nil\n");
207234353Sdim			break;
208193326Sed
209193326Sed		case SDP_DATA_UINT8:
210224145Sdim		case SDP_DATA_INT8:
211224145Sdim		case SDP_DATA_BOOL:
212224145Sdim			SDP_GET8(value.uint8, start);
213224145Sdim			fprintf(stdout, "u/int8/bool %u\n", value.uint8);
214224145Sdim			break;
215224145Sdim
216224145Sdim		case SDP_DATA_UINT16:
217224145Sdim		case SDP_DATA_INT16:
218224145Sdim		case SDP_DATA_UUID16:
219224145Sdim			SDP_GET16(value.uint16, start);
220224145Sdim			fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
221280031Sdim			break;
222224145Sdim
223280031Sdim		case SDP_DATA_UINT32:
224224145Sdim		case SDP_DATA_INT32:
225224145Sdim		case SDP_DATA_UUID32:
226224145Sdim			SDP_GET32(value.uint32, start);
227224145Sdim			fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
228234353Sdim			break;
229234353Sdim
230224145Sdim		case SDP_DATA_UINT64:
231224145Sdim		case SDP_DATA_INT64:
232218893Sdim			SDP_GET64(value.uint64, start);
233218893Sdim			fprintf(stdout, "u/int64 %llu\n", value.uint64);
234218893Sdim			break;
235218893Sdim
236218893Sdim		case SDP_DATA_UINT128:
237218893Sdim		case SDP_DATA_INT128:
238219077Sdim		case SDP_DATA_UUID128:
239218893Sdim			SDP_GET128(&value.int128, start);
240280031Sdim			fprintf(stdout, "u/int/uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
241218893Sdim				*(uint32_t *)&value.int128.b[0],
242218893Sdim				*(uint16_t *)&value.int128.b[4],
243218893Sdim				*(uint16_t *)&value.int128.b[6],
244218893Sdim				*(uint16_t *)&value.int128.b[8],
245218893Sdim				*(uint16_t *)&value.int128.b[10],
246218893Sdim				*(uint32_t *)&value.int128.b[12]);
247218893Sdim			break;
248234353Sdim
249218893Sdim		case SDP_DATA_STR8:
250218893Sdim		case SDP_DATA_URL8:
251193326Sed			SDP_GET8(len, start);
252193326Sed			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
253198092Srdivacky			start += len;
254226633Sdim			break;
255193326Sed
256193326Sed		case SDP_DATA_STR16:
257193326Sed		case SDP_DATA_URL16:
258193326Sed			SDP_GET16(len, start);
259193326Sed			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
260193326Sed			start += len;
261193326Sed			break;
262193326Sed
263193326Sed		case SDP_DATA_STR32:
264193326Sed		case SDP_DATA_URL32:
265234353Sdim			SDP_GET32(len, start);
266234353Sdim			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
267234353Sdim			start += len;
268219077Sdim			break;
269193326Sed
270193326Sed		case SDP_DATA_SEQ8:
271219077Sdim		case SDP_DATA_ALT8:
272219077Sdim			SDP_GET8(len, start);
273219077Sdim			for (; len > 0; start ++, len --)
274219077Sdim				fprintf(stdout, "%#2.2x ", *start);
275193326Sed			fprintf(stdout, "\n");
276193326Sed			break;
277193326Sed
278280031Sdim		case SDP_DATA_SEQ16:
279280031Sdim		case SDP_DATA_ALT16:
280280031Sdim			SDP_GET16(len, start);
281280031Sdim			for (; len > 0; start ++, len --)
282193326Sed				fprintf(stdout, "%#2.2x ", *start);
283193326Sed			fprintf(stdout, "\n");
284193326Sed			break;
285193326Sed
286193326Sed		case SDP_DATA_SEQ32:
287218893Sdim		case SDP_DATA_ALT32:
288193326Sed			SDP_GET32(len, start);
289193326Sed			for (; len > 0; start ++, len --)
290198092Srdivacky				fprintf(stdout, "%#2.2x ", *start);
291198092Srdivacky			fprintf(stdout, "\n");
292198092Srdivacky			break;
293208600Srdivacky
294198092Srdivacky		default:
295198092Srdivacky			fprintf(stderr, "Invalid Protocol Descriptor. " \
296198092Srdivacky					"Unknown data type: %#02x\n", type);
297198092Srdivacky			return;
298198092Srdivacky			/* NOT REACHED */
299208600Srdivacky		}
300208600Srdivacky	}
301198092Srdivacky} /* print_protocol_descriptor */
302198092Srdivacky
303198092Srdivackystatic void
304198092Srdivackyprint_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
305198092Srdivacky{
306198092Srdivacky	uint32_t	type, len;
307198092Srdivacky
308249423Sdim	if (end - start < 2) {
309249423Sdim		fprintf(stderr, "Invalid Protocol Descriptor List. " \
310198092Srdivacky				"Too short, len=%d\n", end - start);
311198092Srdivacky		return;
312249423Sdim	}
313198092Srdivacky
314193326Sed	SDP_GET8(type, start);
315193326Sed	switch (type) {
316193326Sed	case SDP_DATA_SEQ8:
317193326Sed		SDP_GET8(len, start);
318193326Sed		break;
319193326Sed
320193326Sed	case SDP_DATA_SEQ16:
321296417Sdim		SDP_GET16(len, start);
322195341Sed		break;
323193326Sed
324219077Sdim	case SDP_DATA_SEQ32:
325296417Sdim		SDP_GET32(len, start);
326296417Sdim		break;
327296417Sdim
328296417Sdim	default:
329296417Sdim		fprintf(stderr, "Invalid Protocol Descriptor List. " \
330219077Sdim				"Not a sequence, type=%#x\n", type);
331219077Sdim		return;
332219077Sdim		/* NOT REACHED */
333219077Sdim	}
334219077Sdim
335219077Sdim	while (start < end) {
336219077Sdim		SDP_GET8(type, start);
337219077Sdim		switch (type) {
338219077Sdim		case SDP_DATA_SEQ8:
339219077Sdim			SDP_GET8(len, start);
340219077Sdim			break;
341219077Sdim
342219077Sdim		case SDP_DATA_SEQ16:
343219077Sdim			SDP_GET16(len, start);
344219077Sdim			break;
345280031Sdim
346219077Sdim		case SDP_DATA_SEQ32:
347219077Sdim			SDP_GET32(len, start);
348219077Sdim			break;
349219077Sdim
350219077Sdim		default:
351219077Sdim			fprintf(stderr, "Invalid Protocol Descriptor List. " \
352219077Sdim					"Not a sequence, type=%#x\n", type);
353219077Sdim			return;
354219077Sdim			/* NOT REACHED */
355219077Sdim		}
356219077Sdim
357219077Sdim		print_protocol_descriptor(start, start + len);
358219077Sdim		start += len;
359219077Sdim	}
360219077Sdim} /* print_protocol_descriptor_list */
361219077Sdim
362219077Sdim/*
363219077Sdim * Print Bluetooth Profile Descriptor List
364219077Sdim *
365219077Sdim * The BluetoothProfileDescriptorList attribute consists of a data element
366219077Sdim * sequence in which each element is a profile descriptor that contains
367219077Sdim * information about a Bluetooth profile to which the service represented by
368219077Sdim * this service record conforms. Each profile descriptor is a data element
369219077Sdim * sequence whose first element is the UUID assigned to the profile and whose
370219077Sdim * second element is a 16-bit profile version number. Each version of a profile
371219077Sdim * is assigned a 16-bit unsigned integer profile version number, which consists
372219077Sdim * of two 8-bit fields. The higher-order 8 bits contain the major version
373219077Sdim * number field and the lower-order 8 bits contain the minor version number
374219077Sdim * field.
375219077Sdim */
376219077Sdim
377219077Sdimstatic void
378219077Sdimprint_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
379219077Sdim{
380219077Sdim	uint32_t	type, len, value;
381219077Sdim
382219077Sdim	if (end - start < 2) {
383219077Sdim		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
384219077Sdim				"Too short, len=%d\n", end - start);
385219077Sdim		return;
386219077Sdim	}
387219077Sdim
388219077Sdim	SDP_GET8(type, start);
389219077Sdim	switch (type) {
390219077Sdim	case SDP_DATA_SEQ8:
391219077Sdim		SDP_GET8(len, start);
392219077Sdim		break;
393219077Sdim
394219077Sdim	case SDP_DATA_SEQ16:
395219077Sdim		SDP_GET16(len, start);
396219077Sdim		break;
397219077Sdim
398219077Sdim	case SDP_DATA_SEQ32:
399219077Sdim		SDP_GET32(len, start);
400219077Sdim		break;
401219077Sdim
402219077Sdim	default:
403219077Sdim		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
404219077Sdim				"Not a sequence, type=%#x\n", type);
405219077Sdim		return;
406219077Sdim		/* NOT REACHED */
407219077Sdim	}
408219077Sdim
409219077Sdim	while (start < end) {
410219077Sdim		SDP_GET8(type, start);
411280031Sdim		switch (type) {
412219077Sdim		case SDP_DATA_SEQ8:
413219077Sdim			SDP_GET8(len, start);
414219077Sdim			break;
415219077Sdim
416219077Sdim		case SDP_DATA_SEQ16:
417219077Sdim			SDP_GET16(len, start);
418219077Sdim			break;
419219077Sdim
420219077Sdim		case SDP_DATA_SEQ32:
421219077Sdim			SDP_GET32(len, start);
422219077Sdim			break;
423219077Sdim
424219077Sdim		default:
425234353Sdim			fprintf(stderr, "Invalid Bluetooth Profile " \
426234353Sdim					"Descriptor List. " \
427219077Sdim					"Not a sequence, type=%#x\n", type);
428219077Sdim			return;
429219077Sdim			/* NOT REACHED */
430219077Sdim		}
431219077Sdim
432219077Sdim		/* Get UUID */
433219077Sdim		SDP_GET8(type, start);
434219077Sdim		switch (type) {
435219077Sdim		case SDP_DATA_UUID16:
436219077Sdim			SDP_GET16(value, start);
437219077Sdim			fprintf(stdout, "\t%s (%#4.4x) ",
438219077Sdim					sdp_uuid2desc(value), value);
439221345Sdim			break;
440221345Sdim
441221345Sdim		case SDP_DATA_UUID32:
442221345Sdim			SDP_GET32(value, start);
443288943Sdim			fprintf(stdout, "\t%#8.8x ", value);
444288943Sdim			break;
445288943Sdim
446221345Sdim		case SDP_DATA_UUID128: {
447221345Sdim			int128_t	uuid;
448288943Sdim
449288943Sdim			SDP_GET128(&uuid, start);
450288943Sdim			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
451221345Sdim					*(uint32_t *)&uuid.b[0],
452288943Sdim					*(uint16_t *)&uuid.b[4],
453288943Sdim					*(uint16_t *)&uuid.b[6],
454221345Sdim					*(uint16_t *)&uuid.b[8],
455288943Sdim					*(uint16_t *)&uuid.b[10],
456221345Sdim					*(uint32_t *)&uuid.b[12]);
457221345Sdim			} break;
458221345Sdim
459221345Sdim		default:
460221345Sdim			fprintf(stderr, "Invalid Bluetooth Profile " \
461221345Sdim					"Descriptor List. " \
462221345Sdim					"Not a UUID, type=%#x\n", type);
463221345Sdim			return;
464221345Sdim			/* NOT REACHED */
465221345Sdim		}
466221345Sdim
467221345Sdim		/* Get version */
468221345Sdim		SDP_GET8(type, start);
469221345Sdim		if (type != SDP_DATA_UINT16) {
470221345Sdim			fprintf(stderr, "Invalid Bluetooth Profile " \
471221345Sdim					"Descriptor List. " \
472221345Sdim					"Invalid version type=%#x\n", type);
473221345Sdim			return;
474221345Sdim		}
475221345Sdim
476221345Sdim		SDP_GET16(value, start);
477221345Sdim		fprintf(stdout, "ver. %d.%d\n",
478221345Sdim				(value >> 8) & 0xff, value & 0xff);
479221345Sdim	}
480221345Sdim} /* print_bluetooth_profile_descriptor_list */
481221345Sdim
482221345Sdim/* Perform SDP search command */
483221345Sdimstatic int
484276479Sdimdo_sdp_search(void *xs, int argc, char **argv)
485221345Sdim{
486221345Sdim	char		*ep = NULL;
487221345Sdim	int32_t		 n, type, value;
488221345Sdim	uint16_t	 service;
489221345Sdim
490221345Sdim	/* Parse command line arguments */
491221345Sdim	switch (argc) {
492221345Sdim	case 1:
493221345Sdim		n = strtoul(argv[0], &ep, 16);
494221345Sdim		if (*ep != 0) {
495221345Sdim			switch (tolower(argv[0][0])) {
496221345Sdim			case 'c': /* CIP/CTP */
497221345Sdim				switch (tolower(argv[0][1])) {
498276479Sdim				case 'i':
499276479Sdim					service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
500221345Sdim					break;
501221345Sdim
502221345Sdim				case 't':
503221345Sdim					service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
504221345Sdim					break;
505221345Sdim
506221345Sdim				default:
507221345Sdim					return (USAGE);
508221345Sdim					/* NOT REACHED */
509221345Sdim				}
510221345Sdim				break;
511221345Sdim
512221345Sdim			case 'd': /* DialUp Networking */
513221345Sdim				service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
514221345Sdim				break;
515221345Sdim
516221345Sdim			case 'f': /* Fax/OBEX File Transfer */
517221345Sdim				switch (tolower(argv[0][1])) {
518221345Sdim				case 'a':
519221345Sdim					service = SDP_SERVICE_CLASS_FAX;
520221345Sdim					break;
521221345Sdim
522276479Sdim				case 't':
523221345Sdim					service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
524221345Sdim					break;
525221345Sdim
526221345Sdim				default:
527221345Sdim					return (USAGE);
528221345Sdim					/* NOT REACHED */
529221345Sdim				}
530221345Sdim				break;
531221345Sdim
532221345Sdim			case 'g': /* GN */
533221345Sdim				service = SDP_SERVICE_CLASS_GN;
534221345Sdim				break;
535276479Sdim
536276479Sdim			case 'h': /* Headset/HID */
537221345Sdim				switch (tolower(argv[0][1])) {
538221345Sdim				case 'i':
539221345Sdim					service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
540221345Sdim					break;
541221345Sdim
542221345Sdim				case 's':
543221345Sdim					service = SDP_SERVICE_CLASS_HEADSET;
544221345Sdim					break;
545221345Sdim
546221345Sdim				default:
547221345Sdim					return (USAGE);
548221345Sdim					/* NOT REACHED */
549221345Sdim				}
550221345Sdim				break;
551221345Sdim
552221345Sdim			case 'l': /* LAN Access Using PPP */
553221345Sdim				service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
554221345Sdim				break;
555221345Sdim
556221345Sdim			case 'n': /* NAP */
557221345Sdim				service = SDP_SERVICE_CLASS_NAP;
558221345Sdim				break;
559221345Sdim
560221345Sdim			case 'o': /* OBEX Object Push */
561221345Sdim				service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
562221345Sdim				break;
563221345Sdim
564221345Sdim			case 's': /* Serial Port */
565221345Sdim				service = SDP_SERVICE_CLASS_SERIAL_PORT;
566221345Sdim				break;
567221345Sdim
568221345Sdim			default:
569221345Sdim				return (USAGE);
570221345Sdim				/* NOT REACHED */
571221345Sdim			}
572221345Sdim		} else
573221345Sdim			service = (uint16_t) n;
574221345Sdim		break;
575221345Sdim
576221345Sdim	default:
577221345Sdim		return (USAGE);
578221345Sdim	}
579221345Sdim
580221345Sdim	if (service < SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER)
581221345Sdim		return (USAGE);
582221345Sdim
583221345Sdim	/* Initialize attribute values array */
584221345Sdim	for (n = 0; n < values_len; n ++) {
585221345Sdim		values[n].flags = SDP_ATTR_INVALID;
586221345Sdim		values[n].attr = 0;
587221345Sdim		values[n].vlen = BSIZE;
588221345Sdim		values[n].value = buffer[n];
589221345Sdim	}
590221345Sdim
591221345Sdim	/* Do SDP Service Search Attribute Request */
592221345Sdim	n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
593221345Sdim	if (n != 0)
594221345Sdim		return (ERROR);
595221345Sdim
596221345Sdim	/* Print attributes values */
597280031Sdim	for (n = 0; n < values_len; n ++) {
598280031Sdim		if (values[n].flags != SDP_ATTR_OK)
599280031Sdim			break;
600280031Sdim
601280031Sdim		switch (values[n].attr) {
602280031Sdim		case SDP_ATTR_SERVICE_RECORD_HANDLE:
603280031Sdim			fprintf(stdout, "\n");
604280031Sdim			if (values[n].vlen == 5) {
605280031Sdim				SDP_GET8(type, values[n].value);
606280031Sdim				if (type == SDP_DATA_UINT32) {
607280031Sdim					SDP_GET32(value, values[n].value);
608221345Sdim					fprintf(stdout, "Record Handle: " \
609221345Sdim							"%#8.8x\n", value);
610221345Sdim				} else
611221345Sdim					fprintf(stderr, "Invalid type=%#x " \
612221345Sdim							"Record Handle " \
613221345Sdim							"attribute!\n", type);
614221345Sdim			} else
615221345Sdim				fprintf(stderr, "Invalid size=%d for Record " \
616226633Sdim						"Handle attribute\n",
617221345Sdim						values[n].vlen);
618221345Sdim			break;
619221345Sdim
620261991Sdim		case SDP_ATTR_SERVICE_CLASS_ID_LIST:
621221345Sdim			fprintf(stdout, "Service Class ID List:\n");
622221345Sdim			print_service_class_id_list(values[n].value,
623221345Sdim					values[n].value + values[n].vlen);
624221345Sdim			break;
625221345Sdim
626221345Sdim		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
627221345Sdim			fprintf(stdout, "Protocol Descriptor List:\n");
628221345Sdim			print_protocol_descriptor_list(values[n].value,
629221345Sdim					values[n].value + values[n].vlen);
630221345Sdim			break;
631221345Sdim
632221345Sdim		case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
633221345Sdim			fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
634221345Sdim			print_bluetooth_profile_descriptor_list(values[n].value,
635221345Sdim					values[n].value + values[n].vlen);
636221345Sdim			break;
637221345Sdim
638221345Sdim		default:
639280031Sdim			fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
640221345Sdim					values[n].attr);
641221345Sdim			break;
642221345Sdim		}
643221345Sdim	}
644221345Sdim
645221345Sdim	return (OK);
646221345Sdim} /* do_sdp_search */
647221345Sdim
648221345Sdim/* Perform SDP browse command */
649221345Sdimstatic int
650221345Sdimdo_sdp_browse(void *xs, int argc, char **argv)
651221345Sdim{
652221345Sdim#undef	_STR
653221345Sdim#undef	STR
654276479Sdim#define	_STR(x)	#x
655221345Sdim#define	STR(x)	_STR(x)
656221345Sdim
657221345Sdim	static char const * const	av[] = {
658221345Sdim		STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
659221345Sdim		NULL
660221345Sdim	};
661221345Sdim
662221345Sdim	switch (argc) {
663221345Sdim	case 0:
664221345Sdim		argc = 1;
665221345Sdim		argv = (char **) av;
666221345Sdim		/* FALL THROUGH */
667221345Sdim	case 1:
668221345Sdim		return (do_sdp_search(xs, argc, argv));
669221345Sdim	}
670221345Sdim
671221345Sdim	return (USAGE);
672221345Sdim} /* do_sdp_browse */
673221345Sdim
674221345Sdim/* List of SDP commands */
675221345Sdimstruct sdp_command	sdp_commands[] = {
676221345Sdim{
677221345Sdim"Browse [<Group>]",
678221345Sdim"Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
679221345Sdim"to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
680221345Sdim"\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
681221345Sdimdo_sdp_browse
682221345Sdim},
683221345Sdim{
684221345Sdim"Search <Service>",
685"Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
686"service to search for. For some services it is possible to use service name\n"\
687"instead of service UUID\n\n" \
688"\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
689"\tKnown service names\n" \
690"\t===================\n" \
691"\tCIP   - Common ISDN Access\n" \
692"\tCTP   - Cordless Telephony\n" \
693"\tDUN   - DialUp Networking\n" \
694"\tFAX   - Fax\n" \
695"\tFTRN  - OBEX File Transfer\n" \
696"\tGN    - GN\n" \
697"\tHID   - Human Interface Device\n" \
698"\tHSET  - Headset\n" \
699"\tLAN   - LAN Access Using PPP\n" \
700"\tNAP   - Network Access Point\n" \
701"\tOPUSH - OBEX Object Push\n" \
702"\tSP    - Serial Port\n",
703do_sdp_search
704},
705{ NULL, NULL, NULL }
706};
707
708