link_policy.c revision 128079
1/*
2 * link_policy.c
3 *
4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $Id: link_policy.c,v 1.3 2003/08/18 19:19:54 max Exp $
29 * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/link_policy.c 128079 2004-04-09 23:58:53Z emax $
30 */
31
32#include <bluetooth.h>
33#include <errno.h>
34#include <stdio.h>
35#include <string.h>
36#include "hccontrol.h"
37
38/* Send Role Discovery to the unit */
39static int
40hci_role_discovery(int s, int argc, char **argv)
41{
42	ng_hci_role_discovery_cp	cp;
43	ng_hci_role_discovery_rp	rp;
44	int				n;
45
46	/* parse command parameters */
47	switch (argc) {
48	case 1:
49		/* connection handle */
50		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
51			return (USAGE);
52
53		cp.con_handle = (uint16_t) (n & 0x0fff);
54		cp.con_handle = htole16(cp.con_handle);
55		break;
56
57	default:
58		return (USAGE);
59	}
60
61	/* send request */
62	n = sizeof(rp);
63	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
64			NG_HCI_OCF_ROLE_DISCOVERY),
65			(char const *) &cp, sizeof(cp),
66			(char *) &rp, &n) == ERROR)
67		return (ERROR);
68
69	if (rp.status != 0x00) {
70		fprintf(stdout, "Status: %s [%#02x]\n",
71			hci_status2str(rp.status), rp.status);
72		return (FAILED);
73	}
74
75	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
76	fprintf(stdout, "Role: %s [%#x]\n",
77		(rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role);
78
79	return (OK);
80} /* hci_role_discovery */
81
82/* Send Swith Role to the unit */
83static int
84hci_switch_role(int s, int argc, char **argv)
85{
86	int			 n0;
87	char			 b[512];
88	ng_hci_switch_role_cp	 cp;
89	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
90
91	/* parse command parameters */
92	switch (argc) {
93	case 2:
94		/* bdaddr */
95		if (!bt_aton(argv[0], &cp.bdaddr)) {
96			struct hostent	*he = NULL;
97
98			if ((he = bt_gethostbyname(argv[0])) == NULL)
99				return (USAGE);
100
101			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
102		}
103
104		/* role */
105		if (sscanf(argv[1], "%d", &n0) != 1)
106			return (USAGE);
107
108		cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER;
109		break;
110
111	default:
112		return (USAGE);
113	}
114
115	/* send request and expect status response */
116	n0 = sizeof(b);
117	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
118			NG_HCI_OCF_SWITCH_ROLE),
119			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
120		return (ERROR);
121
122	if (*b != 0x00)
123		return (FAILED);
124
125	/* wait for event */
126again:
127	n0 = sizeof(b);
128	if (hci_recv(s, b, &n0) == ERROR)
129		return (ERROR);
130	if (n0 < sizeof(*e)) {
131		errno = EIO;
132		return (ERROR);
133	}
134
135	if (e->event == NG_HCI_EVENT_ROLE_CHANGE) {
136		ng_hci_role_change_ep	*ep = (ng_hci_role_change_ep *)(e + 1);
137
138		if (ep->status != 0x00) {
139			fprintf(stdout, "Status: %s [%#02x]\n",
140				hci_status2str(ep->status), ep->status);
141			return (FAILED);
142		}
143
144		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
145		fprintf(stdout, "Role: %s [%#x]\n",
146			(ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave",
147			ep->role);
148	} else
149		goto again;
150
151	return (OK);
152} /* hci_switch_role */
153
154/* Send Read_Link_Policy_Settings command to the unit */
155static int
156hci_read_link_policy_settings(int s, int argc, char **argv)
157{
158	ng_hci_read_link_policy_settings_cp	cp;
159	ng_hci_read_link_policy_settings_rp	rp;
160	int					n;
161
162	/* parse command parameters */
163	switch (argc) {
164	case 1:
165		/* connection handle */
166		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
167			return (USAGE);
168
169		cp.con_handle = (uint16_t) (n & 0x0fff);
170		cp.con_handle = htole16(cp.con_handle);
171		break;
172
173	default:
174		return (USAGE);
175	}
176
177	/* send request */
178	n = sizeof(rp);
179	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
180			NG_HCI_OCF_READ_LINK_POLICY_SETTINGS),
181			(char const *) &cp, sizeof(cp),
182			(char *) &rp, &n) == ERROR)
183		return (ERROR);
184
185	if (rp.status != 0x00) {
186		fprintf(stdout, "Status: %s [%#02x]\n",
187			hci_status2str(rp.status), rp.status);
188		return (FAILED);
189	}
190
191	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
192	fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings));
193
194	return (OK);
195} /* hci_read_link_policy_settings */
196
197/* Send Write_Link_Policy_Settings command to the unit */
198static int
199hci_write_link_policy_settings(int s, int argc, char **argv)
200{
201	ng_hci_write_link_policy_settings_cp	cp;
202	ng_hci_write_link_policy_settings_rp	rp;
203	int					n;
204
205	/* parse command parameters */
206	switch (argc) {
207	case 2:
208		/* connection handle */
209		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
210			return (USAGE);
211
212		cp.con_handle = (uint16_t) (n & 0x0fff);
213		cp.con_handle = htole16(cp.con_handle);
214
215		/* link policy settings */
216		if (sscanf(argv[1], "%x", &n) != 1)
217			return (USAGE);
218
219		cp.settings = (uint16_t) (n & 0x0ffff);
220		cp.settings = htole16(cp.settings);
221		break;
222
223	default:
224		return (USAGE);
225	}
226
227	/* send request */
228	n = sizeof(rp);
229	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
230			NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS),
231			(char const *) &cp, sizeof(cp),
232			(char *) &rp, &n) == ERROR)
233		return (ERROR);
234
235	if (rp.status != 0x00) {
236		fprintf(stdout, "Status: %s [%#02x]\n",
237			hci_status2str(rp.status), rp.status);
238		return (FAILED);
239	}
240
241	return (OK);
242} /* hci_write_link_policy_settings */
243
244struct hci_command	link_policy_commands[] = {
245{
246"role_discovery <connection_handle>",
247"\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \
248"which role the device is performing for a particular Connection Handle.\n" \
249"The connection handle must be a connection handle for an ACL connection.\n\n" \
250"\t<connection_handle> - dddd; connection handle",
251&hci_role_discovery
252},
253{
254"switch_role <bdaddr> <role>",
255"\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \
256"current role the device is performing for a particular connection with\n" \
257"another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\
258"for which connection the role switch is to be performed. The Role indicates\n"\
259"the requested new role that the local device performs. Note: the BD_ADDR\n" \
260"command parameter must specify a Bluetooth device for which a connection\n"
261"already exists.\n\n" \
262"\t<bdaddr> - xx:xx:xx:xx:xx:xx; device bdaddr\n" \
263"\t<role>   - dd; role; 0 - Master, 1 - Slave",
264&hci_switch_role
265},
266{
267"read_link_policy_settings <connection_handle>",
268"\nThis command will read the Link Policy setting for the specified connection\n"\
269"handle. The link policy settings parameter determines the behavior of the\n" \
270"local Link Manager when it receives a request from a remote device or it\n" \
271"determines itself to change the master-slave role or to enter the hold,\n" \
272"sniff, or park mode. The local Link Manager will automatically accept or\n" \
273"reject such a request from the remote device, and may even autonomously\n" \
274"request itself, depending on the value of the link policy settings parameter\n"\
275"for the corresponding connection handle. The connection handle must be a\n" \
276"connection handle for an ACL connection.\n\n" \
277"\t<connection_handle> - dddd; connection handle",
278&hci_read_link_policy_settings
279},
280{
281"write_link_policy_settings <connection_handle> <settings>",
282"\nThis command will write the Link Policy setting for the specified connection\n"\
283"handle. The link policy settings parameter determines the behavior of the\n" \
284"local Link Manager when it receives a request from a remote device or it\n" \
285"determines itself to change the master-slave role or to enter the hold,\n" \
286"sniff, or park mode. The local Link Manager will automatically accept or\n" \
287"reject such a request from the remote device, and may even autonomously\n" \
288"request itself, depending on the value of the link policy settings parameter\n"\
289"for the corresponding connection handle. The connection handle must be a\n" \
290"connection handle for an ACL connection. Multiple Link Manager policies may\n"\
291"be specified for the link policy settings parameter by performing a bitwise\n"\
292"OR operation of the different activity types.\n\n" \
293"\t<connection_handle> - dddd; connection handle\n" \
294"\t<settings>          - xxxx; settings\n" \
295"\t\t0x0000 - Disable All LM Modes (Default)\n" \
296"\t\t0x0001 - Enable Master Slave Switch\n" \
297"\t\t0x0002 - Enable Hold Mode\n" \
298"\t\t0x0004 - Enable Sniff Mode\n" \
299"\t\t0x0008 - Enable Park Mode\n",
300&hci_write_link_policy_settings
301},
302{
303NULL,
304}};
305
306