1107120Sjulian/*
2107120Sjulian * link_policy.c
3107120Sjulian *
4107120Sjulian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5107120Sjulian * All rights reserved.
6107120Sjulian *
7107120Sjulian * Redistribution and use in source and binary forms, with or without
8107120Sjulian * modification, are permitted provided that the following conditions
9107120Sjulian * are met:
10107120Sjulian * 1. Redistributions of source code must retain the above copyright
11107120Sjulian *    notice, this list of conditions and the following disclaimer.
12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright
13107120Sjulian *    notice, this list of conditions and the following disclaimer in the
14107120Sjulian *    documentation and/or other materials provided with the distribution.
15107120Sjulian *
16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26107120Sjulian * SUCH DAMAGE.
27107120Sjulian *
28121054Semax * $Id: link_policy.c,v 1.3 2003/08/18 19:19:54 max Exp $
29107120Sjulian * $FreeBSD$
30107120Sjulian */
31107120Sjulian
32121054Semax#include <bluetooth.h>
33107120Sjulian#include <errno.h>
34107120Sjulian#include <stdio.h>
35121054Semax#include <string.h>
36107120Sjulian#include "hccontrol.h"
37107120Sjulian
38107120Sjulian/* Send Role Discovery to the unit */
39107120Sjulianstatic int
40107120Sjulianhci_role_discovery(int s, int argc, char **argv)
41107120Sjulian{
42107120Sjulian	ng_hci_role_discovery_cp	cp;
43107120Sjulian	ng_hci_role_discovery_rp	rp;
44107120Sjulian	int				n;
45107120Sjulian
46107120Sjulian	/* parse command parameters */
47107120Sjulian	switch (argc) {
48107120Sjulian	case 1:
49107120Sjulian		/* connection handle */
50107120Sjulian		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
51107120Sjulian			return (USAGE);
52107120Sjulian
53128079Semax		cp.con_handle = (uint16_t) (n & 0x0fff);
54107120Sjulian		cp.con_handle = htole16(cp.con_handle);
55107120Sjulian		break;
56107120Sjulian
57107120Sjulian	default:
58107120Sjulian		return (USAGE);
59107120Sjulian	}
60107120Sjulian
61107120Sjulian	/* send request */
62107120Sjulian	n = sizeof(rp);
63107120Sjulian	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
64107120Sjulian			NG_HCI_OCF_ROLE_DISCOVERY),
65107120Sjulian			(char const *) &cp, sizeof(cp),
66107120Sjulian			(char *) &rp, &n) == ERROR)
67107120Sjulian		return (ERROR);
68107120Sjulian
69107120Sjulian	if (rp.status != 0x00) {
70107120Sjulian		fprintf(stdout, "Status: %s [%#02x]\n",
71107120Sjulian			hci_status2str(rp.status), rp.status);
72107120Sjulian		return (FAILED);
73107120Sjulian	}
74107120Sjulian
75107120Sjulian	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
76107120Sjulian	fprintf(stdout, "Role: %s [%#x]\n",
77107120Sjulian		(rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role);
78107120Sjulian
79107120Sjulian	return (OK);
80107120Sjulian} /* hci_role_discovery */
81107120Sjulian
82107120Sjulian/* Send Swith Role to the unit */
83107120Sjulianstatic int
84107120Sjulianhci_switch_role(int s, int argc, char **argv)
85107120Sjulian{
86121054Semax	int			 n0;
87107120Sjulian	char			 b[512];
88107120Sjulian	ng_hci_switch_role_cp	 cp;
89107120Sjulian	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
90107120Sjulian
91107120Sjulian	/* parse command parameters */
92107120Sjulian	switch (argc) {
93107120Sjulian	case 2:
94107120Sjulian		/* bdaddr */
95121054Semax		if (!bt_aton(argv[0], &cp.bdaddr)) {
96121054Semax			struct hostent	*he = NULL;
97107120Sjulian
98121054Semax			if ((he = bt_gethostbyname(argv[0])) == NULL)
99121054Semax				return (USAGE);
100107120Sjulian
101121054Semax			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
102121054Semax		}
103121054Semax
104107120Sjulian		/* role */
105107120Sjulian		if (sscanf(argv[1], "%d", &n0) != 1)
106107120Sjulian			return (USAGE);
107107120Sjulian
108107120Sjulian		cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER;
109107120Sjulian		break;
110107120Sjulian
111107120Sjulian	default:
112107120Sjulian		return (USAGE);
113107120Sjulian	}
114107120Sjulian
115107120Sjulian	/* send request and expect status response */
116107120Sjulian	n0 = sizeof(b);
117107120Sjulian	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
118107120Sjulian			NG_HCI_OCF_SWITCH_ROLE),
119107120Sjulian			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
120107120Sjulian		return (ERROR);
121107120Sjulian
122107120Sjulian	if (*b != 0x00)
123107120Sjulian		return (FAILED);
124107120Sjulian
125107120Sjulian	/* wait for event */
126107120Sjulianagain:
127107120Sjulian	n0 = sizeof(b);
128107120Sjulian	if (hci_recv(s, b, &n0) == ERROR)
129107120Sjulian		return (ERROR);
130107120Sjulian	if (n0 < sizeof(*e)) {
131107120Sjulian		errno = EIO;
132107120Sjulian		return (ERROR);
133107120Sjulian	}
134107120Sjulian
135107120Sjulian	if (e->event == NG_HCI_EVENT_ROLE_CHANGE) {
136107120Sjulian		ng_hci_role_change_ep	*ep = (ng_hci_role_change_ep *)(e + 1);
137107120Sjulian
138107120Sjulian		if (ep->status != 0x00) {
139107120Sjulian			fprintf(stdout, "Status: %s [%#02x]\n",
140107120Sjulian				hci_status2str(ep->status), ep->status);
141107120Sjulian			return (FAILED);
142107120Sjulian		}
143107120Sjulian
144121054Semax		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
145107120Sjulian		fprintf(stdout, "Role: %s [%#x]\n",
146107120Sjulian			(ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave",
147107120Sjulian			ep->role);
148107120Sjulian	} else
149107120Sjulian		goto again;
150107120Sjulian
151107120Sjulian	return (OK);
152107120Sjulian} /* hci_switch_role */
153107120Sjulian
154107120Sjulian/* Send Read_Link_Policy_Settings command to the unit */
155107120Sjulianstatic int
156107120Sjulianhci_read_link_policy_settings(int s, int argc, char **argv)
157107120Sjulian{
158107120Sjulian	ng_hci_read_link_policy_settings_cp	cp;
159107120Sjulian	ng_hci_read_link_policy_settings_rp	rp;
160107120Sjulian	int					n;
161107120Sjulian
162107120Sjulian	/* parse command parameters */
163107120Sjulian	switch (argc) {
164107120Sjulian	case 1:
165107120Sjulian		/* connection handle */
166107120Sjulian		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
167107120Sjulian			return (USAGE);
168107120Sjulian
169128079Semax		cp.con_handle = (uint16_t) (n & 0x0fff);
170107120Sjulian		cp.con_handle = htole16(cp.con_handle);
171107120Sjulian		break;
172107120Sjulian
173107120Sjulian	default:
174107120Sjulian		return (USAGE);
175107120Sjulian	}
176107120Sjulian
177107120Sjulian	/* send request */
178107120Sjulian	n = sizeof(rp);
179107120Sjulian	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
180107120Sjulian			NG_HCI_OCF_READ_LINK_POLICY_SETTINGS),
181107120Sjulian			(char const *) &cp, sizeof(cp),
182107120Sjulian			(char *) &rp, &n) == ERROR)
183107120Sjulian		return (ERROR);
184107120Sjulian
185107120Sjulian	if (rp.status != 0x00) {
186107120Sjulian		fprintf(stdout, "Status: %s [%#02x]\n",
187107120Sjulian			hci_status2str(rp.status), rp.status);
188107120Sjulian		return (FAILED);
189107120Sjulian	}
190107120Sjulian
191107120Sjulian	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
192107120Sjulian	fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings));
193107120Sjulian
194107120Sjulian	return (OK);
195107120Sjulian} /* hci_read_link_policy_settings */
196107120Sjulian
197107120Sjulian/* Send Write_Link_Policy_Settings command to the unit */
198107120Sjulianstatic int
199107120Sjulianhci_write_link_policy_settings(int s, int argc, char **argv)
200107120Sjulian{
201107120Sjulian	ng_hci_write_link_policy_settings_cp	cp;
202107120Sjulian	ng_hci_write_link_policy_settings_rp	rp;
203107120Sjulian	int					n;
204107120Sjulian
205107120Sjulian	/* parse command parameters */
206107120Sjulian	switch (argc) {
207107120Sjulian	case 2:
208107120Sjulian		/* connection handle */
209107120Sjulian		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
210107120Sjulian			return (USAGE);
211107120Sjulian
212128079Semax		cp.con_handle = (uint16_t) (n & 0x0fff);
213107120Sjulian		cp.con_handle = htole16(cp.con_handle);
214107120Sjulian
215107120Sjulian		/* link policy settings */
216107120Sjulian		if (sscanf(argv[1], "%x", &n) != 1)
217107120Sjulian			return (USAGE);
218107120Sjulian
219128079Semax		cp.settings = (uint16_t) (n & 0x0ffff);
220107120Sjulian		cp.settings = htole16(cp.settings);
221107120Sjulian		break;
222107120Sjulian
223107120Sjulian	default:
224107120Sjulian		return (USAGE);
225107120Sjulian	}
226107120Sjulian
227107120Sjulian	/* send request */
228107120Sjulian	n = sizeof(rp);
229107120Sjulian	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
230107120Sjulian			NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS),
231107120Sjulian			(char const *) &cp, sizeof(cp),
232107120Sjulian			(char *) &rp, &n) == ERROR)
233107120Sjulian		return (ERROR);
234107120Sjulian
235107120Sjulian	if (rp.status != 0x00) {
236107120Sjulian		fprintf(stdout, "Status: %s [%#02x]\n",
237107120Sjulian			hci_status2str(rp.status), rp.status);
238107120Sjulian		return (FAILED);
239107120Sjulian	}
240107120Sjulian
241107120Sjulian	return (OK);
242107120Sjulian} /* hci_write_link_policy_settings */
243107120Sjulian
244107120Sjulianstruct hci_command	link_policy_commands[] = {
245107120Sjulian{
246122451Semax"role_discovery <connection_handle>",
247107120Sjulian"\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \
248107120Sjulian"which role the device is performing for a particular Connection Handle.\n" \
249107120Sjulian"The connection handle must be a connection handle for an ACL connection.\n\n" \
250107120Sjulian"\t<connection_handle> - dddd; connection handle",
251107120Sjulian&hci_role_discovery
252107120Sjulian},
253107120Sjulian{
254133178Semax"switch_role <BD_ADDR> <role>",
255107120Sjulian"\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \
256107120Sjulian"current role the device is performing for a particular connection with\n" \
257107120Sjulian"another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\
258107120Sjulian"for which connection the role switch is to be performed. The Role indicates\n"\
259107120Sjulian"the requested new role that the local device performs. Note: the BD_ADDR\n" \
260107120Sjulian"command parameter must specify a Bluetooth device for which a connection\n"
261107120Sjulian"already exists.\n\n" \
262133178Semax"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \
263133178Semax"\t<role>    - dd; role; 0 - Master, 1 - Slave",
264107120Sjulian&hci_switch_role
265107120Sjulian},
266107120Sjulian{
267107120Sjulian"read_link_policy_settings <connection_handle>",
268107120Sjulian"\nThis command will read the Link Policy setting for the specified connection\n"\
269107120Sjulian"handle. The link policy settings parameter determines the behavior of the\n" \
270107120Sjulian"local Link Manager when it receives a request from a remote device or it\n" \
271107120Sjulian"determines itself to change the master-slave role or to enter the hold,\n" \
272107120Sjulian"sniff, or park mode. The local Link Manager will automatically accept or\n" \
273107120Sjulian"reject such a request from the remote device, and may even autonomously\n" \
274107120Sjulian"request itself, depending on the value of the link policy settings parameter\n"\
275107120Sjulian"for the corresponding connection handle. The connection handle must be a\n" \
276107120Sjulian"connection handle for an ACL connection.\n\n" \
277107120Sjulian"\t<connection_handle> - dddd; connection handle",
278107120Sjulian&hci_read_link_policy_settings
279107120Sjulian},
280107120Sjulian{
281107120Sjulian"write_link_policy_settings <connection_handle> <settings>",
282107120Sjulian"\nThis command will write the Link Policy setting for the specified connection\n"\
283107120Sjulian"handle. The link policy settings parameter determines the behavior of the\n" \
284107120Sjulian"local Link Manager when it receives a request from a remote device or it\n" \
285107120Sjulian"determines itself to change the master-slave role or to enter the hold,\n" \
286107120Sjulian"sniff, or park mode. The local Link Manager will automatically accept or\n" \
287107120Sjulian"reject such a request from the remote device, and may even autonomously\n" \
288107120Sjulian"request itself, depending on the value of the link policy settings parameter\n"\
289107120Sjulian"for the corresponding connection handle. The connection handle must be a\n" \
290107120Sjulian"connection handle for an ACL connection. Multiple Link Manager policies may\n"\
291107120Sjulian"be specified for the link policy settings parameter by performing a bitwise\n"\
292107120Sjulian"OR operation of the different activity types.\n\n" \
293107120Sjulian"\t<connection_handle> - dddd; connection handle\n" \
294107120Sjulian"\t<settings>          - xxxx; settings\n" \
295107120Sjulian"\t\t0x0000 - Disable All LM Modes (Default)\n" \
296107120Sjulian"\t\t0x0001 - Enable Master Slave Switch\n" \
297107120Sjulian"\t\t0x0002 - Enable Hold Mode\n" \
298107120Sjulian"\t\t0x0004 - Enable Sniff Mode\n" \
299107120Sjulian"\t\t0x0008 - Enable Park Mode\n",
300107120Sjulian&hci_write_link_policy_settings
301107120Sjulian},
302107120Sjulian{
303107120SjulianNULL,
304107120Sjulian}};
305107120Sjulian
306