xref: /freebsd/usr.sbin/bluetooth/hccontrol/link_policy.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
11de7b4b8SPedro F. Giffuni /*-
2878ed226SJulian Elischer  * link_policy.c
3878ed226SJulian Elischer  *
4*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni  *
6878ed226SJulian Elischer  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7878ed226SJulian Elischer  * All rights reserved.
8878ed226SJulian Elischer  *
9878ed226SJulian Elischer  * Redistribution and use in source and binary forms, with or without
10878ed226SJulian Elischer  * modification, are permitted provided that the following conditions
11878ed226SJulian Elischer  * are met:
12878ed226SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
13878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
14878ed226SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
15878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
16878ed226SJulian Elischer  *    documentation and/or other materials provided with the distribution.
17878ed226SJulian Elischer  *
18878ed226SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19878ed226SJulian Elischer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20878ed226SJulian Elischer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21878ed226SJulian Elischer  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22878ed226SJulian Elischer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23878ed226SJulian Elischer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24878ed226SJulian Elischer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25878ed226SJulian Elischer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26878ed226SJulian Elischer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27878ed226SJulian Elischer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28878ed226SJulian Elischer  * SUCH DAMAGE.
29878ed226SJulian Elischer  *
300986ab12SMaksim Yevmenkin  * $Id: link_policy.c,v 1.3 2003/08/18 19:19:54 max Exp $
31878ed226SJulian Elischer  * $FreeBSD$
32878ed226SJulian Elischer  */
33878ed226SJulian Elischer 
348d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
350986ab12SMaksim Yevmenkin #include <bluetooth.h>
36878ed226SJulian Elischer #include <errno.h>
37878ed226SJulian Elischer #include <stdio.h>
380986ab12SMaksim Yevmenkin #include <string.h>
39878ed226SJulian Elischer #include "hccontrol.h"
40878ed226SJulian Elischer 
41878ed226SJulian Elischer /* Send Role Discovery to the unit */
42878ed226SJulian Elischer static int
43878ed226SJulian Elischer hci_role_discovery(int s, int argc, char **argv)
44878ed226SJulian Elischer {
45878ed226SJulian Elischer 	ng_hci_role_discovery_cp	cp;
46878ed226SJulian Elischer 	ng_hci_role_discovery_rp	rp;
47878ed226SJulian Elischer 	int				n;
48878ed226SJulian Elischer 
49878ed226SJulian Elischer 	/* parse command parameters */
50878ed226SJulian Elischer 	switch (argc) {
51878ed226SJulian Elischer 	case 1:
52878ed226SJulian Elischer 		/* connection handle */
53878ed226SJulian Elischer 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
54878ed226SJulian Elischer 			return (USAGE);
55878ed226SJulian Elischer 
56079a8a3eSMaksim Yevmenkin 		cp.con_handle = (uint16_t) (n & 0x0fff);
57878ed226SJulian Elischer 		cp.con_handle = htole16(cp.con_handle);
58878ed226SJulian Elischer 		break;
59878ed226SJulian Elischer 
60878ed226SJulian Elischer 	default:
61878ed226SJulian Elischer 		return (USAGE);
62878ed226SJulian Elischer 	}
63878ed226SJulian Elischer 
64878ed226SJulian Elischer 	/* send request */
65878ed226SJulian Elischer 	n = sizeof(rp);
66878ed226SJulian Elischer 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
67878ed226SJulian Elischer 			NG_HCI_OCF_ROLE_DISCOVERY),
68878ed226SJulian Elischer 			(char const *) &cp, sizeof(cp),
69878ed226SJulian Elischer 			(char *) &rp, &n) == ERROR)
70878ed226SJulian Elischer 		return (ERROR);
71878ed226SJulian Elischer 
72878ed226SJulian Elischer 	if (rp.status != 0x00) {
73878ed226SJulian Elischer 		fprintf(stdout, "Status: %s [%#02x]\n",
74878ed226SJulian Elischer 			hci_status2str(rp.status), rp.status);
75878ed226SJulian Elischer 		return (FAILED);
76878ed226SJulian Elischer 	}
77878ed226SJulian Elischer 
78878ed226SJulian Elischer 	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
79878ed226SJulian Elischer 	fprintf(stdout, "Role: %s [%#x]\n",
80878ed226SJulian Elischer 		(rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role);
81878ed226SJulian Elischer 
82878ed226SJulian Elischer 	return (OK);
83878ed226SJulian Elischer } /* hci_role_discovery */
84878ed226SJulian Elischer 
85878ed226SJulian Elischer /* Send Swith Role to the unit */
86878ed226SJulian Elischer static int
87878ed226SJulian Elischer hci_switch_role(int s, int argc, char **argv)
88878ed226SJulian Elischer {
890986ab12SMaksim Yevmenkin 	int			 n0;
90878ed226SJulian Elischer 	char			 b[512];
91878ed226SJulian Elischer 	ng_hci_switch_role_cp	 cp;
92878ed226SJulian Elischer 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
93878ed226SJulian Elischer 
94878ed226SJulian Elischer 	/* parse command parameters */
95878ed226SJulian Elischer 	switch (argc) {
96878ed226SJulian Elischer 	case 2:
97878ed226SJulian Elischer 		/* bdaddr */
980986ab12SMaksim Yevmenkin 		if (!bt_aton(argv[0], &cp.bdaddr)) {
990986ab12SMaksim Yevmenkin 			struct hostent	*he = NULL;
1000986ab12SMaksim Yevmenkin 
1010986ab12SMaksim Yevmenkin 			if ((he = bt_gethostbyname(argv[0])) == NULL)
102878ed226SJulian Elischer 				return (USAGE);
103878ed226SJulian Elischer 
1040986ab12SMaksim Yevmenkin 			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
1050986ab12SMaksim Yevmenkin 		}
106878ed226SJulian Elischer 
107878ed226SJulian Elischer 		/* role */
108878ed226SJulian Elischer 		if (sscanf(argv[1], "%d", &n0) != 1)
109878ed226SJulian Elischer 			return (USAGE);
110878ed226SJulian Elischer 
111878ed226SJulian Elischer 		cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER;
112878ed226SJulian Elischer 		break;
113878ed226SJulian Elischer 
114878ed226SJulian Elischer 	default:
115878ed226SJulian Elischer 		return (USAGE);
116878ed226SJulian Elischer 	}
117878ed226SJulian Elischer 
118878ed226SJulian Elischer 	/* send request and expect status response */
119878ed226SJulian Elischer 	n0 = sizeof(b);
120878ed226SJulian Elischer 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
121878ed226SJulian Elischer 			NG_HCI_OCF_SWITCH_ROLE),
122878ed226SJulian Elischer 			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
123878ed226SJulian Elischer 		return (ERROR);
124878ed226SJulian Elischer 
125878ed226SJulian Elischer 	if (*b != 0x00)
126878ed226SJulian Elischer 		return (FAILED);
127878ed226SJulian Elischer 
128878ed226SJulian Elischer 	/* wait for event */
129878ed226SJulian Elischer again:
130878ed226SJulian Elischer 	n0 = sizeof(b);
131878ed226SJulian Elischer 	if (hci_recv(s, b, &n0) == ERROR)
132878ed226SJulian Elischer 		return (ERROR);
133878ed226SJulian Elischer 	if (n0 < sizeof(*e)) {
134878ed226SJulian Elischer 		errno = EIO;
135878ed226SJulian Elischer 		return (ERROR);
136878ed226SJulian Elischer 	}
137878ed226SJulian Elischer 
138878ed226SJulian Elischer 	if (e->event == NG_HCI_EVENT_ROLE_CHANGE) {
139878ed226SJulian Elischer 		ng_hci_role_change_ep	*ep = (ng_hci_role_change_ep *)(e + 1);
140878ed226SJulian Elischer 
141878ed226SJulian Elischer 		if (ep->status != 0x00) {
142878ed226SJulian Elischer 			fprintf(stdout, "Status: %s [%#02x]\n",
143878ed226SJulian Elischer 				hci_status2str(ep->status), ep->status);
144878ed226SJulian Elischer 			return (FAILED);
145878ed226SJulian Elischer 		}
146878ed226SJulian Elischer 
1470986ab12SMaksim Yevmenkin 		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
148878ed226SJulian Elischer 		fprintf(stdout, "Role: %s [%#x]\n",
149878ed226SJulian Elischer 			(ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave",
150878ed226SJulian Elischer 			ep->role);
151878ed226SJulian Elischer 	} else
152878ed226SJulian Elischer 		goto again;
153878ed226SJulian Elischer 
154878ed226SJulian Elischer 	return (OK);
155878ed226SJulian Elischer } /* hci_switch_role */
156878ed226SJulian Elischer 
157878ed226SJulian Elischer /* Send Read_Link_Policy_Settings command to the unit */
158878ed226SJulian Elischer static int
159878ed226SJulian Elischer hci_read_link_policy_settings(int s, int argc, char **argv)
160878ed226SJulian Elischer {
161878ed226SJulian Elischer 	ng_hci_read_link_policy_settings_cp	cp;
162878ed226SJulian Elischer 	ng_hci_read_link_policy_settings_rp	rp;
163878ed226SJulian Elischer 	int					n;
164878ed226SJulian Elischer 
165878ed226SJulian Elischer 	/* parse command parameters */
166878ed226SJulian Elischer 	switch (argc) {
167878ed226SJulian Elischer 	case 1:
168878ed226SJulian Elischer 		/* connection handle */
169878ed226SJulian Elischer 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
170878ed226SJulian Elischer 			return (USAGE);
171878ed226SJulian Elischer 
172079a8a3eSMaksim Yevmenkin 		cp.con_handle = (uint16_t) (n & 0x0fff);
173878ed226SJulian Elischer 		cp.con_handle = htole16(cp.con_handle);
174878ed226SJulian Elischer 		break;
175878ed226SJulian Elischer 
176878ed226SJulian Elischer 	default:
177878ed226SJulian Elischer 		return (USAGE);
178878ed226SJulian Elischer 	}
179878ed226SJulian Elischer 
180878ed226SJulian Elischer 	/* send request */
181878ed226SJulian Elischer 	n = sizeof(rp);
182878ed226SJulian Elischer 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
183878ed226SJulian Elischer 			NG_HCI_OCF_READ_LINK_POLICY_SETTINGS),
184878ed226SJulian Elischer 			(char const *) &cp, sizeof(cp),
185878ed226SJulian Elischer 			(char *) &rp, &n) == ERROR)
186878ed226SJulian Elischer 		return (ERROR);
187878ed226SJulian Elischer 
188878ed226SJulian Elischer 	if (rp.status != 0x00) {
189878ed226SJulian Elischer 		fprintf(stdout, "Status: %s [%#02x]\n",
190878ed226SJulian Elischer 			hci_status2str(rp.status), rp.status);
191878ed226SJulian Elischer 		return (FAILED);
192878ed226SJulian Elischer 	}
193878ed226SJulian Elischer 
194878ed226SJulian Elischer 	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
195878ed226SJulian Elischer 	fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings));
196878ed226SJulian Elischer 
197878ed226SJulian Elischer 	return (OK);
198878ed226SJulian Elischer } /* hci_read_link_policy_settings */
199878ed226SJulian Elischer 
200878ed226SJulian Elischer /* Send Write_Link_Policy_Settings command to the unit */
201878ed226SJulian Elischer static int
202878ed226SJulian Elischer hci_write_link_policy_settings(int s, int argc, char **argv)
203878ed226SJulian Elischer {
204878ed226SJulian Elischer 	ng_hci_write_link_policy_settings_cp	cp;
205878ed226SJulian Elischer 	ng_hci_write_link_policy_settings_rp	rp;
206878ed226SJulian Elischer 	int					n;
207878ed226SJulian Elischer 
208878ed226SJulian Elischer 	/* parse command parameters */
209878ed226SJulian Elischer 	switch (argc) {
210878ed226SJulian Elischer 	case 2:
211878ed226SJulian Elischer 		/* connection handle */
212878ed226SJulian Elischer 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
213878ed226SJulian Elischer 			return (USAGE);
214878ed226SJulian Elischer 
215079a8a3eSMaksim Yevmenkin 		cp.con_handle = (uint16_t) (n & 0x0fff);
216878ed226SJulian Elischer 		cp.con_handle = htole16(cp.con_handle);
217878ed226SJulian Elischer 
218878ed226SJulian Elischer 		/* link policy settings */
219878ed226SJulian Elischer 		if (sscanf(argv[1], "%x", &n) != 1)
220878ed226SJulian Elischer 			return (USAGE);
221878ed226SJulian Elischer 
222079a8a3eSMaksim Yevmenkin 		cp.settings = (uint16_t) (n & 0x0ffff);
223878ed226SJulian Elischer 		cp.settings = htole16(cp.settings);
224878ed226SJulian Elischer 		break;
225878ed226SJulian Elischer 
226878ed226SJulian Elischer 	default:
227878ed226SJulian Elischer 		return (USAGE);
228878ed226SJulian Elischer 	}
229878ed226SJulian Elischer 
230878ed226SJulian Elischer 	/* send request */
231878ed226SJulian Elischer 	n = sizeof(rp);
232878ed226SJulian Elischer 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
233878ed226SJulian Elischer 			NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS),
234878ed226SJulian Elischer 			(char const *) &cp, sizeof(cp),
235878ed226SJulian Elischer 			(char *) &rp, &n) == ERROR)
236878ed226SJulian Elischer 		return (ERROR);
237878ed226SJulian Elischer 
238878ed226SJulian Elischer 	if (rp.status != 0x00) {
239878ed226SJulian Elischer 		fprintf(stdout, "Status: %s [%#02x]\n",
240878ed226SJulian Elischer 			hci_status2str(rp.status), rp.status);
241878ed226SJulian Elischer 		return (FAILED);
242878ed226SJulian Elischer 	}
243878ed226SJulian Elischer 
244878ed226SJulian Elischer 	return (OK);
245878ed226SJulian Elischer } /* hci_write_link_policy_settings */
246878ed226SJulian Elischer 
247878ed226SJulian Elischer struct hci_command	link_policy_commands[] = {
248878ed226SJulian Elischer {
2490eff7205SMaksim Yevmenkin "role_discovery <connection_handle>",
250878ed226SJulian Elischer "\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \
251878ed226SJulian Elischer "which role the device is performing for a particular Connection Handle.\n" \
252878ed226SJulian Elischer "The connection handle must be a connection handle for an ACL connection.\n\n" \
253878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle",
254878ed226SJulian Elischer &hci_role_discovery
255878ed226SJulian Elischer },
256878ed226SJulian Elischer {
2572aa65cf7SMaksim Yevmenkin "switch_role <BD_ADDR> <role>",
258878ed226SJulian Elischer "\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \
259878ed226SJulian Elischer "current role the device is performing for a particular connection with\n" \
260878ed226SJulian Elischer "another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\
261878ed226SJulian Elischer "for which connection the role switch is to be performed. The Role indicates\n"\
262878ed226SJulian Elischer "the requested new role that the local device performs. Note: the BD_ADDR\n" \
263878ed226SJulian Elischer "command parameter must specify a Bluetooth device for which a connection\n"
264878ed226SJulian Elischer "already exists.\n\n" \
2652aa65cf7SMaksim Yevmenkin "\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \
266878ed226SJulian Elischer "\t<role>    - dd; role; 0 - Master, 1 - Slave",
267878ed226SJulian Elischer &hci_switch_role
268878ed226SJulian Elischer },
269878ed226SJulian Elischer {
270878ed226SJulian Elischer "read_link_policy_settings <connection_handle>",
271878ed226SJulian Elischer "\nThis command will read the Link Policy setting for the specified connection\n"\
272878ed226SJulian Elischer "handle. The link policy settings parameter determines the behavior of the\n" \
273878ed226SJulian Elischer "local Link Manager when it receives a request from a remote device or it\n" \
274878ed226SJulian Elischer "determines itself to change the master-slave role or to enter the hold,\n" \
275878ed226SJulian Elischer "sniff, or park mode. The local Link Manager will automatically accept or\n" \
276878ed226SJulian Elischer "reject such a request from the remote device, and may even autonomously\n" \
277878ed226SJulian Elischer "request itself, depending on the value of the link policy settings parameter\n"\
278878ed226SJulian Elischer "for the corresponding connection handle. The connection handle must be a\n" \
279878ed226SJulian Elischer "connection handle for an ACL connection.\n\n" \
280878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle",
281878ed226SJulian Elischer &hci_read_link_policy_settings
282878ed226SJulian Elischer },
283878ed226SJulian Elischer {
284878ed226SJulian Elischer "write_link_policy_settings <connection_handle> <settings>",
285878ed226SJulian Elischer "\nThis command will write the Link Policy setting for the specified connection\n"\
286878ed226SJulian Elischer "handle. The link policy settings parameter determines the behavior of the\n" \
287878ed226SJulian Elischer "local Link Manager when it receives a request from a remote device or it\n" \
288878ed226SJulian Elischer "determines itself to change the master-slave role or to enter the hold,\n" \
289878ed226SJulian Elischer "sniff, or park mode. The local Link Manager will automatically accept or\n" \
290878ed226SJulian Elischer "reject such a request from the remote device, and may even autonomously\n" \
291878ed226SJulian Elischer "request itself, depending on the value of the link policy settings parameter\n"\
292878ed226SJulian Elischer "for the corresponding connection handle. The connection handle must be a\n" \
293878ed226SJulian Elischer "connection handle for an ACL connection. Multiple Link Manager policies may\n"\
294878ed226SJulian Elischer "be specified for the link policy settings parameter by performing a bitwise\n"\
295878ed226SJulian Elischer "OR operation of the different activity types.\n\n" \
296878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle\n" \
297878ed226SJulian Elischer "\t<settings>          - xxxx; settings\n" \
298878ed226SJulian Elischer "\t\t0x0000 - Disable All LM Modes (Default)\n" \
299878ed226SJulian Elischer "\t\t0x0001 - Enable Master Slave Switch\n" \
300878ed226SJulian Elischer "\t\t0x0002 - Enable Hold Mode\n" \
301878ed226SJulian Elischer "\t\t0x0004 - Enable Sniff Mode\n" \
302878ed226SJulian Elischer "\t\t0x0008 - Enable Park Mode\n",
303878ed226SJulian Elischer &hci_write_link_policy_settings
304878ed226SJulian Elischer },
305878ed226SJulian Elischer {
306878ed226SJulian Elischer NULL,
307878ed226SJulian Elischer }};
308878ed226SJulian Elischer 
309