xref: /netbsd-src/usr.bin/sdpquery/command.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
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 
43 static sdp_session_t open_session(void);
44 static void build_ssp(sdp_data_t *, int, const char **);
45 
46 static 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 
97 int
98 do_sdp_browse(int argc, const char **argv)
99 {
100 #define STR(x)	__STRING(x)
101 	const char *av = STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
102 #undef STR
103 
104 	if (argc > 1)
105 		errx(EXIT_FAILURE, "Too many arguments");
106 
107 	if (argc == 0) {
108 		argc = 1;
109 		argv = &av;
110 	}
111 
112 	return do_sdp_search(argc, argv);
113 }
114 
115 int
116 do_sdp_record(int argc, const char **argv)
117 {
118 	sdp_session_t	ss;
119 	sdp_data_t	rsp;
120 	char *		ep;
121 	unsigned long	handle;
122 	bool		rv;
123 
124 	if (argc == 0)
125 		errx(EXIT_FAILURE, "Record handle required");
126 
127 	ss = open_session();
128 
129 	for (; argc-- > 0; argv++) {
130 		handle = strtoul(*argv, &ep, 0);
131 		if (*argv[0] == '\0' || *ep != '\0' || handle > UINT32_MAX)
132 			errx(EXIT_FAILURE, "Invalid handle: %s\n", *argv);
133 
134 		rv = sdp_service_attribute(ss, (uint32_t)handle, NULL, &rsp);
135 		if (!rv)
136 			warn("%s", *argv);
137 		else
138 			print_record(&rsp);
139 
140 		if (argc > 0)
141 			printf("\n\n");
142 	}
143 
144 	sdp_close(ss);
145 	return EXIT_SUCCESS;
146 }
147 
148 int
149 do_sdp_search(int argc, const char **argv)
150 {
151 	sdp_session_t	ss;
152 	sdp_data_t	ssp, rec, rsp;
153 	bool		rv;
154 
155 	if (argc < 1)
156 		errx(EXIT_FAILURE, "UUID required");
157 
158 	if (argc > 12)
159 		errx(EXIT_FAILURE, "Too many UUIDs");
160 
161 	build_ssp(&ssp, argc, argv);
162 
163 	ss = open_session();
164 
165 	rv = sdp_service_search_attribute(ss, &ssp, NULL, &rsp);
166 	if (!rv)
167 		err(EXIT_FAILURE, "sdp_service_search_attribute");
168 
169 	while (sdp_get_seq(&rsp, &rec)) {
170 		if (!rv)
171 			printf("\n\n");
172 		else
173 			rv = false;
174 
175 		print_record(&rec);
176 	}
177 
178 	if (rsp.next != rsp.end) {
179 		printf("\n\nAdditional Data:\n");
180 		sdp_data_print(&rsp, 4);
181 	}
182 
183 	sdp_close(ss);
184 
185 	return EXIT_SUCCESS;
186 }
187 
188 static sdp_session_t
189 open_session(void)
190 {
191 	sdp_session_t ss;
192 
193 	if (bdaddr_any(&remote_addr))
194 		ss = sdp_open_local(control_socket);
195 	else
196 		ss = sdp_open(&local_addr, &remote_addr);
197 
198 	if (ss == NULL)
199 		err(EXIT_FAILURE, "sdp_open");
200 
201 	return ss;
202 }
203 
204 /*
205  * build ServiceSearchPattern from arglist
206  */
207 static void
208 build_ssp(sdp_data_t *ssp, int argc, const char **argv)
209 {
210 	static uint8_t	data[12 * sizeof(uuid_t)];
211 	char *		ep;
212 	uintmax_t	umax;
213 	uuid_t		uuid;
214 	uint32_t	status;
215 	int		i;
216 
217 	ssp->next = data;
218 	ssp->end = data + sizeof(data);
219 
220 	for (; argc-- > 0; argv++) {
221 		uuid_from_string(*argv, &uuid, &status);
222 		if (status != uuid_s_ok) {
223 			umax = strtoumax(*argv, &ep, 0);
224 			if (*argv[0] == '\0' || *ep != '\0') {
225 				for (i = 0;; i++) {
226 					if (i == __arraycount(aliases))
227 						errx(EXIT_FAILURE,
228 						    "%s: Bad UUID", *argv);
229 
230 					if (strcasecmp(aliases[i].name,
231 					    *argv) == 0)
232 						break;
233 				}
234 
235 				umax = aliases[i].uuid;
236 			} else if (umax > UINT32_MAX)
237 				errx(EXIT_FAILURE, "%s: Bad UUID", *argv);
238 
239 			uuid = BLUETOOTH_BASE_UUID;
240 			uuid.time_low = (uint32_t)umax;
241 		}
242 
243 		sdp_put_uuid(ssp, &uuid);
244 	}
245 
246 	ssp->end = ssp->next;
247 	ssp->next = data;
248 }
249