xref: /freebsd/usr.sbin/bluetooth/hccontrol/link_policy.c (revision 42b388439bd3795e09258c57a74ce9eec3651c7b)
11de7b4b8SPedro F. Giffuni /*-
2878ed226SJulian Elischer  * link_policy.c
3878ed226SJulian Elischer  *
44d846d26SWarner 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  */
32878ed226SJulian Elischer 
338d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
340986ab12SMaksim Yevmenkin #include <bluetooth.h>
35878ed226SJulian Elischer #include <errno.h>
36878ed226SJulian Elischer #include <stdio.h>
370986ab12SMaksim Yevmenkin #include <string.h>
38878ed226SJulian Elischer #include "hccontrol.h"
39878ed226SJulian Elischer 
40878ed226SJulian Elischer /* Send Role Discovery to the unit */
41878ed226SJulian Elischer static int
hci_role_discovery(int s,int argc,char ** argv)42878ed226SJulian Elischer hci_role_discovery(int s, int argc, char **argv)
43878ed226SJulian Elischer {
44878ed226SJulian Elischer 	ng_hci_role_discovery_cp	cp;
45878ed226SJulian Elischer 	ng_hci_role_discovery_rp	rp;
46878ed226SJulian Elischer 	int				n;
47878ed226SJulian Elischer 
48878ed226SJulian Elischer 	/* parse command parameters */
49878ed226SJulian Elischer 	switch (argc) {
50878ed226SJulian Elischer 	case 1:
51878ed226SJulian Elischer 		/* connection handle */
52878ed226SJulian Elischer 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
53878ed226SJulian Elischer 			return (USAGE);
54878ed226SJulian Elischer 
55079a8a3eSMaksim Yevmenkin 		cp.con_handle = (uint16_t) (n & 0x0fff);
56878ed226SJulian Elischer 		cp.con_handle = htole16(cp.con_handle);
57878ed226SJulian Elischer 		break;
58878ed226SJulian Elischer 
59878ed226SJulian Elischer 	default:
60878ed226SJulian Elischer 		return (USAGE);
61878ed226SJulian Elischer 	}
62878ed226SJulian Elischer 
63878ed226SJulian Elischer 	/* send request */
64878ed226SJulian Elischer 	n = sizeof(rp);
65878ed226SJulian Elischer 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
66878ed226SJulian Elischer 			NG_HCI_OCF_ROLE_DISCOVERY),
67878ed226SJulian Elischer 			(char const *) &cp, sizeof(cp),
68878ed226SJulian Elischer 			(char *) &rp, &n) == ERROR)
69878ed226SJulian Elischer 		return (ERROR);
70878ed226SJulian Elischer 
71878ed226SJulian Elischer 	if (rp.status != 0x00) {
72878ed226SJulian Elischer 		fprintf(stdout, "Status: %s [%#02x]\n",
73878ed226SJulian Elischer 			hci_status2str(rp.status), rp.status);
74878ed226SJulian Elischer 		return (FAILED);
75878ed226SJulian Elischer 	}
76878ed226SJulian Elischer 
77878ed226SJulian Elischer 	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
78878ed226SJulian Elischer 	fprintf(stdout, "Role: %s [%#x]\n",
79878ed226SJulian Elischer 		(rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role);
80878ed226SJulian Elischer 
81878ed226SJulian Elischer 	return (OK);
82878ed226SJulian Elischer } /* hci_role_discovery */
83878ed226SJulian Elischer 
84*66ebda7aSElyes Haouas /* Send Switch Role to the unit */
85878ed226SJulian Elischer static int
hci_switch_role(int s,int argc,char ** argv)86878ed226SJulian Elischer hci_switch_role(int s, int argc, char **argv)
87878ed226SJulian Elischer {
880986ab12SMaksim Yevmenkin 	int			 n0;
89878ed226SJulian Elischer 	char			 b[512];
90878ed226SJulian Elischer 	ng_hci_switch_role_cp	 cp;
91878ed226SJulian Elischer 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
92878ed226SJulian Elischer 
93878ed226SJulian Elischer 	/* parse command parameters */
94878ed226SJulian Elischer 	switch (argc) {
95878ed226SJulian Elischer 	case 2:
96878ed226SJulian Elischer 		/* bdaddr */
970986ab12SMaksim Yevmenkin 		if (!bt_aton(argv[0], &cp.bdaddr)) {
980986ab12SMaksim Yevmenkin 			struct hostent	*he = NULL;
990986ab12SMaksim Yevmenkin 
1000986ab12SMaksim Yevmenkin 			if ((he = bt_gethostbyname(argv[0])) == NULL)
101878ed226SJulian Elischer 				return (USAGE);
102878ed226SJulian Elischer 
1030986ab12SMaksim Yevmenkin 			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
1040986ab12SMaksim Yevmenkin 		}
105878ed226SJulian Elischer 
106878ed226SJulian Elischer 		/* role */
107878ed226SJulian Elischer 		if (sscanf(argv[1], "%d", &n0) != 1)
108878ed226SJulian Elischer 			return (USAGE);
109878ed226SJulian Elischer 
110878ed226SJulian Elischer 		cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER;
111878ed226SJulian Elischer 		break;
112878ed226SJulian Elischer 
113878ed226SJulian Elischer 	default:
114878ed226SJulian Elischer 		return (USAGE);
115878ed226SJulian Elischer 	}
116878ed226SJulian Elischer 
117878ed226SJulian Elischer 	/* send request and expect status response */
118878ed226SJulian Elischer 	n0 = sizeof(b);
119878ed226SJulian Elischer 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
120878ed226SJulian Elischer 			NG_HCI_OCF_SWITCH_ROLE),
121878ed226SJulian Elischer 			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
122878ed226SJulian Elischer 		return (ERROR);
123878ed226SJulian Elischer 
124878ed226SJulian Elischer 	if (*b != 0x00)
125878ed226SJulian Elischer 		return (FAILED);
126878ed226SJulian Elischer 
127878ed226SJulian Elischer 	/* wait for event */
128878ed226SJulian Elischer again:
129878ed226SJulian Elischer 	n0 = sizeof(b);
130878ed226SJulian Elischer 	if (hci_recv(s, b, &n0) == ERROR)
131878ed226SJulian Elischer 		return (ERROR);
132878ed226SJulian Elischer 	if (n0 < sizeof(*e)) {
133878ed226SJulian Elischer 		errno = EIO;
134878ed226SJulian Elischer 		return (ERROR);
135878ed226SJulian Elischer 	}
136878ed226SJulian Elischer 
137878ed226SJulian Elischer 	if (e->event == NG_HCI_EVENT_ROLE_CHANGE) {
138878ed226SJulian Elischer 		ng_hci_role_change_ep	*ep = (ng_hci_role_change_ep *)(e + 1);
139878ed226SJulian Elischer 
140878ed226SJulian Elischer 		if (ep->status != 0x00) {
141878ed226SJulian Elischer 			fprintf(stdout, "Status: %s [%#02x]\n",
142878ed226SJulian Elischer 				hci_status2str(ep->status), ep->status);
143878ed226SJulian Elischer 			return (FAILED);
144878ed226SJulian Elischer 		}
145878ed226SJulian Elischer 
1460986ab12SMaksim Yevmenkin 		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
147878ed226SJulian Elischer 		fprintf(stdout, "Role: %s [%#x]\n",
148878ed226SJulian Elischer 			(ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave",
149878ed226SJulian Elischer 			ep->role);
150878ed226SJulian Elischer 	} else
151878ed226SJulian Elischer 		goto again;
152878ed226SJulian Elischer 
153878ed226SJulian Elischer 	return (OK);
154878ed226SJulian Elischer } /* hci_switch_role */
155878ed226SJulian Elischer 
156878ed226SJulian Elischer /* Send Read_Link_Policy_Settings command to the unit */
157878ed226SJulian Elischer static int
hci_read_link_policy_settings(int s,int argc,char ** argv)158878ed226SJulian Elischer hci_read_link_policy_settings(int s, int argc, char **argv)
159878ed226SJulian Elischer {
160878ed226SJulian Elischer 	ng_hci_read_link_policy_settings_cp	cp;
161878ed226SJulian Elischer 	ng_hci_read_link_policy_settings_rp	rp;
162878ed226SJulian Elischer 	int					n;
163878ed226SJulian Elischer 
164878ed226SJulian Elischer 	/* parse command parameters */
165878ed226SJulian Elischer 	switch (argc) {
166878ed226SJulian Elischer 	case 1:
167878ed226SJulian Elischer 		/* connection handle */
168878ed226SJulian Elischer 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
169878ed226SJulian Elischer 			return (USAGE);
170878ed226SJulian Elischer 
171079a8a3eSMaksim Yevmenkin 		cp.con_handle = (uint16_t) (n & 0x0fff);
172878ed226SJulian Elischer 		cp.con_handle = htole16(cp.con_handle);
173878ed226SJulian Elischer 		break;
174878ed226SJulian Elischer 
175878ed226SJulian Elischer 	default:
176878ed226SJulian Elischer 		return (USAGE);
177878ed226SJulian Elischer 	}
178878ed226SJulian Elischer 
179878ed226SJulian Elischer 	/* send request */
180878ed226SJulian Elischer 	n = sizeof(rp);
181878ed226SJulian Elischer 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
182878ed226SJulian Elischer 			NG_HCI_OCF_READ_LINK_POLICY_SETTINGS),
183878ed226SJulian Elischer 			(char const *) &cp, sizeof(cp),
184878ed226SJulian Elischer 			(char *) &rp, &n) == ERROR)
185878ed226SJulian Elischer 		return (ERROR);
186878ed226SJulian Elischer 
187878ed226SJulian Elischer 	if (rp.status != 0x00) {
188878ed226SJulian Elischer 		fprintf(stdout, "Status: %s [%#02x]\n",
189878ed226SJulian Elischer 			hci_status2str(rp.status), rp.status);
190878ed226SJulian Elischer 		return (FAILED);
191878ed226SJulian Elischer 	}
192878ed226SJulian Elischer 
193878ed226SJulian Elischer 	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
194878ed226SJulian Elischer 	fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings));
195878ed226SJulian Elischer 
196878ed226SJulian Elischer 	return (OK);
197878ed226SJulian Elischer } /* hci_read_link_policy_settings */
198878ed226SJulian Elischer 
199878ed226SJulian Elischer /* Send Write_Link_Policy_Settings command to the unit */
200878ed226SJulian Elischer static int
hci_write_link_policy_settings(int s,int argc,char ** argv)201878ed226SJulian Elischer hci_write_link_policy_settings(int s, int argc, char **argv)
202878ed226SJulian Elischer {
203878ed226SJulian Elischer 	ng_hci_write_link_policy_settings_cp	cp;
204878ed226SJulian Elischer 	ng_hci_write_link_policy_settings_rp	rp;
205878ed226SJulian Elischer 	int					n;
206878ed226SJulian Elischer 
207878ed226SJulian Elischer 	/* parse command parameters */
208878ed226SJulian Elischer 	switch (argc) {
209878ed226SJulian Elischer 	case 2:
210878ed226SJulian Elischer 		/* connection handle */
211878ed226SJulian Elischer 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
212878ed226SJulian Elischer 			return (USAGE);
213878ed226SJulian Elischer 
214079a8a3eSMaksim Yevmenkin 		cp.con_handle = (uint16_t) (n & 0x0fff);
215878ed226SJulian Elischer 		cp.con_handle = htole16(cp.con_handle);
216878ed226SJulian Elischer 
217878ed226SJulian Elischer 		/* link policy settings */
218878ed226SJulian Elischer 		if (sscanf(argv[1], "%x", &n) != 1)
219878ed226SJulian Elischer 			return (USAGE);
220878ed226SJulian Elischer 
221079a8a3eSMaksim Yevmenkin 		cp.settings = (uint16_t) (n & 0x0ffff);
222878ed226SJulian Elischer 		cp.settings = htole16(cp.settings);
223878ed226SJulian Elischer 		break;
224878ed226SJulian Elischer 
225878ed226SJulian Elischer 	default:
226878ed226SJulian Elischer 		return (USAGE);
227878ed226SJulian Elischer 	}
228878ed226SJulian Elischer 
229878ed226SJulian Elischer 	/* send request */
230878ed226SJulian Elischer 	n = sizeof(rp);
231878ed226SJulian Elischer 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
232878ed226SJulian Elischer 			NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS),
233878ed226SJulian Elischer 			(char const *) &cp, sizeof(cp),
234878ed226SJulian Elischer 			(char *) &rp, &n) == ERROR)
235878ed226SJulian Elischer 		return (ERROR);
236878ed226SJulian Elischer 
237878ed226SJulian Elischer 	if (rp.status != 0x00) {
238878ed226SJulian Elischer 		fprintf(stdout, "Status: %s [%#02x]\n",
239878ed226SJulian Elischer 			hci_status2str(rp.status), rp.status);
240878ed226SJulian Elischer 		return (FAILED);
241878ed226SJulian Elischer 	}
242878ed226SJulian Elischer 
243878ed226SJulian Elischer 	return (OK);
244878ed226SJulian Elischer } /* hci_write_link_policy_settings */
245878ed226SJulian Elischer 
246878ed226SJulian Elischer struct hci_command	link_policy_commands[] = {
247878ed226SJulian Elischer {
2480eff7205SMaksim Yevmenkin "role_discovery <connection_handle>",
249878ed226SJulian Elischer "\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \
250878ed226SJulian Elischer "which role the device is performing for a particular Connection Handle.\n" \
251878ed226SJulian Elischer "The connection handle must be a connection handle for an ACL connection.\n\n" \
252878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle",
253878ed226SJulian Elischer &hci_role_discovery
254878ed226SJulian Elischer },
255878ed226SJulian Elischer {
2562aa65cf7SMaksim Yevmenkin "switch_role <BD_ADDR> <role>",
257878ed226SJulian Elischer "\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \
258878ed226SJulian Elischer "current role the device is performing for a particular connection with\n" \
259878ed226SJulian Elischer "another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\
260878ed226SJulian Elischer "for which connection the role switch is to be performed. The Role indicates\n"\
261878ed226SJulian Elischer "the requested new role that the local device performs. Note: the BD_ADDR\n" \
262878ed226SJulian Elischer "command parameter must specify a Bluetooth device for which a connection\n"
263878ed226SJulian Elischer "already exists.\n\n" \
2642aa65cf7SMaksim Yevmenkin "\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \
265878ed226SJulian Elischer "\t<role>    - dd; role; 0 - Master, 1 - Slave",
266878ed226SJulian Elischer &hci_switch_role
267878ed226SJulian Elischer },
268878ed226SJulian Elischer {
269878ed226SJulian Elischer "read_link_policy_settings <connection_handle>",
270878ed226SJulian Elischer "\nThis command will read the Link Policy setting for the specified connection\n"\
271878ed226SJulian Elischer "handle. The link policy settings parameter determines the behavior of the\n" \
272878ed226SJulian Elischer "local Link Manager when it receives a request from a remote device or it\n" \
273878ed226SJulian Elischer "determines itself to change the master-slave role or to enter the hold,\n" \
274878ed226SJulian Elischer "sniff, or park mode. The local Link Manager will automatically accept or\n" \
275878ed226SJulian Elischer "reject such a request from the remote device, and may even autonomously\n" \
276878ed226SJulian Elischer "request itself, depending on the value of the link policy settings parameter\n"\
277878ed226SJulian Elischer "for the corresponding connection handle. The connection handle must be a\n" \
278878ed226SJulian Elischer "connection handle for an ACL connection.\n\n" \
279878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle",
280878ed226SJulian Elischer &hci_read_link_policy_settings
281878ed226SJulian Elischer },
282878ed226SJulian Elischer {
283878ed226SJulian Elischer "write_link_policy_settings <connection_handle> <settings>",
284878ed226SJulian Elischer "\nThis command will write the Link Policy setting for the specified connection\n"\
285878ed226SJulian Elischer "handle. The link policy settings parameter determines the behavior of the\n" \
286878ed226SJulian Elischer "local Link Manager when it receives a request from a remote device or it\n" \
287878ed226SJulian Elischer "determines itself to change the master-slave role or to enter the hold,\n" \
288878ed226SJulian Elischer "sniff, or park mode. The local Link Manager will automatically accept or\n" \
289878ed226SJulian Elischer "reject such a request from the remote device, and may even autonomously\n" \
290878ed226SJulian Elischer "request itself, depending on the value of the link policy settings parameter\n"\
291878ed226SJulian Elischer "for the corresponding connection handle. The connection handle must be a\n" \
292878ed226SJulian Elischer "connection handle for an ACL connection. Multiple Link Manager policies may\n"\
293878ed226SJulian Elischer "be specified for the link policy settings parameter by performing a bitwise\n"\
294878ed226SJulian Elischer "OR operation of the different activity types.\n\n" \
295878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle\n" \
296878ed226SJulian Elischer "\t<settings>          - xxxx; settings\n" \
297878ed226SJulian Elischer "\t\t0x0000 - Disable All LM Modes (Default)\n" \
298878ed226SJulian Elischer "\t\t0x0001 - Enable Master Slave Switch\n" \
299878ed226SJulian Elischer "\t\t0x0002 - Enable Hold Mode\n" \
300878ed226SJulian Elischer "\t\t0x0004 - Enable Sniff Mode\n" \
301878ed226SJulian Elischer "\t\t0x0008 - Enable Park Mode\n",
302878ed226SJulian Elischer &hci_write_link_policy_settings
303878ed226SJulian Elischer },
304878ed226SJulian Elischer {
305878ed226SJulian Elischer NULL,
306878ed226SJulian Elischer }};
307878ed226SJulian Elischer 
308