freebsd-dev/usr.sbin/bluetooth/hccontrol/link_policy.c
Julian Elischer 878ed22696 The second try a committing the bluetooth code
Has been seen to work on several cards and communicating with
several mobile phones to use them as modems etc.

We are still talking with 3com to try get them to allow us to include
the firmware for their pccard in the driver but the driver is here..
In the mean time
it can be downloaded from the 3com website and loaded using the utility
bt3cfw(8) (supplied) (instructions in the man page)

Not yet linked to the build

Submitted by:	Maksim Yevmenkin <myevmenk@exodus.net>
Approved by:	re
2002-11-20 23:01:59 +00:00

311 lines
9.5 KiB
C

/*
* link_policy.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: link_policy.c,v 1.3 2002/09/17 16:33:44 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/endian.h>
#include <errno.h>
#include <ng_hci.h>
#include <stdio.h>
#include "hccontrol.h"
/* Send Role Discovery to the unit */
static int
hci_role_discovery(int s, int argc, char **argv)
{
ng_hci_role_discovery_cp cp;
ng_hci_role_discovery_rp rp;
int n;
/* parse command parameters */
switch (argc) {
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
NG_HCI_OCF_ROLE_DISCOVERY),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
fprintf(stdout, "Role: %s [%#x]\n",
(rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role);
return (OK);
} /* hci_role_discovery */
/* Send Swith Role to the unit */
static int
hci_switch_role(int s, int argc, char **argv)
{
int n0, n1, n2, n3, n4, n5;
char b[512];
ng_hci_switch_role_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* parse command parameters */
switch (argc) {
case 2:
/* bdaddr */
if (sscanf(argv[0], "%x:%x:%x:%x:%x:%x",
&n5, &n4, &n3, &n2, &n1, &n0) != 6)
return (USAGE);
cp.bdaddr.b[0] = n0 & 0xff;
cp.bdaddr.b[1] = n1 & 0xff;
cp.bdaddr.b[2] = n2 & 0xff;
cp.bdaddr.b[3] = n3 & 0xff;
cp.bdaddr.b[4] = n4 & 0xff;
cp.bdaddr.b[5] = n5 & 0xff;
/* role */
if (sscanf(argv[1], "%d", &n0) != 1)
return (USAGE);
cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER;
break;
default:
return (USAGE);
}
/* send request and expect status response */
n0 = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
NG_HCI_OCF_SWITCH_ROLE),
(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n0 = sizeof(b);
if (hci_recv(s, b, &n0) == ERROR)
return (ERROR);
if (n0 < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_ROLE_CHANGE) {
ng_hci_role_change_ep *ep = (ng_hci_role_change_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
fprintf(stdout, "Role: %s [%#x]\n",
(ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave",
ep->role);
} else
goto again;
return (OK);
} /* hci_switch_role */
/* Send Read_Link_Policy_Settings command to the unit */
static int
hci_read_link_policy_settings(int s, int argc, char **argv)
{
ng_hci_read_link_policy_settings_cp cp;
ng_hci_read_link_policy_settings_rp rp;
int n;
/* parse command parameters */
switch (argc) {
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
NG_HCI_OCF_READ_LINK_POLICY_SETTINGS),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings));
return (OK);
} /* hci_read_link_policy_settings */
/* Send Write_Link_Policy_Settings command to the unit */
static int
hci_write_link_policy_settings(int s, int argc, char **argv)
{
ng_hci_write_link_policy_settings_cp cp;
ng_hci_write_link_policy_settings_rp rp;
int n;
/* parse command parameters */
switch (argc) {
case 2:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
/* link policy settings */
if (sscanf(argv[1], "%x", &n) != 1)
return (USAGE);
cp.settings = (u_int16_t) (n & 0x0ffff);
cp.settings = htole16(cp.settings);
break;
default:
return (USAGE);
}
/* send request */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
return (OK);
} /* hci_write_link_policy_settings */
struct hci_command link_policy_commands[] = {
{
"role_discovery <conection_handle>",
"\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \
"which role the device is performing for a particular Connection Handle.\n" \
"The connection handle must be a connection handle for an ACL connection.\n\n" \
"\t<connection_handle> - dddd; connection handle",
&hci_role_discovery
},
{
"switch_role <bdaddr> <role>",
"\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \
"current role the device is performing for a particular connection with\n" \
"another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\
"for which connection the role switch is to be performed. The Role indicates\n"\
"the requested new role that the local device performs. Note: the BD_ADDR\n" \
"command parameter must specify a Bluetooth device for which a connection\n"
"already exists.\n\n" \
"\t<bdaddr> - xx:xx:xx:xx:xx:xx; device bdaddr\n" \
"\t<role> - dd; role; 0 - Master, 1 - Slave",
&hci_switch_role
},
{
"read_link_policy_settings <connection_handle>",
"\nThis command will read the Link Policy setting for the specified connection\n"\
"handle. The link policy settings parameter determines the behavior of the\n" \
"local Link Manager when it receives a request from a remote device or it\n" \
"determines itself to change the master-slave role or to enter the hold,\n" \
"sniff, or park mode. The local Link Manager will automatically accept or\n" \
"reject such a request from the remote device, and may even autonomously\n" \
"request itself, depending on the value of the link policy settings parameter\n"\
"for the corresponding connection handle. The connection handle must be a\n" \
"connection handle for an ACL connection.\n\n" \
"\t<connection_handle> - dddd; connection handle",
&hci_read_link_policy_settings
},
{
"write_link_policy_settings <connection_handle> <settings>",
"\nThis command will write the Link Policy setting for the specified connection\n"\
"handle. The link policy settings parameter determines the behavior of the\n" \
"local Link Manager when it receives a request from a remote device or it\n" \
"determines itself to change the master-slave role or to enter the hold,\n" \
"sniff, or park mode. The local Link Manager will automatically accept or\n" \
"reject such a request from the remote device, and may even autonomously\n" \
"request itself, depending on the value of the link policy settings parameter\n"\
"for the corresponding connection handle. The connection handle must be a\n" \
"connection handle for an ACL connection. Multiple Link Manager policies may\n"\
"be specified for the link policy settings parameter by performing a bitwise\n"\
"OR operation of the different activity types.\n\n" \
"\t<connection_handle> - dddd; connection handle\n" \
"\t<settings> - xxxx; settings\n" \
"\t\t0x0000 - Disable All LM Modes (Default)\n" \
"\t\t0x0001 - Enable Master Slave Switch\n" \
"\t\t0x0002 - Enable Hold Mode\n" \
"\t\t0x0004 - Enable Sniff Mode\n" \
"\t\t0x0008 - Enable Park Mode\n",
&hci_write_link_policy_settings
},
{
NULL,
}};