1/*	$NetBSD: command.c,v 1.3 2009/12/05 16:54:13 plunky Exp $	*/
2
3/*-
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Iain Hibbert.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: command.c,v 1.3 2009/12/05 16:54:13 plunky Exp $");
34
35#include <bluetooth.h>
36#include <err.h>
37#include <sdp.h>
38#include <stdlib.h>
39#include <string.h>
40
41#include "sdpquery.h"
42
43static sdp_session_t open_session(void);
44static void build_ssp(sdp_data_t *, int, const char **);
45
46static struct alias {
47	uint16_t	uuid;
48	const char *	name;
49	const char *	desc;
50} aliases[] = {
51	{ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION,
52	  "A2DP",	"Advanced Audio Distribution Profile"		},
53	{ SDP_UUID_PROTOCOL_BNEP,
54	  "BNEP",	"Bluetooth Network Encapsulation Protocol"	},
55	{ SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS,
56	  "CIP",	"Common ISDN Access Service"			},
57	{ SDP_SERVICE_CLASS_CORDLESS_TELEPHONY,
58	  "CTP",	"Cordless Telephony Service"			},
59	{ SDP_SERVICE_CLASS_DIALUP_NETWORKING,
60	  "DUN",	"Dial Up Networking Service"			},
61	{ SDP_SERVICE_CLASS_FAX,
62	  "FAX",	"Fax Service"					},
63	{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
64	  "FTRN",	"File Transfer Service"				},
65	{ SDP_SERVICE_CLASS_GN,
66	  "GN",		"Group ad-hoc Network Service"			},
67	{ SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE,
68	  "HID",	"Human Interface Device Service"		},
69	{ SDP_SERVICE_CLASS_HANDSFREE,
70	  "HF",		"Handsfree Service"				},
71	{ SDP_SERVICE_CLASS_HEADSET,
72	  "HSET",	"Headset Service"				},
73	{ SDP_UUID_PROTOCOL_L2CAP,
74	  "L2CAP",	"Logical Link Control and Adapatation Protocol"	},
75	{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
76	  "LAN",	"Lan access using PPP Service"			},
77	{ SDP_SERVICE_CLASS_NAP,
78	  "NAP",	"Network Access Point Service"			},
79	{ SDP_UUID_PROTOCOL_OBEX,
80	  "OBEX",	"Object Exchange Protocol"			},
81	{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
82	  "OPUSH",	"Object Push Service"				},
83	{ SDP_SERVICE_CLASS_PANU,
84	  "PANU",	"Personal Area Networking User Service"		},
85	{ SDP_SERVICE_CLASS_PNP_INFORMATION,
86	  "PNP",	"PNP Information Service"			},
87	{ SDP_UUID_PROTOCOL_RFCOMM,
88	  "RFCOMM",	"RFCOMM Protocol"				},
89	{ SDP_UUID_PROTOCOL_SDP,
90	  "SDP",	"Service Discovery Protocol"			},
91	{ SDP_SERVICE_CLASS_SERIAL_PORT,
92	  "SP",		"Serial Port Service"				},
93	{ SDP_SERVICE_CLASS_IR_MC_SYNC,
94	  "SYNC",	"IrMC Sync Client Service"			},
95};
96
97int
98do_sdp_browse(int argc, const char **argv)
99{
100	const char *av = ___STRING(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
101
102	if (argc > 1)
103		errx(EXIT_FAILURE, "Too many arguments");
104
105	if (argc == 0) {
106		argc = 1;
107		argv = &av;
108	}
109
110	return do_sdp_search(argc, argv);
111}
112
113int
114do_sdp_record(int argc, const char **argv)
115{
116	sdp_session_t	ss;
117	sdp_data_t	rsp;
118	char *		ep;
119	unsigned long	handle;
120	bool		rv;
121
122	if (argc == 0)
123		errx(EXIT_FAILURE, "Record handle required");
124
125	ss = open_session();
126
127	for (; argc-- > 0; argv++) {
128		handle = strtoul(*argv, &ep, 0);
129		if (*argv[0] == '\0' || *ep != '\0' || handle > UINT32_MAX)
130			errx(EXIT_FAILURE, "Invalid handle: %s\n", *argv);
131
132		rv = sdp_service_attribute(ss, (uint32_t)handle, NULL, &rsp);
133		if (!rv)
134			warn("%s", *argv);
135		else
136			print_record(&rsp);
137
138		if (argc > 0)
139			printf("\n\n");
140	}
141
142	sdp_close(ss);
143	return EXIT_SUCCESS;
144}
145
146int
147do_sdp_search(int argc, const char **argv)
148{
149	sdp_session_t	ss;
150	sdp_data_t	ssp, rec, rsp;
151	bool		rv;
152
153	if (argc < 1)
154		errx(EXIT_FAILURE, "UUID required");
155
156	if (argc > 12)
157		errx(EXIT_FAILURE, "Too many UUIDs");
158
159	build_ssp(&ssp, argc, argv);
160
161	ss = open_session();
162
163	rv = sdp_service_search_attribute(ss, &ssp, NULL, &rsp);
164	if (!rv)
165		err(EXIT_FAILURE, "sdp_service_search_attribute");
166
167	while (sdp_get_seq(&rsp, &rec)) {
168		if (!rv)
169			printf("\n\n");
170		else
171			rv = false;
172
173		print_record(&rec);
174	}
175
176	if (rsp.next != rsp.end) {
177		printf("\n\nAdditional Data:\n");
178		sdp_data_print(&rsp, 4);
179	}
180
181	sdp_close(ss);
182
183	return EXIT_SUCCESS;
184}
185
186static sdp_session_t
187open_session(void)
188{
189	sdp_session_t ss;
190
191	if (bdaddr_any(&remote_addr))
192		ss = sdp_open_local(control_socket);
193	else
194		ss = sdp_open(&local_addr, &remote_addr);
195
196	if (ss == NULL)
197		err(EXIT_FAILURE, "sdp_open");
198
199	return ss;
200}
201
202/*
203 * build ServiceSearchPattern from arglist
204 */
205static void
206build_ssp(sdp_data_t *ssp, int argc, const char **argv)
207{
208	static uint8_t	data[12 * sizeof(uuid_t)];
209	char *		ep;
210	uintmax_t	umax;
211	uuid_t		uuid;
212	uint32_t	status;
213	int		i;
214
215	ssp->next = data;
216	ssp->end = data + sizeof(data);
217
218	for (; argc-- > 0; argv++) {
219		uuid_from_string(*argv, &uuid, &status);
220		if (status != uuid_s_ok) {
221			umax = strtoumax(*argv, &ep, 0);
222			if (*argv[0] == '\0' || *ep != '\0') {
223				for (i = 0;; i++) {
224					if (i == __arraycount(aliases))
225						errx(EXIT_FAILURE,
226						    "%s: Bad UUID", *argv);
227
228					if (strcasecmp(aliases[i].name,
229					    *argv) == 0)
230						break;
231				}
232
233				umax = aliases[i].uuid;
234			} else if (umax > UINT32_MAX)
235				errx(EXIT_FAILURE, "%s: Bad UUID", *argv);
236
237			uuid = BLUETOOTH_BASE_UUID;
238			uuid.time_low = (uint32_t)umax;
239		}
240
241		sdp_put_uuid(ssp, &uuid);
242	}
243
244	ssp->end = ssp->next;
245	ssp->next = data;
246}
247