summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bluetooth
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2002-11-20 23:01:59 +0000
committerjulian <julian@FreeBSD.org>2002-11-20 23:01:59 +0000
commitd72cb748a8219735d80767b8847995b1ff103f9a (patch)
treec38e3c48c390af16003a1f451848e93558978422 /usr.sbin/bluetooth
parent97980d0d57dd5c2944c5f3306726610a3a1b6e51 (diff)
downloadFreeBSD-src-d72cb748a8219735d80767b8847995b1ff103f9a.zip
FreeBSD-src-d72cb748a8219735d80767b8847995b1ff103f9a.tar.gz
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
Diffstat (limited to 'usr.sbin/bluetooth')
-rw-r--r--usr.sbin/bluetooth/Makefile12
-rw-r--r--usr.sbin/bluetooth/bt3cfw/Makefile15
-rw-r--r--usr.sbin/bluetooth/bt3cfw/bt3cfw.869
-rw-r--r--usr.sbin/bluetooth/bt3cfw/bt3cfw.c227
-rw-r--r--usr.sbin/bluetooth/hccontrol/Makefile14
-rw-r--r--usr.sbin/bluetooth/hccontrol/hccontrol.8163
-rw-r--r--usr.sbin/bluetooth/hccontrol/hccontrol.c274
-rw-r--r--usr.sbin/bluetooth/hccontrol/hccontrol.h75
-rw-r--r--usr.sbin/bluetooth/hccontrol/host_controller_baseband.c1713
-rw-r--r--usr.sbin/bluetooth/hccontrol/info.c219
-rw-r--r--usr.sbin/bluetooth/hccontrol/link_control.c973
-rw-r--r--usr.sbin/bluetooth/hccontrol/link_policy.c310
-rw-r--r--usr.sbin/bluetooth/hccontrol/node.c518
-rw-r--r--usr.sbin/bluetooth/hccontrol/send_recv.c184
-rw-r--r--usr.sbin/bluetooth/hccontrol/status.c245
-rw-r--r--usr.sbin/bluetooth/hccontrol/util.c350
-rw-r--r--usr.sbin/bluetooth/hcseriald/Makefile17
-rw-r--r--usr.sbin/bluetooth/hcseriald/hcseriald.881
-rw-r--r--usr.sbin/bluetooth/hcseriald/hcseriald.c279
-rw-r--r--usr.sbin/bluetooth/l2control/Makefile12
-rw-r--r--usr.sbin/bluetooth/l2control/l2cap.c256
-rw-r--r--usr.sbin/bluetooth/l2control/l2control.884
-rw-r--r--usr.sbin/bluetooth/l2control/l2control.c226
-rw-r--r--usr.sbin/bluetooth/l2control/l2control.h49
-rw-r--r--usr.sbin/bluetooth/l2ping/Makefile12
-rw-r--r--usr.sbin/bluetooth/l2ping/l2ping.887
-rw-r--r--usr.sbin/bluetooth/l2ping/l2ping.c279
27 files changed, 6743 insertions, 0 deletions
diff --git a/usr.sbin/bluetooth/Makefile b/usr.sbin/bluetooth/Makefile
new file mode 100644
index 0000000..821a003
--- /dev/null
+++ b/usr.sbin/bluetooth/Makefile
@@ -0,0 +1,12 @@
+# $Id$
+# $FreeBSD$
+
+SUBDIR= \
+ bt3cfw \
+ hccontrol \
+ hcseriald \
+ l2control \
+ l2ping
+
+.include <bsd.subdir.mk>
+
diff --git a/usr.sbin/bluetooth/bt3cfw/Makefile b/usr.sbin/bluetooth/bt3cfw/Makefile
new file mode 100644
index 0000000..05ae1ab
--- /dev/null
+++ b/usr.sbin/bluetooth/bt3cfw/Makefile
@@ -0,0 +1,15 @@
+# $Id: Makefile,v 1.1.1.1 2002/11/12 00:39:18 max Exp $
+# $FreeBSD$
+
+DESTDIR= /usr/sbin/
+MANDIR= ../share/man/man
+PROG= bt3cfw
+MAN8= bt3cfw.8
+WARNS?= 2
+CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include
+SRCS= bt3cfw.c
+
+DPADD= ${LIBNETGRAPH}
+LDADD= -lnetgraph
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/bt3cfw/bt3cfw.8 b/usr.sbin/bluetooth/bt3cfw/bt3cfw.8
new file mode 100644
index 0000000..e85cb16
--- /dev/null
+++ b/usr.sbin/bluetooth/bt3cfw/bt3cfw.8
@@ -0,0 +1,69 @@
+.\" bt3cfw.1
+.\"
+.\" 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: bt3cfw.8,v 1.1.1.1 2002/11/12 00:39:18 max Exp $
+.\" $FreeBSD$
+.Dd November 11, 2002
+.Dt BT3CFW 8
+.Os
+.Sh NAME
+.Nm BT3CFW
+.Nd Firmware download utility for 3Com Bluetooth PC card driver
+.Sh SYNOPSIS
+.Nm
+.Op Fl n Ar Netgraph node name
+.Op Fl f Ar Firmware file name
+.Sh DESCRIPTION
+The
+.Nm
+utility connects to the specified Netgraph driver node of type
+.Dv BTCCC
+and downloads specified firmware file.
+.Pp
+Due to copyright issues I will no longer provide firmware with the card
+driver. The firmware can be obtained from the Windows driver package that
+can be downloaded from the 3COM web site at no charge. The firmware name
+is BT3CPCC.BIN. I'm using original firmware that came with the card on CD-ROM.
+.Bd -literal -offset indent
+MD5 (BT3CPCC.BIN) = 36170fda56ea9fdbf1702c966f8a97f1
+.Ed
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl n Ar Netgraph node name
+Connect to the specified Netgraph driver node of type
+.Dv BTCCC .
+.It Fl f Ar Firmware file name
+Specify firmware file name for download.
+.El
+.Sh BUGS
+Please report if found.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr ng_bt3c 4
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.sbin/bluetooth/bt3cfw/bt3cfw.c b/usr.sbin/bluetooth/bt3cfw/bt3cfw.c
new file mode 100644
index 0000000..09252ac
--- /dev/null
+++ b/usr.sbin/bluetooth/bt3cfw/bt3cfw.c
@@ -0,0 +1,227 @@
+/*
+ * bt3cfw.c
+ *
+ * Copyright (c) 2001 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: bt3cfw.c,v 1.1.1.1 2002/11/12 00:39:18 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <netgraph.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "ng_bt3c.h"
+
+#define BT3CFW_IDENT "bt3cfw"
+#define BT3CFW_MAX_FIRMWARE_SIZE 0xffff
+
+/* Convert hex ASCII to int4 */
+static int
+hexa2int4(const char *a)
+{
+ if ('0' <= *a && *a <= '9')
+ return (*a - '0');
+
+ if ('A' <= *a && *a <= 'F')
+ return (*a - 'A' + 0xa);
+
+ if ('a' <= *a && *a <= 'f')
+ return (*a - 'a' + 0xa);
+
+ syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a);
+ exit(255);
+}
+
+/* Convert hex ASCII to int8 */
+static int
+hexa2int8(const char *a)
+{
+ return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
+}
+
+/* Convert hex ASCII to int16 */
+static int
+hexa2int16(const char *a)
+{
+ return ((hexa2int8(a) << 8) | hexa2int8(a + 2));
+}
+
+/* Convert hex ASCII to int32 */
+static int
+hexa2int32(const char *a)
+{
+ return ((hexa2int16(a) << 16) | hexa2int16(a + 4));
+}
+
+/* Display usage() and exit */
+static void
+usage(void)
+{
+ syslog(LOG_ERR, "Usage: %s -f FirmwareFile -n NodeName", BT3CFW_IDENT);
+ exit(255);
+}
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+ FILE *firmware_file = NULL;
+ char buffer[80], path[NG_PATHLEN + 1],
+ *firmware_filename = NULL;
+ u_int8_t *firmware = NULL;
+ int firmware_size, opt, cs, ds;
+
+ memset(path, 0, sizeof(path));
+ openlog(BT3CFW_IDENT, LOG_NDELAY|LOG_PID|LOG_PERROR, LOG_USER);
+
+ while ((opt = getopt(argc, argv, "f:hn:")) != -1) {
+ switch (opt) {
+ case 'f':
+ firmware_filename = optarg;
+ break;
+
+ case 'n':
+ snprintf(path, sizeof(path), "%s:", optarg);
+ break;
+
+ case 'h':
+ default:
+ usage();
+ /* NOT REACHED */
+ }
+ }
+
+ if (firmware_filename == NULL || path[0] == 0)
+ usage();
+ /* NOT REACHED */
+
+ firmware = (u_int8_t *) calloc(BT3CFW_MAX_FIRMWARE_SIZE,
+ sizeof(u_int8_t));
+ if (firmware == NULL) {
+ syslog(LOG_ERR, "Could not allocate firmware buffer");
+ exit(255);
+ }
+
+ if ((firmware_file = fopen(firmware_filename, "r")) == NULL) {
+ syslog(LOG_ERR, "Could not open BT3C firmware file %s. %s (%d)",
+ firmware_filename, strerror(errno), errno);
+ exit(255);
+ }
+
+ firmware_size = 0;
+
+ while (fgets(buffer, sizeof(buffer), firmware_file)) {
+ int i, size, address, cs, fcs;
+
+ size = hexa2int8(buffer + 2);
+ address = hexa2int32(buffer + 4);
+ fcs = hexa2int8(buffer + 2 + size * 2);
+
+ if (buffer[1] == '3') {
+ ng_bt3c_firmware_block_ep *block = NULL;
+ u_int16_t *data = NULL;
+
+ block = (ng_bt3c_firmware_block_ep *)
+ (firmware + firmware_size);
+
+ firmware_size += sizeof(*block);
+ if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) {
+ syslog(LOG_ERR, "Could not add new firmware " \
+ "block. Firmware file %s is " \
+ "too big, firmware_size=%d",
+ firmware_filename,
+ firmware_size);
+ exit(255);
+ }
+
+ block->block_address = address;
+ block->block_size = (size - 4) / 2;
+ block->block_alignment = (block->block_size * 2) % 3;
+ if (block->block_alignment != 0)
+ block->block_alignment = 3 - block->block_alignment;
+
+ firmware_size += (block->block_size * 2);
+ firmware_size += block->block_alignment;
+ if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) {
+ syslog(LOG_ERR, "Could not add new firmware " \
+ "data. Firmware file %s is " \
+ "too big, firmware_size=%d",
+ firmware_filename,
+ firmware_size);
+ exit(255);
+ }
+
+ /* First part of the cheksum: size and address */
+ cs = 0;
+ for (i = 0; i < 5; i++)
+ cs += hexa2int8(buffer + 2 + i * 2);
+
+ /* Data + second part of the cheksum: data */
+ data = (u_int16_t *)(block + 1);
+ for (i = 0; i < block->block_size; i++) {
+ data[i] = hexa2int16(buffer + (i * 4) + 12);
+ cs += (((data[i] & 0xff00) >> 8) & 0xff);
+ cs += (data[i] & 0x00ff);
+ }
+ } else
+ for (cs = 0, i = 0; i < size; i++)
+ cs += hexa2int8(buffer + 2 + i * 2);
+
+ if (((cs + fcs) & 0xff) != 0xff) {
+ syslog(LOG_ERR, "Invalid firmware file %s. Checksum " \
+ "error, cs=%#x, fcs=%#x, checksum=%#x",
+ firmware_filename, (cs & 0xff), fcs,
+ ((cs + fcs) & 0xff));
+ exit(255);
+ }
+ }
+
+ /* Send firmware to the card */
+ if (NgMkSockNode(NULL, &cs, &ds) < 0) {
+ syslog(LOG_ERR, "Could not create Netgraph socket. %s (%d)",
+ strerror(errno), errno);
+ exit(255);
+ }
+
+ if (NgSendMsg(cs, path, NGM_BT3C_COOKIE,
+ NGM_BT3C_NODE_DOWNLOAD_FIRMWARE,
+ (void const *) firmware, firmware_size) < 0) {
+ syslog(LOG_ERR, "Could not send Netgraph message. %s (%d)",
+ strerror(errno), errno);
+ exit(255);
+ }
+
+ free(firmware);
+ firmware = NULL;
+
+ return (0);
+}
+
diff --git a/usr.sbin/bluetooth/hccontrol/Makefile b/usr.sbin/bluetooth/hccontrol/Makefile
new file mode 100644
index 0000000..c816c3c
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/Makefile
@@ -0,0 +1,14 @@
+# $Id: Makefile,v 1.6 2002/09/06 18:52:41 max Exp $
+# $FreeBSD$
+
+DESTDIR= /usr/sbin/
+MANDIR= ../share/man/man
+PROG= hccontrol
+MAN8= hccontrol.8
+WARNS?= 2
+CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include
+SRCS= send_recv.c link_policy.c link_control.c \
+ host_controller_baseband.c info.c status.c node.c hccontrol.c \
+ util.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/hccontrol/hccontrol.8 b/usr.sbin/bluetooth/hccontrol/hccontrol.8
new file mode 100644
index 0000000..555cf32
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/hccontrol.8
@@ -0,0 +1,163 @@
+.\" hccontrol.8
+.\"
+.\" 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: hccontrol.8,v 1.8 2002/11/12 22:33:17 max Exp $
+.\" $FreeBSD$
+.Dd June 14, 2002
+.Dt HCCONTROL 8
+.Os
+.Sh NAME
+.Nm hccontrol
+.Nd HCI configuration utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl n Ar HCI node name
+.Op Ar command
+.Op Ar parameters ...
+.Sh DESCRIPTION
+The
+.Nm
+utility connects to the specified Netgraph node of type
+.Em HCI
+and attempts to send specified command to the HCI Netgraph node or to the
+associated Bluetooth device.
+.Nm
+will print results to the standard output and error messages to
+the standard error.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl n Ar HCI node name
+Connect to the specified HCI Netgraph node.
+.It command
+One of the supported commands (see below). Special command
+.Dq help
+can be used to obtain the list of all supported commands. To get more
+information about specific command use
+.Dq help command .
+.It parameters
+One or more optional space separated command parameters.
+.El
+.Sh COMMANDS
+The currently supported HCI commands in
+.Nm
+are:
+.Pp
+.Bd -literal -offset indent -compact
+Inquiry
+Create_Connection
+Disconnect
+Add_SCO_Connection
+Change_Connection_Packet_Type
+Remote_Name_Request
+Read_Remote_Supported_Features
+Read_Remote_Version_Information
+Read_Clock_Offset
+Role_Discovery
+Switch_Role
+Read_Link_Policy_Settings
+Write_Link_Policy_Settings
+Reset
+Read_Pin_Type
+Write_Pin_Type
+Read_Stored_Link_Key
+Write_Stored_Link_Key
+Delete_Stored_Link_Key
+Change_Local_Name
+Read_Local_Name
+Read_Connection_Accept_Timeout
+Write_Connection_Accept_Timeout
+Read_Page_Timeout
+Write_Page_Timeout
+Read_Scan_Enable
+Write_Scan_Enable
+Read_Page_Scan_Activity
+Write_Page_Scan_Activity
+Read_Inquiry_Scan_Activity
+Write_Inquiry_Scan_Activity
+Read_Authentication_Enable
+Write_Authentication_Enable
+Read_Encryption_Mode
+Write_Encryption_Mode
+Read_Class_Of_Device
+Write_Class_Of_Device
+Read_Voice_Settings
+Write_Voice_Settings
+Read_Number_Broadcast_Retransmissions
+Write_Number_Broadcast_Retransmissions
+Read_Hold_Mode_Activity
+Write_Hold_Mode_Activity
+Read_SCO_Flow_Control_Enable
+Write_SCO_Flow_Control_Enable
+Read_Link_Supervision_Timeout
+Write_Link_Supervision_Timeout
+Read_Local_Version_Information
+Read_Local_Supported_Features
+Read_Buffer_Size
+Read_Country_Code
+Read_BD_ADDR
+Read_Failed_Contact_Counter
+Reset_Failed_Contact_Counter
+Get_Link_Quality
+Read_RSSI
+.Ed
+.Pp
+The currently supported node commands in
+.Nm
+are:
+.Pp
+.Bd -literal -offset indent -compact
+Read_Node_State
+Initialize
+Read_Debug_Level
+Write_Debug_Level
+Read_Command_Timeout
+Write_Command_Timeout
+Read_Node_Buffer_Size
+Read_Node_BD_ADDR
+Read_Node_Features
+Read_Node_Stat
+Reset_Node_Stat
+Flush_Neighbor_Cache
+Read_Neighbor_Cache
+Read_Connection_List
+Read_Node_Link_Policy_Settings_Mask
+Write_Node_Link_Policy_Settings_Mask
+Read_Node_Packet_Mask
+Write_Node_Packet_Mask
+.Ed
+.Pp
+.Sh BUGS
+Most likely. Please report if found.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ng_hci 4 ,
+.Xr hcseriald 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.sbin/bluetooth/hccontrol/hccontrol.c b/usr.sbin/bluetooth/hccontrol/hccontrol.c
new file mode 100644
index 0000000..12b70eb
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/hccontrol.c
@@ -0,0 +1,274 @@
+/*
+ * hccontrol.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: hccontrol.c,v 1.11 2002/09/12 18:19:43 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <assert.h>
+#include <bitstring.h>
+#include <err.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <ng_l2cap.h>
+#include <ng_btsocket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "hccontrol.h"
+
+/* Prototypes */
+static int do_hci_command (char const *, int, char **);
+static struct hci_command * find_hci_command (char const *, struct hci_command *);
+static void print_hci_command (struct hci_command *);
+static void usage (void);
+
+/* Globals */
+int verbose = 0;
+int timeout;
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+ char *node = NULL;
+ int n;
+
+ /* Process command line arguments */
+ while ((n = getopt(argc, argv, "n:v")) != -1) {
+ switch (n) {
+ case 'n':
+ node = optarg;
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (*argv == NULL)
+ usage();
+
+ n = do_hci_command(node, argc, argv);
+
+ return (n);
+} /* main */
+
+/* Create socket and bind it */
+static int
+socket_open(char const *node)
+{
+ struct sockaddr_hci addr;
+ struct ng_btsocket_hci_raw_filter filter;
+ int s, mib[4];
+ size_t size;
+
+ if (node == NULL)
+ usage();
+
+ s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+ if (s < 0)
+ err(1, "Could not create socket");
+
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_len = sizeof(addr);
+ addr.hci_family = AF_BLUETOOTH;
+ strncpy(addr.hci_node, node, sizeof(addr.hci_node));
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ err(2, "Could not bind socket, node=%s", node);
+
+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ err(3, "Could not connect socket, node=%s", node);
+
+ memset(&filter, 0, sizeof(filter));
+ bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_COMPL - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_RESULT - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_CON_COMPL - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_DISCON_COMPL - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_RETURN_LINK_KEYS - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_CON_PKT_TYPE_CHANGED - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_ROLE_CHANGE - 1);
+
+ if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER,
+ (void * const) &filter, sizeof(filter)) < 0)
+ err(4, "Could not setsockopt()");
+
+ size = (sizeof(mib)/sizeof(mib[0]));
+ if (sysctlnametomib("net.bluetooth.hci.command_timeout",mib,&size) < 0)
+ err(5, "Could not sysctlnametomib()");
+
+ if (sysctl(mib, sizeof(mib)/sizeof(mib[0]),
+ (void *) &timeout, &size, NULL, 0) < 0)
+ err(6, "Could not sysctl()");
+
+ timeout ++;
+
+ return (s);
+} /* socket_open */
+
+/* Execute commands */
+static int
+do_hci_command(char const *node, int argc, char **argv)
+{
+ char *cmd = argv[0];
+ struct hci_command *c = NULL;
+ int s, e, help;
+
+ help = 0;
+ if (strcasecmp(cmd, "help") == 0) {
+ argc --;
+ argv ++;
+
+ if (argc <= 0) {
+ fprintf(stdout, "Supported commands:\n");
+ print_hci_command(link_control_commands);
+ print_hci_command(link_policy_commands);
+ print_hci_command(host_controller_baseband_commands);
+ print_hci_command(info_commands);
+ print_hci_command(status_commands);
+ print_hci_command(node_commands);
+ fprintf(stdout, "\nFor more information use " \
+ "'help command'\n");
+
+ return (OK);
+ }
+
+ help = 1;
+ cmd = argv[0];
+ }
+
+ c = find_hci_command(cmd, link_control_commands);
+ if (c != NULL)
+ goto execute;
+
+ c = find_hci_command(cmd, link_policy_commands);
+ if (c != NULL)
+ goto execute;
+
+ c = find_hci_command(cmd, host_controller_baseband_commands);
+ if (c != NULL)
+ goto execute;
+
+ c = find_hci_command(cmd, info_commands);
+ if (c != NULL)
+ goto execute;
+
+ c = find_hci_command(cmd, status_commands);
+ if (c != NULL)
+ goto execute;
+
+ c = find_hci_command(cmd, node_commands);
+ if (c == NULL) {
+ fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
+ return (ERROR);
+ }
+execute:
+ if (!help) {
+ s = socket_open(node);
+ e = (c->handler)(s, -- argc, ++ argv);
+ close(s);
+ } else
+ e = USAGE;
+
+ switch (e) {
+ case OK:
+ case FAILED:
+ break;
+
+ case ERROR:
+ fprintf(stdout, "Could not execute command \"%s\". %s\n",
+ cmd, strerror(errno));
+ break;
+
+ case USAGE:
+ fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
+ break;
+
+ default: assert(0); break;
+ }
+
+
+ return (e);
+} /* do_hci_command */
+
+/* Try to find command in specified category */
+static struct hci_command *
+find_hci_command(char const *command, struct hci_command *category)
+{
+ struct hci_command *c = NULL;
+
+ for (c = category; c->command != NULL; c++) {
+ char *c_end = strchr(c->command, ' ');
+
+ if (c_end != NULL) {
+ int len = c_end - c->command;
+
+ if (strncasecmp(command, c->command, len) == 0)
+ return (c);
+ } else if (strcasecmp(command, c->command) == 0)
+ return (c);
+ }
+
+ return (NULL);
+} /* find_hci_command */
+
+/* Try to find command in specified category */
+static void
+print_hci_command(struct hci_command *category)
+{
+ struct hci_command *c = NULL;
+
+ for (c = category; c->command != NULL; c++)
+ fprintf(stdout, "\t%s\n", c->command);
+} /* print_hci_command */
+
+/* Usage */
+static void
+usage(void)
+{
+ fprintf(stdout, "Usage: hccontrol -n HCI_node_name cmd [p1] [..]]\n");
+ exit(255);
+} /* usage */
+
diff --git a/usr.sbin/bluetooth/hccontrol/hccontrol.h b/usr.sbin/bluetooth/hccontrol/hccontrol.h
new file mode 100644
index 0000000..8bcf764
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/hccontrol.h
@@ -0,0 +1,75 @@
+/*
+ * hccontrol.h
+ *
+ * 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: hccontrol.h,v 1.8 2002/09/12 18:19:43 max Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _HCCONTROL_H_
+#define _HCCONTROL_H_
+
+#define OK 0 /* everything was OK */
+#define ERROR 1 /* could not execute command */
+#define FAILED 2 /* error was reported */
+#define USAGE 3 /* invalid parameters */
+
+struct hci_command {
+ char const *command;
+ char const *description;
+ int (*handler)(int, int, char **);
+};
+
+extern int timeout;
+extern int verbose;
+extern struct hci_command link_control_commands[];
+extern struct hci_command link_policy_commands[];
+extern struct hci_command host_controller_baseband_commands[];
+extern struct hci_command info_commands[];
+extern struct hci_command status_commands[];
+extern struct hci_command node_commands[];
+
+int hci_request (int, int, char const *, int, char *, int *);
+int hci_simple_request (int, int, char *, int *);
+int hci_send (int, char const *, int);
+int hci_recv (int, char *, int *);
+
+char const * const hci_link2str (int);
+char const * const hci_pin2str (int);
+char const * const hci_scan2str (int);
+char const * const hci_encrypt2str (int, int);
+char const * const hci_coding2str (int);
+char const * const hci_vdata2str (int);
+char const * const hci_hmode2str (int, char *, int);
+char const * const hci_ver2str (int);
+char const * const hci_manufacturer2str(int);
+char const * const hci_features2str (u_int8_t *, char *, int);
+char const * const hci_cc2str (int);
+char const * const hci_con_state2str (int);
+char const * const hci_status2str (int);
+
+#endif /* _HCCONTROL_H_ */
+
diff --git a/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c b/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c
new file mode 100644
index 0000000..3aa1571
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c
@@ -0,0 +1,1713 @@
+/*
+ * host_controller_baseband.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: host_controller_baseband.c,v 1.12 2002/11/19 18:34:06 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <stdio.h>
+#include <string.h>
+#include "hccontrol.h"
+
+/* Convert hex ASCII to int4 */
+static int
+hci_hexa2int4(const char *a)
+{
+ if ('0' <= *a && *a <= '9')
+ return (*a - '0');
+
+ if ('A' <= *a && *a <= 'F')
+ return (*a - 'A' + 0xa);
+
+ if ('a' <= *a && *a <= 'f')
+ return (*a - 'a' + 0xa);
+
+ return (-1);
+}
+
+/* Convert hex ASCII to int8 */
+static int
+hci_hexa2int8(const char *a)
+{
+ int hi = hci_hexa2int4(a);
+ int lo = hci_hexa2int4(a + 1);
+
+ if (hi < 0 || lo < 0)
+ return (-1);
+
+ return ((hi << 4) | lo);
+}
+
+/* Convert ascii hex string to the u_int8_t[] */
+static int
+hci_hexstring2array(char const *s, u_int8_t *a, int asize)
+{
+ int i, l, b;
+
+ l = strlen(s) / 2;
+ if (l > asize)
+ l = asize;
+
+ for (i = 0; i < l; i++) {
+ b = hci_hexa2int8(s + i * 2);
+ if (b < 0)
+ return (-1);
+
+ a[i] = (b & 0xff);
+ }
+
+ return (0);
+}
+
+/* Send RESET to the unit */
+static int
+hci_reset(int s, int argc, char **argv)
+{
+ ng_hci_status_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_RESET), (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_reset */
+
+/* Send Read_PIN_Type command to the unit */
+static int
+hci_read_pin_type(int s, int argc, char **argv)
+{
+ ng_hci_read_pin_type_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_PIN_TYPE),
+ (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, "PIN type: %s [%#02x]\n",
+ hci_pin2str(rp.pin_type), rp.pin_type);
+
+ return (OK);
+} /* hci_read_pin_type */
+
+/* Send Write_PIN_Type command to the unit */
+static int
+hci_write_pin_type(int s, int argc, char **argv)
+{
+ ng_hci_write_pin_type_cp cp;
+ ng_hci_write_pin_type_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
+ return (USAGE);
+
+ cp.pin_type = (u_int8_t) n;
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_PIN_TYPE),
+ (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_pin_type */
+
+/* Send Read_Stored_Link_Key command to the unit */
+static int
+hci_read_stored_link_key(int s, int argc, char **argv)
+{
+ struct {
+ ng_hci_cmd_pkt_t hdr;
+ ng_hci_read_stored_link_key_cp cp;
+ } __attribute__ ((packed)) cmd;
+
+ struct {
+ ng_hci_event_pkt_t hdr;
+ union {
+ ng_hci_command_compl_ep cc;
+ ng_hci_return_link_keys_ep key;
+ u_int8_t b[NG_HCI_EVENT_PKT_SIZE];
+ } ep;
+ } __attribute__ ((packed)) event;
+
+ int n,a0,a1,a2,a3,a4,a5;
+
+ /* Send command */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.type = NG_HCI_CMD_PKT;
+ cmd.hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_STORED_LINK_KEY));
+ cmd.hdr.length = sizeof(cmd.cp);
+
+ switch (argc) {
+ case 1:
+ /* parse BD_ADDR */
+ if (sscanf(argv[0], "%x:%x:%x:%x:%x:%x", &a5, &a4, &a3, &a2,
+ &a1, &a0) != 6)
+ return (USAGE);
+
+ cmd.cp.bdaddr.b[0] = (a0 & 0xff);
+ cmd.cp.bdaddr.b[1] = (a1 & 0xff);
+ cmd.cp.bdaddr.b[2] = (a2 & 0xff);
+ cmd.cp.bdaddr.b[3] = (a3 & 0xff);
+ cmd.cp.bdaddr.b[4] = (a4 & 0xff);
+ cmd.cp.bdaddr.b[5] = (a5 & 0xff);
+ break;
+
+ default:
+ cmd.cp.read_all = 1;
+ break;
+ }
+
+ if (hci_send(s, (char const *) &cmd, sizeof(cmd)) != OK)
+ return (ERROR);
+
+ /* Receive events */
+again:
+ memset(&event, 0, sizeof(event));
+ n = sizeof(event);
+ if (hci_recv(s, (char *) &event, &n) != OK)
+ return (ERROR);
+
+ if (n <= sizeof(event.hdr)) {
+ errno = EMSGSIZE;
+ return (ERROR);
+ }
+
+ if (event.hdr.type != NG_HCI_EVENT_PKT) {
+ errno = EIO;
+ return (ERROR);
+ }
+
+ /* Parse event */
+ switch (event.hdr.event) {
+ case NG_HCI_EVENT_COMMAND_COMPL: {
+ ng_hci_read_stored_link_key_rp *rp = NULL;
+
+ if (event.ep.cc.opcode == 0x0000 ||
+ event.ep.cc.opcode != cmd.hdr.opcode)
+ goto again;
+
+ rp = (ng_hci_read_stored_link_key_rp *)(event.ep.b +
+ sizeof(event.ep.cc));
+
+ fprintf(stdout, "Complete: Status: %s [%#x]\n",
+ hci_status2str(rp->status), rp->status);
+ fprintf(stdout, "Maximum Number of keys: %d\n",
+ le16toh(rp->max_num_keys));
+ fprintf(stdout, "Number of keys read: %d\n",
+ le16toh(rp->num_keys_read));
+ } break;
+
+ case NG_HCI_EVENT_RETURN_LINK_KEYS: {
+ struct _key {
+ bdaddr_t bdaddr;
+ u_int8_t key[NG_HCI_KEY_SIZE];
+ } __attribute__ ((packed)) *k = NULL;
+
+ fprintf(stdout, "Event: Number of keys: %d\n",
+ event.ep.key.num_keys);
+
+ k = (struct _key *)(event.ep.b + sizeof(event.ep.key));
+ for (n = 0; n < event.ep.key.num_keys; n++) {
+ fprintf(stdout, "\t%d: %02x:%02x:%02x:%02x:%02x:%02x ",
+ n + 1,
+ k->bdaddr.b[5], k->bdaddr.b[4], k->bdaddr.b[3],
+ k->bdaddr.b[2], k->bdaddr.b[1], k->bdaddr.b[0]);
+
+ for (a0 = 0; a0 < sizeof(k->key); a0++)
+ fprintf(stdout, "%02x", k->key[a0]);
+ fprintf(stdout, "\n");
+
+ k ++;
+ }
+
+ goto again;
+
+ } break;
+
+ default:
+ goto again;
+ }
+
+ return (OK);
+} /* hci_read_store_link_key */
+
+/* Send Write_Stored_Link_Key command to the unit */
+static int
+hci_write_stored_link_key(int s, int argc, char **argv)
+{
+ struct {
+ ng_hci_write_stored_link_key_cp p;
+ bdaddr_t bdaddr;
+ u_int8_t key[NG_HCI_KEY_SIZE];
+ } cp;
+ ng_hci_write_stored_link_key_rp rp;
+ int32_t n, a0, a1, a2, a3, a4, a5;
+
+ memset(&cp, 0, sizeof(cp));
+
+ switch (argc) {
+ case 2:
+ cp.p.num_keys_write = 1;
+
+ /* parse BD_ADDR */
+ if (sscanf(argv[0], "%x:%x:%x:%x:%x:%x",
+ &a5, &a4, &a3, &a2, &a1, &a0) != 6)
+ return (USAGE);
+
+ cp.bdaddr.b[0] = (a0 & 0xff);
+ cp.bdaddr.b[1] = (a1 & 0xff);
+ cp.bdaddr.b[2] = (a2 & 0xff);
+ cp.bdaddr.b[3] = (a3 & 0xff);
+ cp.bdaddr.b[4] = (a4 & 0xff);
+ cp.bdaddr.b[5] = (a5 & 0xff);
+
+ /* parse key */
+ if (hci_hexstring2array(argv[1], cp.key, sizeof(cp.key)) < 0)
+ return (USAGE);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_STORED_LINK_KEY),
+ (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, "Number of keys written: %d\n", rp.num_keys_written);
+
+ return (OK);
+} /* hci_write_stored_link_key */
+
+
+/* Send Delete_Stored_Link_Key command to the unit */
+static int
+hci_delete_stored_link_key(int s, int argc, char **argv)
+{
+ ng_hci_delete_stored_link_key_cp cp;
+ ng_hci_delete_stored_link_key_rp rp;
+ int32_t n, a0, a1, a2, a3, a4, a5;
+
+ memset(&cp, 0, sizeof(cp));
+
+ switch (argc) {
+ case 1:
+ /* parse BD_ADDR */
+ if (sscanf(argv[0], "%x:%x:%x:%x:%x:%x",
+ &a5, &a4, &a3, &a2, &a1, &a0) != 6)
+ return (USAGE);
+
+ cp.bdaddr.b[0] = (a0 & 0xff);
+ cp.bdaddr.b[1] = (a1 & 0xff);
+ cp.bdaddr.b[2] = (a2 & 0xff);
+ cp.bdaddr.b[3] = (a3 & 0xff);
+ cp.bdaddr.b[4] = (a4 & 0xff);
+ cp.bdaddr.b[5] = (a5 & 0xff);
+ break;
+
+ default:
+ cp.delete_all = 1;
+ break;
+ }
+
+ /* send command */
+ n = sizeof(cp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_DELETE_STORED_LINK_KEY),
+ (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, "Number of keys deleted: %d\n", rp.num_keys_deleted);
+
+ return (OK);
+} /* hci_delete_stored_link_key */
+
+/* Send Change_Local_Name command to the unit */
+static int
+hci_change_local_name(int s, int argc, char **argv)
+{
+ ng_hci_change_local_name_cp cp;
+ ng_hci_change_local_name_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ snprintf(cp.name, sizeof(cp.name), "%s", argv[0]);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_CHANGE_LOCAL_NAME),
+ (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_change_local_name */
+
+/* Send Read_Local_Name command to the unit */
+static int
+hci_read_local_name(int s, int argc, char **argv)
+{
+ ng_hci_read_local_name_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_LOCAL_NAME),
+ (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, "Local name: %s\n", rp.name);
+
+ return (OK);
+} /* hci_read_local_name */
+
+/* Send Read_Connection_Accept_Timeout to the unit */
+static int
+hci_read_connection_accept_timeout(int s, int argc, char **argv)
+{
+ ng_hci_read_con_accept_timo_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_CON_ACCEPT_TIMO),
+ (char *) &rp, &n) == ERROR)
+ return (ERROR);
+
+ if (rp.status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(rp.status), rp.status);
+ return (FAILED);
+ }
+
+ rp.timeout = le16toh(rp.timeout);
+ fprintf(stdout, "Connection accept timeout: %.2f msec [%d slots]\n",
+ rp.timeout * 0.625, rp.timeout);
+
+ return (OK);
+} /* hci_read_connection_accept_timeout */
+
+/* Send Write_Connection_Accept_Timeout to the unit */
+static int
+hci_write_connection_accept_timeout(int s, int argc, char **argv)
+{
+ ng_hci_write_con_accept_timo_cp cp;
+ ng_hci_write_con_accept_timo_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 1 || n > 0xb540)
+ return (USAGE);
+
+ cp.timeout = (u_int16_t) n;
+ cp.timeout = htole16(cp.timeout);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO),
+ (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_connection_accept_timeout */
+
+/* Send Read_Page_Timeout command to the unit */
+static int
+hci_read_page_timeout(int s, int argc, char **argv)
+{
+ ng_hci_read_page_timo_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_PAGE_TIMO),
+ (char *) &rp, &n) == ERROR)
+ return (ERROR);
+
+ if (rp.status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(rp.status), rp.status);
+ return (FAILED);
+ }
+
+ rp.timeout = le16toh(rp.timeout);
+ fprintf(stdout, "Page timeout: %.2f msec [%d slots]\n",
+ rp.timeout * 0.625, rp.timeout);
+
+ return (OK);
+} /* hci_read_page_timeoout */
+
+/* Send Write_Page_Timeout command to the unit */
+static int
+hci_write_page_timeout(int s, int argc, char **argv)
+{
+ ng_hci_write_page_timo_cp cp;
+ ng_hci_write_page_timo_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 1 || n > 0xffff)
+ return (USAGE);
+
+ cp.timeout = (u_int16_t) n;
+ cp.timeout = htole16(cp.timeout);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_PAGE_TIMO),
+ (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_page_timeout */
+
+/* Send Read_Scan_Enable command to the unit */
+static int
+hci_read_scan_enable(int s, int argc, char **argv)
+{
+ ng_hci_read_scan_enable_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_SCAN_ENABLE),
+ (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, "Scan enable: %s [%#02x]\n",
+ hci_scan2str(rp.scan_enable), rp.scan_enable);
+
+ return (OK);
+} /* hci_read_scan_enable */
+
+/* Send Write_Scan_Enable command to the unit */
+static int
+hci_write_scan_enable(int s, int argc, char **argv)
+{
+ ng_hci_write_scan_enable_cp cp;
+ ng_hci_write_scan_enable_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 3)
+ return (USAGE);
+
+ cp.scan_enable = (u_int8_t) n;
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_SCAN_ENABLE),
+ (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_scan_enable */
+
+/* Send Read_Page_Scan_Activity command to the unit */
+static int
+hci_read_page_scan_activity(int s, int argc, char **argv)
+{
+ ng_hci_read_page_scan_activity_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY),
+ (char *) &rp, &n) == ERROR)
+ return (ERROR);
+
+ if (rp.status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(rp.status), rp.status);
+ return (FAILED);
+ }
+
+ rp.page_scan_interval = le16toh(rp.page_scan_interval);
+ rp.page_scan_window = le16toh(rp.page_scan_window);
+
+ fprintf(stdout, "Page Scan Interval: %.2f msec [%d slots]\n",
+ rp.page_scan_interval * 0.625, rp.page_scan_interval);
+ fprintf(stdout, "Page Scan Window: %.2f msec [%d slots]\n",
+ rp.page_scan_window * 0.625, rp.page_scan_window);
+
+ return (OK);
+} /* hci_read_page_scan_activity */
+
+/* Send Write_Page_Scan_Activity command to the unit */
+static int
+hci_write_page_scan_activity(int s, int argc, char **argv)
+{
+ ng_hci_write_page_scan_activity_cp cp;
+ ng_hci_write_page_scan_activity_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 2:
+ /* page scan interval */
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
+ return (USAGE);
+
+ cp.page_scan_interval = (u_int16_t) n;
+
+ /* page scan window */
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
+ return (USAGE);
+
+ cp.page_scan_window = (u_int16_t) n;
+
+ if (cp.page_scan_window > cp.page_scan_interval)
+ return (USAGE);
+
+ cp.page_scan_interval = htole16(cp.page_scan_interval);
+ cp.page_scan_window = htole16(cp.page_scan_window);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY),
+ (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_page_scan_activity */
+
+/* Send Read_Inquiry_Scan_Activity command to the unit */
+static int
+hci_read_inquiry_scan_activity(int s, int argc, char **argv)
+{
+ ng_hci_read_inquiry_scan_activity_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY),
+ (char *) &rp, &n) == ERROR)
+ return (ERROR);
+
+ if (rp.status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(rp.status), rp.status);
+ return (FAILED);
+ }
+
+ rp.inquiry_scan_interval = le16toh(rp.inquiry_scan_interval);
+ rp.inquiry_scan_window = le16toh(rp.inquiry_scan_window);
+
+ fprintf(stdout, "Inquiry Scan Interval: %.2f msec [%d slots]\n",
+ rp.inquiry_scan_interval * 0.625, rp.inquiry_scan_interval);
+ fprintf(stdout, "Inquiry Scan Window: %.2f msec [%d slots]\n",
+ rp.inquiry_scan_window * 0.625, rp.inquiry_scan_interval);
+
+ return (OK);
+} /* hci_read_inquiry_scan_activity */
+
+/* Send Write_Inquiry_Scan_Activity command to the unit */
+static int
+hci_write_inquiry_scan_activity(int s, int argc, char **argv)
+{
+ ng_hci_write_inquiry_scan_activity_cp cp;
+ ng_hci_write_inquiry_scan_activity_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 2:
+ /* inquiry scan interval */
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
+ return (USAGE);
+
+ cp.inquiry_scan_interval = (u_int16_t) n;
+
+ /* inquiry scan window */
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
+ return (USAGE);
+
+ cp.inquiry_scan_window = (u_int16_t) n;
+
+ if (cp.inquiry_scan_window > cp.inquiry_scan_interval)
+ return (USAGE);
+
+ cp.inquiry_scan_interval =
+ htole16(cp.inquiry_scan_interval);
+ cp.inquiry_scan_window = htole16(cp.inquiry_scan_window);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY),
+ (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_inquiry_scan_activity */
+
+/* Send Read_Authentication_Enable command to the unit */
+static int
+hci_read_authentication_enable(int s, int argc, char **argv)
+{
+ ng_hci_read_auth_enable_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_AUTH_ENABLE),
+ (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, "Authentication Enable: %s [%d]\n",
+ rp.auth_enable? "Enabled" : "Disabled", rp.auth_enable);
+
+ return (OK);
+} /* hci_read_authentication_enable */
+
+/* Send Write_Authentication_Enable command to the unit */
+static int
+hci_write_authentication_enable(int s, int argc, char **argv)
+{
+ ng_hci_write_auth_enable_cp cp;
+ ng_hci_write_auth_enable_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
+ return (USAGE);
+
+ cp.auth_enable = (u_int8_t) n;
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_AUTH_ENABLE),
+ (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_authentication_enable */
+
+/* Send Read_Encryption_Mode command to the unit */
+static int
+hci_read_encryption_mode(int s, int argc, char **argv)
+{
+ ng_hci_read_encryption_mode_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_ENCRYPTION_MODE),
+ (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, "Encryption mode: %s [%#02x]\n",
+ hci_encrypt2str(rp.encryption_mode, 0), rp.encryption_mode);
+
+ return (OK);
+} /* hci_read_encryption_mode */
+
+/* Send Write_Encryption_Mode command to the unit */
+static int
+hci_write_encryption_mode(int s, int argc, char **argv)
+{
+ ng_hci_write_encryption_mode_cp cp;
+ ng_hci_write_encryption_mode_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 2)
+ return (USAGE);
+
+ cp.encryption_mode = (u_int8_t) n;
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_ENCRYPTION_MODE),
+ (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_encryption_mode */
+
+/* Send Read_Class_Of_Device command to the unit */
+static int
+hci_read_class_of_device(int s, int argc, char **argv)
+{
+ ng_hci_read_unit_class_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_UNIT_CLASS),
+ (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, "Class: %02x:%02x:%02x\n",
+ rp.uclass[2], rp.uclass[1], rp.uclass[0]);
+
+ return (0);
+} /* hci_read_class_of_device */
+
+/* Send Write_Class_Of_Device command to the unit */
+static int
+hci_write_class_of_device(int s, int argc, char **argv)
+{
+ ng_hci_write_unit_class_cp cp;
+ ng_hci_write_unit_class_rp rp;
+ int n0, n1, n2;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3)
+ return (USAGE);
+
+ cp.uclass[0] = (n0 & 0xff);
+ cp.uclass[1] = (n1 & 0xff);
+ cp.uclass[2] = (n2 & 0xff);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n0 = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_UNIT_CLASS),
+ (char const *) &cp, sizeof(cp),
+ (char *) &rp, &n0) == 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_class_of_device */
+
+/* Send Read_Voice_Settings command to the unit */
+static int
+hci_read_voice_settings(int s, int argc, char **argv)
+{
+ ng_hci_read_voice_settings_rp rp;
+ int n,
+ input_coding,
+ input_data_format,
+ input_sample_size;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_VOICE_SETTINGS),
+ (char *) &rp, &n) == ERROR)
+ return (ERROR);
+
+ if (rp.status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(rp.status), rp.status);
+ return (FAILED);
+ }
+
+ rp.settings = le16toh(rp.settings);
+
+ input_coding = (rp.settings & 0x0300) >> 8;
+ input_data_format = (rp.settings & 0x00c0) >> 6;
+ input_sample_size = (rp.settings & 0x0020) >> 5;
+
+ fprintf(stdout, "Voice settings: %#04x\n", rp.settings);
+ fprintf(stdout, "Input coding: %s [%d]\n",
+ hci_coding2str(input_coding), input_coding);
+ fprintf(stdout, "Input data format: %s [%d]\n",
+ hci_vdata2str(input_data_format), input_data_format);
+
+ if (input_coding == 0x00) /* Only for Linear PCM */
+ fprintf(stdout, "Input sample size: %d bit [%d]\n",
+ input_sample_size? 16 : 8, input_sample_size);
+
+ return (OK);
+} /* hci_read_voice_settings */
+
+/* Send Write_Voice_Settings command to the unit */
+static int
+hci_write_voice_settings(int s, int argc, char **argv)
+{
+ ng_hci_write_voice_settings_cp cp;
+ ng_hci_write_voice_settings_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%x", &n) != 1)
+ return (USAGE);
+
+ cp.settings = (u_int16_t) n;
+ cp.settings = htole16(cp.settings);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_VOICE_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_voice_settings */
+
+/* Send Read_Number_Broadcast_Restransmissions */
+static int
+hci_read_number_broadcast_retransmissions(int s, int argc, char **argv)
+{
+ ng_hci_read_num_broadcast_retrans_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS),
+ (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, "Number of broadcast retransmissions: %d\n",
+ rp.counter);
+
+ return (OK);
+} /* hci_read_number_broadcast_retransmissions */
+
+/* Send Write_Number_Broadcast_Restransmissions */
+static int
+hci_write_number_broadcast_retransmissions(int s, int argc, char **argv)
+{
+ ng_hci_write_num_broadcast_retrans_cp cp;
+ ng_hci_write_num_broadcast_retrans_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0xff)
+ return (USAGE);
+
+ cp.counter = (u_int8_t) n;
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS),
+ (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_number_broadcast_retransmissions */
+
+/* Send Read_Hold_Mode_Activity command to the unit */
+static int
+hci_read_hold_mode_activity(int s, int argc, char **argv)
+{
+ ng_hci_read_hold_mode_activity_rp rp;
+ int n;
+ char buffer[1024];
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY),
+ (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, "Hold Mode Activities: %#02x\n", rp.hold_mode_activity);
+ if (rp.hold_mode_activity == 0)
+ fprintf(stdout, "Maintain current Power State");
+ else
+ fprintf(stdout, "%s", hci_hmode2str(rp.hold_mode_activity,
+ buffer, sizeof(buffer)));
+
+ fprintf(stdout, "\n");
+
+ return (OK);
+} /* hci_read_hold_mode_activity */
+
+/* Send Write_Hold_Mode_Activity command to the unit */
+static int
+hci_write_hold_mode_activity(int s, int argc, char **argv)
+{
+ ng_hci_write_hold_mode_activity_cp cp;
+ ng_hci_write_hold_mode_activity_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 4)
+ return (USAGE);
+
+ cp.hold_mode_activity = (u_int8_t) n;
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY),
+ (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_hold_mode_activity */
+
+/* Send Read_SCO_Flow_Control_Enable command to the unit */
+static int
+hci_read_sco_flow_control_enable(int s, int argc, char **argv)
+{
+ ng_hci_read_sco_flow_control_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_SCO_FLOW_CONTROL),
+ (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, "SCO flow control %s [%d]\n",
+ rp.flow_control? "enabled" : "disabled", rp.flow_control);
+
+ return (OK);
+} /* hci_read_sco_flow_control_enable */
+
+/* Send Write_SCO_Flow_Control_Enable command to the unit */
+static int
+hci_write_sco_flow_control_enable(int s, int argc, char **argv)
+{
+ ng_hci_write_sco_flow_control_cp cp;
+ ng_hci_write_sco_flow_control_rp rp;
+ int n;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
+ return (USAGE);
+
+ cp.flow_control = (u_int8_t) n;
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL),
+ (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_sco_flow_control_enable */
+
+/* Send Read_Link_Supervision_Timeout command to the unit */
+static int
+hci_read_link_supervision_timeout(int s, int argc, char **argv)
+{
+ ng_hci_read_link_supervision_timo_cp cp;
+ ng_hci_read_link_supervision_timo_rp rp;
+ int n;
+
+ 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 command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO),
+ (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);
+ }
+
+ rp.timeout = le16toh(rp.timeout);
+
+ fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
+ fprintf(stdout, "Link supervision timeout: %.2f msec [%d slots]\n",
+ rp.timeout * 0.625, rp.timeout);
+
+ return (OK);
+} /* hci_read_link_supervision_timeout */
+
+/* Send Write_Link_Supervision_Timeout command to the unit */
+static int
+hci_write_link_supervision_timeout(int s, int argc, char **argv)
+{
+ ng_hci_write_link_supervision_timo_cp cp;
+ ng_hci_write_link_supervision_timo_rp rp;
+ int n;
+
+ 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 supervision timeout */
+ if (sscanf(argv[1], "%d", &n) != 1 || n < 0 || n > 0xeff)
+ return (USAGE);
+
+ cp.timeout = (u_int16_t) (n & 0x0fff);
+ cp.timeout = htole16(cp.timeout);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO),
+ (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_supervision_timeout */
+
+struct hci_command host_controller_baseband_commands[] = {
+{
+"reset",
+"\nThe Reset command will reset the Host Controller and the Link Manager.\n" \
+"After the reset is completed, the current operational state will be lost,\n" \
+"the Bluetooth unit will enter standby mode and the Host Controller will\n" \
+"automatically revert to the default values for the parameters for which\n" \
+"default values are defined in the specification.",
+&hci_reset
+},
+{
+"read_pin_type",
+"\nThe Read_PIN_Type command is used for the Host to read whether the Link\n" \
+"Manager assumes that the Host supports variable PIN codes only a fixed PIN\n" \
+"code.",
+&hci_read_pin_type
+},
+{
+"write_pin_type <pin_type>",
+"\nThe Write_PIN_Type command is used for the Host to write to the Host\n" \
+"Controller whether the Host supports variable PIN codes or only a fixed PIN\n"\
+"code.\n\n" \
+"\t<pin_type> - dd; 0 - Variable; 1 - Fixed",
+&hci_write_pin_type
+},
+{
+"read_stored_link_key [<bdaddr>]",
+"\nThe Read_Stored_Link_Key command provides the ability to read one or\n" \
+"more link keys stored in the Bluetooth Host Controller. The Bluetooth Host\n" \
+"Controller can store a limited number of link keys for other Bluetooth\n" \
+"devices.\n\n" \
+"\t<bdaddr> - xx:xx:xx:xx:xx:xx BD_ADDR",
+&hci_read_stored_link_key
+},
+{
+"write_stored_link_key <bdaddr> <key>",
+"\nThe Write_Stored_Link_Key command provides the ability to write one\n" \
+"or more link keys to be stored in the Bluetooth Host Controller. The\n" \
+"Bluetooth Host Controller can store a limited number of link keys for other\n"\
+"Bluetooth devices. If no additional space is available in the Bluetooth\n"\
+"Host Controller then no additional link keys will be stored.\n\n" \
+"\t<bdaddr> - xx:xx:xx:xx:xx:xx BD_ADDR\n" \
+"\t<key> - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx up to 16 bytes link key",
+&hci_write_stored_link_key
+},
+{
+"delete_stored_link_key [<bdaddr>]",
+"\nThe Delete_Stored_Link_Key command provides the ability to remove one\n" \
+"or more of the link keys stored in the Bluetooth Host Controller. The\n" \
+"Bluetooth Host Controller can store a limited number of link keys for other\n"\
+"Bluetooth devices.\n\n" \
+"\t<bdaddr> - xx:xx:xx:xx:xx:xx BD_ADDR",
+&hci_delete_stored_link_key
+},
+{
+"change_local_name <name>",
+"\nThe Change_Local_Name command provides the ability to modify the user\n" \
+"friendly name for the Bluetooth unit.\n\n" \
+"\t<name> - string",
+&hci_change_local_name
+},
+{
+"read_local_name",
+"\nThe Read_Local_Name command provides the ability to read the\n" \
+"stored user-friendly name for the Bluetooth unit.",
+&hci_read_local_name
+},
+{
+"read_connection_accept_timeout",
+"\nThis command will read the value for the Connection_Accept_Timeout\n" \
+"configuration parameter. The Connection_Accept_Timeout configuration\n" \
+"parameter allows the Bluetooth hardware to automatically deny a\n" \
+"connection request after a specified time period has occurred and\n" \
+"the new connection is not accepted. Connection Accept Timeout\n" \
+"measured in Number of Baseband slots.",
+&hci_read_connection_accept_timeout
+},
+{
+"write_connection_accept_timeout <timeout>",
+"\nThis command will write the value for the Connection_Accept_Timeout\n" \
+"configuration parameter.\n\n" \
+"\t<timeout> - dddd; measured in number of baseband slots.",
+&hci_write_connection_accept_timeout
+},
+{
+"read_page_timeout",
+"\nThis command will read the value for the Page_Timeout configuration\n" \
+"parameter. The Page_Timeout configuration parameter defines the\n" \
+"maximum time the local Link Manager will wait for a baseband page\n" \
+"response from the remote unit at a locally initiated connection\n" \
+"attempt. Page Timeout measured in Number of Baseband slots.",
+&hci_read_page_timeout
+},
+{
+"write_page_timeout <timeout>",
+"\nThis command will write the value for the Page_Timeout configuration\n" \
+"parameter.\n\n" \
+"\t<timeout> - dddd; measured in number of baseband slots.",
+&hci_write_page_timeout
+},
+{
+"read_scan_enable",
+"\nThis command will read the value for the Scan_Enable parameter. The\n" \
+"Scan_Enable parameter controls whether or not the Bluetooth uint\n" \
+"will periodically scan for page attempts and/or inquiry requests\n" \
+"from other Bluetooth unit.\n\n" \
+"\t0x00 - No Scans enabled.\n" \
+"\t0x01 - Inquiry Scan enabled. Page Scan disabled.\n" \
+"\t0x02 - Inquiry Scan disabled. Page Scan enabled.\n" \
+"\t0x03 - Inquiry Scan enabled. Page Scan enabled.",
+&hci_read_scan_enable
+},
+{
+"write_scan_enable <scan_enable>",
+"\nThis command will write the value for the Scan_Enable parameter.\n" \
+"The Scan_Enable parameter controls whether or not the Bluetooth\n" \
+"unit will periodically scan for page attempts and/or inquiry\n" \
+"requests from other Bluetooth unit.\n\n" \
+"\t<scan_enable> - dd;\n" \
+"\t0 - No Scans enabled.\n" \
+"\t1 - Inquiry Scan enabled. Page Scan disabled.\n" \
+"\t2 - Inquiry Scan disabled. Page Scan enabled.\n" \
+"\t3 - Inquiry Scan enabled. Page Scan enabled.",
+&hci_write_scan_enable
+},
+{
+"read_page_scan_activity",
+"\nThis command will read the value for Page_Scan_Activity configuration\n" \
+"parameters. The Page_Scan_Interval configuration parameter defines the\n" \
+"amount of time between consecutive page scans. This time interval is \n" \
+"defined from when the Host Controller started its last page scan until\n" \
+"it begins the next page scan. The Page_Scan_Window configuration parameter\n" \
+"defines the amount of time for the duration of the page scan. The\n" \
+"Page_Scan_Window can only be less than or equal to the Page_Scan_Interval.",
+&hci_read_page_scan_activity
+},
+{
+"write_page_scan_activity interval(dddd) window(dddd)",
+"\nThis command will write the value for Page_Scan_Activity configuration\n" \
+"parameter. The Page_Scan_Interval configuration parameter defines the\n" \
+"amount of time between consecutive page scans. This is defined as the time\n" \
+"interval from when the Host Controller started its last page scan until it\n" \
+"begins the next page scan. The Page_Scan_Window configuration parameter\n" \
+"defines the amount of time for the duration of the page scan. \n" \
+"The Page_Scan_Window can only be less than or equal to the Page_Scan_Interval.\n\n" \
+"\t<interval> - Range: 0x0012 -– 0x100, Time = N * 0.625 msec\n" \
+"\t<window> - Range: 0x0012 -– 0x100, Time = N * 0.625 msen",
+&hci_write_page_scan_activity
+},
+{
+"read_inquiry_scan_activity",
+"\nThis command will read the value for Inquiry_Scan_Activity configuration\n" \
+"parameter. The Inquiry_Scan_Interval configuration parameter defines the\n" \
+"amount of time between consecutive inquiry scans. This is defined as the\n" \
+"time interval from when the Host Controller started its last inquiry scan\n" \
+"until it begins the next inquiry scan.",
+&hci_read_inquiry_scan_activity
+},
+{
+"write_inquiry_scan_activity interval(dddd) window(dddd)",
+"\nThis command will write the value for Inquiry_Scan_Activity configuration\n"\
+"parameter. The Inquiry_Scan_Interval configuration parameter defines the\n" \
+"amount of time between consecutive inquiry scans. This is defined as the\n" \
+"time interval from when the Host Controller started its last inquiry scan\n" \
+"until it begins the next inquiry scan. The Inquiry_Scan_Window configuration\n" \
+"parameter defines the amount of time for the duration of the inquiry scan.\n" \
+"The Inquiry_Scan_Window can only be less than or equal to the Inquiry_Scan_Interval.\n\n" \
+"\t<interval> - Range: 0x0012 -– 0x100, Time = N * 0.625 msec\n" \
+"\t<window> - Range: 0x0012 -– 0x100, Time = N * 0.625 msen",
+&hci_write_inquiry_scan_activity
+},
+{
+"read_authentication_enable",
+"\nThis command will read the value for the Authentication_Enable parameter.\n"\
+"The Authentication_Enable parameter controls if the local unit requires\n"\
+"to authenticate the remote unit at connection setup (between the\n" \
+"Create_Connection command or acceptance of an incoming ACL connection\n"\
+"and the corresponding Connection Complete event). At connection setup, only\n"\
+"the unit(s) with the Authentication_Enable parameter enabled will try to\n"\
+"authenticate the other unit.",
+&hci_read_authentication_enable
+},
+{
+"write_authentication_enable enable(0|1)",
+"\nThis command will write the value for the Authentication_Enable parameter.\n"\
+"The Authentication_Enable parameter controls if the local unit requires to\n"\
+"authenticate the remote unit at connection setup (between the\n" \
+"Create_Connection command or acceptance of an incoming ACL connection\n" \
+"and the corresponding Connection Complete event). At connection setup, only\n"\
+"the unit(s) with the Authentication_Enable parameter enabled will try to\n"\
+"authenticate the other unit.",
+&hci_write_authentication_enable
+},
+{
+"read_encryption_mode",
+"\nThis command will read the value for the Encryption_Mode parameter. The\n" \
+"Encryption_Mode parameter controls if the local unit requires encryption\n" \
+"to the remote unit at connection setup (between the Create_Connection\n" \
+"command or acceptance of an incoming ACL connection and the corresponding\n" \
+"Connection Complete event). At connection setup, only the unit(s) with\n" \
+"the Authentication_Enable parameter enabled and Encryption_Mode parameter\n" \
+"enabled will try to encrypt the connection to the other unit.\n\n" \
+"\t<encryption_mode>:\n" \
+"\t0x00 - Encryption disabled.\n" \
+"\t0x01 - Encryption only for point-to-point packets.\n" \
+"\t0x02 - Encryption for both point-to-point and broadcast packets.",
+&hci_read_encryption_mode
+},
+{
+"write_encryption_mode mode(0|1|2)",
+"\tThis command will write the value for the Encryption_Mode parameter.\n" \
+"The Encryption_Mode parameter controls if the local unit requires\n" \
+"encryption to the remote unit at connection setup (between the\n" \
+"Create_Connection command or acceptance of an incoming ACL connection\n" \
+"and the corresponding Connection Complete event). At connection setup,\n" \
+"only the unit(s) with the Authentication_Enable parameter enabled and\n" \
+"Encryption_Mode parameter enabled will try to encrypt the connection to\n" \
+"the other unit.\n\n" \
+"\t<encryption_mode> (dd)\n" \
+"\t0 - Encryption disabled.\n" \
+"\t1 - Encryption only for point-to-point packets.\n" \
+"\t2 - Encryption for both point-to-point and broadcast packets.",
+&hci_write_encryption_mode
+},
+{
+"read_class_of_device",
+"\nThis command will read the value for the Class_of_Device parameter.\n" \
+"The Class_of_Device parameter is used to indicate the capabilities of\n" \
+"the local unit to other units.",
+&hci_read_class_of_device
+},
+{
+"write_class_of_device class(xx:xx:xx)",
+"\nThis command will write the value for the Class_of_Device parameter.\n" \
+"The Class_of_Device parameter is used to indicate the capabilities of \n" \
+"the local unit to other units.\n\n" \
+"\t<class> (xx:xx:xx) - class of device",
+&hci_write_class_of_device
+},
+{
+"read_voice_settings",
+"\nThis command will read the values for the Voice_Setting parameter.\n" \
+"The Voice_Setting parameter controls all the various settings for voice\n" \
+"connections. These settings apply to all voice connections, and cannot be\n" \
+"set for individual voice connections. The Voice_Setting parameter controls\n" \
+"the configuration for voice connections: Input Coding, Air coding format,\n" \
+"input data format, Input sample size, and linear PCM parameter.",
+&hci_read_voice_settings
+},
+{
+"write_voice_settings settings(xxxx)",
+"\nThis command will write the values for the Voice_Setting parameter.\n" \
+"The Voice_Setting parameter controls all the various settings for voice\n" \
+"connections. These settings apply to all voice connections, and cannot be\n" \
+"set for individual voice connections. The Voice_Setting parameter controls\n" \
+"the configuration for voice connections: Input Coding, Air coding format,\n" \
+"input data format, Input sample size, and linear PCM parameter.\n\n" \
+"\t<voice_settings> (xxxx) - voice settings",
+&hci_write_voice_settings
+},
+{
+"read_number_broadcast_retransmissions",
+"\nThis command will read the unit's parameter value for the Number of\n" \
+"Broadcast Retransmissions. Broadcast packets are not acknowledged and are\n" \
+"unreliable.",
+&hci_read_number_broadcast_retransmissions
+},
+{
+"write_number_broadcast_retransmissions count(dd)",
+"\nThis command will write the unit's parameter value for the Number of\n" \
+"Broadcast Retransmissions. Broadcast packets are not acknowledged and are\n" \
+"unreliable.\n\n" \
+"\t<count> (dd) - number of broadcast retransimissions",
+&hci_write_number_broadcast_retransmissions
+},
+{
+"read_hold_mode_activity",
+"\nThis command will read the value for the Hold_Mode_Activity parameter.\n" \
+"The Hold_Mode_Activity value is used to determine what activities should\n" \
+"be suspended when the unit is in hold mode.",
+&hci_read_hold_mode_activity
+},
+{
+"write_hold_mode_activity settings(0|1|2|4)",
+"\nThis command will write the value for the Hold_Mode_Activity parameter.\n" \
+"The Hold_Mode_Activity value is used to determine what activities should\n" \
+"be suspended when the unit is in hold mode.\n\n" \
+"\t<settings> (dd) - bit mask:\n" \
+"\t0 - Maintain current Power State. Default\n" \
+"\t1 - Suspend Page Scan.\n" \
+"\t2 - Suspend Inquiry Scan.\n" \
+"\t4 - Suspend Periodic Inquiries.",
+&hci_write_hold_mode_activity
+},
+{
+"read_sco_flow_control_enable",
+"\nThe Read_SCO_Flow_Control_Enable command provides the ability to read\n" \
+"the SCO_Flow_Control_Enable setting. By using this setting, the Host can\n" \
+"decide if the Host Controller will send Number Of Completed Packets events\n" \
+"for SCO Connection Handles. This setting allows the Host to enable and\n" \
+"disable SCO flow control.",
+&hci_read_sco_flow_control_enable
+},
+{
+"write_sco_flow_control_enable enable(0|1)",
+"\nThe Write_SCO_Flow_Control_Enable command provides the ability to write\n" \
+"the SCO_Flow_Control_Enable setting. By using this setting, the Host can\n" \
+"decide if the Host Controller will send Number Of Completed Packets events\n" \
+"for SCO Connection Handles. This setting allows the Host to enable and\n" \
+"disable SCO flow control. The SCO_Flow_Control_Enable setting can only be\n" \
+"changed if no connections exist.",
+&hci_write_sco_flow_control_enable
+},
+{
+"read_link_supervision_timeout <connection_handle>",
+"\nThis command will read the value for the Link_Supervision_Timeout\n" \
+"parameter for the device. The Link_Supervision_Timeout parameter is used\n" \
+"by the master or slave Bluetooth device to monitor link loss. If, for any\n" \
+"reason, no Baseband packets are received from that Connection Handle for a\n" \
+"duration longer than the Link_Supervision_Timeout, the connection is\n"
+"disconnected.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n",
+&hci_read_link_supervision_timeout
+},
+{
+"write_link_supervision_timeout <connection_handle> <timeout>",
+"\nThis command will write the value for the Link_Supervision_Timeout\n" \
+"parameter for the device. The Link_Supervision_Timeout parameter is used\n" \
+"by the master or slave Bluetooth device to monitor link loss. If, for any\n" \
+"reason, no Baseband packets are received from that connection handle for a\n" \
+"duration longer than the Link_Supervision_Timeout, the connection is\n" \
+"disconnected.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n" \
+"\t<timeout> - dddd; timeout measured in number of baseband slots\n",
+&hci_write_link_supervision_timeout
+},
+{ NULL, }
+};
+
diff --git a/usr.sbin/bluetooth/hccontrol/info.c b/usr.sbin/bluetooth/hccontrol/info.c
new file mode 100644
index 0000000..447a493
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/info.c
@@ -0,0 +1,219 @@
+/*
+ * info.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: info.c,v 1.7 2002/09/06 18:52:41 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <stdio.h>
+#include <string.h>
+#include "hccontrol.h"
+
+/* Send Read_Local_Version_Information command to the unit */
+static int
+hci_read_local_version_information(int s, int argc, char **argv)
+{
+ ng_hci_read_local_ver_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+ NG_HCI_OCF_READ_LOCAL_VER), (char *) &rp, &n) == ERROR)
+ return (ERROR);
+
+ if (rp.status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(rp.status), rp.status);
+ return (FAILED);
+ }
+
+ rp.manufacturer = le16toh(rp.manufacturer);
+
+ fprintf(stdout, "HCI version: %s [%#02x]\n",
+ hci_ver2str(rp.hci_version), rp.hci_version);
+ fprintf(stdout, "HCI revision: %#04x\n",
+ le16toh(rp.hci_revision));
+ fprintf(stdout, "LMP version: %#02x\n", rp.lmp_version);
+ fprintf(stdout, "LMP sub-version: %#04x\n",
+ le16toh(rp.lmp_subversion));
+ fprintf(stdout, "Manufacturer: %s [%#04x]\n",
+ hci_manufacturer2str(rp.manufacturer), rp.manufacturer);
+
+ return (OK);
+} /* hci_read_local_version_information */
+
+/* Send Read_Local_Supported_Features command to the unit */
+static int
+hci_read_local_supported_features(int s, int argc, char **argv)
+{
+ ng_hci_read_local_features_rp rp;
+ int n;
+ char buffer[1024];
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+ NG_HCI_OCF_READ_LOCAL_FEATURES),
+ (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, "Features: ");
+ for (n = 0; n < sizeof(rp.features); n++)
+ fprintf(stdout, "%#02x ", rp.features[n]);
+ fprintf(stdout, "\n%s\n", hci_features2str(rp.features,
+ buffer, sizeof(buffer)));
+
+ return (OK);
+} /* hci_read_local_supported_features */
+
+/* Sent Read_Buffer_Size command to the unit */
+static int
+hci_read_buffer_size(int s, int argc, char **argv)
+{
+ ng_hci_read_buffer_size_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+ NG_HCI_OCF_READ_BUFFER_SIZE),
+ (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, "Max. ACL packet size: %d bytes\n",
+ le16toh(rp.max_acl_size));
+ fprintf(stdout, "Number of ACL packets: %d\n",
+ le16toh(rp.num_acl_pkt));
+ fprintf(stdout, "Max. SCO packet size: %d bytes\n",
+ rp.max_sco_size);
+ fprintf(stdout, "Number of SCO packets: %d\n",
+ le16toh(rp.num_sco_pkt));
+
+ return (OK);
+} /* hci_read_buffer_size */
+
+/* Send Read_Country_Code command to the unit */
+static int
+hci_read_country_code(int s, int argc, char **argv)
+{
+ ng_hci_read_country_code_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+ NG_HCI_OCF_READ_COUNTRY_CODE),
+ (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, "Country code: %s [%#02x]\n",
+ hci_cc2str(rp.country_code), rp.country_code);
+
+ return (OK);
+} /* hci_read_country_code */
+
+/* Send Read_BD_ADDR command to the unit */
+static int
+hci_read_bd_addr(int s, int argc, char **argv)
+{
+ ng_hci_read_bdaddr_rp rp;
+ int n;
+
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+ NG_HCI_OCF_READ_BDADDR), (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, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ rp.bdaddr.b[5], rp.bdaddr.b[4], rp.bdaddr.b[3],
+ rp.bdaddr.b[2], rp.bdaddr.b[1], rp.bdaddr.b[0]);
+
+ return (OK);
+} /* hci_read_bd_addr */
+
+struct hci_command info_commands[] = {
+{
+"read_local_version_information",
+"\nThis command will read the values for the version information for the\n" \
+"local Bluetooth unit.",
+&hci_read_local_version_information
+},
+{
+"read_local_supported_features",
+"\nThis command requests a list of the supported features for the local\n" \
+"unit. This command will return a list of the LMP features.",
+&hci_read_local_supported_features
+},
+{
+"read_buffer_size",
+"\nThe Read_Buffer_Size command is used to read the maximum size of the\n" \
+"data portion of HCI ACL and SCO Data Packets sent from the Host to the\n" \
+"Host Controller.",
+&hci_read_buffer_size
+},
+{
+"read_country_code",
+"\nThis command will read the value for the Country_Code return parameter.\n" \
+"The Country_Code defines which range of frequency band of the ISM 2.4 GHz\n" \
+"band will be used by the unit.",
+&hci_read_country_code
+},
+{
+"read_bd_addr",
+"\nThis command will read the value for the BD_ADDR parameter. The BD_ADDR\n" \
+"is a 48-bit unique identifier for a Bluetooth unit.",
+&hci_read_bd_addr
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/bluetooth/hccontrol/link_control.c b/usr.sbin/bluetooth/hccontrol/link_control.c
new file mode 100644
index 0000000..68bf35f
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/link_control.c
@@ -0,0 +1,973 @@
+/*
+ * link_control.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_control.c,v 1.12 2002/09/17 16:36:46 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <stdio.h>
+#include <string.h>
+#include "hccontrol.h"
+
+static void hci_inquiry_response (int n, u_int8_t **b);
+
+/* Send Inquiry command to the unit */
+static int
+hci_inquiry(int s, int argc, char **argv)
+{
+ int n0, n1, n2, timo;
+ u_int8_t b[512];
+ ng_hci_inquiry_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+
+ /* set defaults */
+ cp.lap[2] = 0x9e;
+ cp.lap[1] = 0x8b;
+ cp.lap[0] = 0x33;
+ cp.inquiry_length = 5;
+ cp.num_responses = 8;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 3:
+ /* LAP */
+ if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3)
+ return (USAGE);
+
+ cp.lap[0] = (n0 & 0xff);
+ cp.lap[1] = (n1 & 0xff);
+ cp.lap[2] = (n2 & 0xff);
+
+ /* inquiry length (N * 1.28) sec, range 0x01 - 0x30 */
+ case 2:
+ if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x1 || n0 > 0x30)
+ return (USAGE);
+
+ cp.inquiry_length = (n0 & 0xff);
+
+ /* number of responses, range 0x00 - 0xff */
+ case 1:
+ if (sscanf(argv[2], "%d", &n0) != 1 || n0 > 0xff)
+ return (USAGE);
+
+ cp.num_responses = (n0 & 0xff);
+
+ /* use defaults */
+ case 0:
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send request and expect status back */
+ n0 = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_INQUIRY), (char const *) &cp, sizeof(cp),
+ b, &n0) == ERROR)
+ return (ERROR);
+
+ if (*b != 0x00)
+ return (FAILED);
+
+ timo = timeout;
+ timeout = cp.inquiry_length * 1.28 + 1;
+
+wait_for_more:
+ /* wait for inquiry events */
+ n0 = sizeof(b);
+ if (hci_recv(s, b, &n0) == ERROR) {
+ timeout = timo;
+ return (ERROR);
+ }
+
+ if (n0 < sizeof(*e)) {
+ timeout = timo;
+ errno = EIO;
+ return (ERROR);
+ }
+
+ switch (e->event) {
+ case NG_HCI_EVENT_INQUIRY_RESULT: {
+ ng_hci_inquiry_result_ep *ir =
+ (ng_hci_inquiry_result_ep *)(e + 1);
+ u_int8_t *r = (u_int8_t *)(ir + 1);
+
+ fprintf(stdout, "Inquiry result, num_responses=%d\n",
+ ir->num_responses);
+
+ for (n0 = 0; n0 < ir->num_responses; n0++)
+ hci_inquiry_response(n0, &r);
+
+ goto wait_for_more;
+ }
+
+ case NG_HCI_EVENT_INQUIRY_COMPL:
+ fprintf(stdout, "Inquiry complete. Status: %s [%#02x]\n",
+ hci_status2str(*(b + sizeof(*e))), *(b + sizeof(*e)));
+ break;
+
+ default:
+ goto wait_for_more;
+ }
+
+ timeout = timo;
+
+ return (OK);
+} /* hci_inquiry */
+
+/* Print Inquiry_Result event */
+static void
+hci_inquiry_response(int n, u_int8_t **b)
+{
+ struct inquiry_response {
+ bdaddr_t bdaddr;
+ u_int8_t page_scan_rep_mode;
+ u_int8_t page_scan_period_mode;
+ u_int8_t page_scan_mode;
+ u_int8_t class[NG_HCI_CLASS_SIZE];
+ u_int16_t clock_offset;
+ } *ir = (struct inquiry_response *)(*b);
+
+ fprintf(stdout, "Inquiry result #%d\n", n);
+ fprintf(stdout, "\tBD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ir->bdaddr.b[5], ir->bdaddr.b[4], ir->bdaddr.b[3],
+ ir->bdaddr.b[2], ir->bdaddr.b[1], ir->bdaddr.b[0]);
+ fprintf(stdout, "\tPage Scan Rep. Mode: %#02x\n",
+ ir->page_scan_rep_mode);
+ fprintf(stdout, "\tPage Scan Period Mode: %#02x\n",
+ ir->page_scan_period_mode);
+ fprintf(stdout, "\tPage Scan Mode: %#02x\n",
+ ir->page_scan_mode);
+ fprintf(stdout, "\tClass: %02x:%02x:%02x\n",
+ ir->class[2], ir->class[1], ir->class[0]);
+ fprintf(stdout, "\tClock offset: %#04x\n",
+ le16toh(ir->clock_offset));
+
+ *b += sizeof(*ir);
+} /* hci_inquiry_response */
+
+/* Send Create_Connection command to the unit */
+static int
+hci_create_connection(int s, int argc, char **argv)
+{
+ int n0, n1, n2, n3, n4, n5;
+ char b[512];
+ ng_hci_create_con_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+
+ /* Set defaults */
+ memset(&cp, 0, sizeof(cp));
+ cp.pkt_type = htole16( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
+ NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
+ NG_HCI_PKT_DM5);
+ cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
+ cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
+ cp.clock_offset = 0;
+ cp.accept_role_switch = 1;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 6:
+ /* accept role switch */
+ if (sscanf(argv[2], "%d", &n0) != 1)
+ return (USAGE);
+
+ cp.accept_role_switch = n0 ? 1 : 0;
+
+ case 5:
+ /* clock offset */
+ if (sscanf(argv[2], "%d", &n0) != 1)
+ return (USAGE);
+
+ cp.clock_offset = (n0 & 0xffff);
+ cp.clock_offset = htole16(cp.clock_offset);
+
+ case 4:
+ /* page scan mode */
+ if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 3)
+ return (USAGE);
+
+ cp.page_scan_mode = (n0 & 0xff);
+
+ case 3:
+ /* page scan rep mode */
+ if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 2)
+ return (USAGE);
+
+ cp.page_scan_rep_mode = (n0 & 0xff);
+
+ case 2:
+ /* packet type */
+ if (sscanf(argv[1], "%x", &n0) != 1)
+ return (USAGE);
+
+ n0 &= ( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
+ NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
+ NG_HCI_PKT_DM5);
+ if (n0 == 0)
+ return (USAGE);
+
+ cp.pkt_type = (n0 & 0xffff);
+ cp.pkt_type = htole16(cp.pkt_type);
+
+ case 1:
+ /* BD_ADDR */
+ 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);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send request and expect status response */
+ n0 = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_CREATE_CON),
+ (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_CON_COMPL) {
+ ng_hci_con_compl_ep *ep = (ng_hci_con_compl_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, "Connection handle: %d\n",
+ le16toh(ep->con_handle));
+ fprintf(stdout, "Encryption mode: %s [%d]\n",
+ hci_encrypt2str(ep->encryption_mode, 0),
+ ep->encryption_mode);
+ } else
+ goto again;
+
+ return (OK);
+} /* hci_create_connection */
+
+/* Send Disconnect command to the unit */
+static int
+hci_disconnect(int s, int argc, char **argv)
+{
+ int n;
+ char b[512];
+ ng_hci_discon_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+
+ /* Set defaults */
+ memset(&cp, 0, sizeof(cp));
+ cp.reason = 0x13;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 2:
+ /* reason */
+ if (sscanf(argv[1], "%d", &n) != 1 || n <= 0x00 || n > 0xff)
+ return (USAGE);
+
+ cp.reason = (u_int8_t) (n & 0xff);
+
+ 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 and expect status response */
+ n = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_DISCON),
+ (char const *) &cp, sizeof(cp), b, &n) == ERROR)
+ return (ERROR);
+
+ if (*b != 0x00)
+ return (FAILED);
+
+ /* wait for event */
+again:
+ n = sizeof(b);
+ if (hci_recv(s, b, &n) == ERROR)
+ return (ERROR);
+ if (n < sizeof(*e)) {
+ errno = EIO;
+ return (ERROR);
+ }
+
+ if (e->event == NG_HCI_EVENT_DISCON_COMPL) {
+ ng_hci_discon_compl_ep *ep = (ng_hci_discon_compl_ep *)(e + 1);
+
+ if (ep->status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(ep->status), ep->status);
+ return (FAILED);
+ }
+
+ fprintf(stdout, "Connection handle: %d\n",
+ le16toh(ep->con_handle));
+ fprintf(stdout, "Reason: %s [%#02x]\n",
+ hci_status2str(ep->reason), ep->reason);
+ } else
+ goto again;
+
+ return (OK);
+} /* hci_diconnect */
+
+/* Send Add_SCO_Connection command to the unit */
+static int
+hci_add_sco_connection(int s, int argc, char **argv)
+{
+ int n;
+ char b[512];
+ ng_hci_add_sco_con_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+
+ /* Set defaults */
+ memset(&cp, 0, sizeof(cp));
+ cp.pkt_type = htole16(NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);
+
+ /* parse command parameters */
+ switch (argc) {
+ case 2:
+ /* packet type */
+ if (sscanf(argv[0], "%x", &n) != 1)
+ return (USAGE);
+
+ n &= (NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);
+ if (n == 0)
+ return (USAGE);
+
+ cp.pkt_type = (u_int16_t) (n & 0x0fff);
+ cp.pkt_type = htole16(cp.pkt_type);
+
+ case 1:
+ /* acl 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 and expect status response */
+ n = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_ADD_SCO_CON),
+ (char const *) &cp, sizeof(cp), b, &n) == ERROR)
+ return (ERROR);
+
+ if (*b != 0x00)
+ return (FAILED);
+
+ /* wait for event */
+again:
+ n = sizeof(b);
+ if (hci_recv(s, b, &n) == ERROR)
+ return (ERROR);
+ if (n < sizeof(*e)) {
+ errno = EIO;
+ return (ERROR);
+ }
+
+ if (e->event == NG_HCI_EVENT_CON_COMPL) {
+ ng_hci_con_compl_ep *ep = (ng_hci_con_compl_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, "Connection handle: %d\n",
+ le16toh(ep->con_handle));
+ fprintf(stdout, "Encryption mode: %s [%d]\n",
+ hci_encrypt2str(ep->encryption_mode, 0),
+ ep->encryption_mode);
+ } else
+ goto again;
+
+ return (OK);
+} /* Add_SCO_Connection */
+
+/* Send Change_Connection_Packet_Type command to the unit */
+static int
+hci_change_connection_packet_type(int s, int argc, char **argv)
+{
+ int n;
+ char b[512];
+ ng_hci_change_con_pkt_type_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+
+ 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);
+
+ /* packet type */
+ if (sscanf(argv[1], "%x", &n) != 1)
+ return (USAGE);
+
+ cp.pkt_type = (u_int16_t) (n & 0xffff);
+ cp.pkt_type = htole16(cp.pkt_type);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send request and expect status response */
+ n = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_CHANGE_CON_PKT_TYPE),
+ (char const *) &cp, sizeof(cp), b, &n) == ERROR)
+ return (ERROR);
+
+ if (*b != 0x00)
+ return (FAILED);
+
+ /* wait for event */
+again:
+ n = sizeof(b);
+ if (hci_recv(s, b, &n) == ERROR)
+ return (ERROR);
+ if (n < sizeof(*e)) {
+ errno = EIO;
+ return (ERROR);
+ }
+
+ if (e->event == NG_HCI_EVENT_CON_PKT_TYPE_CHANGED) {
+ ng_hci_con_pkt_type_changed_ep *ep =
+ (ng_hci_con_pkt_type_changed_ep *)(e + 1);
+
+ if (ep->status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(ep->status), ep->status);
+ return (FAILED);
+ }
+
+ fprintf(stdout, "Connection handle: %d\n",
+ le16toh(ep->con_handle));
+ fprintf(stdout, "Packet type: %#04x\n",
+ le16toh(ep->pkt_type));
+ } else
+ goto again;
+
+ return (OK);
+} /* hci_change_connection_packet_type */
+
+/* Send Remote_Name_Request command to the unit */
+static int
+hci_remote_name_request(int s, int argc, char **argv)
+{
+ int n0, n1, n2, n3, n4, n5;
+ char b[512];
+ ng_hci_remote_name_req_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 4:
+ /* BD_ADDR */
+ 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);
+
+ /* page_scan_rep_mode */
+ if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x02)
+ return (USAGE);
+
+ cp.page_scan_rep_mode = (n0 & 0xff);
+
+ /* page_scan_mode */
+ if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x03)
+ return (USAGE);
+
+ cp.page_scan_mode = (n0 & 0xff);
+
+ /* clock_offset */
+ if (sscanf(argv[3], "%x", &n0) != 1)
+ return (USAGE);
+
+ cp.clock_offset = (n0 & 0xffff);
+ cp.clock_offset = htole16(cp.clock_offset);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send request and expect status response */
+ n0 = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_REMOTE_NAME_REQ),
+ (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_REMOTE_NAME_REQ_COMPL) {
+ ng_hci_remote_name_req_compl_ep *ep =
+ (ng_hci_remote_name_req_compl_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, "Name: %s\n", ep->name);
+ } else
+ goto again;
+
+ return (OK);
+} /* hci_remote_name_request */
+
+/* Send Read_Remote_Supported_Features command to the unit */
+static int
+hci_read_remote_supported_features(int s, int argc, char **argv)
+{
+ int n;
+ char b[512];
+ ng_hci_read_remote_features_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+ char buffer[1024];
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ /* connecton handle */
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
+ return (USAGE);
+
+ cp.con_handle = (n & 0x0fff);
+ cp.con_handle = htole16(cp.con_handle);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send request and expect status response */
+ n = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_READ_REMOTE_FEATURES),
+ (char const *) &cp, sizeof(cp), b, &n) == ERROR)
+ return (ERROR);
+
+ if (*b != 0x00)
+ return (FAILED);
+
+ /* wait for event */
+again:
+ n = sizeof(b);
+ if (hci_recv(s, b, &n) == ERROR)
+ return (ERROR);
+
+ if (n < sizeof(*e)) {
+ errno = EIO;
+ return (ERROR);
+ }
+
+ if (e->event == NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL) {
+ ng_hci_read_remote_features_compl_ep *ep =
+ (ng_hci_read_remote_features_compl_ep *)(e + 1);
+
+ if (ep->status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(ep->status), ep->status);
+ return (FAILED);
+ }
+
+ fprintf(stdout, "Connection handle: %d\n",
+ le16toh(ep->con_handle));
+ fprintf(stdout, "Features: ");
+ for (n = 0; n < sizeof(ep->features); n++)
+ fprintf(stdout, "%#02x ", ep->features[n]);
+ fprintf(stdout, "\n%s\n", hci_features2str(ep->features,
+ buffer, sizeof(buffer)));
+ } else
+ goto again;
+
+ return (OK);
+} /* hci_read_remote_supported_features */
+
+/* Send Read_Remote_Version_Information command to the unit */
+static int
+hci_read_remote_version_information(int s, int argc, char **argv)
+{
+ int n;
+ char b[512];
+ ng_hci_read_remote_ver_info_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ /* connecton handle */
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
+ return (USAGE);
+
+ cp.con_handle = (n & 0x0fff);
+ cp.con_handle = htole16(cp.con_handle);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send request and expect status response */
+ n = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_READ_REMOTE_VER_INFO),
+ (char const *) &cp, sizeof(cp), b, &n) == ERROR)
+ return (ERROR);
+
+ if (*b != 0x00)
+ return (FAILED);
+
+ /* wait for event */
+again:
+ n = sizeof(b);
+ if (hci_recv(s, b, &n) == ERROR)
+ return (ERROR);
+
+ if (n < sizeof(*e)) {
+ errno = EIO;
+ return (ERROR);
+ }
+
+ if (e->event == NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL) {
+ ng_hci_read_remote_ver_info_compl_ep *ep =
+ (ng_hci_read_remote_ver_info_compl_ep *)(e + 1);
+
+ if (ep->status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(ep->status), ep->status);
+ return (FAILED);
+ }
+
+ ep->manufacturer = le16toh(ep->manufacturer);
+
+ fprintf(stdout, "Connection handle: %d\n",
+ le16toh(ep->con_handle));
+ fprintf(stdout, "LMP version: %#02x\n", ep->lmp_version);
+ fprintf(stdout, "LMP sub-version: %#04x\n",
+ le16toh(ep->lmp_subversion));
+ fprintf(stdout, "Manufacturer: %s [%#04x]\n",
+ hci_manufacturer2str(ep->manufacturer),
+ ep->manufacturer);
+ } else
+ goto again;
+
+ return (OK);
+} /* hci_read_remote_version_information */
+
+/* Send Read_Clock_Offset command to the unit */
+static int
+hci_read_clock_offset(int s, int argc, char **argv)
+{
+ int n;
+ char b[512];
+ ng_hci_read_clock_offset_cp cp;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
+
+ /* parse command parameters */
+ switch (argc) {
+ case 1:
+ /* connecton handle */
+ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
+ return (USAGE);
+
+ cp.con_handle = (n & 0x0fff);
+ cp.con_handle = htole16(cp.con_handle);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ /* send request and expect status response */
+ n = sizeof(b);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_READ_CLOCK_OFFSET),
+ (char const *) &cp, sizeof(cp), b, &n) == ERROR)
+ return (ERROR);
+
+ if (*b != 0x00)
+ return (FAILED);
+
+ /* wait for event */
+again:
+ n = sizeof(b);
+ if (hci_recv(s, b, &n) == ERROR)
+ return (ERROR);
+
+ if (n < sizeof(*e)) {
+ errno = EIO;
+ return (ERROR);
+ }
+
+ if (e->event == NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL) {
+ ng_hci_read_clock_offset_compl_ep *ep =
+ (ng_hci_read_clock_offset_compl_ep *)(e + 1);
+
+ if (ep->status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(ep->status), ep->status);
+ return (FAILED);
+ }
+
+ fprintf(stdout, "Connection handle: %d\n",
+ le16toh(ep->con_handle));
+ fprintf(stdout, "Clock offset: %#04x\n",
+ le16toh(ep->clock_offset));
+ } else
+ goto again;
+
+ return (OK);
+} /* hci_read_clock_offset */
+
+struct hci_command link_control_commands[] = {
+{
+"inquiry <LAP> <inquiry_length> <num_reponses>",
+"\nThis command will cause the Bluetooth unit to enter Inquiry Mode.\n" \
+"Inquiry Mode is used to discover other nearby Bluetooth units. The LAP\n" \
+"input parameter contains the LAP from which the inquiry access code shall\n" \
+"be derived when the inquiry procedure is made. The Inquiry_Length parameter\n"\
+"specifies the total duration of the Inquiry Mode and, when this time\n" \
+"expires, Inquiry will be halted. The Num_Responses parameter specifies the\n" \
+"number of responses that can be received before the Inquiry is halted.\n\n" \
+"\t<LAP> - xx:xx:xx; 9e:8b:33 (GIAC), 93:8b:00 (LDIAC)\n" \
+"\t<inquiry_length> - dd; total length == dd * 1.28 sec\n" \
+"\t<num_responses> - dd",
+&hci_inquiry
+},
+{
+"create_connection <BD_ADDR> <pkt> <rep_mode> <ps_mode> <clck_off> <role_sw>",
+"" \
+"\t<BD_ADDR> - remote unit address\n\n" \
+"\t<pkt> - xxxx; packet type\n" \
+"" \
+"\t\tACL packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0008 DM1\n" \
+"\t\t0x0010 DH1\n" \
+"\t\t0x0400 DM3\n" \
+"\t\t0x0800 DH3\n" \
+"\t\t0x4000 DM5\n" \
+"\t\t0x8000 DH5\n\n" \
+"" \
+"\trep_mode - d; page scan repetition mode\n" \
+"" \
+"\t\tPage scan repetition modes\n" \
+"\t\t--------------------------\n" \
+"\t\t0 Page scan repetition mode 0\n" \
+"\t\t1 Page scan repetition mode 1\n" \
+"\t\t2 Page scan repetition mode 2\n" \
+"\n" \
+"\tps_mode - d; Page scan mode\n" \
+"" \
+"\t\tPage scan modes\n" \
+"\t\t---------------\n" \
+"\t\t0 Mandatory page scan mode\n" \
+"\t\t1 Optional page scan mode1\n" \
+"\t\t2 Optional page scan mode2\n" \
+"\t\t3 Optional page scan mode3\n" \
+"\n" \
+"\tclck_off - dddd; clock offset. Use 0 if unknown\n\n" \
+"\trole_sw - d; allow (1) or deny role switch\n",
+&hci_create_connection
+},
+{
+"disconnect <connection_handle> <reason>",
+"\nThe Disconnection command is used to terminate an existing connection.\n" \
+"The connection handle command parameter indicates which connection is to\n" \
+"be disconnected. The Reason command parameter indicates the reason for\n" \
+"ending the connection.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n" \
+"\t<reason> - dd; reason; usually 19 (0x13) - user ended;\n" \
+"\t also 0x05, 0x13-0x15, 0x1A, 0x29",
+&hci_disconnect
+},
+{
+"add_sco_connection <acl connection handle> <packet type>",
+"This command will cause the link manager to create a SCO connection using\n" \
+"the ACL connection specified by the connection handle command parameter.\n" \
+"The Link Manager will determine how the new connection is established. This\n"\
+"connection is determined by the current state of the device, its piconet,\n" \
+"and the state of the device to be connected. The packet type command parameter\n" \
+"specifies which packet types the Link Manager should use for the connection.\n"\
+"The Link Manager must only use the packet type(s) specified by the packet\n" \
+"type command parameter for sending HCI SCO data packets. Multiple packet\n" \
+"types may be specified for the packet type command parameter by performing\n" \
+"a bitwise OR operation of the different packet types. Note: An SCO connection\n" \
+"can only be created when an ACL connection already exists and when it is\n" \
+"not put in park mode.\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n" \
+"\t<packet_type> - xxxx; packet type\n" \
+"" \
+"\t\tSCO packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0020 HV1\n" \
+"\t\t0x0040 HV2\n" \
+"\t\t0x0080 HV3\n",
+&hci_add_sco_connection
+},
+{
+"change_connection_packet_type <connection_hande> <packet_type>",
+"The Change_Connection_Packet_Type command is used to change which packet\n" \
+"types can be used for a connection that is currently established. This\n" \
+"allows current connections to be dynamically modified to support different\n" \
+"types of user data. The Packet_Type command parameter specifies which\n" \
+"packet types the Link Manager can use for the connection. Multiple packet\n" \
+"types may be specified for the Packet_Type command parameter by bitwise OR\n" \
+"operation of the different packet types.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n" \
+"\t<packet_type> - xxxx; packet type mask\n" \
+"" \
+"\t\tACL packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0008 DM1\n" \
+"\t\t0x0010 DH1\n" \
+"\t\t0x0400 DM3\n" \
+"\t\t0x0800 DH3\n" \
+"\t\t0x4000 DM5\n" \
+"\t\t0x8000 DH5\n\n" \
+"" \
+"\t\tSCO packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0020 HV1\n" \
+"\t\t0x0040 HV2\n" \
+"\t\t0x0080 HV3\n" \
+"",
+&hci_change_connection_packet_type
+},
+{
+"remote_name_request <bdaddr> <ps_rep_mode> <ps_mode> <clock_offset>",
+"\nThe Remote_Name_Request command is used to obtain the user-friendly\n" \
+"name of another Bluetooth unit.\n\n" \
+"\t<bdaddr> - xx:xx:xx:xx:xx:xx remote unit BD_ADDR\n" \
+"\t<ps_rep_mode> - dd; page scan repetition mode [0-2]\n" \
+"\t<ps_mode> - dd; page scan mode [0-3]\n" \
+"\t<clock_offset> - xxxx; clock offset [0 - 0xffff]",
+&hci_remote_name_request
+},
+{
+"read_remote_supported_features <connection_handle>",
+"\nThis command requests a list of the supported features for the remote\n" \
+"unit identified by the connection handle parameter. The connection handle\n" \
+"must be a connection handle for an ACL connection.\n\n" \
+"\t<connection_handle> - dddd; connection handle",
+&hci_read_remote_supported_features
+},
+{
+"read_remote_version_information <connection_handle>",
+"\nThis command will obtain the values for the version information for the\n" \
+"remote Bluetooth unit identified by the connection handle parameter. The\n" \
+"connection handle must be a connection handle for an ACL connection.\n\n" \
+"\t<conneciton_handle> - dddd; connection handle",
+&hci_read_remote_version_information
+},
+{
+"read_clock_offset <connection_handle>",
+"\nThis command allows the Host to read clock offset to remote unit.\n" \
+"\t<conneciton_handle> - dddd; connection handle",
+&hci_read_clock_offset
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/bluetooth/hccontrol/link_policy.c b/usr.sbin/bluetooth/hccontrol/link_policy.c
new file mode 100644
index 0000000..dec9259
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/link_policy.c
@@ -0,0 +1,310 @@
+/*
+ * 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,
+}};
+
diff --git a/usr.sbin/bluetooth/hccontrol/node.c b/usr.sbin/bluetooth/hccontrol/node.c
new file mode 100644
index 0000000..b7ff33a
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/node.c
@@ -0,0 +1,518 @@
+/*
+ * node.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: node.c,v 1.8 2002/11/12 22:33:17 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <bitstring.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <ng_l2cap.h>
+#include <ng_btsocket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "hccontrol.h"
+
+/* Send Read_Node_State command to the node */
+static int
+hci_read_node_state(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_state r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "Node: %s\nState: %#x\n", r.hci_node, r.state);
+
+ return (OK);
+} /* hci_read_node_state */
+
+/* Send Intitialize command to the node */
+static int
+hci_node_initialize(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_init r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_INIT, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ return (OK);
+} /* hci_node_initialize */
+
+/* Send Read_Debug_Level command to the node */
+static int
+hci_read_debug_level(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_debug r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "Node: %s\nDebug level: %d\n", r.hci_node, r.debug);
+
+ return (OK);
+} /* hci_read_debug_level */
+
+/* Send Write_Debug_Level command to the node */
+static int
+hci_write_debug_level(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_debug r;
+
+ memset(&r, 0, sizeof(r));
+ switch (argc) {
+ case 1:
+ r.debug = atoi(argv[0]);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ return (OK);
+} /* hci_write_debug_level */
+
+/* Send Read_Node_Buffer_Size command to the node */
+static int
+hci_read_node_buffer_size(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_buffer r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "Node: %s\n",
+ r.hci_node);
+ fprintf(stdout, "Number of free command buffers: %d\n",
+ r.buffer.cmd_free);
+ fprintf(stdout, "Max. ACL packet size: %d\n",
+ r.buffer.acl_size);
+ fprintf(stdout, "Numbef of free ACL buffers: %d\n",
+ r.buffer.acl_free);
+ fprintf(stdout, "Total number of ACL buffers: %d\n",
+ r.buffer.acl_pkts);
+ fprintf(stdout, "Max. SCO packet size: %d\n",
+ r.buffer.sco_size);
+ fprintf(stdout, "Numbef of free SCO buffers: %d\n",
+ r.buffer.sco_free);
+ fprintf(stdout, "Total number of SCO buffers: %d\n",
+ r.buffer.sco_pkts);
+
+ return (OK);
+} /* hci_read_node_buffer_size */
+
+/* Send Read_Node_BD_ADDR command to the node */
+static int
+hci_read_node_bd_addr(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_bdaddr r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "Node: %s\n", r.hci_node);
+ fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ r.bdaddr.b[5], r.bdaddr.b[4], r.bdaddr.b[3],
+ r.bdaddr.b[2], r.bdaddr.b[1], r.bdaddr.b[0]);
+
+ return (OK);
+} /* hci_read_node_bd_addr */
+
+/* Send Read_Node_Features command to the node */
+static int
+hci_read_node_features(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_features r;
+ int n;
+ char buffer[1024];
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "Node: %s\nFeatures: ", r.hci_node);
+ for (n = 0; n < sizeof(r.features)/sizeof(r.features[0]); n++)
+ fprintf(stdout, "%#02x ", r.features[n]);
+ fprintf(stdout, "\n%s\n", hci_features2str(r.features,
+ buffer, sizeof(buffer)));
+
+ return (OK);
+} /* hci_read_node_features */
+
+/* Send Read_Node_Stat command to the node */
+static int
+hci_read_node_stat(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_stat r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "Node: %s\n", r.hci_node);
+ fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent);
+ fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv);
+ fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv);
+ fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent);
+ fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv);
+ fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent);
+ fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv);
+ fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent);
+
+ return (OK);
+} /* hci_read_node_stat */
+
+/* Send Reset_Node_Stat command to the node */
+static int
+hci_reset_node_stat(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_reset_stat r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ return (OK);
+} /* hci_reset_node_stat */
+
+/* Send Flush_Neighbor_Cache command to the node */
+static int
+hci_flush_neighbor_cache(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_flush_neighbor_cache r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE,
+ &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ return (OK);
+} /* hci_flush_neighbor_cache */
+
+/* Send Read_Neighbor_Cache command to the node */
+static int
+hci_read_neighbor_cache(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_neighbor_cache r;
+ int n, error = OK;
+
+ memset(&r, 0, sizeof(r));
+ r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM;
+ r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM,
+ sizeof(ng_hci_node_neighbor_cache_entry_ep));
+ if (r.entries == NULL) {
+ errno = ENOMEM;
+ return (ERROR);
+ }
+
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r,
+ sizeof(r)) < 0) {
+ error = ERROR;
+ goto out;
+ }
+
+ fprintf(stdout, "Neighbor cache for the node: %s\n", r.hci_node);
+ fprintf(stdout,
+"BD_ADDR " \
+"Features " \
+"Clock offset " \
+"Page scan " \
+"Rep. scan\n");
+
+ for (n = 0; n < r.num_entries; n++) {
+ fprintf(stdout,
+"%02x:%02x:%02x:%02x:%02x:%02x " \
+"%02x %02x %02x %02x %02x %02x %02x %02x " \
+"%#12x " \
+"%#9x " \
+"%#9x\n",
+ r.entries[n].bdaddr.b[5], r.entries[n].bdaddr.b[4],
+ r.entries[n].bdaddr.b[3], r.entries[n].bdaddr.b[2],
+ r.entries[n].bdaddr.b[1], r.entries[n].bdaddr.b[0],
+ r.entries[n].features[0], r.entries[n].features[1],
+ r.entries[n].features[2], r.entries[n].features[3],
+ r.entries[n].features[4], r.entries[n].features[5],
+ r.entries[n].features[6], r.entries[n].features[7],
+ r.entries[n].clock_offset, r.entries[n].page_scan_mode,
+ r.entries[n].page_scan_rep_mode);
+ }
+out:
+ free(r.entries);
+
+ return (error);
+} /* hci_read_neightbor_cache */
+
+/* Send Read_Connection_List command to the node */
+static int
+hci_read_connection_list(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_con_list r;
+ int n, error = OK;
+
+ memset(&r, 0, sizeof(r));
+ r.num_connections = NG_HCI_MAX_CON_NUM;
+ r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep));
+ if (r.connections == NULL) {
+ errno = ENOMEM;
+ return (ERROR);
+ }
+
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
+ error = ERROR;
+ goto out;
+ }
+
+ fprintf(stdout, "Connections list for the node: %s\n", r.hci_node);
+ fprintf(stdout,
+"Remote BD_ADDR " \
+"Handle " \
+"Type " \
+"Mode " \
+"Role " \
+"Encrypt " \
+"Pending " \
+"Queue " \
+"State\n");
+
+ for (n = 0; n < r.num_connections; n++) {
+ fprintf(stdout,
+"%02x:%02x:%02x:%02x:%02x:%02x " \
+"%6d " \
+"%4.4s " \
+"%4d " \
+"%4.4s " \
+"%7.7s " \
+"%7d " \
+"%5d " \
+"%s\n",
+ r.connections[n].bdaddr.b[5],
+ r.connections[n].bdaddr.b[4],
+ r.connections[n].bdaddr.b[3],
+ r.connections[n].bdaddr.b[2],
+ r.connections[n].bdaddr.b[1],
+ r.connections[n].bdaddr.b[0],
+ r.connections[n].con_handle,
+ (r.connections[n].link_type == NG_HCI_LINK_ACL)?
+ "ACL" : "SCO",
+ r.connections[n].mode,
+ (r.connections[n].role == NG_HCI_ROLE_MASTER)?
+ "MAST" : "SLAV",
+ hci_encrypt2str(r.connections[n].encryption_mode, 1),
+ r.connections[n].pending,
+ r.connections[n].queue_len,
+ hci_con_state2str(r.connections[n].state));
+ }
+out:
+ free(r.connections);
+
+ return (error);
+} /* hci_read_connection_list */
+
+/* Send Read_Link_Policy_Settings_Mask command to the node */
+int
+hci_read_link_policy_settings_mask(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_link_policy_mask r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "Node: %s\nLink Policy Settings mask: %#04x\n",
+ r.hci_node, r.policy_mask);
+
+ return (OK);
+} /* hci_read_link_policy_settings_mask */
+
+/* Send Write_Link_Policy_Settings_Mask command to the node */
+int
+hci_write_link_policy_settings_mask(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_link_policy_mask r;
+ int m;
+
+ memset(&r, 0, sizeof(r));
+
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%x", &m) != 1)
+ return (USAGE);
+
+ r.policy_mask = (m & 0xffff);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ return (OK);
+} /* hci_write_link_policy_settings_mask */
+
+/* Send Read_Packet_Mask command to the node */
+int
+hci_read_packet_mask(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_packet_mask r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "Node: %s\nPacket mask: %#04x\n",
+ r.hci_node, r.packet_mask);
+
+ return (OK);
+} /* hci_read_packet_mask */
+
+/* Send Write_Packet_Mask command to the node */
+int
+hci_write_packet_mask(int s, int argc, char **argv)
+{
+ struct ng_btsocket_hci_raw_node_packet_mask r;
+ int m;
+
+ memset(&r, 0, sizeof(r));
+
+ switch (argc) {
+ case 1:
+ if (sscanf(argv[0], "%x", &m) != 1)
+ return (USAGE);
+
+ r.packet_mask = (m & 0xffff);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ return (OK);
+} /* hci_write_packet_mask */
+
+struct hci_command node_commands[] = {
+{
+"read_node_state",
+"Get HCI node state",
+&hci_read_node_state
+},
+{
+"initialize",
+"Initialize HCI node",
+&hci_node_initialize
+},
+{
+"read_debug_level",
+"Read HCI node debug level",
+&hci_read_debug_level
+},
+{
+"write_debug_level <level>",
+"Write HCI node debug level",
+&hci_write_debug_level
+},
+{
+"read_node_buffer_size",
+"Read HCI node buffer information",
+&hci_read_node_buffer_size
+},
+{
+"read_node_bd_addr",
+"Read HCI node BD_ADDR",
+&hci_read_node_bd_addr
+},
+{
+"read_node_features",
+"Read HCI node features",
+&hci_read_node_features
+},
+{
+"read_node_stat",
+"Read HCI node statistic information",
+&hci_read_node_stat
+},
+{
+"reset_node_stat",
+"Reset HCI node statistic information",
+&hci_reset_node_stat
+},
+{
+"flush_neighbor_cache",
+"Flush HCI node neighbor cache",
+&hci_flush_neighbor_cache
+},
+{
+"read_neighbor_cache",
+"Read HCI node neighbor cache",
+&hci_read_neighbor_cache
+},
+{
+"read_connection_list",
+"Read connection list",
+&hci_read_connection_list
+},
+{
+"read_node_link_policy_settings_mask",
+"Read Link Policy Settinngs mask for the node",
+&hci_read_link_policy_settings_mask
+},
+{
+"write_node_link_policy_settings_mask <policy_mask>",
+"Write Link Policy Settinngs mask for the node. Policy mask - xxxx",
+&hci_write_link_policy_settings_mask
+},
+{
+"read_node_packet_mask",
+"Read Packet mask for the node",
+&hci_read_packet_mask
+},
+{
+"write_node_packet_mask <packet_mask>",
+"Write Packet mask for the node. Packet mask - xxxx",
+&hci_write_packet_mask
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/bluetooth/hccontrol/send_recv.c b/usr.sbin/bluetooth/hccontrol/send_recv.c
new file mode 100644
index 0000000..aff6f93
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/send_recv.c
@@ -0,0 +1,184 @@
+/*
+ * send_recv.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: send_recv.c,v 1.4 2002/09/04 21:31:30 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/endian.h>
+#include <assert.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <string.h>
+#include <unistd.h>
+#include "hccontrol.h"
+
+/* Send HCI request to the unit */
+int
+hci_request(int s, int opcode, char const *cp, int cp_size, char *rp, int *rp_size)
+{
+ char buffer[512];
+ int n;
+ ng_hci_cmd_pkt_t *c = (ng_hci_cmd_pkt_t *) buffer;
+ ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) buffer;
+
+ assert(rp != NULL);
+ assert(*rp_size != NULL);
+ assert(*rp_size > 0);
+
+ c->type = NG_HCI_CMD_PKT;
+ c->opcode = (u_int16_t) opcode;
+ c->opcode = htole16(c->opcode);
+
+ if (cp != NULL) {
+ assert(0 < cp_size && cp_size <= NG_HCI_CMD_PKT_SIZE);
+
+ c->length = (u_int8_t) cp_size;
+ memcpy(buffer + sizeof(*c), cp, cp_size);
+ } else
+ c->length = 0;
+
+ if (hci_send(s, buffer, sizeof(*c) + cp_size) == ERROR)
+ return (ERROR);
+
+again:
+ n = sizeof(buffer);
+ if (hci_recv(s, buffer, &n) == ERROR)
+ return (ERROR);
+
+ if (n < sizeof(*e)) {
+ errno = EMSGSIZE;
+ return (ERROR);
+ }
+
+ if (e->type != NG_HCI_EVENT_PKT) {
+ errno = EIO;
+ return (ERROR);
+ }
+
+ switch (e->event) {
+ case NG_HCI_EVENT_COMMAND_COMPL: {
+ ng_hci_command_compl_ep *cc =
+ (ng_hci_command_compl_ep *)(e + 1);
+
+ cc->opcode = le16toh(cc->opcode);
+
+ if (cc->opcode == 0x0000 || cc->opcode != opcode)
+ goto again;
+
+ n -= (sizeof(*e) + sizeof(*cc));
+ if (n < *rp_size)
+ *rp_size = n;
+
+ memcpy(rp, buffer + sizeof(*e) + sizeof(*cc), *rp_size);
+ } break;
+
+ case NG_HCI_EVENT_COMMAND_STATUS: {
+ ng_hci_command_status_ep *cs =
+ (ng_hci_command_status_ep *)(e + 1);
+
+ cs->opcode = le16toh(cs->opcode);
+
+ if (cs->opcode == 0x0000 || cs->opcode != opcode)
+ goto again;
+
+ *rp_size = 1;
+ *rp = cs->status;
+ } break;
+
+ default:
+ goto again;
+ }
+
+ return (OK);
+} /* hci_request */
+
+/* Send simple HCI request - Just HCI command packet (no parameters) */
+int
+hci_simple_request(int s, int opcode, char *rp, int *rp_size)
+{
+ return (hci_request(s, opcode, NULL, 0, rp, rp_size));
+} /* hci_simple_request */
+
+/* Send HCI data to the unit */
+int
+hci_send(int s, char const *buffer, int size)
+{
+ assert(buffer != NULL);
+ assert(size >= sizeof(ng_hci_cmd_pkt_t));
+ assert(size <= sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE);
+
+ if (send(s, buffer, size, 0) < 0)
+ return (ERROR);
+
+ return (OK);
+} /* hci_send */
+
+/* Receive HCI data from the unit */
+int
+hci_recv(int s, char *buffer, int *size)
+{
+ struct timeval tv;
+ fd_set rfd;
+ int n;
+
+ assert(buffer != NULL);
+ assert(size != NULL);
+ assert(*size > sizeof(ng_hci_event_pkt_t));
+
+again:
+ FD_ZERO(&rfd);
+ FD_SET(s, &rfd);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ n = select(s + 1, &rfd, NULL, NULL, &tv);
+ if (n <= 0) {
+ if (n < 0) {
+ if (errno == EINTR)
+ goto again;
+ } else
+ errno = ETIMEDOUT;
+
+ return (ERROR);
+ }
+
+ assert(FD_ISSET(s, &rfd));
+
+ n = recv(s, buffer, *size, 0);
+ if (n < 0)
+ return (ERROR);
+
+ *size = n;
+
+ return (OK);
+} /* hci_recv */
+
diff --git a/usr.sbin/bluetooth/hccontrol/status.c b/usr.sbin/bluetooth/hccontrol/status.c
new file mode 100644
index 0000000..c857349
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/status.c
@@ -0,0 +1,245 @@
+/*
+ * status.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: status.c,v 1.2 2002/09/06 18:52:41 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 Read_Failed_Contact_Counter command to the unit */
+static int
+hci_read_failed_contact_counter(int s, int argc, char **argv)
+{
+ ng_hci_read_failed_contact_cntr_cp cp;
+ ng_hci_read_failed_contact_cntr_rp rp;
+ int n;
+
+ 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 command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
+ NG_HCI_OCF_READ_FAILED_CONTACT_CNTR),
+ (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, "Failed contact counter: %d\n", le16toh(rp.counter));
+
+ return (OK);
+} /* hci_read_failed_contact_counter */
+
+/* Send Reset_Failed_Contact_Counter command to the unit */
+static int
+hci_reset_failed_contact_counter(int s, int argc, char **argv)
+{
+ ng_hci_reset_failed_contact_cntr_cp cp;
+ ng_hci_reset_failed_contact_cntr_rp rp;
+ int n;
+
+ 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 command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
+ NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR),
+ (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_reset_failed_contact_counter */
+
+/* Sent Get_Link_Quality command to the unit */
+static int
+hci_get_link_quality(int s, int argc, char **argv)
+{
+ ng_hci_get_link_quality_cp cp;
+ ng_hci_get_link_quality_rp rp;
+ int n;
+
+ 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 command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
+ NG_HCI_OCF_GET_LINK_QUALITY),
+ (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 quality: %d\n", le16toh(rp.quality));
+
+ return (OK);
+} /* hci_get_link_quality */
+
+/* Send Read_RSSI command to the unit */
+static int
+hci_read_rssi(int s, int argc, char **argv)
+{
+ ng_hci_read_rssi_cp cp;
+ ng_hci_read_rssi_rp rp;
+ int n;
+
+ 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 command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
+ NG_HCI_OCF_READ_RSSI),
+ (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, "RSSI: %d dB\n", (int) rp.rssi);
+
+ return (OK);
+} /* hci_read_rssi */
+
+struct hci_command status_commands[] = {
+{
+"read_failed_contact_counter <connection_handle>",
+"\nThis command will read the value for the Failed_Contact_Counter\n" \
+"parameter for a particular ACL connection to another device.\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n",
+&hci_read_failed_contact_counter
+},
+{
+"reset_failed_contact_counter <connection_handle>",
+"\nThis command will reset the value for the Failed_Contact_Counter\n" \
+"parameter for a particular ACL connection to another device.\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n",
+&hci_reset_failed_contact_counter
+},
+{
+"get_link_quality <connection_handle>",
+"\nThis command will return the value for the Link_Quality for the\n" \
+"specified ACL connection handle. This command will return a Link_Quality\n" \
+"value from 0-255, which represents the quality of the link between two\n" \
+"Bluetooth devices. The higher the value, the better the link quality is.\n" \
+"Each Bluetooth module vendor will determine how to measure the link quality." \
+"\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n",
+&hci_get_link_quality
+},
+{
+"read_rssi <connection_handle>",
+"\nThis command will read the value for the difference between the\n" \
+"measured Received Signal Strength Indication (RSSI) and the limits of\n" \
+"the Golden Receive Power Range for a ACL connection handle to another\n" \
+"Bluetooth device. Any positive RSSI value returned by the Host Controller\n" \
+"indicates how many dB the RSSI is above the upper limit, any negative\n" \
+"value indicates how many dB the RSSI is below the lower limit. The value\n" \
+"zero indicates that the RSSI is inside the Golden Receive Power Range.\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n",
+&hci_read_rssi
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/bluetooth/hccontrol/util.c b/usr.sbin/bluetooth/hccontrol/util.c
new file mode 100644
index 0000000..51868b4
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/util.c
@@ -0,0 +1,350 @@
+/*
+ * util.c
+ *
+ * Copyright (c) 2001 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: util.c,v 1.2 2002/09/12 18:19:43 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#define SIZE(x) (sizeof((x))/sizeof((x)[0]))
+
+char const * const
+hci_link2str(int link_type)
+{
+ static char const * const t[] = {
+ /* NG_HCI_LINK_SCO */ "SCO",
+ /* NG_HCI_LINK_ACL */ "ACL"
+ };
+
+ return (link_type >= SIZE(t)? "?" : t[link_type]);
+} /* hci_link2str */
+
+char const * const
+hci_pin2str(int type)
+{
+ static char const * const t[] = {
+ /* 0x00 */ "Variable PIN",
+ /* 0x01 */ "Fixed PIN"
+ };
+
+ return (type >= SIZE(t)? "?" : t[type]);
+} /* hci_pin2str */
+
+char const * const
+hci_scan2str(int scan)
+{
+ static char const * const t[] = {
+ /* 0x00 */ "No Scan enabled",
+ /* 0x01 */ "Inquiry Scan enabled. Page Scan disabled",
+ /* 0x02 */ "Inquiry Scan disabled. Page Scan enabled",
+ /* 0x03 */ "Inquiry Scan enabled. Page Scan enabled"
+ };
+
+ return (scan >= SIZE(t)? "?" : t[scan]);
+} /* hci_scan2str */
+
+char const * const
+hci_encrypt2str(int encrypt, int brief)
+{
+ static char const * const t[] = {
+ /* 0x00 */ "Disabled",
+ /* 0x01 */ "Only for point-to-point packets",
+ /* 0x02 */ "Both point-to-point and broadcast packets"
+ };
+
+ static char const * const t1[] = {
+ /* NG_HCI_ENCRYPTION_MODE_NONE */ "NONE",
+ /* NG_HCI_ENCRYPTION_MODE_P2P */ "P2P",
+ /* NG_HCI_ENCRYPTION_MODE_ALL */ "ALL",
+ };
+
+ if (brief)
+ return (encrypt >= SIZE(t1)? "?" : t1[encrypt]);
+
+ return (encrypt >= SIZE(t)? "?" : t[encrypt]);
+} /* hci_encrypt2str */
+
+char const * const
+hci_coding2str(int coding)
+{
+ static char const * const t[] = {
+ /* 0x00 */ "Linear",
+ /* 0x01 */ "u-law",
+ /* 0x02 */ "A-law",
+ /* 0x03 */ "Reserved"
+ };
+
+ return (coding >= SIZE(t)? "?" : t[coding]);
+} /* hci_coding2str */
+
+char const * const
+hci_vdata2str(int data)
+{
+ static char const * const t[] = {
+ /* 0x00 */ "1's complement",
+ /* 0x01 */ "2's complement",
+ /* 0x02 */ "Sign-Magnitude",
+ /* 0x03 */ "Reserved"
+ };
+
+ return (data >= SIZE(t)? "?" : t[data]);
+} /* hci_vdata2str */
+
+char const * const
+hci_hmode2str(int mode, char *buffer, int size)
+{
+ static char const * const t[] = {
+ /* 0x01 */ "Suspend Page Scan ",
+ /* 0x02 */ "Suspend Inquiry Scan ",
+ /* 0x04 */ "Suspend Periodic Inquiries "
+ };
+
+ if (buffer != NULL && size > 0) {
+ int n;
+
+ memset(buffer, 0, size);
+ for (n = 0; n < SIZE(t); n++) {
+ int len = strlen(buffer);
+
+ if (len >= size)
+ break;
+ if (mode & (1 << n))
+ strncat(buffer, t[n], size - len);
+ }
+ }
+
+ return (buffer);
+} /* hci_hmode2str */
+
+char const * const
+hci_ver2str(int ver)
+{
+ static char const * const t[] = {
+ /* 0x00 */ "v1.0B",
+ /* 0x01 */ "v1.1"
+ };
+
+ return (ver >= SIZE(t)? "?" : t[ver]);
+} /* hci_ver2str */
+
+char const * const
+hci_manufacturer2str(int m)
+{
+ static char const * const t[] = {
+ /* 0000 */ "Ericsson Mobile Comunications",
+ /* 0001 */ "Nokia Mobile Phones",
+ /* 0002 */ "Intel Corp.",
+ /* 0003 */ "IBM Corp.",
+ /* 0004 */ "Toshiba Corp.",
+ /* 0005 */ "3Com",
+ /* 0006 */ "Microsoft",
+ /* 0007 */ "Lucent",
+ /* 0008 */ "Motorola",
+ /* 0009 */ "Infineon Technologies AG",
+ /* 0010 */ "Cambridge Silicon Radio",
+ /* 0011 */ "Silicon Wave",
+ /* 0012 */ "Digianswer A/S",
+ /* 0013 */ "Texas Instruments Inc.",
+ /* 0014 */ "Parthus Technologies Inc.",
+ /* 0015 */ "Broadcom Corporation",
+ /* 0016 */ "Mitel Semiconductor",
+ /* 0017 */ "Widcomm, Inc.",
+ /* 0018 */ "Telencomm Inc.",
+ /* 0019 */ "Atmel Corporation",
+ /* 0020 */ "Mitsubishi Electric Corporation",
+ /* 0021 */ "RTX Telecom A/S",
+ /* 0022 */ "KC Technology Inc.",
+ /* 0023 */ "Newlogic",
+ /* 0024 */ "Transilica, Inc.",
+ /* 0025 */ "Rohde & Schwartz GmbH & Co. KG",
+ /* 0026 */ "TTPCom Limited",
+ /* 0027 */ "Signia Technologies, Inc.",
+ /* 0028 */ "Conexant Systems Inc.",
+ /* 0029 */ "Qualcomm",
+ /* 0030 */ "Inventel",
+ /* 0031 */ "AVM Berlin",
+ /* 0032 */ "BandSpeed, Inc.",
+ /* 0033 */ "Mansella Ltd",
+ /* 0034 */ "NEC Corporation",
+ /* 0035 */ "WavePlus Technology Co., Ltd.",
+ /* 0036 */ "Alcatel",
+ /* 0037 */ "Philips Semiconductors",
+ /* 0038 */ "C Technologies",
+ /* 0039 */ "Open Interface",
+ /* 0040 */ "R F Micro Devices",
+ /* 0041 */ "Hitachi Ltd",
+ /* 0042 */ "Symbol Technologies, Inc.",
+ /* 0043 */ "Tenovis",
+ /* 0044 */ "Macronix International Co. Ltd.",
+ /* 0045 */ "GCT Semiconductor",
+ /* 0046 */ "Norwood Systems",
+ /* 0047 */ "MewTel Technology Inc."
+ };
+
+ return (m >= SIZE(t)? "?" : t[m]);
+} /* hci_manufacturer2str */
+
+char const * const
+hci_features2str(u_int8_t *features, char *buffer, int size)
+{
+ static char const * const t[][8] = {
+ { /* byte 0 */
+ /* 0 */ "<3-Slot> ",
+ /* 1 */ "<5-Slot> ",
+ /* 2 */ "<Encryption> ",
+ /* 3 */ "<Slot offset> ",
+ /* 4 */ "<Timing accuracy> ",
+ /* 5 */ "<Switch> ",
+ /* 6 */ "<Hold mode> ",
+ /* 7 */ "<Sniff mode> "
+ },
+ { /* byte 1 */
+ /* 0 */ "<Park mode> ",
+ /* 1 */ "<RSSI> ",
+ /* 2 */ "<Channel quality> ",
+ /* 3 */ "<SCO link> ",
+ /* 4 */ "<HV2 packets> ",
+ /* 5 */ "<HV3 packets> ",
+ /* 6 */ "<u-law log> ",
+ /* 7 */ "<A-law log> "
+ },
+ { /* byte 2 */
+ /* 0 */ "<CVSD> ",
+ /* 1 */ "<Paging scheme> ",
+ /* 2 */ "<Power control> ",
+ /* 3 */ "<Transparent SCO data> ",
+ /* 4 */ "<Flow control lag (bit0)> ",
+ /* 5 */ "<Flow control lag (bit1)> ",
+ /* 6 */ "<Flow control lag (bit2)> ",
+ /* 7 */ "<Unknown2.7> "
+ }};
+
+ if (buffer != NULL && size > 0) {
+ int n, i, len0, len1;
+
+ memset(buffer, 0, size);
+ len1 = 0;
+
+ for (n = 0; n < SIZE(t); n++) {
+ for (i = 0; i < SIZE(t[n]); i++) {
+ len0 = strlen(buffer);
+ if (len0 >= size)
+ goto done;
+
+ if (features[n] & (1 << i)) {
+ if (len1 + strlen(t[n][i]) > 60) {
+ len1 = 0;
+ buffer[len0 - 1] = '\n';
+ }
+
+ len1 += strlen(t[n][i]);
+ strncat(buffer, t[n][i], size - len0);
+ }
+ }
+ }
+ }
+done:
+ return (buffer);
+} /* hci_features2str */
+
+char const * const
+hci_cc2str(int cc)
+{
+ static char const * const t[] = {
+ /* 0x00 */ "North America, Europe, Japan",
+ /* 0x01 */ "France"
+ };
+
+ return (cc >= SIZE(t)? "?" : t[cc]);
+} /* hci_cc2str */
+
+char const * const
+hci_con_state2str(int state)
+{
+ static char const * const t[] = {
+ /* NG_HCI_CON_CLOSED */ "CLOSED",
+ /* NG_HCI_CON_W4_LP_CON_RSP */ "W4_LP_CON_RSP",
+ /* NG_HCI_CON_W4_CONN_COMPLETE */ "W4_CONN_COMPLETE",
+ /* NG_HCI_CON_OPEN */ "OPEN"
+ };
+
+ return (state >= SIZE(t)? "UNKNOWN" : t[state]);
+} /* hci_con_state2str */
+
+char const * const
+hci_status2str(int status)
+{
+ static char const * const t[] = {
+ /* 0x00 */ "No error",
+ /* 0x01 */ "Unknown HCI command",
+ /* 0x02 */ "No connection",
+ /* 0x03 */ "Hardware failure",
+ /* 0x04 */ "Page timeout",
+ /* 0x05 */ "Authentication failure",
+ /* 0x06 */ "Key missing",
+ /* 0x07 */ "Memory full",
+ /* 0x08 */ "Connection timeout",
+ /* 0x09 */ "Max number of connections",
+ /* 0x0a */ "Max number of SCO connections to a unit",
+ /* 0x0b */ "ACL connection already exists",
+ /* 0x0c */ "Command disallowed",
+ /* 0x0d */ "Host rejected due to limited resources",
+ /* 0x0e */ "Host rejected due to securiity reasons",
+ /* 0x0f */ "Host rejected due to remote unit is a personal unit",
+ /* 0x10 */ "Host timeout",
+ /* 0x11 */ "Unsupported feature or parameter value",
+ /* 0x12 */ "Invalid HCI command parameter",
+ /* 0x13 */ "Other end terminated connection: User ended connection",
+ /* 0x14 */ "Other end terminated connection: Low resources",
+ /* 0x15 */ "Other end terminated connection: About to power off",
+ /* 0x16 */ "Connection terminated by local host",
+ /* 0x17 */ "Repeated attempts",
+ /* 0x18 */ "Pairing not allowed",
+ /* 0x19 */ "Unknown LMP PDU",
+ /* 0x1a */ "Unsupported remote feature",
+ /* 0x1b */ "SCO offset rejected",
+ /* 0x1c */ "SCO interval rejected",
+ /* 0x1d */ "SCO air mode rejected",
+ /* 0x1e */ "Invalid LMP parameters",
+ /* 0x1f */ "Unspecified error",
+ /* 0x20 */ "Unsupported LMP parameter value",
+ /* 0x21 */ "Role change not allowed",
+ /* 0x22 */ "LMP response timeout",
+ /* 0x23 */ "LMP error transaction collision",
+ /* 0x24 */ "LMP PSU not allowed",
+ /* 0x25 */ "Encryption mode not acceptable",
+ /* 0x26 */ "Unit key used",
+ /* 0x27 */ "QoS is not supported",
+ /* 0x28 */ "Instant passed",
+ /* 0x29 */ "Paring with unit key not supported"
+ };
+
+ return (status >= SIZE(t)? "Unknown error" : t[status]);
+} /* hci_status2str */
+
diff --git a/usr.sbin/bluetooth/hcseriald/Makefile b/usr.sbin/bluetooth/hcseriald/Makefile
new file mode 100644
index 0000000..4153cd6
--- /dev/null
+++ b/usr.sbin/bluetooth/hcseriald/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.4 2002/09/04 21:29:58 max Exp $
+# $FreeBSD$
+
+DESTDIR= /usr/sbin/
+MANDIR= ../share/man/man
+
+PROG= hcseriald
+MAN8= hcseriald.8
+
+WARNS?= 2
+CFLAGS+= -Wall -O2 -I../../../sys/netgraph/bluetooth/include
+SRCS= hcseriald.c
+
+DPADD= ${LIBNETGRAPH}
+LDADD= -lnetgraph
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/hcseriald/hcseriald.8 b/usr.sbin/bluetooth/hcseriald/hcseriald.8
new file mode 100644
index 0000000..d4b641d
--- /dev/null
+++ b/usr.sbin/bluetooth/hcseriald/hcseriald.8
@@ -0,0 +1,81 @@
+.\" hcseriald.8
+.\"
+.\" 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: hcseriald.8,v 1.3 2002/11/09 19:16:50 max Exp $
+.\" $FreeBSD$
+.Dd June 14, 2002
+.Dt HCSERIALD 8
+.Os
+.Sh NAME
+.Nm hcseriald
+.Nd supervise serial Bluetooth devices
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar device
+.Op Fl n Ar node name
+.Op Fl s Ar speed
+.Op Fl d
+.Sh DESCRIPTION
+The
+.Nm
+handles serial Bluetooth devices. It does one simple thing. It opens
+specified serial device, sets device parameters and pushes
+.Em H4
+line discipline.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl f Ar device
+Callout device name. Example:
+.Fl f
+.Pa /dev/cuaa0 .
+.It Fl n Ar node name
+Set H4 Netgraph node name. Example:
+.Fl n Ar sio0 .
+.It Fl s Ar speed
+Set serial device speed to
+.Em speed .
+Example:
+.Fl s Ar 115200 .
+.It Fl d
+Do not disassociate from the controlling terminal, i.e. run in foreground.
+.El
+.Sh FILES
+.Bl -tag -width /dev/consolectl -compact
+.It Pa /var/run/hcserial.*.pid
+process id of the currently running
+.Nm
+daemon. Where
+.Dq *
+is a H4 Netgraph node name.
+.El
+.Sh SEE ALSO
+.Xr tty 4 ,
+.Xr ng_h4 4 ,
+.Xr ng_hci 4 ,
+.Xr hccontrol 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.sbin/bluetooth/hcseriald/hcseriald.c b/usr.sbin/bluetooth/hcseriald/hcseriald.c
new file mode 100644
index 0000000..bb0e819
--- /dev/null
+++ b/usr.sbin/bluetooth/hcseriald/hcseriald.c
@@ -0,0 +1,279 @@
+/*
+ * hcseriald.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: hcseriald.c,v 1.4 2002/09/04 21:29:58 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph.h>
+#include <ng_h4.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* Prototypes */
+static int open_device (char const *, speed_t, char const *);
+static void sighandler (int);
+static void usage ();
+
+static char const * const hcseriald = "hcseriald";
+static int done = 0;
+
+int
+main(int argc, char *argv[])
+{
+ char *device = NULL, *name = NULL;
+ speed_t speed = 115200;
+ int n, detach = 1;
+ char p[FILENAME_MAX];
+ FILE *f = NULL;
+ struct sigaction sa;
+
+ /* Process command line arguments */
+ while ((n = getopt(argc, argv, "df:n:s:")) != -1) {
+ switch (n) {
+ case 'd':
+ detach = 0;
+ break;
+
+ case 'f':
+ device = optarg;
+ break;
+
+ case 'n':
+ name = optarg;
+ break;
+
+ case 's':
+ speed = atoi(optarg);
+ if (speed < 0)
+ usage(argv[0]);
+ break;
+
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (device == NULL || name == NULL)
+ usage(argv[0]);
+
+ openlog(hcseriald, LOG_PID | LOG_NDELAY, LOG_USER);
+
+ /* Open device */
+ n = open_device(device, speed, name);
+
+ if (detach) {
+ pid_t pid = fork();
+
+ if (pid == (pid_t) -1) {
+ syslog(LOG_ERR, "Could not fork(). %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ if (pid != 0)
+ exit(0);
+
+ if (daemon(0, 0) < 0) {
+ syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+ }
+
+ /* Write PID file */
+ snprintf(p, sizeof(p), "/var/run/%s.%s.pid", hcseriald, name);
+ f = fopen(p, "w");
+ if (f == NULL) {
+ syslog(LOG_ERR, "Could not fopen(%s). %s (%d)",
+ p, strerror(errno), errno);
+ exit(1);
+ }
+ fprintf(f, "%d", getpid());
+ fclose(f);
+
+ /* Install signal handler */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sighandler;
+
+ if (sigaction(SIGTERM, &sa, NULL) < 0) {
+ syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ if (sigaction(SIGHUP, &sa, NULL) < 0) {
+ syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ if (sigaction(SIGINT, &sa, NULL) < 0) {
+ syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ /* Keep running */
+ while (!done)
+ select(0, NULL, NULL, NULL, NULL);
+
+ /* Remove PID file and close device */
+ unlink(p);
+ close(n);
+ closelog();
+
+ return (0);
+} /* main */
+
+/* Open terminal, set settings, push H4 line discipline and set node name */
+static int
+open_device(char const *device, speed_t speed, char const *name)
+{
+ int fd, disc, cs, ds;
+ struct termios t;
+ struct nodeinfo ni;
+ struct ngm_name n;
+ char p[NG_NODELEN + 1];
+
+ /* Open terminal device and setup H4 line discipline */
+ fd = open(device, O_RDWR|O_NOCTTY);
+ if (fd < 0) {
+ syslog(LOG_ERR, "Could not open(%s). %s (%d)",
+ device, strerror(errno), errno);
+ exit(1);
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (tcgetattr(fd, &t) < 0) {
+ syslog(LOG_ERR, "Could not tcgetattr(%s). %s (%d)",
+ device, strerror(errno), errno);
+ exit(1);
+ }
+
+ cfmakeraw(&t);
+
+ t.c_cflag |= CLOCAL; /* clocal */
+ t.c_cflag &= ~CSIZE; /* cs8 */
+ t.c_cflag |= CS8; /* cs8 */
+ t.c_cflag &= ~PARENB; /* -parenb */
+ t.c_cflag &= ~CSTOPB; /* -cstopb */
+ t.c_cflag |= CRTSCTS; /* crtscts */
+
+ if (tcsetattr(fd, TCSANOW, &t) < 0) {
+ syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
+ device, strerror(errno), errno);
+ exit(1);
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (cfsetspeed(&t, speed) < 0) {
+ syslog(LOG_ERR, "Could not cfsetspeed(%s). %s (%d)",
+ device, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (tcsetattr(fd, TCSANOW, &t) < 0) {
+ syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
+ device, strerror(errno), errno);
+ exit(1);
+ }
+
+ disc = H4DISC;
+ if (ioctl(fd, TIOCSETD, &disc) < 0) {
+ syslog(LOG_ERR, "Could not ioctl(%s, TIOCSETD, %d). %s (%d)",
+ device, disc, strerror(errno), errno);
+ exit(1);
+ }
+
+ /* Get default name of the Netgraph node */
+ memset(&ni, 0, sizeof(ni));
+ if (ioctl(fd, NGIOCGINFO, &ni) < 0) {
+ syslog(LOG_ERR, "Could not ioctl(%d, NGIOGINFO). %s (%d)",
+ fd, strerror(errno), errno);
+ exit(1);
+ }
+
+ /* Assign new name to the Netgraph node */
+ snprintf(p, sizeof(p), "%s:", ni.name);
+ snprintf(n.name, sizeof(n.name), "%s", name);
+
+ if (NgMkSockNode(NULL, &cs, &ds) < 0) {
+ syslog(LOG_ERR, "Could not NgMkSockNode(). %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ if (NgSendMsg(cs, p, NGM_GENERIC_COOKIE, NGM_NAME, &n, sizeof(n)) < 0) {
+ syslog(LOG_ERR, "Could not NgSendMsg(%d, %s, NGM_NAME, %s). " \
+ "%s (%d)", cs, p, n.name, strerror(errno), errno);
+ exit(1);
+ }
+
+ close(cs);
+ close(ds);
+
+ return (fd);
+} /* open_device */
+
+/* Signal handler */
+static void
+sighandler(int s)
+{
+ done = 1;
+} /* sighandler */
+
+/* Usage */
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: %s -f device -n node_name [-s speed -d]\n" \
+ "Where:\n" \
+ "\t-f device tty device name, ex. /dev/cuaa1\n" \
+ "\t-n node_name set Netgraph node name to node_name\n" \
+ "\t-s speed set tty speed, ex. 115200\n" \
+ "\t-d run in foreground\n",
+ hcseriald);
+ exit(255);
+} /* usage */
+
diff --git a/usr.sbin/bluetooth/l2control/Makefile b/usr.sbin/bluetooth/l2control/Makefile
new file mode 100644
index 0000000..b098874
--- /dev/null
+++ b/usr.sbin/bluetooth/l2control/Makefile
@@ -0,0 +1,12 @@
+# $Id: Makefile,v 1.3 2002/09/04 21:30:40 max Exp $
+# $FreeBSD$
+
+DESTDIR= /usr/sbin/
+MANDIR= ../share/man/man
+PROG= l2control
+MAN8= l2control.8
+WARNS?= 2
+CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include
+SRCS= l2cap.c l2control.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/l2control/l2cap.c b/usr.sbin/bluetooth/l2control/l2cap.c
new file mode 100644
index 0000000..a0f2d24
--- /dev/null
+++ b/usr.sbin/bluetooth/l2control/l2cap.c
@@ -0,0 +1,256 @@
+/*
+ * l2cap.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: l2cap.c,v 1.6 2002/09/04 21:30:40 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <bitstring.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <ng_l2cap.h>
+#include <ng_btsocket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "l2control.h"
+
+#define SIZE(x) (sizeof((x))/sizeof((x)[0]))
+
+/* Send read_node_flags command to the node */
+static int
+l2cap_read_node_flags(int s, int argc, char **argv)
+{
+ struct ng_btsocket_l2cap_raw_node_flags r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_L2CAP_NODE_GET_FLAGS, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n",
+ r.src.b[5], r.src.b[4], r.src.b[3],
+ r.src.b[2], r.src.b[1], r.src.b[0]);
+ fprintf(stdout, "Connectionless traffic flags:\n");
+ fprintf(stdout, "\tSDP: %s\n",
+ (r.flags & NG_L2CAP_CLT_SDP_DISABLED)? "disabled" : "enabled");
+ fprintf(stdout, "\tRFCOMM: %s\n",
+ (r.flags & NG_L2CAP_CLT_RFCOMM_DISABLED)? "disabled":"enabled");
+ fprintf(stdout, "\tTCP: %s\n",
+ (r.flags & NG_L2CAP_CLT_TCP_DISABLED)? "disabled" : "enabled");
+
+ return (OK);
+} /* l2cap_read_node_flags */
+
+/* Send read_debug_level command to the node */
+static int
+l2cap_read_debug_level(int s, int argc, char **argv)
+{
+ struct ng_btsocket_l2cap_raw_node_debug r;
+
+ memset(&r, 0, sizeof(r));
+ if (ioctl(s, SIOC_L2CAP_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n",
+ r.src.b[5], r.src.b[4], r.src.b[3],
+ r.src.b[2], r.src.b[1], r.src.b[0]);
+ fprintf(stdout, "Debug level: %d\n", r.debug);
+
+ return (OK);
+} /* l2cap_read_debug_level */
+
+/* Send write_debug_level command to the node */
+static int
+l2cap_write_debug_level(int s, int argc, char **argv)
+{
+ struct ng_btsocket_l2cap_raw_node_debug r;
+
+ memset(&r, 0, sizeof(r));
+ switch (argc) {
+ case 1:
+ r.debug = atoi(argv[0]);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+ if (ioctl(s, SIOC_L2CAP_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
+ return (ERROR);
+
+ return (OK);
+} /* l2cap_write_debug_level */
+
+/* Send read_connection_list command to the node */
+static int
+l2cap_read_connection_list(int s, int argc, char **argv)
+{
+ static char const * const state[] = {
+ /* NG_L2CAP_CON_CLOSED */ "CLOSED",
+ /* NG_L2CAP_W4_LP_CON_CFM */ "W4_LP_CON_CFM",
+ /* NG_L2CAP_CON_OPEN */ "OPEN"
+ };
+#define con_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)])
+
+ struct ng_btsocket_l2cap_raw_con_list r;
+ int n, error = OK;
+
+ memset(&r, 0, sizeof(r));
+ r.num_connections = NG_L2CAP_MAX_CON_NUM;
+ r.connections = calloc(NG_L2CAP_MAX_CON_NUM,
+ sizeof(ng_l2cap_node_con_ep));
+ if (r.connections == NULL) {
+ errno = ENOMEM;
+ return (ERROR);
+ }
+
+ if (ioctl(s, SIOC_L2CAP_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
+ error = ERROR;
+ goto out;
+ }
+
+ fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n",
+ r.src.b[5], r.src.b[4], r.src.b[3],
+ r.src.b[2], r.src.b[1], r.src.b[0]);
+ fprintf(stdout, "L2CAP connections:\n");
+ fprintf(stdout,
+"Remote BD_ADDR Handle Flags Pending State\n");
+ for (n = 0; n < r.num_connections; n++) {
+ fprintf(stdout,
+ "%02x:%02x:%02x:%02x:%02x:%02x " \
+ " %5d " \
+ "%2.2s %2.2s " \
+ "%7d " \
+ "%s\n",
+ r.connections[n].remote.b[5],
+ r.connections[n].remote.b[4],
+ r.connections[n].remote.b[3],
+ r.connections[n].remote.b[2],
+ r.connections[n].remote.b[1],
+ r.connections[n].remote.b[0],
+ r.connections[n].con_handle,
+ ((r.connections[n].flags & NG_L2CAP_CON_TX)? "TX" : ""),
+ ((r.connections[n].flags & NG_L2CAP_CON_RX)? "RX" : ""),
+ r.connections[n].pending,
+ con_state2str(r.connections[n].state));
+ }
+out:
+ free(r.connections);
+
+ return (error);
+} /* l2cap_read_connection_list */
+
+/* Send read_channel_list command to the node */
+static int
+l2cap_read_channel_list(int s, int argc, char **argv)
+{
+ static char const * const state[] = {
+ /* NG_L2CAP_CLOSED */ "CLOSED",
+ /* NG_L2CAP_W4_L2CAP_CON_RSP */ "W4_L2CAP_CON_RSP",
+ /* NG_L2CAP_W4_L2CA_CON_RSP */ "W4_L2CA_CON_RSP",
+ /* NG_L2CAP_CONFIG */ "CONFIG",
+ /* NG_L2CAP_OPEN */ "OPEN",
+ /* NG_L2CAP_W4_L2CAP_DISCON_RSP */ "W4_L2CAP_DISCON_RSP",
+ /* NG_L2CAP_W4_L2CA_DISCON_RSP */ "W4_L2CA_DISCON_RSP"
+ };
+#define ch_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)])
+
+ struct ng_btsocket_l2cap_raw_chan_list r;
+ int n, error = OK;
+
+ memset(&r, 0, sizeof(r));
+ r.num_channels = NG_L2CAP_MAX_CHAN_NUM;
+ r.channels = calloc(NG_L2CAP_MAX_CHAN_NUM,
+ sizeof(ng_l2cap_node_chan_ep));
+ if (r.channels == NULL) {
+ errno = ENOMEM;
+ return (ERROR);
+ }
+
+ if (ioctl(s, SIOC_L2CAP_NODE_GET_CHAN_LIST, &r, sizeof(r)) < 0) {
+ error = ERROR;
+ goto out;
+ }
+
+ fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n",
+ r.src.b[5], r.src.b[4], r.src.b[3],
+ r.src.b[2], r.src.b[1], r.src.b[0]);
+ fprintf(stdout, "L2CAP channels:\n");
+ fprintf(stdout,
+"Remote BD_ADDR SCID/ DCID PSM IMTU/ OMTU State\n");
+ for (n = 0; n < r.num_channels; n++) {
+ fprintf(stdout,
+ "%02x:%02x:%02x:%02x:%02x:%02x " \
+ "%5d/%5d %5d " \
+ "%5d/%5d " \
+ "%s\n",
+ r.channels[n].remote.b[5], r.channels[n].remote.b[4],
+ r.channels[n].remote.b[3], r.channels[n].remote.b[2],
+ r.channels[n].remote.b[1], r.channels[n].remote.b[0],
+ r.channels[n].scid, r.channels[n].dcid,
+ r.channels[n].psm, r.channels[n].imtu,
+ r.channels[n].omtu,
+ ch_state2str(r.channels[n].state));
+ }
+out:
+ free(r.channels);
+
+ return (error);
+} /* l2cap_read_channel_list */
+
+struct l2cap_command l2cap_commands[] = {
+{
+"read_node_flags",
+"Get L2CAP node flags",
+&l2cap_read_node_flags
+},
+{
+"read_debug_level",
+"Get L2CAP node debug level",
+&l2cap_read_debug_level
+},
+{
+"write_debug_level <level>",
+"Set L2CAP node debug level",
+&l2cap_write_debug_level
+},
+{
+"read_connection_list",
+"Read list of the L2CAP connections",
+&l2cap_read_connection_list
+},
+{
+"read_channel_list",
+"Read list of the L2CAP channels",
+&l2cap_read_channel_list
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/bluetooth/l2control/l2control.8 b/usr.sbin/bluetooth/l2control/l2control.8
new file mode 100644
index 0000000..9efa251
--- /dev/null
+++ b/usr.sbin/bluetooth/l2control/l2control.8
@@ -0,0 +1,84 @@
+.\" l2control.8
+.\"
+.\" 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: l2control.8,v 1.4 2002/11/09 19:18:16 max Exp $
+.\" $FreeBSD$
+.Dd June 14, 2002
+.Dt L2CONTROL 8
+.Os
+.Sh NAME
+.Nm l2control
+.Nd L2CAP configuration utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar local BD_ADDR
+.Op Ar command
+.Op Ar parameters ...
+.Sh DESCRIPTION
+The
+.Nm
+utility connects to the local device with specified BD_ADDR and attempts
+to send specified command.
+.Nm
+will print results to the standard output and error messages to
+the standard error.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar local BD_ADDR
+Connect to the local device with specified BD_ADDR. Example:
+.Fl a Ar 00:01:02:03:04:05 .
+.It command
+One of the supported commands (see below). Special command
+.Dq help
+can be used to obtain the list of all supported commands. To get more
+information about specific command use
+.Dq help command .
+.It parameters
+One or more optional space separated command parameters.
+.El
+.Sh COMMANDS
+The currently supported node commands in
+.Nm
+are:
+.Pp
+.Bd -literal -offset indent -compact
+Read_Node_Flags
+Read_Debug_Level
+Write_Debug_Level
+Read_Connection_List
+Read_Channel_List
+.Ed
+.Pp
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ng_l2cap 4 ,
+.Xr l2ping 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.sbin/bluetooth/l2control/l2control.c b/usr.sbin/bluetooth/l2control/l2control.c
new file mode 100644
index 0000000..ef65826
--- /dev/null
+++ b/usr.sbin/bluetooth/l2control/l2control.c
@@ -0,0 +1,226 @@
+/*
+ * l2control.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: l2control.c,v 1.5 2002/09/04 21:30:40 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <bitstring.h>
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <ng_l2cap.h>
+#include <ng_btsocket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "l2control.h"
+
+/* Prototypes */
+static int do_l2cap_command (bdaddr_p, int, char **);
+static struct l2cap_command * find_l2cap_command (char const *,
+ struct l2cap_command *);
+static void print_l2cap_command (struct l2cap_command *);
+static void usage (void);
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+ int n;
+ bdaddr_t bdaddr;
+
+ memset(&bdaddr, 0, sizeof(bdaddr));
+
+ /* Process command line arguments */
+ while ((n = getopt(argc, argv, "a:")) != -1) {
+ switch (n) {
+ case 'a': {
+ int a0, a1, a2, a3, a4, a5;
+
+ if (sscanf(optarg, "%x:%x:%x:%x:%x:%x",
+ &a5, &a4, &a3, &a2, &a1, &a0) != 6) {
+ usage();
+ break;
+ }
+
+ bdaddr.b[0] = (a0 & 0xff);
+ bdaddr.b[1] = (a1 & 0xff);
+ bdaddr.b[2] = (a2 & 0xff);
+ bdaddr.b[3] = (a3 & 0xff);
+ bdaddr.b[4] = (a4 & 0xff);
+ bdaddr.b[5] = (a5 & 0xff);
+ } break;
+
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (*argv == NULL)
+ usage();
+
+ return (do_l2cap_command(&bdaddr, argc, argv));
+} /* main */
+
+/* Execute commands */
+static int
+do_l2cap_command(bdaddr_p bdaddr, int argc, char **argv)
+{
+ char *cmd = argv[0];
+ struct l2cap_command *c = NULL;
+ struct sockaddr_l2cap sa;
+ int s, e, help;
+
+ help = 0;
+ if (strcasecmp(cmd, "help") == 0) {
+ argc --;
+ argv ++;
+
+ if (argc <= 0) {
+ fprintf(stdout, "Supported commands:\n");
+ print_l2cap_command(l2cap_commands);
+ fprintf(stdout, "\nFor more information use " \
+ "'help command'\n");
+
+ return (OK);
+ }
+
+ help = 1;
+ cmd = argv[0];
+ }
+
+ c = find_l2cap_command(cmd, l2cap_commands);
+ if (c == NULL) {
+ fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
+ return (ERROR);
+ }
+
+ if (!help) {
+ if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0)
+ usage();
+
+ memset(&sa, 0, sizeof(sa));
+ sa.l2cap_len = sizeof(sa);
+ sa.l2cap_family = AF_BLUETOOTH;
+ memcpy(&sa.l2cap_bdaddr, bdaddr, sizeof(sa.l2cap_bdaddr));
+
+ s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP);
+ if (s < 0)
+ err(1, "Could not create socket");
+
+ if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ err(2,
+"Could not bind socket, bdaddr=%x:%x:%x:%x:%x:%x",
+ sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
+ sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
+ sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
+
+ if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ err(2,
+"Could not connect socket, bdaddr=%x:%x:%x:%x:%x:%x",
+ sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
+ sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
+ sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
+
+ e = 0x0ffff;
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &e, sizeof(e)) < 0)
+ err(3, "Coult not setsockopt(RCVBUF, %d)", e);
+
+ e = (c->handler)(s, -- argc, ++ argv);
+
+ close(s);
+ } else
+ e = USAGE;
+
+ switch (e) {
+ case OK:
+ case FAILED:
+ break;
+
+ case ERROR:
+ fprintf(stdout, "Could not execute command \"%s\". %s\n",
+ cmd, strerror(errno));
+ break;
+
+ case USAGE:
+ fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
+ break;
+
+ default: assert(0); break;
+ }
+
+ return (e);
+} /* do_l2cap_command */
+
+/* Try to find command in specified category */
+static struct l2cap_command *
+find_l2cap_command(char const *command, struct l2cap_command *category)
+{
+ struct l2cap_command *c = NULL;
+
+ for (c = category; c->command != NULL; c++) {
+ char *c_end = strchr(c->command, ' ');
+
+ if (c_end != NULL) {
+ int len = c_end - c->command;
+
+ if (strncasecmp(command, c->command, len) == 0)
+ return (c);
+ } else if (strcasecmp(command, c->command) == 0)
+ return (c);
+ }
+
+ return (NULL);
+} /* find_l2cap_command */
+
+/* Try to find command in specified category */
+static void
+print_l2cap_command(struct l2cap_command *category)
+{
+ struct l2cap_command *c = NULL;
+
+ for (c = category; c->command != NULL; c++)
+ fprintf(stdout, "\t%s\n", c->command);
+} /* print_l2cap_command */
+
+/* Usage */
+static void
+usage(void)
+{
+ fprintf(stdout, "Usage: l2control -a BD_ADDR cmd [p1] [..]]\n");
+ exit(255);
+} /* usage */
+
diff --git a/usr.sbin/bluetooth/l2control/l2control.h b/usr.sbin/bluetooth/l2control/l2control.h
new file mode 100644
index 0000000..0f6e5dc
--- /dev/null
+++ b/usr.sbin/bluetooth/l2control/l2control.h
@@ -0,0 +1,49 @@
+/*
+ * l2control.h
+ *
+ * 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: l2control.h,v 1.2 2002/09/04 21:30:40 max Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _L2CONTROL_H_
+#define _L2CONTROL_H_
+
+#define OK 0 /* everything was OK */
+#define ERROR 1 /* could not execute command */
+#define FAILED 2 /* error was reported */
+#define USAGE 3 /* invalid parameters */
+
+struct l2cap_command {
+ char const *command;
+ char const *description;
+ int (*handler)(int, int, char **);
+};
+
+extern struct l2cap_command l2cap_commands[];
+
+#endif /* _L2CONTROL_H_ */
+
diff --git a/usr.sbin/bluetooth/l2ping/Makefile b/usr.sbin/bluetooth/l2ping/Makefile
new file mode 100644
index 0000000..f2dad31
--- /dev/null
+++ b/usr.sbin/bluetooth/l2ping/Makefile
@@ -0,0 +1,12 @@
+# $Id: Makefile,v 1.4 2002/09/04 21:28:05 max Exp $
+# $FreeBSD$
+
+DESTDIR= /usr/sbin/
+MANDIR= ../share/man/man
+PROG= l2ping
+MAN8= l2ping.8
+SRCS= l2ping.c
+WARNS?= 2
+CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/l2ping/l2ping.8 b/usr.sbin/bluetooth/l2ping/l2ping.8
new file mode 100644
index 0000000..aa79ad9
--- /dev/null
+++ b/usr.sbin/bluetooth/l2ping/l2ping.8
@@ -0,0 +1,87 @@
+.\" l2ping.8
+.\"
+.\" 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: l2ping.8,v 1.4 2002/11/09 19:20:09 max Exp $
+.\" $FreeBSD$
+.Dd June 14, 2002
+.Dt L2PING 8
+.Os
+.Sh NAME
+.Nm l2ping
+.Nd send L2CAP ECHO_REQUEST to remote devices
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar remote BD_ADDR
+.Op Fl S Ar source BD_ADDR
+.Op Fl c Ar count
+.Op Fl f
+.Op Fl i Ar delay
+.Op Fl s Ar size
+.Sh DESCRIPTION
+The
+.Nm
+uses L2CAP ECHO_REQUEST datagram to elicit a L2CAP ECHO_RESPONSE from a
+remote device.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar remote BD_ADDR
+Address of remote device to ping. Example:
+.Fl a Ar 00:01:02:03:04:05 .
+.It Fl S Ar source BD_ADDR
+Send L2CAP ECHO_REQUEST from local device that has BD_ADDR. Example:
+.Fl S Ar 00:05:04:03:02:01 .
+.It Fl c Ar count
+Number of packets to send. If this option is not specified,
+.Nm
+will operate until interrupted.
+.It Fl f
+.Dq Flood
+ping, i.e. no delay between packets.
+.It Fl i Ar wait
+Wait
+.Em wait
+seconds between sending each packet. The default is to wait for one
+second between each packet. This option is ignored if
+.Fl f
+has been specified.
+.It Fl s Ar size
+Specify the number of payload bytes to be sent. The default is 64. The
+maximum size is 65531. Use this option with caution. Some implementations
+may not like large sizes and may hang or even crash.
+.El
+.Sh BUGS
+Could collect more statistic. Could check for duplicated, corrupted
+and lost packets.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ng_l2cap 4 ,
+.Xr l2control 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.sbin/bluetooth/l2ping/l2ping.c b/usr.sbin/bluetooth/l2ping/l2ping.c
new file mode 100644
index 0000000..a7ffd37
--- /dev/null
+++ b/usr.sbin/bluetooth/l2ping/l2ping.c
@@ -0,0 +1,279 @@
+/*
+ * l2ping.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: l2ping.c,v 1.9 2002/09/04 21:28:05 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <assert.h>
+#include <bitstring.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ng_hci.h>
+#include <ng_l2cap.h>
+#include <ng_btsocket.h>
+
+static void usage (void);
+static void tv_sub (struct timeval *, struct timeval const *);
+static double tv2msec (struct timeval const *);
+
+#undef min
+#define min(x, y) (((x) > (y))? (y) : (x))
+
+static char const pattern[] = "1234567890-";
+#define PATTERN_SIZE (sizeof(pattern) - 1)
+
+/*
+ * Main
+ */
+
+int
+main(int argc, char *argv[])
+{
+ struct ng_btsocket_l2cap_raw_ping r;
+ int n, s, count, wait, flood, fail;
+ struct timeval a, b;
+
+ /* Set defaults */
+ memset(&r, 0, sizeof(r));
+ r.echo_data = calloc(NG_L2CAP_MAX_ECHO_SIZE, sizeof(u_int8_t));
+ if (r.echo_data == NULL) {
+ fprintf(stderr, "Failed to allocate echo data buffer");
+ exit(1);
+ }
+
+ r.echo_size = 64; /* bytes */
+ count = -1; /* unlimited */
+ wait = 1; /* sec */
+ flood = 0;
+
+ /* Parse command line arguments */
+ while ((n = getopt(argc, argv, "a:c:fi:n:s:S:")) != -1) {
+ switch (n) {
+ case 'a':
+ case 'S': {
+ int a0, a1, a2, a3, a4, a5;
+
+ if (sscanf(optarg, "%x:%x:%x:%x:%x:%x",
+ &a5, &a4, &a3, &a2, &a1, &a0) != 6)
+ usage();
+
+ if (n == 'a') {
+ /* destination bdaddr */
+ r.echo_dst.b[0] = (a0 & 0xff);
+ r.echo_dst.b[1] = (a1 & 0xff);
+ r.echo_dst.b[2] = (a2 & 0xff);
+ r.echo_dst.b[3] = (a3 & 0xff);
+ r.echo_dst.b[4] = (a4 & 0xff);
+ r.echo_dst.b[5] = (a5 & 0xff);
+ } else {
+ /* source bdaddr */
+ r.echo_src.b[0] = (a0 & 0xff);
+ r.echo_src.b[1] = (a1 & 0xff);
+ r.echo_src.b[2] = (a2 & 0xff);
+ r.echo_src.b[3] = (a3 & 0xff);
+ r.echo_src.b[4] = (a4 & 0xff);
+ r.echo_src.b[5] = (a5 & 0xff);
+ }
+ } break;
+
+ case 'c':
+ count = atoi(optarg);
+ if (count <= 0)
+ usage();
+ break;
+
+ case 'f':
+ flood = 1;
+ break;
+
+ case 'i':
+ wait = atoi(optarg);
+ if (wait <= 0)
+ usage();
+ break;
+
+ case 's':
+ r.echo_size = atoi(optarg);
+ if ((int) r.echo_size < sizeof(int))
+ usage();
+
+ if (r.echo_size > NG_L2CAP_MAX_ECHO_SIZE)
+ r.echo_size = NG_L2CAP_MAX_ECHO_SIZE;
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (memcmp(&r.echo_dst, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
+ usage();
+
+ s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP);
+ if (s < 0)
+ err(2, "Could not create socket");
+
+ if (memcmp(&r.echo_src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) != 0) {
+ struct sockaddr_l2cap sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.l2cap_len = sizeof(sa);
+ sa.l2cap_family = AF_BLUETOOTH;
+ memcpy(&sa.l2cap_bdaddr, &r.echo_src, sizeof(bdaddr_t));
+
+ if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ err(3,
+"Could not bind socket, src bdaddr=%x:%x:%x:%x:%x:%x",
+ sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
+ sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
+ sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
+
+ if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ err(4,
+"Could not connect socket, src bdaddr=%x:%x:%x:%x:%x:%x",
+ sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
+ sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
+ sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
+ }
+
+ /* Fill pattern */
+ for (n = 0; n < r.echo_size; ) {
+ int avail = min(r.echo_size - n, PATTERN_SIZE);
+
+ memcpy(r.echo_data + n, pattern, avail);
+ n += avail;
+ }
+
+ /* Start ping'ing */
+ for (n = 0; count == -1 || count > 0; n ++) {
+ if (gettimeofday(&a, NULL) < 0)
+ err(5, "Could not gettimeofday(a)");
+
+ fail = 0;
+ *((int *)(r.echo_data)) = htonl(n);
+ if (ioctl(s, SIOC_L2CAP_L2CA_PING, &r, sizeof(r)) < 0) {
+ r.result = errno;
+ fail = 1;
+/*
+ warn("Could not ping, dst bdaddr=%x:%x:%x:%x:%x:%x",
+ r.echo_dst.b[5], r.echo_dst.b[4],
+ r.echo_dst.b[3], r.echo_dst.b[2],
+ r.echo_dst.b[1], r.echo_dst.b[0]);
+*/
+ }
+
+ if (gettimeofday(&b, NULL) < 0)
+ err(7, "Could not gettimeofday(b)");
+
+ tv_sub(&b, &a);
+
+ fprintf(stdout,
+"%d bytes from %x:%x:%x:%x:%x:%x seq_no=%d time=%.3f ms result=%#x %s\n",
+ r.echo_size,
+ r.echo_dst.b[5], r.echo_dst.b[4],
+ r.echo_dst.b[3], r.echo_dst.b[2],
+ r.echo_dst.b[1], r.echo_dst.b[0],
+ ntohl(*((int *)(r.echo_data))),
+ tv2msec(&b), r.result,
+ ((fail == 0)? "" : strerror(errno)));
+
+ if (!flood) {
+ /* Wait */
+ a.tv_sec = wait;
+ a.tv_usec = 0;
+ select(0, NULL, NULL, NULL, &a);
+ }
+
+ if (count != -1)
+ count --;
+ }
+
+ free(r.echo_data);
+ close(s);
+
+ return (0);
+} /* main */
+
+/*
+ * a -= b, for timevals
+ */
+
+static void
+tv_sub(struct timeval *a, struct timeval const *b)
+{
+ if (a->tv_usec < b->tv_usec) {
+ a->tv_usec += 1000000;
+ a->tv_sec -= 1;
+ }
+
+ a->tv_usec -= b->tv_usec;
+ a->tv_sec -= b->tv_sec;
+} /* tv_sub */
+
+/*
+ * convert tv to msec
+ */
+
+static double
+tv2msec(struct timeval const *tvp)
+{
+ return(((double)tvp->tv_usec)/1000.0 + ((double)tvp->tv_sec)*1000.0);
+} /* tv2msec */
+
+/*
+ * Usage
+ */
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: l2ping -a bd_addr " \
+ "[-S bd_addr -c count -i wait -s size]\n");
+ fprintf(stderr, "Where:\n");
+ fprintf(stderr, "\t-S bd_addr - Source BD_ADDR\n");
+ fprintf(stderr, "\t-a bd_addr - Remote BD_ADDR to ping\n");
+ fprintf(stderr, "\t-c count - Number of packets to send\n");
+ fprintf(stderr, "\t-f - No delay (soft of flood)\n");
+ fprintf(stderr, "\t-i wait - Delay between packets (sec)\n");
+ fprintf(stderr, "\t-s size - Packet size (bytes), " \
+ "between %d and %d\n", sizeof(int), NG_L2CAP_MAX_ECHO_SIZE);
+
+ exit(255);
+} /* usage */
+
OpenPOWER on IntegriCloud