xref: /freebsd/usr.sbin/bluetooth/sdpcontrol/search.c (revision f32d9c4bd3aaf08abad053749c82b8c5d4afca27)
10986ab12SMaksim Yevmenkin /*
20986ab12SMaksim Yevmenkin  * search.c
30986ab12SMaksim Yevmenkin  *
40986ab12SMaksim Yevmenkin  * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
50986ab12SMaksim Yevmenkin  * All rights reserved.
60986ab12SMaksim Yevmenkin  *
70986ab12SMaksim Yevmenkin  * Redistribution and use in source and binary forms, with or without
80986ab12SMaksim Yevmenkin  * modification, are permitted provided that the following conditions
90986ab12SMaksim Yevmenkin  * are met:
100986ab12SMaksim Yevmenkin  * 1. Redistributions of source code must retain the above copyright
110986ab12SMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer.
120986ab12SMaksim Yevmenkin  * 2. Redistributions in binary form must reproduce the above copyright
130986ab12SMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer in the
140986ab12SMaksim Yevmenkin  *    documentation and/or other materials provided with the distribution.
150986ab12SMaksim Yevmenkin  *
160986ab12SMaksim Yevmenkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170986ab12SMaksim Yevmenkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180986ab12SMaksim Yevmenkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190986ab12SMaksim Yevmenkin  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200986ab12SMaksim Yevmenkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210986ab12SMaksim Yevmenkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220986ab12SMaksim Yevmenkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230986ab12SMaksim Yevmenkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240986ab12SMaksim Yevmenkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250986ab12SMaksim Yevmenkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260986ab12SMaksim Yevmenkin  * SUCH DAMAGE.
270986ab12SMaksim Yevmenkin  *
280986ab12SMaksim Yevmenkin  * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
290986ab12SMaksim Yevmenkin  * $FreeBSD$
300986ab12SMaksim Yevmenkin  */
310986ab12SMaksim Yevmenkin 
3243d33de9SMaksim Yevmenkin #include <netinet/in.h>
338d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
340986ab12SMaksim Yevmenkin #include <bluetooth.h>
350986ab12SMaksim Yevmenkin #include <ctype.h>
360986ab12SMaksim Yevmenkin #include <sdp.h>
370986ab12SMaksim Yevmenkin #include <stdio.h>
380986ab12SMaksim Yevmenkin #include <stdlib.h>
390986ab12SMaksim Yevmenkin #include "sdpcontrol.h"
400986ab12SMaksim Yevmenkin 
410986ab12SMaksim Yevmenkin /* List of the attributes we are looking for */
42a4b187faSMaksim Yevmenkin static uint32_t	attrs[] =
430986ab12SMaksim Yevmenkin {
440986ab12SMaksim Yevmenkin 	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_RECORD_HANDLE,
450986ab12SMaksim Yevmenkin 			SDP_ATTR_SERVICE_RECORD_HANDLE),
460986ab12SMaksim Yevmenkin 	SDP_ATTR_RANGE(	SDP_ATTR_SERVICE_CLASS_ID_LIST,
470986ab12SMaksim Yevmenkin 			SDP_ATTR_SERVICE_CLASS_ID_LIST),
480986ab12SMaksim Yevmenkin 	SDP_ATTR_RANGE(	SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
490986ab12SMaksim Yevmenkin 			SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
500986ab12SMaksim Yevmenkin 	SDP_ATTR_RANGE(	SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
510986ab12SMaksim Yevmenkin 			SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
520986ab12SMaksim Yevmenkin };
530986ab12SMaksim Yevmenkin #define attrs_len	(sizeof(attrs)/sizeof(attrs[0]))
540986ab12SMaksim Yevmenkin 
550986ab12SMaksim Yevmenkin /* Buffer for the attributes */
560986ab12SMaksim Yevmenkin #define NRECS	25	/* request this much records from the SDP server */
570986ab12SMaksim Yevmenkin #define	BSIZE	256	/* one attribute buffer size */
58a4b187faSMaksim Yevmenkin static uint8_t		buffer[NRECS * attrs_len][BSIZE];
590986ab12SMaksim Yevmenkin 
600986ab12SMaksim Yevmenkin /* SDP attributes */
610986ab12SMaksim Yevmenkin static sdp_attr_t	values[NRECS * attrs_len];
620986ab12SMaksim Yevmenkin #define values_len	(sizeof(values)/sizeof(values[0]))
630986ab12SMaksim Yevmenkin 
640986ab12SMaksim Yevmenkin /*
650986ab12SMaksim Yevmenkin  * Print Service Class ID List
660986ab12SMaksim Yevmenkin  *
670986ab12SMaksim Yevmenkin  * The ServiceClassIDList attribute consists of a data element sequence in
680986ab12SMaksim Yevmenkin  * which each data element is a UUID representing the service classes that
690986ab12SMaksim Yevmenkin  * a given service record conforms to. The UUIDs are listed in order from
700986ab12SMaksim Yevmenkin  * the most specific class to the most general class. The ServiceClassIDList
710986ab12SMaksim Yevmenkin  * must contain at least one service class UUID.
720986ab12SMaksim Yevmenkin  */
730986ab12SMaksim Yevmenkin 
740986ab12SMaksim Yevmenkin static void
75a4b187faSMaksim Yevmenkin print_service_class_id_list(uint8_t const *start, uint8_t const *end)
760986ab12SMaksim Yevmenkin {
77a4b187faSMaksim Yevmenkin 	uint32_t	type, len, value;
780986ab12SMaksim Yevmenkin 
790986ab12SMaksim Yevmenkin 	if (end - start < 2) {
800986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Service Class ID List. " \
814ae439a3SMaksim Yevmenkin 				"Too short, len=%zd\n", end - start);
820986ab12SMaksim Yevmenkin 		return;
830986ab12SMaksim Yevmenkin 	}
840986ab12SMaksim Yevmenkin 
850986ab12SMaksim Yevmenkin 	SDP_GET8(type, start);
860986ab12SMaksim Yevmenkin 	switch (type) {
870986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ8:
880986ab12SMaksim Yevmenkin 		SDP_GET8(len, start);
890986ab12SMaksim Yevmenkin 		break;
900986ab12SMaksim Yevmenkin 
910986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ16:
920986ab12SMaksim Yevmenkin 		SDP_GET16(len, start);
930986ab12SMaksim Yevmenkin 		break;
940986ab12SMaksim Yevmenkin 
950986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ32:
960986ab12SMaksim Yevmenkin 		SDP_GET32(len, start);
970986ab12SMaksim Yevmenkin 		break;
980986ab12SMaksim Yevmenkin 
990986ab12SMaksim Yevmenkin 	default:
1000986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Service Class ID List. " \
1010986ab12SMaksim Yevmenkin 				"Not a sequence, type=%#x\n", type);
1020986ab12SMaksim Yevmenkin 		return;
1030986ab12SMaksim Yevmenkin 		/* NOT REACHED */
1040986ab12SMaksim Yevmenkin 	}
1050986ab12SMaksim Yevmenkin 
106*f32d9c4bSMaksim Yevmenkin 	if (len > (end - start)) {
107*f32d9c4bSMaksim Yevmenkin 		fprintf(stderr, "Invalid Service Class ID List. " \
108*f32d9c4bSMaksim Yevmenkin 				"Too long len=%d\n", len);
109*f32d9c4bSMaksim Yevmenkin 		return;
110*f32d9c4bSMaksim Yevmenkin 	}
111*f32d9c4bSMaksim Yevmenkin 
1120986ab12SMaksim Yevmenkin 	while (start < end) {
1130986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
1140986ab12SMaksim Yevmenkin 		switch (type) {
1150986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID16:
1160986ab12SMaksim Yevmenkin 			SDP_GET16(value, start);
1170986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%s (%#4.4x)\n",
1180986ab12SMaksim Yevmenkin 					sdp_uuid2desc(value), value);
1190986ab12SMaksim Yevmenkin 			break;
1200986ab12SMaksim Yevmenkin 
1210986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID32:
1220986ab12SMaksim Yevmenkin 			SDP_GET32(value, start);
1230986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%#8.8x\n", value);
1240986ab12SMaksim Yevmenkin 			break;
1250986ab12SMaksim Yevmenkin 
1260986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID128: {
1270986ab12SMaksim Yevmenkin 			int128_t	uuid;
1280986ab12SMaksim Yevmenkin 
12943d33de9SMaksim Yevmenkin 			SDP_GET_UUID128(&uuid, start);
1300986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
13143d33de9SMaksim Yevmenkin 					ntohl(*(uint32_t *)&uuid.b[0]),
13243d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[4]),
13343d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[6]),
13443d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[8]),
13543d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[10]),
13643d33de9SMaksim Yevmenkin 					ntohl(*(uint32_t *)&uuid.b[12]));
1370986ab12SMaksim Yevmenkin 			} break;
1380986ab12SMaksim Yevmenkin 
1390986ab12SMaksim Yevmenkin 		default:
1400986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Service Class ID List. " \
1410986ab12SMaksim Yevmenkin 					"Not a UUID, type=%#x\n", type);
1420986ab12SMaksim Yevmenkin 			return;
1430986ab12SMaksim Yevmenkin 			/* NOT REACHED */
1440986ab12SMaksim Yevmenkin 		}
1450986ab12SMaksim Yevmenkin 	}
1460986ab12SMaksim Yevmenkin } /* print_service_class_id_list */
1470986ab12SMaksim Yevmenkin 
1480986ab12SMaksim Yevmenkin /*
1490986ab12SMaksim Yevmenkin  * Print Protocol Descriptor List
1500986ab12SMaksim Yevmenkin  *
1510986ab12SMaksim Yevmenkin  * If the ProtocolDescriptorList describes a single stack, it takes the form
1520986ab12SMaksim Yevmenkin  * of a data element sequence in which each element of the sequence is a
1530986ab12SMaksim Yevmenkin  * protocol descriptor. Each protocol descriptor is, in turn, a data element
1540986ab12SMaksim Yevmenkin  * sequence whose first element is a UUID identifying the protocol and whose
1550986ab12SMaksim Yevmenkin  * successive elements are protocol-specific parameters. The protocol
1560986ab12SMaksim Yevmenkin  * descriptors are listed in order from the lowest layer protocol to the
1570986ab12SMaksim Yevmenkin  * highest layer protocol used to gain access to the service. If it is possible
1580986ab12SMaksim Yevmenkin  * for more than one kind of protocol stack to be used to gain access to the
1590986ab12SMaksim Yevmenkin  * service, the ProtocolDescriptorList takes the form of a data element
1600986ab12SMaksim Yevmenkin  * alternative where each member is a data element sequence as described above.
1610986ab12SMaksim Yevmenkin  */
1620986ab12SMaksim Yevmenkin 
1630986ab12SMaksim Yevmenkin static void
164a4b187faSMaksim Yevmenkin print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
1650986ab12SMaksim Yevmenkin {
1660986ab12SMaksim Yevmenkin 	union {
1670986ab12SMaksim Yevmenkin 		uint8_t		uint8;
1680986ab12SMaksim Yevmenkin 		uint16_t	uint16;
1690986ab12SMaksim Yevmenkin 		uint32_t	uint32;
1700986ab12SMaksim Yevmenkin 		uint64_t	uint64;
1710986ab12SMaksim Yevmenkin 		int128_t	int128;
1720986ab12SMaksim Yevmenkin 	}			value;
173a4b187faSMaksim Yevmenkin 	uint32_t		type, len, param;
1740986ab12SMaksim Yevmenkin 
1750986ab12SMaksim Yevmenkin 	/* Get Protocol UUID */
1760986ab12SMaksim Yevmenkin 	SDP_GET8(type, start);
1770986ab12SMaksim Yevmenkin 	switch (type) {
1780986ab12SMaksim Yevmenkin 	case SDP_DATA_UUID16:
1790986ab12SMaksim Yevmenkin 		SDP_GET16(value.uint16, start);
1800986ab12SMaksim Yevmenkin 		fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
1810986ab12SMaksim Yevmenkin 				value.uint16);
1820986ab12SMaksim Yevmenkin 		break;
1830986ab12SMaksim Yevmenkin 
1840986ab12SMaksim Yevmenkin 	case SDP_DATA_UUID32:
1850986ab12SMaksim Yevmenkin 		SDP_GET32(value.uint32, start);
1860986ab12SMaksim Yevmenkin 		fprintf(stdout, "\t%#8.8x\n", value.uint32);
1870986ab12SMaksim Yevmenkin 		break;
1880986ab12SMaksim Yevmenkin 
1890986ab12SMaksim Yevmenkin 	case SDP_DATA_UUID128:
19043d33de9SMaksim Yevmenkin 		SDP_GET_UUID128(&value.int128, start);
1910986ab12SMaksim Yevmenkin 		fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
19243d33de9SMaksim Yevmenkin 				ntohl(*(uint32_t *)&value.int128.b[0]),
19343d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[4]),
19443d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[6]),
19543d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[8]),
19643d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[10]),
19743d33de9SMaksim Yevmenkin 				ntohl(*(uint32_t *)&value.int128.b[12]));
1980986ab12SMaksim Yevmenkin 		break;
1990986ab12SMaksim Yevmenkin 
2000986ab12SMaksim Yevmenkin 	default:
2010986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Protocol Descriptor. " \
2020986ab12SMaksim Yevmenkin 				"Not a UUID, type=%#x\n", type);
2030986ab12SMaksim Yevmenkin 		return;
2040986ab12SMaksim Yevmenkin 		/* NOT REACHED */
2050986ab12SMaksim Yevmenkin 	}
2060986ab12SMaksim Yevmenkin 
2070986ab12SMaksim Yevmenkin 	/* Protocol specific parameters */
2080986ab12SMaksim Yevmenkin 	for (param = 1; start < end; param ++) {
2090986ab12SMaksim Yevmenkin 		fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
2100986ab12SMaksim Yevmenkin 
2110986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
2120986ab12SMaksim Yevmenkin 		switch (type) {
2130986ab12SMaksim Yevmenkin 		case SDP_DATA_NIL:
2140986ab12SMaksim Yevmenkin 			fprintf(stdout, "nil\n");
2150986ab12SMaksim Yevmenkin 			break;
2160986ab12SMaksim Yevmenkin 
2170986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT8:
2180986ab12SMaksim Yevmenkin 		case SDP_DATA_INT8:
2190986ab12SMaksim Yevmenkin 		case SDP_DATA_BOOL:
2200986ab12SMaksim Yevmenkin 			SDP_GET8(value.uint8, start);
2210986ab12SMaksim Yevmenkin 			fprintf(stdout, "u/int8/bool %u\n", value.uint8);
2220986ab12SMaksim Yevmenkin 			break;
2230986ab12SMaksim Yevmenkin 
2240986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT16:
2250986ab12SMaksim Yevmenkin 		case SDP_DATA_INT16:
2260986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID16:
2270986ab12SMaksim Yevmenkin 			SDP_GET16(value.uint16, start);
2280986ab12SMaksim Yevmenkin 			fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
2290986ab12SMaksim Yevmenkin 			break;
2300986ab12SMaksim Yevmenkin 
2310986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT32:
2320986ab12SMaksim Yevmenkin 		case SDP_DATA_INT32:
2330986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID32:
2340986ab12SMaksim Yevmenkin 			SDP_GET32(value.uint32, start);
2350986ab12SMaksim Yevmenkin 			fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
2360986ab12SMaksim Yevmenkin 			break;
2370986ab12SMaksim Yevmenkin 
2380986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT64:
2390986ab12SMaksim Yevmenkin 		case SDP_DATA_INT64:
2400986ab12SMaksim Yevmenkin 			SDP_GET64(value.uint64, start);
2414ae439a3SMaksim Yevmenkin 			fprintf(stdout, "u/int64 %ju\n", value.uint64);
2420986ab12SMaksim Yevmenkin 			break;
2430986ab12SMaksim Yevmenkin 
2440986ab12SMaksim Yevmenkin 		case SDP_DATA_UINT128:
2450986ab12SMaksim Yevmenkin 		case SDP_DATA_INT128:
2460986ab12SMaksim Yevmenkin 			SDP_GET128(&value.int128, start);
24743d33de9SMaksim Yevmenkin 			fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
248a4b187faSMaksim Yevmenkin 				*(uint32_t *)&value.int128.b[0],
24943d33de9SMaksim Yevmenkin 				*(uint32_t *)&value.int128.b[4],
25043d33de9SMaksim Yevmenkin 				*(uint32_t *)&value.int128.b[8],
251a4b187faSMaksim Yevmenkin 				*(uint32_t *)&value.int128.b[12]);
2520986ab12SMaksim Yevmenkin 			break;
2530986ab12SMaksim Yevmenkin 
25443d33de9SMaksim Yevmenkin 		case SDP_DATA_UUID128:
25543d33de9SMaksim Yevmenkin 			SDP_GET_UUID128(&value.int128, start);
25643d33de9SMaksim Yevmenkin 			fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
25743d33de9SMaksim Yevmenkin 				ntohl(*(uint32_t *)&value.int128.b[0]),
25843d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[4]),
25943d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[6]),
26043d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[8]),
26143d33de9SMaksim Yevmenkin 				ntohs(*(uint16_t *)&value.int128.b[10]),
26243d33de9SMaksim Yevmenkin 				ntohl(*(uint32_t *)&value.int128.b[12]));
26343d33de9SMaksim Yevmenkin 			break;
26443d33de9SMaksim Yevmenkin 
2650986ab12SMaksim Yevmenkin 		case SDP_DATA_STR8:
2660986ab12SMaksim Yevmenkin 		case SDP_DATA_URL8:
2670986ab12SMaksim Yevmenkin 			SDP_GET8(len, start);
268*f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
269*f32d9c4bSMaksim Yevmenkin 				fprintf(stdout, "%c", *start);
270*f32d9c4bSMaksim Yevmenkin 			fprintf(stdout, "\n");
2710986ab12SMaksim Yevmenkin 			break;
2720986ab12SMaksim Yevmenkin 
2730986ab12SMaksim Yevmenkin 		case SDP_DATA_STR16:
2740986ab12SMaksim Yevmenkin 		case SDP_DATA_URL16:
2750986ab12SMaksim Yevmenkin 			SDP_GET16(len, start);
276*f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
277*f32d9c4bSMaksim Yevmenkin 				fprintf(stdout, "%c", *start);
278*f32d9c4bSMaksim Yevmenkin 			fprintf(stdout, "\n");
2790986ab12SMaksim Yevmenkin 			break;
2800986ab12SMaksim Yevmenkin 
2810986ab12SMaksim Yevmenkin 		case SDP_DATA_STR32:
2820986ab12SMaksim Yevmenkin 		case SDP_DATA_URL32:
2830986ab12SMaksim Yevmenkin 			SDP_GET32(len, start);
284*f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
285*f32d9c4bSMaksim Yevmenkin 				fprintf(stdout, "%c", *start);
286*f32d9c4bSMaksim Yevmenkin 			fprintf(stdout, "\n");
2870986ab12SMaksim Yevmenkin 			break;
2880986ab12SMaksim Yevmenkin 
2890986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ8:
2900986ab12SMaksim Yevmenkin 		case SDP_DATA_ALT8:
2910986ab12SMaksim Yevmenkin 			SDP_GET8(len, start);
292*f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
2930986ab12SMaksim Yevmenkin 				fprintf(stdout, "%#2.2x ", *start);
2940986ab12SMaksim Yevmenkin 			fprintf(stdout, "\n");
2950986ab12SMaksim Yevmenkin 			break;
2960986ab12SMaksim Yevmenkin 
2970986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ16:
2980986ab12SMaksim Yevmenkin 		case SDP_DATA_ALT16:
2990986ab12SMaksim Yevmenkin 			SDP_GET16(len, start);
300*f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
3010986ab12SMaksim Yevmenkin 				fprintf(stdout, "%#2.2x ", *start);
3020986ab12SMaksim Yevmenkin 			fprintf(stdout, "\n");
3030986ab12SMaksim Yevmenkin 			break;
3040986ab12SMaksim Yevmenkin 
3050986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ32:
3060986ab12SMaksim Yevmenkin 		case SDP_DATA_ALT32:
3070986ab12SMaksim Yevmenkin 			SDP_GET32(len, start);
308*f32d9c4bSMaksim Yevmenkin 			for (; start < end && len > 0; start ++, len --)
3090986ab12SMaksim Yevmenkin 				fprintf(stdout, "%#2.2x ", *start);
3100986ab12SMaksim Yevmenkin 			fprintf(stdout, "\n");
3110986ab12SMaksim Yevmenkin 			break;
3120986ab12SMaksim Yevmenkin 
3130986ab12SMaksim Yevmenkin 		default:
3140986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Protocol Descriptor. " \
3150986ab12SMaksim Yevmenkin 					"Unknown data type: %#02x\n", type);
3160986ab12SMaksim Yevmenkin 			return;
3170986ab12SMaksim Yevmenkin 			/* NOT REACHED */
3180986ab12SMaksim Yevmenkin 		}
3190986ab12SMaksim Yevmenkin 	}
3200986ab12SMaksim Yevmenkin } /* print_protocol_descriptor */
3210986ab12SMaksim Yevmenkin 
3220986ab12SMaksim Yevmenkin static void
323a4b187faSMaksim Yevmenkin print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
3240986ab12SMaksim Yevmenkin {
325a4b187faSMaksim Yevmenkin 	uint32_t	type, len;
3260986ab12SMaksim Yevmenkin 
3270986ab12SMaksim Yevmenkin 	if (end - start < 2) {
3280986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Protocol Descriptor List. " \
3294ae439a3SMaksim Yevmenkin 				"Too short, len=%zd\n", end - start);
3300986ab12SMaksim Yevmenkin 		return;
3310986ab12SMaksim Yevmenkin 	}
3320986ab12SMaksim Yevmenkin 
3330986ab12SMaksim Yevmenkin 	SDP_GET8(type, start);
3340986ab12SMaksim Yevmenkin 	switch (type) {
3350986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ8:
3360986ab12SMaksim Yevmenkin 		SDP_GET8(len, start);
3370986ab12SMaksim Yevmenkin 		break;
3380986ab12SMaksim Yevmenkin 
3390986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ16:
3400986ab12SMaksim Yevmenkin 		SDP_GET16(len, start);
3410986ab12SMaksim Yevmenkin 		break;
3420986ab12SMaksim Yevmenkin 
3430986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ32:
3440986ab12SMaksim Yevmenkin 		SDP_GET32(len, start);
3450986ab12SMaksim Yevmenkin 		break;
3460986ab12SMaksim Yevmenkin 
3470986ab12SMaksim Yevmenkin 	default:
3480986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Protocol Descriptor List. " \
3490986ab12SMaksim Yevmenkin 				"Not a sequence, type=%#x\n", type);
3500986ab12SMaksim Yevmenkin 		return;
3510986ab12SMaksim Yevmenkin 		/* NOT REACHED */
3520986ab12SMaksim Yevmenkin 	}
3530986ab12SMaksim Yevmenkin 
354*f32d9c4bSMaksim Yevmenkin 	if (len > (end - start)) {
355*f32d9c4bSMaksim Yevmenkin 		fprintf(stderr, "Invalid Protocol Descriptor List. " \
356*f32d9c4bSMaksim Yevmenkin 				"Too long, len=%d\n", len);
357*f32d9c4bSMaksim Yevmenkin 		return;
358*f32d9c4bSMaksim Yevmenkin 	}
359*f32d9c4bSMaksim Yevmenkin 
3600986ab12SMaksim Yevmenkin 	while (start < end) {
3610986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
3620986ab12SMaksim Yevmenkin 		switch (type) {
3630986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ8:
3640986ab12SMaksim Yevmenkin 			SDP_GET8(len, start);
3650986ab12SMaksim Yevmenkin 			break;
3660986ab12SMaksim Yevmenkin 
3670986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ16:
3680986ab12SMaksim Yevmenkin 			SDP_GET16(len, start);
3690986ab12SMaksim Yevmenkin 			break;
3700986ab12SMaksim Yevmenkin 
3710986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ32:
3720986ab12SMaksim Yevmenkin 			SDP_GET32(len, start);
3730986ab12SMaksim Yevmenkin 			break;
3740986ab12SMaksim Yevmenkin 
3750986ab12SMaksim Yevmenkin 		default:
3760986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Protocol Descriptor List. " \
3770986ab12SMaksim Yevmenkin 					"Not a sequence, type=%#x\n", type);
3780986ab12SMaksim Yevmenkin 			return;
3790986ab12SMaksim Yevmenkin 			/* NOT REACHED */
3800986ab12SMaksim Yevmenkin 		}
3810986ab12SMaksim Yevmenkin 
382*f32d9c4bSMaksim Yevmenkin 		if (len > (end - start)) {
383*f32d9c4bSMaksim Yevmenkin 			fprintf(stderr, "Invalid Protocol Descriptor List. " \
384*f32d9c4bSMaksim Yevmenkin 					"Too long, len=%d\n", len);
385*f32d9c4bSMaksim Yevmenkin 			return;
386*f32d9c4bSMaksim Yevmenkin 		}
387*f32d9c4bSMaksim Yevmenkin 
3880986ab12SMaksim Yevmenkin 		print_protocol_descriptor(start, start + len);
3890986ab12SMaksim Yevmenkin 		start += len;
3900986ab12SMaksim Yevmenkin 	}
3910986ab12SMaksim Yevmenkin } /* print_protocol_descriptor_list */
3920986ab12SMaksim Yevmenkin 
3930986ab12SMaksim Yevmenkin /*
3940986ab12SMaksim Yevmenkin  * Print Bluetooth Profile Descriptor List
3950986ab12SMaksim Yevmenkin  *
3960986ab12SMaksim Yevmenkin  * The BluetoothProfileDescriptorList attribute consists of a data element
3970986ab12SMaksim Yevmenkin  * sequence in which each element is a profile descriptor that contains
3980986ab12SMaksim Yevmenkin  * information about a Bluetooth profile to which the service represented by
3990986ab12SMaksim Yevmenkin  * this service record conforms. Each profile descriptor is a data element
4000986ab12SMaksim Yevmenkin  * sequence whose first element is the UUID assigned to the profile and whose
4010986ab12SMaksim Yevmenkin  * second element is a 16-bit profile version number. Each version of a profile
4020986ab12SMaksim Yevmenkin  * is assigned a 16-bit unsigned integer profile version number, which consists
4030986ab12SMaksim Yevmenkin  * of two 8-bit fields. The higher-order 8 bits contain the major version
4040986ab12SMaksim Yevmenkin  * number field and the lower-order 8 bits contain the minor version number
4050986ab12SMaksim Yevmenkin  * field.
4060986ab12SMaksim Yevmenkin  */
4070986ab12SMaksim Yevmenkin 
4080986ab12SMaksim Yevmenkin static void
409a4b187faSMaksim Yevmenkin print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
4100986ab12SMaksim Yevmenkin {
411a4b187faSMaksim Yevmenkin 	uint32_t	type, len, value;
4120986ab12SMaksim Yevmenkin 
4130986ab12SMaksim Yevmenkin 	if (end - start < 2) {
4140986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
4154ae439a3SMaksim Yevmenkin 				"Too short, len=%zd\n", end - start);
4160986ab12SMaksim Yevmenkin 		return;
4170986ab12SMaksim Yevmenkin 	}
4180986ab12SMaksim Yevmenkin 
4190986ab12SMaksim Yevmenkin 	SDP_GET8(type, start);
4200986ab12SMaksim Yevmenkin 	switch (type) {
4210986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ8:
4220986ab12SMaksim Yevmenkin 		SDP_GET8(len, start);
4230986ab12SMaksim Yevmenkin 		break;
4240986ab12SMaksim Yevmenkin 
4250986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ16:
4260986ab12SMaksim Yevmenkin 		SDP_GET16(len, start);
4270986ab12SMaksim Yevmenkin 		break;
4280986ab12SMaksim Yevmenkin 
4290986ab12SMaksim Yevmenkin 	case SDP_DATA_SEQ32:
4300986ab12SMaksim Yevmenkin 		SDP_GET32(len, start);
4310986ab12SMaksim Yevmenkin 		break;
4320986ab12SMaksim Yevmenkin 
4330986ab12SMaksim Yevmenkin 	default:
4340986ab12SMaksim Yevmenkin 		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
4350986ab12SMaksim Yevmenkin 				"Not a sequence, type=%#x\n", type);
4360986ab12SMaksim Yevmenkin 		return;
4370986ab12SMaksim Yevmenkin 		/* NOT REACHED */
4380986ab12SMaksim Yevmenkin 	}
4390986ab12SMaksim Yevmenkin 
440*f32d9c4bSMaksim Yevmenkin 	if (len > (end - start)) {
441*f32d9c4bSMaksim Yevmenkin 		fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
442*f32d9c4bSMaksim Yevmenkin 				"Too long, len=%d\n", len);
443*f32d9c4bSMaksim Yevmenkin 		return;
444*f32d9c4bSMaksim Yevmenkin 	}
445*f32d9c4bSMaksim Yevmenkin 
4460986ab12SMaksim Yevmenkin 	while (start < end) {
4470986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
4480986ab12SMaksim Yevmenkin 		switch (type) {
4490986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ8:
4500986ab12SMaksim Yevmenkin 			SDP_GET8(len, start);
4510986ab12SMaksim Yevmenkin 			break;
4520986ab12SMaksim Yevmenkin 
4530986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ16:
4540986ab12SMaksim Yevmenkin 			SDP_GET16(len, start);
4550986ab12SMaksim Yevmenkin 			break;
4560986ab12SMaksim Yevmenkin 
4570986ab12SMaksim Yevmenkin 		case SDP_DATA_SEQ32:
4580986ab12SMaksim Yevmenkin 			SDP_GET32(len, start);
4590986ab12SMaksim Yevmenkin 			break;
4600986ab12SMaksim Yevmenkin 
4610986ab12SMaksim Yevmenkin 		default:
4620986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Bluetooth Profile " \
4630986ab12SMaksim Yevmenkin 					"Descriptor List. " \
4640986ab12SMaksim Yevmenkin 					"Not a sequence, type=%#x\n", type);
4650986ab12SMaksim Yevmenkin 			return;
4660986ab12SMaksim Yevmenkin 			/* NOT REACHED */
4670986ab12SMaksim Yevmenkin 		}
4680986ab12SMaksim Yevmenkin 
469*f32d9c4bSMaksim Yevmenkin 		if (len > (end - start)) {
470*f32d9c4bSMaksim Yevmenkin 			fprintf(stderr, "Invalid Bluetooth Profile " \
471*f32d9c4bSMaksim Yevmenkin 					"Descriptor List. " \
472*f32d9c4bSMaksim Yevmenkin 					"Too long, len=%d\n", len);
473*f32d9c4bSMaksim Yevmenkin 			return;
474*f32d9c4bSMaksim Yevmenkin 		}
475*f32d9c4bSMaksim Yevmenkin 
4760986ab12SMaksim Yevmenkin 		/* Get UUID */
4770986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
4780986ab12SMaksim Yevmenkin 		switch (type) {
4790986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID16:
4800986ab12SMaksim Yevmenkin 			SDP_GET16(value, start);
4810986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%s (%#4.4x) ",
4820986ab12SMaksim Yevmenkin 					sdp_uuid2desc(value), value);
4830986ab12SMaksim Yevmenkin 			break;
4840986ab12SMaksim Yevmenkin 
4850986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID32:
4860986ab12SMaksim Yevmenkin 			SDP_GET32(value, start);
4870986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%#8.8x ", value);
4880986ab12SMaksim Yevmenkin 			break;
4890986ab12SMaksim Yevmenkin 
4900986ab12SMaksim Yevmenkin 		case SDP_DATA_UUID128: {
4910986ab12SMaksim Yevmenkin 			int128_t	uuid;
4920986ab12SMaksim Yevmenkin 
49343d33de9SMaksim Yevmenkin 			SDP_GET_UUID128(&uuid, start);
4940986ab12SMaksim Yevmenkin 			fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
49543d33de9SMaksim Yevmenkin 					ntohl(*(uint32_t *)&uuid.b[0]),
49643d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[4]),
49743d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[6]),
49843d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[8]),
49943d33de9SMaksim Yevmenkin 					ntohs(*(uint16_t *)&uuid.b[10]),
50043d33de9SMaksim Yevmenkin 					ntohl(*(uint32_t *)&uuid.b[12]));
5010986ab12SMaksim Yevmenkin 			} break;
5020986ab12SMaksim Yevmenkin 
5030986ab12SMaksim Yevmenkin 		default:
5040986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Bluetooth Profile " \
5050986ab12SMaksim Yevmenkin 					"Descriptor List. " \
5060986ab12SMaksim Yevmenkin 					"Not a UUID, type=%#x\n", type);
5070986ab12SMaksim Yevmenkin 			return;
5080986ab12SMaksim Yevmenkin 			/* NOT REACHED */
5090986ab12SMaksim Yevmenkin 		}
5100986ab12SMaksim Yevmenkin 
5110986ab12SMaksim Yevmenkin 		/* Get version */
5120986ab12SMaksim Yevmenkin 		SDP_GET8(type, start);
5130986ab12SMaksim Yevmenkin 		if (type != SDP_DATA_UINT16) {
5140986ab12SMaksim Yevmenkin 			fprintf(stderr, "Invalid Bluetooth Profile " \
5150986ab12SMaksim Yevmenkin 					"Descriptor List. " \
5160986ab12SMaksim Yevmenkin 					"Invalid version type=%#x\n", type);
5170986ab12SMaksim Yevmenkin 			return;
5180986ab12SMaksim Yevmenkin 		}
5190986ab12SMaksim Yevmenkin 
5200986ab12SMaksim Yevmenkin 		SDP_GET16(value, start);
5210986ab12SMaksim Yevmenkin 		fprintf(stdout, "ver. %d.%d\n",
5220986ab12SMaksim Yevmenkin 				(value >> 8) & 0xff, value & 0xff);
5230986ab12SMaksim Yevmenkin 	}
5240986ab12SMaksim Yevmenkin } /* print_bluetooth_profile_descriptor_list */
5250986ab12SMaksim Yevmenkin 
5260986ab12SMaksim Yevmenkin /* Perform SDP search command */
5270986ab12SMaksim Yevmenkin static int
5280986ab12SMaksim Yevmenkin do_sdp_search(void *xs, int argc, char **argv)
5290986ab12SMaksim Yevmenkin {
5300986ab12SMaksim Yevmenkin 	char		*ep = NULL;
5310986ab12SMaksim Yevmenkin 	int32_t		 n, type, value;
532a4b187faSMaksim Yevmenkin 	uint16_t	 service;
5330986ab12SMaksim Yevmenkin 
5340986ab12SMaksim Yevmenkin 	/* Parse command line arguments */
5350986ab12SMaksim Yevmenkin 	switch (argc) {
5360986ab12SMaksim Yevmenkin 	case 1:
5370986ab12SMaksim Yevmenkin 		n = strtoul(argv[0], &ep, 16);
5380986ab12SMaksim Yevmenkin 		if (*ep != 0) {
5390986ab12SMaksim Yevmenkin 			switch (tolower(argv[0][0])) {
5400986ab12SMaksim Yevmenkin 			case 'c': /* CIP/CTP */
5410986ab12SMaksim Yevmenkin 				switch (tolower(argv[0][1])) {
5420986ab12SMaksim Yevmenkin 				case 'i':
5430986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
5440986ab12SMaksim Yevmenkin 					break;
5450986ab12SMaksim Yevmenkin 
5460986ab12SMaksim Yevmenkin 				case 't':
5470986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
5480986ab12SMaksim Yevmenkin 					break;
5490986ab12SMaksim Yevmenkin 
5500986ab12SMaksim Yevmenkin 				default:
5510986ab12SMaksim Yevmenkin 					return (USAGE);
5520986ab12SMaksim Yevmenkin 					/* NOT REACHED */
5530986ab12SMaksim Yevmenkin 				}
5540986ab12SMaksim Yevmenkin 				break;
5550986ab12SMaksim Yevmenkin 
5560986ab12SMaksim Yevmenkin 			case 'd': /* DialUp Networking */
5570986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
5580986ab12SMaksim Yevmenkin 				break;
5590986ab12SMaksim Yevmenkin 
5600986ab12SMaksim Yevmenkin 			case 'f': /* Fax/OBEX File Transfer */
5610986ab12SMaksim Yevmenkin 				switch (tolower(argv[0][1])) {
5620986ab12SMaksim Yevmenkin 				case 'a':
5630986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_FAX;
5640986ab12SMaksim Yevmenkin 					break;
5650986ab12SMaksim Yevmenkin 
5660986ab12SMaksim Yevmenkin 				case 't':
5670986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
5680986ab12SMaksim Yevmenkin 					break;
5690986ab12SMaksim Yevmenkin 
5700986ab12SMaksim Yevmenkin 				default:
5710986ab12SMaksim Yevmenkin 					return (USAGE);
5720986ab12SMaksim Yevmenkin 					/* NOT REACHED */
5730986ab12SMaksim Yevmenkin 				}
5740986ab12SMaksim Yevmenkin 				break;
5750986ab12SMaksim Yevmenkin 
5760986ab12SMaksim Yevmenkin 			case 'g': /* GN */
5770986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_GN;
5780986ab12SMaksim Yevmenkin 				break;
5790986ab12SMaksim Yevmenkin 
5800986ab12SMaksim Yevmenkin 			case 'h': /* Headset/HID */
5810986ab12SMaksim Yevmenkin 				switch (tolower(argv[0][1])) {
5820986ab12SMaksim Yevmenkin 				case 'i':
5830986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
5840986ab12SMaksim Yevmenkin 					break;
5850986ab12SMaksim Yevmenkin 
5860986ab12SMaksim Yevmenkin 				case 's':
5870986ab12SMaksim Yevmenkin 					service = SDP_SERVICE_CLASS_HEADSET;
5880986ab12SMaksim Yevmenkin 					break;
5890986ab12SMaksim Yevmenkin 
5900986ab12SMaksim Yevmenkin 				default:
5910986ab12SMaksim Yevmenkin 					return (USAGE);
5920986ab12SMaksim Yevmenkin 					/* NOT REACHED */
5930986ab12SMaksim Yevmenkin 				}
5940986ab12SMaksim Yevmenkin 				break;
5950986ab12SMaksim Yevmenkin 
5960986ab12SMaksim Yevmenkin 			case 'l': /* LAN Access Using PPP */
5970986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
5980986ab12SMaksim Yevmenkin 				break;
5990986ab12SMaksim Yevmenkin 
6000986ab12SMaksim Yevmenkin 			case 'n': /* NAP */
6010986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_NAP;
6020986ab12SMaksim Yevmenkin 				break;
6030986ab12SMaksim Yevmenkin 
6040986ab12SMaksim Yevmenkin 			case 'o': /* OBEX Object Push */
6050986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
6060986ab12SMaksim Yevmenkin 				break;
6070986ab12SMaksim Yevmenkin 
6080986ab12SMaksim Yevmenkin 			case 's': /* Serial Port */
6090986ab12SMaksim Yevmenkin 				service = SDP_SERVICE_CLASS_SERIAL_PORT;
6100986ab12SMaksim Yevmenkin 				break;
6110986ab12SMaksim Yevmenkin 
6120986ab12SMaksim Yevmenkin 			default:
6130986ab12SMaksim Yevmenkin 				return (USAGE);
6140986ab12SMaksim Yevmenkin 				/* NOT REACHED */
6150986ab12SMaksim Yevmenkin 			}
6160986ab12SMaksim Yevmenkin 		} else
617a4b187faSMaksim Yevmenkin 			service = (uint16_t) n;
6180986ab12SMaksim Yevmenkin 		break;
6190986ab12SMaksim Yevmenkin 
6200986ab12SMaksim Yevmenkin 	default:
6210986ab12SMaksim Yevmenkin 		return (USAGE);
6220986ab12SMaksim Yevmenkin 	}
6230986ab12SMaksim Yevmenkin 
6240986ab12SMaksim Yevmenkin 	/* Initialize attribute values array */
6250986ab12SMaksim Yevmenkin 	for (n = 0; n < values_len; n ++) {
6260986ab12SMaksim Yevmenkin 		values[n].flags = SDP_ATTR_INVALID;
6270986ab12SMaksim Yevmenkin 		values[n].attr = 0;
6280986ab12SMaksim Yevmenkin 		values[n].vlen = BSIZE;
6290986ab12SMaksim Yevmenkin 		values[n].value = buffer[n];
6300986ab12SMaksim Yevmenkin 	}
6310986ab12SMaksim Yevmenkin 
6320986ab12SMaksim Yevmenkin 	/* Do SDP Service Search Attribute Request */
6330986ab12SMaksim Yevmenkin 	n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
6340986ab12SMaksim Yevmenkin 	if (n != 0)
6350986ab12SMaksim Yevmenkin 		return (ERROR);
6360986ab12SMaksim Yevmenkin 
6370986ab12SMaksim Yevmenkin 	/* Print attributes values */
6380986ab12SMaksim Yevmenkin 	for (n = 0; n < values_len; n ++) {
6390986ab12SMaksim Yevmenkin 		if (values[n].flags != SDP_ATTR_OK)
6400986ab12SMaksim Yevmenkin 			break;
6410986ab12SMaksim Yevmenkin 
6420986ab12SMaksim Yevmenkin 		switch (values[n].attr) {
6430986ab12SMaksim Yevmenkin 		case SDP_ATTR_SERVICE_RECORD_HANDLE:
6440986ab12SMaksim Yevmenkin 			fprintf(stdout, "\n");
6450986ab12SMaksim Yevmenkin 			if (values[n].vlen == 5) {
6460986ab12SMaksim Yevmenkin 				SDP_GET8(type, values[n].value);
6470986ab12SMaksim Yevmenkin 				if (type == SDP_DATA_UINT32) {
6480986ab12SMaksim Yevmenkin 					SDP_GET32(value, values[n].value);
6490986ab12SMaksim Yevmenkin 					fprintf(stdout, "Record Handle: " \
6500986ab12SMaksim Yevmenkin 							"%#8.8x\n", value);
6510986ab12SMaksim Yevmenkin 				} else
6520986ab12SMaksim Yevmenkin 					fprintf(stderr, "Invalid type=%#x " \
6530986ab12SMaksim Yevmenkin 							"Record Handle " \
6540986ab12SMaksim Yevmenkin 							"attribute!\n", type);
6550986ab12SMaksim Yevmenkin 			} else
6560986ab12SMaksim Yevmenkin 				fprintf(stderr, "Invalid size=%d for Record " \
6570986ab12SMaksim Yevmenkin 						"Handle attribute\n",
6580986ab12SMaksim Yevmenkin 						values[n].vlen);
6590986ab12SMaksim Yevmenkin 			break;
6600986ab12SMaksim Yevmenkin 
6610986ab12SMaksim Yevmenkin 		case SDP_ATTR_SERVICE_CLASS_ID_LIST:
6620986ab12SMaksim Yevmenkin 			fprintf(stdout, "Service Class ID List:\n");
6630986ab12SMaksim Yevmenkin 			print_service_class_id_list(values[n].value,
6640986ab12SMaksim Yevmenkin 					values[n].value + values[n].vlen);
6650986ab12SMaksim Yevmenkin 			break;
6660986ab12SMaksim Yevmenkin 
6670986ab12SMaksim Yevmenkin 		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
6680986ab12SMaksim Yevmenkin 			fprintf(stdout, "Protocol Descriptor List:\n");
6690986ab12SMaksim Yevmenkin 			print_protocol_descriptor_list(values[n].value,
6700986ab12SMaksim Yevmenkin 					values[n].value + values[n].vlen);
6710986ab12SMaksim Yevmenkin 			break;
6720986ab12SMaksim Yevmenkin 
6730986ab12SMaksim Yevmenkin 		case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
6740986ab12SMaksim Yevmenkin 			fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
6750986ab12SMaksim Yevmenkin 			print_bluetooth_profile_descriptor_list(values[n].value,
6760986ab12SMaksim Yevmenkin 					values[n].value + values[n].vlen);
6770986ab12SMaksim Yevmenkin 			break;
6780986ab12SMaksim Yevmenkin 
6790986ab12SMaksim Yevmenkin 		default:
6800986ab12SMaksim Yevmenkin 			fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
6810986ab12SMaksim Yevmenkin 					values[n].attr);
6820986ab12SMaksim Yevmenkin 			break;
6830986ab12SMaksim Yevmenkin 		}
6840986ab12SMaksim Yevmenkin 	}
6850986ab12SMaksim Yevmenkin 
6860986ab12SMaksim Yevmenkin 	return (OK);
6870986ab12SMaksim Yevmenkin } /* do_sdp_search */
6880986ab12SMaksim Yevmenkin 
6890986ab12SMaksim Yevmenkin /* Perform SDP browse command */
6900986ab12SMaksim Yevmenkin static int
6910986ab12SMaksim Yevmenkin do_sdp_browse(void *xs, int argc, char **argv)
6920986ab12SMaksim Yevmenkin {
6930986ab12SMaksim Yevmenkin #undef	_STR
6940986ab12SMaksim Yevmenkin #undef	STR
6950986ab12SMaksim Yevmenkin #define	_STR(x)	#x
6960986ab12SMaksim Yevmenkin #define	STR(x)	_STR(x)
6970986ab12SMaksim Yevmenkin 
6980986ab12SMaksim Yevmenkin 	static char const * const	av[] = {
6990986ab12SMaksim Yevmenkin 		STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
7000986ab12SMaksim Yevmenkin 		NULL
7010986ab12SMaksim Yevmenkin 	};
7020986ab12SMaksim Yevmenkin 
7030986ab12SMaksim Yevmenkin 	switch (argc) {
7040986ab12SMaksim Yevmenkin 	case 0:
7050986ab12SMaksim Yevmenkin 		argc = 1;
7060986ab12SMaksim Yevmenkin 		argv = (char **) av;
7070986ab12SMaksim Yevmenkin 		/* FALL THROUGH */
7080986ab12SMaksim Yevmenkin 	case 1:
7090986ab12SMaksim Yevmenkin 		return (do_sdp_search(xs, argc, argv));
7100986ab12SMaksim Yevmenkin 	}
7110986ab12SMaksim Yevmenkin 
7120986ab12SMaksim Yevmenkin 	return (USAGE);
7130986ab12SMaksim Yevmenkin } /* do_sdp_browse */
7140986ab12SMaksim Yevmenkin 
7150986ab12SMaksim Yevmenkin /* List of SDP commands */
7160986ab12SMaksim Yevmenkin struct sdp_command	sdp_commands[] = {
7170986ab12SMaksim Yevmenkin {
7180986ab12SMaksim Yevmenkin "Browse [<Group>]",
7190986ab12SMaksim Yevmenkin "Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
7200986ab12SMaksim Yevmenkin "to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
7210986ab12SMaksim Yevmenkin "\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
7220986ab12SMaksim Yevmenkin do_sdp_browse
7230986ab12SMaksim Yevmenkin },
7240986ab12SMaksim Yevmenkin {
7250986ab12SMaksim Yevmenkin "Search <Service>",
7260986ab12SMaksim Yevmenkin "Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
7270986ab12SMaksim Yevmenkin "service to search for. For some services it is possible to use service name\n"\
7280986ab12SMaksim Yevmenkin "instead of service UUID\n\n" \
7290986ab12SMaksim Yevmenkin "\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
7300986ab12SMaksim Yevmenkin "\tKnown service names\n" \
7310986ab12SMaksim Yevmenkin "\t===================\n" \
7320986ab12SMaksim Yevmenkin "\tCIP   - Common ISDN Access\n" \
7330986ab12SMaksim Yevmenkin "\tCTP   - Cordless Telephony\n" \
7340986ab12SMaksim Yevmenkin "\tDUN   - DialUp Networking\n" \
7350986ab12SMaksim Yevmenkin "\tFAX   - Fax\n" \
7360986ab12SMaksim Yevmenkin "\tFTRN  - OBEX File Transfer\n" \
7370986ab12SMaksim Yevmenkin "\tGN    - GN\n" \
7380986ab12SMaksim Yevmenkin "\tHID   - Human Interface Device\n" \
7390986ab12SMaksim Yevmenkin "\tHSET  - Headset\n" \
7400986ab12SMaksim Yevmenkin "\tLAN   - LAN Access Using PPP\n" \
7410986ab12SMaksim Yevmenkin "\tNAP   - Network Access Point\n" \
7420986ab12SMaksim Yevmenkin "\tOPUSH - OBEX Object Push\n" \
7430986ab12SMaksim Yevmenkin "\tSP    - Serial Port\n",
7440986ab12SMaksim Yevmenkin do_sdp_search
7450986ab12SMaksim Yevmenkin },
7460986ab12SMaksim Yevmenkin { NULL, NULL, NULL }
7470986ab12SMaksim Yevmenkin };
7480986ab12SMaksim Yevmenkin 
749