l2control.c revision 107120
174011Sjhb/*
268685Sjhb * l2control.c
368685Sjhb *
468685Sjhb * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
568685Sjhb * All rights reserved.
668685Sjhb *
768685Sjhb * Redistribution and use in source and binary forms, with or without
868685Sjhb * modification, are permitted provided that the following conditions
968685Sjhb * are met:
1068685Sjhb * 1. Redistributions of source code must retain the above copyright
1168685Sjhb *    notice, this list of conditions and the following disclaimer.
1268685Sjhb * 2. Redistributions in binary form must reproduce the above copyright
1368685Sjhb *    notice, this list of conditions and the following disclaimer in the
1468685Sjhb *    documentation and/or other materials provided with the distribution.
1568685Sjhb *
1668685Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1768685Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1868685Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1968685Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2068685Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2168685Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2268685Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2368685Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2468685Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2568685Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26284888Skib * SUCH DAMAGE.
27206622Suqs *
2868685Sjhb * $Id: l2control.c,v 1.5 2002/09/04 21:30:40 max Exp $
2968685Sjhb * $FreeBSD: head/usr.sbin/bluetooth/l2control/l2control.c 107120 2002-11-20 23:01:59Z julian $
3068685Sjhb */
3168685Sjhb
3268685Sjhb#include <sys/types.h>
33150628Sjhb#include <sys/socket.h>
3468685Sjhb#include <bitstring.h>
3568685Sjhb#include <assert.h>
3668685Sjhb#include <err.h>
3768685Sjhb#include <errno.h>
3868685Sjhb#include <ng_hci.h>
3968685Sjhb#include <ng_l2cap.h>
4068685Sjhb#include <ng_btsocket.h>
4184306Sru#include <stdio.h>
4284306Sru#include <stdlib.h>
4368685Sjhb#include <string.h>
4489462Sru#include <unistd.h>
4568685Sjhb#include "l2control.h"
4689462Sru
4768685Sjhb/* Prototypes */
4889462Srustatic int                    do_l2cap_command    (bdaddr_p, int, char **);
4989462Srustatic struct l2cap_command * find_l2cap_command  (char const *,
5089462Sru                                                   struct l2cap_command *);
5189462Srustatic void                   print_l2cap_command (struct l2cap_command *);
5268685Sjhbstatic void                   usage               (void);
5389462Sru
54150628Sjhb/* Main */
55150628Sjhbint
5689462Srumain(int argc, char *argv[])
5789462Sru{
5889462Sru	int		n;
5968685Sjhb	bdaddr_t	bdaddr;
6089462Sru
6168685Sjhb	memset(&bdaddr, 0, sizeof(bdaddr));
6289462Sru
6368685Sjhb	/* Process command line arguments */
6489462Sru	while ((n = getopt(argc, argv, "a:")) != -1) {
65254617Sjkim		switch (n) {
66254617Sjkim		case 'a': {
67254617Sjkim			int	a0, a1, a2, a3, a4, a5;
68254617Sjkim
6968685Sjhb			if (sscanf(optarg, "%x:%x:%x:%x:%x:%x",
7068685Sjhb					&a5, &a4, &a3, &a2, &a1, &a0) != 6) {
7168685Sjhb				usage();
7268685Sjhb				break;
7368685Sjhb			}
7468685Sjhb
7589192Sru			bdaddr.b[0] = (a0 & 0xff);
76115440Shmp			bdaddr.b[1] = (a1 & 0xff);
7768685Sjhb			bdaddr.b[2] = (a2 & 0xff);
7868685Sjhb			bdaddr.b[3] = (a3 & 0xff);
7989192Sru			bdaddr.b[4] = (a4 & 0xff);
8089192Sru			bdaddr.b[5] = (a5 & 0xff);
8189192Sru			} break;
8268685Sjhb
8389192Sru		default:
8468685Sjhb			usage();
8589192Sru			break;
8668685Sjhb		}
8789192Sru	}
8868685Sjhb
8989192Sru	argc -= optind;
9068685Sjhb	argv += optind;
9168685Sjhb
9268685Sjhb	if (*argv == NULL)
9368685Sjhb		usage();
9468685Sjhb
9587999Sjake	return (do_l2cap_command(&bdaddr, argc, argv));
9689192Sru} /* main */
9789192Sru
9889192Sru/* Execute commands */
9989192Srustatic int
10089192Srudo_l2cap_command(bdaddr_p bdaddr, int argc, char **argv)
10187999Sjake{
10289192Sru	char			*cmd = argv[0];
10387999Sjake	struct l2cap_command	*c = NULL;
10489192Sru	struct sockaddr_l2cap	 sa;
10587999Sjake	int			 s, e, help;
10689192Sru
10787999Sjake	help = 0;
10887999Sjake	if (strcasecmp(cmd, "help") == 0) {
10987999Sjake		argc --;
11087999Sjake		argv ++;
11187999Sjake
11268685Sjhb		if (argc <= 0) {
11389192Sru			fprintf(stdout, "Supported commands:\n");
11468685Sjhb			print_l2cap_command(l2cap_commands);
11568685Sjhb			fprintf(stdout, "\nFor more information use " \
11668685Sjhb				"'help command'\n");
11789192Sru
11868685Sjhb			return (OK);
11968685Sjhb		}
12068685Sjhb
12168685Sjhb		help = 1;
12268685Sjhb		cmd = argv[0];
12389192Sru	}
12468685Sjhb
12568685Sjhb	c = find_l2cap_command(cmd, l2cap_commands);
126284888Skib	if (c == NULL) {
127284888Skib		fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
128284888Skib		return (ERROR);
12968685Sjhb	}
13068685Sjhb
13168685Sjhb	if (!help) {
13268685Sjhb		if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0)
13368685Sjhb			usage();
13489192Sru
13568685Sjhb		memset(&sa, 0, sizeof(sa));
136115440Shmp		sa.l2cap_len = sizeof(sa);
13768685Sjhb		sa.l2cap_family = AF_BLUETOOTH;
13868685Sjhb		memcpy(&sa.l2cap_bdaddr, bdaddr, sizeof(sa.l2cap_bdaddr));
13968685Sjhb
14068685Sjhb		s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP);
14168685Sjhb		if (s < 0)
142284888Skib			err(1, "Could not create socket");
143284888Skib
144284888Skib		if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
14568685Sjhb			err(2,
14668685Sjhb"Could not bind socket, bdaddr=%x:%x:%x:%x:%x:%x",
14768685Sjhb				sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
14868685Sjhb				sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
14968685Sjhb				sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
15089192Sru
15168685Sjhb		if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
152115440Shmp			err(2,
15368685Sjhb"Could not connect socket, bdaddr=%x:%x:%x:%x:%x:%x",
15468685Sjhb				sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
15568685Sjhb				sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
15668685Sjhb				sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
15768685Sjhb
15868685Sjhb		e = 0x0ffff;
15968685Sjhb		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &e, sizeof(e)) < 0)
16068685Sjhb			err(3, "Coult not setsockopt(RCVBUF, %d)", e);
16168685Sjhb
16268685Sjhb		e = (c->handler)(s, -- argc, ++ argv);
16368685Sjhb
16468685Sjhb		close(s);
16568685Sjhb	} else
16668685Sjhb		e = USAGE;
16768685Sjhb
16879687Sschweikh	switch (e) {
16968685Sjhb	case OK:
17068685Sjhb	case FAILED:
17168685Sjhb		break;
17268685Sjhb
17368685Sjhb	case ERROR:
17468685Sjhb		fprintf(stdout, "Could not execute command \"%s\". %s\n",
17568685Sjhb			cmd, strerror(errno));
17668685Sjhb		break;
17768685Sjhb
17868685Sjhb	case USAGE:
17968685Sjhb		fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
18068685Sjhb		break;
18168685Sjhb
18268685Sjhb	default: assert(0); break;
18389192Sru	}
18489192Sru
18568685Sjhb	return (e);
18668685Sjhb} /* do_l2cap_command */
18789192Sru
18889192Sru/* Try to find command in specified category */
18968685Sjhbstatic struct l2cap_command *
19068685Sjhbfind_l2cap_command(char const *command, struct l2cap_command *category)
19189192Sru{
19289192Sru	struct l2cap_command	*c = NULL;
19368685Sjhb
19468685Sjhb	for (c = category; c->command != NULL; c++) {
195254617Sjkim		char 	*c_end = strchr(c->command, ' ');
19668685Sjhb
197254617Sjkim		if (c_end != NULL) {
19868685Sjhb			int	len = c_end - c->command;
19968685Sjhb
20068685Sjhb			if (strncasecmp(command, c->command, len) == 0)
20168685Sjhb				return (c);
20268685Sjhb		} else if (strcasecmp(command, c->command) == 0)
20389192Sru				return (c);
20489192Sru	}
20589192Sru
20689192Sru	return (NULL);
20789192Sru} /* find_l2cap_command */
20889192Sru
20968685Sjhb/* Try to find command in specified category */
210150628Sjhbstatic void
211150628Sjhbprint_l2cap_command(struct l2cap_command *category)
212150628Sjhb{
213150628Sjhb	struct l2cap_command	*c = NULL;
214254617Sjkim
215150628Sjhb	for (c = category; c->command != NULL; c++)
216150628Sjhb		fprintf(stdout, "\t%s\n", c->command);
217150628Sjhb} /* print_l2cap_command */
218150628Sjhb
219150628Sjhb/* Usage */
220150628Sjhbstatic void
221177276Spjdusage(void)
222177276Spjd{
223150628Sjhb	fprintf(stdout, "Usage: l2control -a BD_ADDR cmd [p1] [..]]\n");
224150628Sjhb	exit(255);
225150628Sjhb} /* usage */
226150628Sjhb
227254617Sjkim