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