ciptool.c revision 1f72ace38b1c7575e4ace602975a3e6915716952
1/*
2 *
3 *  Bluetooth Common ISDN Access Profile (CIP)
4 *
5 *  Copyright (C) 2002-2003  Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 *
22 */
23
24#include <stdio.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <malloc.h>
29#include <getopt.h>
30#include <signal.h>
31#include <sys/poll.h>
32#include <sys/ioctl.h>
33#include <sys/socket.h>
34
35#include <bluetooth/bluetooth.h>
36#include <bluetooth/hci.h>
37#include <bluetooth/hci_lib.h>
38#include <bluetooth/l2cap.h>
39#include <bluetooth/sdp.h>
40#include <bluetooth/sdp_lib.h>
41#include <bluetooth/cmtp.h>
42
43
44static volatile sig_atomic_t __io_canceled = 0;
45
46static void sig_hup(int sig)
47{
48	return;
49}
50
51static void sig_term(int sig)
52{
53	__io_canceled = 1;
54}
55
56static char *cmtp_state[] = {
57	"unknown",
58	"connected",
59	"open",
60	"bound",
61	"listening",
62	"connecting",
63	"connecting",
64	"config",
65	"disconnecting",
66	"closed"
67};
68
69static char *cmtp_flagstostr(uint32_t flags)
70{
71	static char str[100] = "";
72
73	strcat(str, "[");
74
75	if (flags & (1 << CMTP_LOOPBACK))
76		strcat(str, "loopback");
77
78	strcat(str, "]");
79
80	return str;
81}
82
83static int get_psm(bdaddr_t *src, bdaddr_t *dst, unsigned short *psm)
84{
85	sdp_session_t *s;
86	sdp_list_t *srch, *attrs, *rsp;
87	uuid_t svclass;
88	uint16_t attr;
89	int err;
90
91	if (!(s = sdp_connect(src, dst, 0)))
92		return -1;
93
94	sdp_uuid16_create(&svclass, CIP_SVCLASS_ID);
95	srch = sdp_list_append(NULL, &svclass);
96
97	attr = SDP_ATTR_PROTO_DESC_LIST;
98	attrs = sdp_list_append(NULL, &attr);
99
100	err = sdp_service_search_attr_req(s, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
101
102	sdp_close(s);
103
104	if (err)
105		return 0;
106
107	for (; rsp; rsp = rsp->next) {
108		sdp_record_t *rec = (sdp_record_t *) rsp->data;
109		sdp_list_t *protos;
110
111		if (!sdp_get_access_protos(rec, &protos)) {
112			unsigned short p = sdp_get_proto_port(protos, L2CAP_UUID);
113			if (p > 0) {
114				*psm = p;
115				return 1;
116			}
117		}
118	}
119
120	return 0;
121}
122
123static int do_connect(int ctl, int dev_id, bdaddr_t *src, bdaddr_t *dst, unsigned short psm, uint32_t flags)
124{
125	struct cmtp_connadd_req req;
126	struct hci_dev_info di;
127	struct sockaddr_l2 addr;
128	struct l2cap_options opts;
129	int sk, size;
130
131	hci_devinfo(dev_id, &di);
132	if (!(di.link_policy & HCI_LP_RSWITCH)) {
133		printf("Local device is not accepting role switch\n");
134	}
135
136	if ((sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
137		perror("Can't create L2CAP socket");
138		exit(1);
139	}
140
141	addr.l2_family = AF_BLUETOOTH;
142	bacpy(&addr.l2_bdaddr, src);
143	addr.l2_psm = 0;
144
145	if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
146		perror("Can't bind L2CAP socket");
147		close(sk);
148		exit(1);
149	}
150
151	size = sizeof(opts);
152	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
153		perror("Can't get L2CAP options");
154		close(sk);
155		exit(1);
156	}
157
158	opts.imtu = CMTP_DEFAULT_MTU;
159	opts.omtu = CMTP_DEFAULT_MTU;
160	opts.flush_to = 0xffff;
161
162	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
163		perror("Can't set L2CAP options");
164		close(sk);
165		exit(1);
166	}
167
168	addr.l2_family = AF_BLUETOOTH;
169	bacpy(&addr.l2_bdaddr, dst);
170	addr.l2_psm = htobs(psm);
171
172	if (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
173		perror("Can't connect L2CAP socket");
174		close(sk);
175		exit(1);
176	}
177
178	req.sock = sk;
179	req.flags = flags;
180
181	if (ioctl(ctl, CMTPCONNADD, &req) < 0) {
182		perror("Can't create connection");
183		exit(1);
184	}
185
186	return sk;
187}
188
189static void cmd_show(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
190{
191	struct cmtp_connlist_req req;
192	struct cmtp_conninfo ci[16];
193	char addr[18];
194	int i;
195
196	req.cnum = 16;
197	req.ci   = ci;
198
199	if (ioctl(ctl, CMTPGETCONNLIST, &req) < 0) {
200		perror("Can't get connection list");
201		exit(1);
202	}
203
204	for (i = 0; i < req.cnum; i++) {
205		ba2str(&ci[i].bdaddr, addr);
206		printf("%d %s %s %s\n", ci[i].num, addr,
207			cmtp_state[ci[i].state],
208			ci[i].flags ? cmtp_flagstostr(ci[i].flags) : "");
209	}
210}
211
212static void cmd_search(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
213{
214	inquiry_info *info = NULL;
215	bdaddr_t src, dst;
216	unsigned short psm;
217	int i, dev_id, num_rsp, length, flags;
218	char addr[18];
219	uint8_t class[3];
220
221	ba2str(bdaddr, addr);
222	dev_id = hci_devid(addr);
223	if (dev_id < 0) {
224		dev_id = hci_get_route(NULL);
225		hci_devba(dev_id, &src);
226	} else
227		bacpy(&src, bdaddr);
228
229	length  = 8;	/* ~10 seconds */
230	num_rsp = 0;
231	flags   = 0;
232
233	printf("Searching ...\n");
234
235	num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags);
236
237	for (i = 0; i < num_rsp; i++) {
238		memcpy(class, (info+i)->dev_class, 3);
239		if ((class[1] == 2) && ((class[0] / 4) == 5)) {
240			bacpy(&dst, &(info+i)->bdaddr);
241			ba2str(&dst, addr);
242
243			printf("\tChecking service for %s\n", addr);
244			if (!get_psm(&src, &dst, &psm))
245				continue;
246
247			free(info);
248
249			printf("\tConnecting to device %s\n", addr);
250			do_connect(ctl, dev_id, &src, &dst, psm, 0);
251			return;
252		}
253	}
254
255	free(info);
256	fprintf(stderr, "\tNo devices in range or visible\n");
257	exit(1);
258}
259
260static void cmd_create(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
261{
262	bdaddr_t src, dst;
263	unsigned short psm;
264	int dev_id;
265	char addr[18];
266
267	if (argc < 2)
268		return;
269
270	str2ba(argv[1], &dst);
271
272	ba2str(bdaddr, addr);
273	dev_id = hci_devid(addr);
274	if (dev_id < 0) {
275		dev_id = hci_get_route(&dst);
276		hci_devba(dev_id, &src);
277	} else
278		bacpy(&src, bdaddr);
279
280	if (argc < 3) {
281		if (!get_psm(&src, &dst, &psm))
282			psm = 4099;
283	} else
284		psm = atoi(argv[2]);
285
286	do_connect(ctl, dev_id, &src, &dst, psm, 0);
287}
288
289static void cmd_release(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
290{
291	struct cmtp_conndel_req req;
292	struct cmtp_connlist_req cl;
293	struct cmtp_conninfo ci[16];
294
295	if (argc < 2) {
296		cl.cnum = 16;
297		cl.ci   = ci;
298
299		if (ioctl(ctl, CMTPGETCONNLIST, &cl) < 0) {
300			perror("Can't get connection list");
301			exit(1);
302		}
303
304		if (cl.cnum == 0)
305			return;
306
307		if (cl.cnum != 1) {
308			fprintf(stderr, "You have to specifiy the device address.\n");
309			exit(1);
310		}
311
312		bacpy(&req.bdaddr, &ci[0].bdaddr);
313	} else
314		str2ba(argv[1], &req.bdaddr);
315
316	if (ioctl(ctl, CMTPCONNDEL, &req) < 0) {
317		perror("Can't release connection");
318		exit(1);
319	}
320}
321
322static void cmd_loopback(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
323{
324	struct cmtp_conndel_req req;
325	struct sigaction sa;
326	struct pollfd p;
327	bdaddr_t src, dst;
328	unsigned short psm;
329	int dev_id, sk;
330	char addr[18];
331
332	if (argc < 2)
333		return;
334
335	str2ba(argv[1], &dst);
336
337	ba2str(bdaddr, addr);
338	dev_id = hci_devid(addr);
339	if (dev_id < 0) {
340		dev_id = hci_get_route(&dst);
341		hci_devba(dev_id, &src);
342	} else
343		bacpy(&src, bdaddr);
344
345	ba2str(&dst, addr);
346	printf("Connecting to %s in loopback mode\n", addr);
347
348	if (argc < 3) {
349		if (!get_psm(&src, &dst, &psm))
350			psm = 4099;
351	} else
352		psm = atoi(argv[2]);
353
354	sk = do_connect(ctl, dev_id, &src, &dst, psm, (1 << CMTP_LOOPBACK));
355
356	printf("Press CTRL-C for hangup\n");
357
358	memset(&sa, 0, sizeof(sa));
359	sa.sa_flags   = SA_NOCLDSTOP;
360	sa.sa_handler = SIG_IGN;
361	sigaction(SIGCHLD, &sa, NULL);
362	sigaction(SIGPIPE, &sa, NULL);
363
364	sa.sa_handler = sig_term;
365	sigaction(SIGTERM, &sa, NULL);
366	sigaction(SIGINT,  &sa, NULL);
367
368	sa.sa_handler = sig_hup;
369	sigaction(SIGHUP, &sa, NULL);
370
371	p.fd = sk;
372	p.events = POLLERR | POLLHUP;
373
374	while (!__io_canceled) {
375		p.revents = 0;
376		if (poll(&p, 1, 100))
377			break;
378	}
379
380	bacpy(&req.bdaddr, &dst);
381	ioctl(ctl, CMTPCONNDEL, &req);
382}
383
384
385static struct {
386	char *cmd;
387	char *alt;
388	void (*func)(int ctl, bdaddr_t *bdaddr, int argc, char **argv);
389	char *opt;
390	char *doc;
391} command[] = {
392	{ "show",     "list",       cmd_show,     0,          "Show remote connections"      },
393	{ "search",   "scan",       cmd_search,   0,          "Search for a remote device"   },
394	{ "connect",  "create",     cmd_create,   "<bdaddr>", "Connect a remote device"      },
395	{ "release",  "disconnect", cmd_release,  "[bdaddr]", "Disconnect the remote device" },
396	{ "loopback", "test",       cmd_loopback, "<bdaddr>", "Loopback test of a device"    },
397	{ NULL, NULL, NULL, 0, 0 }
398};
399
400static void usage(void)
401{
402	int i;
403
404	printf("ciptool - Bluetooth Common ISDN Access Profile (CIP)\n\n");
405
406	printf("Usage:\n"
407		"\tciptool [options] [command]\n"
408		"\n");
409
410	printf("Options:\n"
411		"\t-i [hciX|bdaddr]   Local HCI device or BD Address\n"
412		"\t-h, --help         Display help\n"
413		"\n");
414
415	printf("Commands:\n");
416	for (i = 0; command[i].cmd; i++)
417		printf("\t%-8s %-10s\t%s\n", command[i].cmd,
418		command[i].opt ? command[i].opt : " ",
419		command[i].doc);
420	printf("\n");
421}
422
423static struct option main_options[] = {
424	{ "help",	0, 0, 'h' },
425	{ "device",	1, 0, 'i' },
426	{ 0, 0, 0, 0 }
427};
428
429int main(int argc, char *argv[])
430{
431	bdaddr_t bdaddr;
432	int i, opt, ctl;
433
434	bacpy(&bdaddr, BDADDR_ANY);
435
436	while ((opt = getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
437		switch(opt) {
438		case 'i':
439			if (!strncmp(optarg, "hci", 3))
440				hci_devba(atoi(optarg + 3), &bdaddr);
441			else
442				str2ba(optarg, &bdaddr);
443			break;
444		case 'h':
445			usage();
446			exit(0);
447		default:
448			exit(0);
449		}
450	}
451
452	argc -= optind;
453	argv += optind;
454	optind = 0;
455
456	if (argc < 1) {
457		usage();
458		return 0;
459	}
460
461	if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_CMTP)) < 0 ) {
462		perror("Can't open CMTP control socket");
463		exit(1);
464	}
465
466	for (i = 0; command[i].cmd; i++) {
467		if (strncmp(command[i].cmd, argv[0], 4) && strncmp(command[i].alt, argv[0], 4))
468			continue;
469		command[i].func(ctl, &bdaddr, argc, argv);
470		close(ctl);
471		exit(0);
472	}
473
474	usage();
475
476	close(ctl);
477
478	return 0;
479}
480