1878ed226SJulian Elischer /* 2878ed226SJulian Elischer * link_policy.c 3878ed226SJulian Elischer * 4878ed226SJulian Elischer * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5878ed226SJulian Elischer * All rights reserved. 6878ed226SJulian Elischer * 7878ed226SJulian Elischer * Redistribution and use in source and binary forms, with or without 8878ed226SJulian Elischer * modification, are permitted provided that the following conditions 9878ed226SJulian Elischer * are met: 10878ed226SJulian Elischer * 1. Redistributions of source code must retain the above copyright 11878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer. 12878ed226SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 13878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer in the 14878ed226SJulian Elischer * documentation and/or other materials provided with the distribution. 15878ed226SJulian Elischer * 16878ed226SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17878ed226SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18878ed226SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19878ed226SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20878ed226SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21878ed226SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22878ed226SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23878ed226SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24878ed226SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25878ed226SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26878ed226SJulian Elischer * SUCH DAMAGE. 27878ed226SJulian Elischer * 28878ed226SJulian Elischer * $Id: link_policy.c,v 1.3 2002/09/17 16:33:44 max Exp $ 29878ed226SJulian Elischer * $FreeBSD$ 30878ed226SJulian Elischer */ 31878ed226SJulian Elischer 32878ed226SJulian Elischer #include <sys/types.h> 33878ed226SJulian Elischer #include <sys/endian.h> 34878ed226SJulian Elischer #include <errno.h> 35878ed226SJulian Elischer #include <ng_hci.h> 36878ed226SJulian Elischer #include <stdio.h> 37878ed226SJulian Elischer #include "hccontrol.h" 38878ed226SJulian Elischer 39878ed226SJulian Elischer /* Send Role Discovery to the unit */ 40878ed226SJulian Elischer static int 41878ed226SJulian Elischer hci_role_discovery(int s, int argc, char **argv) 42878ed226SJulian Elischer { 43878ed226SJulian Elischer ng_hci_role_discovery_cp cp; 44878ed226SJulian Elischer ng_hci_role_discovery_rp rp; 45878ed226SJulian Elischer int n; 46878ed226SJulian Elischer 47878ed226SJulian Elischer /* parse command parameters */ 48878ed226SJulian Elischer switch (argc) { 49878ed226SJulian Elischer case 1: 50878ed226SJulian Elischer /* connection handle */ 51878ed226SJulian Elischer if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 52878ed226SJulian Elischer return (USAGE); 53878ed226SJulian Elischer 54878ed226SJulian Elischer cp.con_handle = (u_int16_t) (n & 0x0fff); 55878ed226SJulian Elischer cp.con_handle = htole16(cp.con_handle); 56878ed226SJulian Elischer break; 57878ed226SJulian Elischer 58878ed226SJulian Elischer default: 59878ed226SJulian Elischer return (USAGE); 60878ed226SJulian Elischer } 61878ed226SJulian Elischer 62878ed226SJulian Elischer /* send request */ 63878ed226SJulian Elischer n = sizeof(rp); 64878ed226SJulian Elischer if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 65878ed226SJulian Elischer NG_HCI_OCF_ROLE_DISCOVERY), 66878ed226SJulian Elischer (char const *) &cp, sizeof(cp), 67878ed226SJulian Elischer (char *) &rp, &n) == ERROR) 68878ed226SJulian Elischer return (ERROR); 69878ed226SJulian Elischer 70878ed226SJulian Elischer if (rp.status != 0x00) { 71878ed226SJulian Elischer fprintf(stdout, "Status: %s [%#02x]\n", 72878ed226SJulian Elischer hci_status2str(rp.status), rp.status); 73878ed226SJulian Elischer return (FAILED); 74878ed226SJulian Elischer } 75878ed226SJulian Elischer 76878ed226SJulian Elischer fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle)); 77878ed226SJulian Elischer fprintf(stdout, "Role: %s [%#x]\n", 78878ed226SJulian Elischer (rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role); 79878ed226SJulian Elischer 80878ed226SJulian Elischer return (OK); 81878ed226SJulian Elischer } /* hci_role_discovery */ 82878ed226SJulian Elischer 83878ed226SJulian Elischer /* Send Swith Role to the unit */ 84878ed226SJulian Elischer static int 85878ed226SJulian Elischer hci_switch_role(int s, int argc, char **argv) 86878ed226SJulian Elischer { 87878ed226SJulian Elischer int n0, n1, n2, n3, n4, n5; 88878ed226SJulian Elischer char b[512]; 89878ed226SJulian Elischer ng_hci_switch_role_cp cp; 90878ed226SJulian Elischer ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 91878ed226SJulian Elischer 92878ed226SJulian Elischer /* parse command parameters */ 93878ed226SJulian Elischer switch (argc) { 94878ed226SJulian Elischer case 2: 95878ed226SJulian Elischer /* bdaddr */ 96878ed226SJulian Elischer if (sscanf(argv[0], "%x:%x:%x:%x:%x:%x", 97878ed226SJulian Elischer &n5, &n4, &n3, &n2, &n1, &n0) != 6) 98878ed226SJulian Elischer return (USAGE); 99878ed226SJulian Elischer 100878ed226SJulian Elischer cp.bdaddr.b[0] = n0 & 0xff; 101878ed226SJulian Elischer cp.bdaddr.b[1] = n1 & 0xff; 102878ed226SJulian Elischer cp.bdaddr.b[2] = n2 & 0xff; 103878ed226SJulian Elischer cp.bdaddr.b[3] = n3 & 0xff; 104878ed226SJulian Elischer cp.bdaddr.b[4] = n4 & 0xff; 105878ed226SJulian Elischer cp.bdaddr.b[5] = n5 & 0xff; 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 147878ed226SJulian Elischer fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", 148878ed226SJulian Elischer ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 149878ed226SJulian Elischer ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 150878ed226SJulian Elischer fprintf(stdout, "Role: %s [%#x]\n", 151878ed226SJulian Elischer (ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", 152878ed226SJulian Elischer ep->role); 153878ed226SJulian Elischer } else 154878ed226SJulian Elischer goto again; 155878ed226SJulian Elischer 156878ed226SJulian Elischer return (OK); 157878ed226SJulian Elischer } /* hci_switch_role */ 158878ed226SJulian Elischer 159878ed226SJulian Elischer /* Send Read_Link_Policy_Settings command to the unit */ 160878ed226SJulian Elischer static int 161878ed226SJulian Elischer hci_read_link_policy_settings(int s, int argc, char **argv) 162878ed226SJulian Elischer { 163878ed226SJulian Elischer ng_hci_read_link_policy_settings_cp cp; 164878ed226SJulian Elischer ng_hci_read_link_policy_settings_rp rp; 165878ed226SJulian Elischer int n; 166878ed226SJulian Elischer 167878ed226SJulian Elischer /* parse command parameters */ 168878ed226SJulian Elischer switch (argc) { 169878ed226SJulian Elischer case 1: 170878ed226SJulian Elischer /* connection handle */ 171878ed226SJulian Elischer if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 172878ed226SJulian Elischer return (USAGE); 173878ed226SJulian Elischer 174878ed226SJulian Elischer cp.con_handle = (u_int16_t) (n & 0x0fff); 175878ed226SJulian Elischer cp.con_handle = htole16(cp.con_handle); 176878ed226SJulian Elischer break; 177878ed226SJulian Elischer 178878ed226SJulian Elischer default: 179878ed226SJulian Elischer return (USAGE); 180878ed226SJulian Elischer } 181878ed226SJulian Elischer 182878ed226SJulian Elischer /* send request */ 183878ed226SJulian Elischer n = sizeof(rp); 184878ed226SJulian Elischer if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 185878ed226SJulian Elischer NG_HCI_OCF_READ_LINK_POLICY_SETTINGS), 186878ed226SJulian Elischer (char const *) &cp, sizeof(cp), 187878ed226SJulian Elischer (char *) &rp, &n) == ERROR) 188878ed226SJulian Elischer return (ERROR); 189878ed226SJulian Elischer 190878ed226SJulian Elischer if (rp.status != 0x00) { 191878ed226SJulian Elischer fprintf(stdout, "Status: %s [%#02x]\n", 192878ed226SJulian Elischer hci_status2str(rp.status), rp.status); 193878ed226SJulian Elischer return (FAILED); 194878ed226SJulian Elischer } 195878ed226SJulian Elischer 196878ed226SJulian Elischer fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle)); 197878ed226SJulian Elischer fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings)); 198878ed226SJulian Elischer 199878ed226SJulian Elischer return (OK); 200878ed226SJulian Elischer } /* hci_read_link_policy_settings */ 201878ed226SJulian Elischer 202878ed226SJulian Elischer /* Send Write_Link_Policy_Settings command to the unit */ 203878ed226SJulian Elischer static int 204878ed226SJulian Elischer hci_write_link_policy_settings(int s, int argc, char **argv) 205878ed226SJulian Elischer { 206878ed226SJulian Elischer ng_hci_write_link_policy_settings_cp cp; 207878ed226SJulian Elischer ng_hci_write_link_policy_settings_rp rp; 208878ed226SJulian Elischer int n; 209878ed226SJulian Elischer 210878ed226SJulian Elischer /* parse command parameters */ 211878ed226SJulian Elischer switch (argc) { 212878ed226SJulian Elischer case 2: 213878ed226SJulian Elischer /* connection handle */ 214878ed226SJulian Elischer if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 215878ed226SJulian Elischer return (USAGE); 216878ed226SJulian Elischer 217878ed226SJulian Elischer cp.con_handle = (u_int16_t) (n & 0x0fff); 218878ed226SJulian Elischer cp.con_handle = htole16(cp.con_handle); 219878ed226SJulian Elischer 220878ed226SJulian Elischer /* link policy settings */ 221878ed226SJulian Elischer if (sscanf(argv[1], "%x", &n) != 1) 222878ed226SJulian Elischer return (USAGE); 223878ed226SJulian Elischer 224878ed226SJulian Elischer cp.settings = (u_int16_t) (n & 0x0ffff); 225878ed226SJulian Elischer cp.settings = htole16(cp.settings); 226878ed226SJulian Elischer break; 227878ed226SJulian Elischer 228878ed226SJulian Elischer default: 229878ed226SJulian Elischer return (USAGE); 230878ed226SJulian Elischer } 231878ed226SJulian Elischer 232878ed226SJulian Elischer /* send request */ 233878ed226SJulian Elischer n = sizeof(rp); 234878ed226SJulian Elischer if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 235878ed226SJulian Elischer NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS), 236878ed226SJulian Elischer (char const *) &cp, sizeof(cp), 237878ed226SJulian Elischer (char *) &rp, &n) == ERROR) 238878ed226SJulian Elischer return (ERROR); 239878ed226SJulian Elischer 240878ed226SJulian Elischer if (rp.status != 0x00) { 241878ed226SJulian Elischer fprintf(stdout, "Status: %s [%#02x]\n", 242878ed226SJulian Elischer hci_status2str(rp.status), rp.status); 243878ed226SJulian Elischer return (FAILED); 244878ed226SJulian Elischer } 245878ed226SJulian Elischer 246878ed226SJulian Elischer return (OK); 247878ed226SJulian Elischer } /* hci_write_link_policy_settings */ 248878ed226SJulian Elischer 249878ed226SJulian Elischer struct hci_command link_policy_commands[] = { 250878ed226SJulian Elischer { 251878ed226SJulian Elischer "role_discovery <conection_handle>", 252878ed226SJulian Elischer "\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \ 253878ed226SJulian Elischer "which role the device is performing for a particular Connection Handle.\n" \ 254878ed226SJulian Elischer "The connection handle must be a connection handle for an ACL connection.\n\n" \ 255878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle", 256878ed226SJulian Elischer &hci_role_discovery 257878ed226SJulian Elischer }, 258878ed226SJulian Elischer { 259878ed226SJulian Elischer "switch_role <bdaddr> <role>", 260878ed226SJulian Elischer "\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \ 261878ed226SJulian Elischer "current role the device is performing for a particular connection with\n" \ 262878ed226SJulian Elischer "another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\ 263878ed226SJulian Elischer "for which connection the role switch is to be performed. The Role indicates\n"\ 264878ed226SJulian Elischer "the requested new role that the local device performs. Note: the BD_ADDR\n" \ 265878ed226SJulian Elischer "command parameter must specify a Bluetooth device for which a connection\n" 266878ed226SJulian Elischer "already exists.\n\n" \ 267878ed226SJulian Elischer "\t<bdaddr> - xx:xx:xx:xx:xx:xx; device bdaddr\n" \ 268878ed226SJulian Elischer "\t<role> - dd; role; 0 - Master, 1 - Slave", 269878ed226SJulian Elischer &hci_switch_role 270878ed226SJulian Elischer }, 271878ed226SJulian Elischer { 272878ed226SJulian Elischer "read_link_policy_settings <connection_handle>", 273878ed226SJulian Elischer "\nThis command will read the Link Policy setting for the specified connection\n"\ 274878ed226SJulian Elischer "handle. The link policy settings parameter determines the behavior of the\n" \ 275878ed226SJulian Elischer "local Link Manager when it receives a request from a remote device or it\n" \ 276878ed226SJulian Elischer "determines itself to change the master-slave role or to enter the hold,\n" \ 277878ed226SJulian Elischer "sniff, or park mode. The local Link Manager will automatically accept or\n" \ 278878ed226SJulian Elischer "reject such a request from the remote device, and may even autonomously\n" \ 279878ed226SJulian Elischer "request itself, depending on the value of the link policy settings parameter\n"\ 280878ed226SJulian Elischer "for the corresponding connection handle. The connection handle must be a\n" \ 281878ed226SJulian Elischer "connection handle for an ACL connection.\n\n" \ 282878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle", 283878ed226SJulian Elischer &hci_read_link_policy_settings 284878ed226SJulian Elischer }, 285878ed226SJulian Elischer { 286878ed226SJulian Elischer "write_link_policy_settings <connection_handle> <settings>", 287878ed226SJulian Elischer "\nThis command will write the Link Policy setting for the specified connection\n"\ 288878ed226SJulian Elischer "handle. The link policy settings parameter determines the behavior of the\n" \ 289878ed226SJulian Elischer "local Link Manager when it receives a request from a remote device or it\n" \ 290878ed226SJulian Elischer "determines itself to change the master-slave role or to enter the hold,\n" \ 291878ed226SJulian Elischer "sniff, or park mode. The local Link Manager will automatically accept or\n" \ 292878ed226SJulian Elischer "reject such a request from the remote device, and may even autonomously\n" \ 293878ed226SJulian Elischer "request itself, depending on the value of the link policy settings parameter\n"\ 294878ed226SJulian Elischer "for the corresponding connection handle. The connection handle must be a\n" \ 295878ed226SJulian Elischer "connection handle for an ACL connection. Multiple Link Manager policies may\n"\ 296878ed226SJulian Elischer "be specified for the link policy settings parameter by performing a bitwise\n"\ 297878ed226SJulian Elischer "OR operation of the different activity types.\n\n" \ 298878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle\n" \ 299878ed226SJulian Elischer "\t<settings> - xxxx; settings\n" \ 300878ed226SJulian Elischer "\t\t0x0000 - Disable All LM Modes (Default)\n" \ 301878ed226SJulian Elischer "\t\t0x0001 - Enable Master Slave Switch\n" \ 302878ed226SJulian Elischer "\t\t0x0002 - Enable Hold Mode\n" \ 303878ed226SJulian Elischer "\t\t0x0004 - Enable Sniff Mode\n" \ 304878ed226SJulian Elischer "\t\t0x0008 - Enable Park Mode\n", 305878ed226SJulian Elischer &hci_write_link_policy_settings 306878ed226SJulian Elischer }, 307878ed226SJulian Elischer { 308878ed226SJulian Elischer NULL, 309878ed226SJulian Elischer }}; 310878ed226SJulian Elischer 311