summaryrefslogtreecommitdiff
path: root/usr.bin/bluetooth
diff options
context:
space:
mode:
authorJulian Elischer <julian@FreeBSD.org>2003-05-10 21:44:42 +0000
committerJulian Elischer <julian@FreeBSD.org>2003-05-10 21:44:42 +0000
commitf2bb1cae36283a8eb5a0f19d8612c6abc5148e8f (patch)
treeed7d8caf163274b56933e0b801c52beb10b3260d /usr.bin/bluetooth
parent7bdf1805b1fad30ffae8bb7c91e2f120dd8159b9 (diff)
downloadsrc-test-f2bb1cae36283a8eb5a0f19d8612c6abc5148e8f.tar.gz
src-test-f2bb1cae36283a8eb5a0f19d8612c6abc5148e8f.zip
Part one of undating the bluetooth code to the newest version
Submitted by: Maksim Yevmenkin <m_evmenkin@yahoo.com> Approved by: re@
Notes
Notes: svn path=/head/; revision=114878
Diffstat (limited to 'usr.bin/bluetooth')
-rw-r--r--usr.bin/bluetooth/Makefile5
-rw-r--r--usr.bin/bluetooth/btsockstat/Makefile6
-rw-r--r--usr.bin/bluetooth/btsockstat/btsockstat.135
-rw-r--r--usr.bin/bluetooth/btsockstat/btsockstat.c196
-rw-r--r--usr.bin/bluetooth/rfcomm_sppd/Makefile15
-rw-r--r--usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1107
-rw-r--r--usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c383
7 files changed, 716 insertions, 31 deletions
diff --git a/usr.bin/bluetooth/Makefile b/usr.bin/bluetooth/Makefile
index 1da9ef21cc2a0..be3146eeab854 100644
--- a/usr.bin/bluetooth/Makefile
+++ b/usr.bin/bluetooth/Makefile
@@ -1,5 +1,8 @@
+# $Id $
# $FreeBSD$
-SUBDIR= btsockstat
+
+SUBDIR= btsockstat \
+ rfcomm_sppd
.include <bsd.subdir.mk>
diff --git a/usr.bin/bluetooth/btsockstat/Makefile b/usr.bin/bluetooth/btsockstat/Makefile
index ea78892de4a73..76148811aa761 100644
--- a/usr.bin/bluetooth/btsockstat/Makefile
+++ b/usr.bin/bluetooth/btsockstat/Makefile
@@ -1,14 +1,16 @@
-# $Id: Makefile,v 1.1.1.1 2002/09/09 16:12:49 max Exp $
+# $Id: Makefile,v 1.3 2003/03/24 23:59:49 max Exp $
# $FreeBSD$
PROG= btsockstat
+BINGRP= kmem
+BINMODE= 2555
MAN1= btsockstat.1
DESTDIR= /usr/bin/
MANDIR= ../share/man/man
WARNS?= 2
-CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include/
+CFLAGS+= -g -I${.CURDIR}/../../../sys/netgraph/bluetooth/include/
SRCS= btsockstat.c
DPADD= ${LIBKVM}
diff --git a/usr.bin/bluetooth/btsockstat/btsockstat.1 b/usr.bin/bluetooth/btsockstat/btsockstat.1
index 357edd2459938..608958ddef51f 100644
--- a/usr.bin/bluetooth/btsockstat/btsockstat.1
+++ b/usr.bin/bluetooth/btsockstat/btsockstat.1
@@ -1,3 +1,5 @@
+.\" btsockstat.1
+.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
@@ -22,8 +24,8 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
+.\" $Id: btsockstat.1,v 1.4 2003/04/27 19:25:15 max Exp $
.\" $FreeBSD$
-.\"
.Dd August 31, 2002
.Dt BTSOCKSTAT 1
.Os
@@ -33,43 +35,42 @@
.Sh SYNOPSIS
.Nm
.Op Fl p Ar protocol
-.Op Fl r
+.Op Fl r
.Op Fl M Ar core
+.Op Fl h
.Sh DESCRIPTION
The
-.Nm
-utility symbolically displays the contents of various Bluetooth sockets
-related data structures.
-There are few output formats, depending on the
+.Nm
+command symbolically displays the contents of various Bluetooth sockets
+related data structures. There are few output formats, depending on the
options for the information presented.
-The
.Nm
-utility
-will print results to the standard output and error messages to the
+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 p Ar protocol
-Display a list of active sockets (protocol control blocks) for each
-specified protocol.
-Supported protocols are:
-.Cm hci_raw , l2cap_raw
+Display a list of active sockets (protocol control blocks) for each
+specified protocol. Supported protocols are:
+.Cm hci_raw , l2cap_raw , l2cap, rfcomm
and
-.Cm l2cap .
+.Cm rfcomm_s .
.It Fl r
Display a list of active routing entries (if any) for specified protocol.
.It Fl M Ar core
-Extract values associated with the name list from the specified core
+Extract values associated with the name list from the specified core
instead of the default
.Pa /dev/kmem .
+.It Fl h
+Display usage message and exit.
.El
.Sh BUGS
-Most likely.
-Please report if found.
+Most likely. Please report if found.
.Sh DIAGNOSTICS
.Ex -std
.Sh SEE ALSO
.Xr ng_btsocket 4
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+
diff --git a/usr.bin/bluetooth/btsockstat/btsockstat.c b/usr.bin/bluetooth/btsockstat/btsockstat.c
index d123502ddc652..7911f400118bd 100644
--- a/usr.bin/bluetooth/btsockstat/btsockstat.c
+++ b/usr.bin/bluetooth/btsockstat/btsockstat.c
@@ -25,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: btsockstat.c,v 1.2 2002/09/16 19:40:14 max Exp $
+ * $Id: btsockstat.c,v 1.4 2003/03/29 22:28:18 max Exp $
* $FreeBSD$
*/
@@ -45,11 +45,13 @@
#include <kvm.h>
#include <limits.h>
+#include <ng_bluetooth.h>
#include <ng_hci.h>
#include <ng_l2cap.h>
#include <ng_btsocket.h>
#include <ng_btsocket_hci_raw.h>
#include <ng_btsocket_l2cap.h>
+#include <ng_btsocket_rfcomm.h>
#include <stdio.h>
#include <stdlib.h>
@@ -60,6 +62,8 @@ static void hcirawpr (kvm_t *kvmd, u_long addr);
static void l2caprawpr (kvm_t *kvmd, u_long addr);
static void l2cappr (kvm_t *kvmd, u_long addr);
static void l2caprtpr (kvm_t *kvmd, u_long addr);
+static void rfcommpr (kvm_t *kvmd, u_long addr);
+static void rfcommpr_s (kvm_t *kvmd, u_long addr);
static kvm_t * kopen (char const *memf);
static int kread (kvm_t *kvmd, u_long addr, char *buffer, int size);
@@ -81,9 +85,16 @@ static struct nlist nl[] = {
{ "_ng_btsocket_l2cap_raw_rt" },
#define N_L2CAP_RT 4
{ "_ng_btsocket_l2cap_rt" },
+#define N_RFCOMM 5
+ { "_ng_btsocket_rfcomm_sockets" },
+#define N_RFCOMM_S 6
+ { "_ng_btsocket_rfcomm_sessions" },
{ "" },
};
+#define state2str(x) \
+ (((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
+
/*
* Main
*/
@@ -108,6 +119,10 @@ main(int argc, char *argv[])
proto = N_L2CAP_RAW;
else if (strcasecmp(optarg, "l2cap") == 0)
proto = N_L2CAP;
+ else if (strcasecmp(optarg, "rfcomm") == 0)
+ proto = N_RFCOMM;
+ else if (strcasecmp(optarg, "rfcomm_s") == 0)
+ proto = N_RFCOMM_S;
else
usage();
/* NOT REACHED */
@@ -124,10 +139,18 @@ main(int argc, char *argv[])
}
}
- if (proto == N_HCI_RAW && route)
+ if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
usage();
/* NOT REACHED */
+ /*
+ * Discard setgid privileges if not the running kernel so that
+ * bad guys can't print interesting stuff from kernel memory.
+ */
+
+ if (memf != NULL)
+ setgid(getgid());
+
kvmd = kopen(memf);
if (kvmd == NULL)
return (1);
@@ -151,6 +174,14 @@ main(int argc, char *argv[])
l2cappr(kvmd, nl[N_L2CAP].n_value);
break;
+ case N_RFCOMM:
+ rfcommpr(kvmd, nl[N_RFCOMM].n_value);
+ break;
+
+ case N_RFCOMM_S:
+ rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
+ break;
+
default:
if (route) {
l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
@@ -159,6 +190,8 @@ main(int argc, char *argv[])
hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
l2cappr(kvmd, nl[N_L2CAP].n_value);
+ rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
+ rfcommpr(kvmd, nl[N_RFCOMM].n_value);
}
break;
}
@@ -252,7 +285,7 @@ l2caprawpr(kvm_t *kvmd, u_long addr)
first = 0;
fprintf(stdout,
"Active raw L2CAP sockets\n" \
-"%-8.8s %-8.8s %-6.6s %-6.6s %-18.18s\n",
+"%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
"Socket",
"PCB",
"Recv-Q",
@@ -270,7 +303,7 @@ l2caprawpr(kvm_t *kvmd, u_long addr)
pcb.src.b[2], pcb.src.b[1], pcb.src.b[0]);
fprintf(stdout,
-"%-8.8x %-8.8x %6d %6d %-18.18s\n",
+"%-8.8x %-8.8x %6d %6d %-17.17s\n",
(int) pcb.so,
(int) this,
so.so_rcv.sb_cc,
@@ -293,8 +326,6 @@ l2cappr(kvm_t *kvmd, u_long addr)
/* NG_BTSOCKET_L2CAP_OPEN */ "OPEN",
/* NG_BTSOCKET_L2CAP_DISCONNECTING */ "DISCON"
};
-#define state2str(x) \
- (((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
ng_btsocket_l2cap_pcb_p this = NULL, next = NULL;
ng_btsocket_l2cap_pcb_t pcb;
@@ -302,7 +333,6 @@ l2cappr(kvm_t *kvmd, u_long addr)
int first = 1;
char local[32], remote[32];
-
if (addr == 0)
return;
@@ -321,7 +351,7 @@ l2cappr(kvm_t *kvmd, u_long addr)
first = 0;
fprintf(stdout,
"Active L2CAP sockets\n" \
-"%-8.8s %-6.6s %-6.6s %-24.24s %-18.18s %-5.5s %s\n",
+"%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
"PCB",
"Recv-Q",
"Send-Q",
@@ -350,7 +380,7 @@ l2cappr(kvm_t *kvmd, u_long addr)
pcb.dst.b[2], pcb.dst.b[1], pcb.dst.b[0]);
fprintf(stdout,
-"%-8.8x %6d %6d %-24.24s %-18.18s %-5d %s\n",
+"%-8.8x %6d %6d %-23.23s %-17.17s %-5d %s\n",
(int) this,
so.so_rcv.sb_cc,
so.so_snd.sb_cc,
@@ -391,7 +421,7 @@ l2caprtpr(kvm_t *kvmd, u_long addr)
fprintf(stdout,
"Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)? "raw " : "");
fprintf(stdout,
-"%-8.8s %-8.8s %-18.18s\n", "RTentry",
+"%-8.8s %-8.8s %-17.17s\n", "RTentry",
"Hook",
"BD_ADDR");
}
@@ -405,7 +435,7 @@ l2caprtpr(kvm_t *kvmd, u_long addr)
rt.src.b[2], rt.src.b[1], rt.src.b[0]);
fprintf(stdout,
-"%-8.8x %-8.8x %-18.18s\n",
+"%-8.8x %-8.8x %-17.17s\n",
(int) this,
(int) rt.hook,
bdaddr);
@@ -413,6 +443,150 @@ l2caprtpr(kvm_t *kvmd, u_long addr)
} /* l2caprtpr */
/*
+ * Print RFCOMM sockets
+ */
+
+static void
+rfcommpr(kvm_t *kvmd, u_long addr)
+{
+ static char const * const states[] = {
+ /* NG_BTSOCKET_RFCOMM_DLC_CLOSED */ "CLOSED",
+ /* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */ "W4CON",
+ /* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */ "CONFIG",
+ /* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */ "CONN",
+ /* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */ "OPEN",
+ /* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
+ };
+
+ ng_btsocket_rfcomm_pcb_p this = NULL, next = NULL;
+ ng_btsocket_rfcomm_pcb_t pcb;
+ struct socket so;
+ int first = 1;
+ char local[32], remote[32];
+
+ if (addr == 0)
+ return;
+
+ if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+ return;
+
+ for ( ; this != NULL; this = next) {
+ if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+ return;
+ if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+ return;
+
+ next = LIST_NEXT(&pcb, next);
+
+ if (first) {
+ first = 0;
+ fprintf(stdout,
+"Active RFCOMM sockets\n" \
+"%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
+ "PCB",
+ "Recv-Q",
+ "Send-Q",
+ "Local address",
+ "Foreign address",
+ "Chan",
+ "DLCI",
+ "State");
+ }
+
+ if (memcmp(&pcb.src, NG_HCI_BDADDR_ANY, sizeof(pcb.src)) == 0) {
+ local[0] = '*';
+ local[1] = 0;
+ } else
+ snprintf(local, sizeof(local),
+"%02x:%02x:%02x:%02x:%02x:%02x",
+ pcb.src.b[5], pcb.src.b[4], pcb.src.b[3],
+ pcb.src.b[2], pcb.src.b[1], pcb.src.b[0]);
+
+ if (memcmp(&pcb.dst, NG_HCI_BDADDR_ANY, sizeof(pcb.dst)) == 0) {
+ remote[0] = '*';
+ remote[1] = 0;
+ } else
+ snprintf(remote, sizeof(remote),
+"%02x:%02x:%02x:%02x:%02x:%02x",
+ pcb.dst.b[5], pcb.dst.b[4], pcb.dst.b[3],
+ pcb.dst.b[2], pcb.dst.b[1], pcb.dst.b[0]);
+
+ fprintf(stdout,
+"%-8.8x %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
+ (int) this,
+ so.so_rcv.sb_cc,
+ so.so_snd.sb_cc,
+ local,
+ remote,
+ pcb.channel,
+ pcb.dlci,
+ (so.so_options & SO_ACCEPTCONN)?
+ "LISTEN" : state2str(pcb.state));
+ }
+} /* rfcommpr */
+
+/*
+ * Print RFCOMM sessions
+ */
+
+static void
+rfcommpr_s(kvm_t *kvmd, u_long addr)
+{
+ static char const * const states[] = {
+ /* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */ "CLOSED",
+ /* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */ "LISTEN",
+ /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */ "CONNECTING",
+ /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */ "CONNECTED",
+ /* NG_BTSOCKET_RFCOMM_SESSION_OPEN */ "OPEN",
+ /* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
+ };
+
+ ng_btsocket_rfcomm_session_p this = NULL, next = NULL;
+ ng_btsocket_rfcomm_session_t s;
+ struct socket so;
+ int first = 1;
+
+ if (addr == 0)
+ return;
+
+ if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+ return;
+
+ for ( ; this != NULL; this = next) {
+ if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
+ return;
+ if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
+ return;
+
+ next = LIST_NEXT(&s, next);
+
+ if (first) {
+ first = 0;
+ fprintf(stdout,
+"Active RFCOMM sessions\n" \
+"%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
+ "L2PCB",
+ "PCB",
+ "Flags",
+ "MTU",
+ "Out-Q",
+ "DLCs",
+ "State");
+ }
+
+ fprintf(stdout,
+"%-8.8x %-8.8x %-4x %-5d %-5d %-4s %s\n",
+ (int) so.so_pcb,
+ (int) this,
+ s.flags,
+ s.mtu,
+ s.outq.len,
+ LIST_EMPTY(&s.dlcs)? "No" : "Yes",
+ state2str(s.state));
+ }
+} /* rfcommpr_s */
+
+/*
* Open kvm
*/
diff --git a/usr.bin/bluetooth/rfcomm_sppd/Makefile b/usr.bin/bluetooth/rfcomm_sppd/Makefile
new file mode 100644
index 0000000000000..53d9f31bb653d
--- /dev/null
+++ b/usr.bin/bluetooth/rfcomm_sppd/Makefile
@@ -0,0 +1,15 @@
+# $Id: Makefile,v 1.2 2003/04/26 23:55:34 max Exp $
+# $FreeBSD$
+
+PROG= rfcomm_sppd
+MAN1= rfcomm_sppd.1
+
+DESTDIR= /usr/bin/
+MANDIR= ../share/man/man
+
+WARNS?= 2
+CFLAGS+= -g -I${.CURDIR}/../../../sys/netgraph/bluetooth/include/
+
+SRCS= rfcomm_sppd.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1
new file mode 100644
index 0000000000000..8c244d6305dcd
--- /dev/null
+++ b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1
@@ -0,0 +1,107 @@
+.\" rfcomm_pppd.1
+.\"
+.\" Copyright (c) 2001-2003 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: rfcomm_sppd.1,v 1.1 2003/04/26 23:55:34 max Exp $
+.\" $FreeBSD$
+.Dd April 26, 2003
+.Dt RFCOMM_SPPD 1
+.Os
+.Sh NAME
+.Nm rfcomm_sppd
+.Nd RFCOMM Serial Port Profile daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar BD_ADDR
+.Op Fl b
+.Op Fl c Ar channel
+.Op Fl t Ar tty
+.Op Fl h
+.Sh DESCRIPTION
+The
+.Nm
+is a Serial Port Profile daemon. It opens RFCOMM connection to the
+specified server's BD_ADDR and channel. Once connection is established
+.Nm
+provides access to the server's remote serial port via
+.Xr pty 4
+interface.
+.Pp
+.Nm
+opens both master and slave pseudo terminals. This is done to ensure that
+RFCOMM connection stays open until
+.Nm
+is terminated. The data received from the master pseudo terminal are sent over
+the RFCOMM connection. The data received from the RFCOMM connection are written
+into master pseudo terminal. The application in its turn opens slave pseudo
+terminal and operates on it just like it would operate over the standard serial
+port.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar BD_ADDR
+This requied option specifies the remote BD_ADDR of the RFCOMM server.
+.It Fl b
+Detach from the controlling terminal, i.e. run in background.
+.It Fl c Ar channel
+This required option specifies RFCOMM channel to connect to. This channel
+must provide Serial Port service.
+.It Fl t Ar tty
+Slave pseudo tty name.
+.It Fl h
+Display usage message and exit.
+.El
+.Sh EXAMPLES
+.Bl -tag -width indent
+.It rfcomm_sppd -a 00:01:02:03:04:05 -c 1 -t /dev/ttyp1
+.Pp
+Will start
+.Nm
+and open RFCOMM connection to the server at
+.Em 00:01:02:03:04:05
+and channel
+.Em 1 .
+Once connection has been established
+.Pa /dev/ttyp1
+can be used to talk to the remote serial port on the server.
+.El
+.Sh FILES
+.Bl -tag -width /dev/tty[p-sP-S][0-9a-v]x -compact
+.It Pa /dev/pty[p-sP-S][0-9a-v]
+master pseudo terminals
+.It Pa /dev/tty[p-sP-S][0-9a-v]
+slave pseudo terminals
+.El
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh BUGS
+.Nm
+currently is not integrated with SDP (Service Discovery Protocol).
+.Sh SEE ALSO
+.Xr pty 4 ,
+.Xr ng_btsocket 4 ,
+.Xr rfcomm_pppd 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c
new file mode 100644
index 0000000000000..dbb203295bed4
--- /dev/null
+++ b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c
@@ -0,0 +1,383 @@
+/*
+ * rfcomm_sppd.c
+ *
+ * Copyright (c) 2003 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: rfcomm_sppd.c,v 1.2 2003/04/27 19:22:30 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <bitstring.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <ng_hci.h>
+#include <ng_l2cap.h>
+#include <ng_btsocket.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>
+
+#define SPPD_IDENT "rfcomm_sppd"
+#define SPPD_BUFFER_SIZE 1024
+#define max(a, b) (((a) > (b))? (a) : (b))
+
+static int sppd_ttys_open (char const *tty, int *amaster, int *aslave);
+static int sppd_read (int fd, char *buffer, int size);
+static int sppd_write (int fd, char *buffer, int size);
+static void sppd_sighandler (int s);
+static void usage (void);
+
+static int done; /* are we done? */
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ struct sockaddr_rfcomm ra;
+ bdaddr_t addr;
+ int n, background, channel, s, amaster, aslave;
+ fd_set rfd;
+ char *tty = NULL, buf[SPPD_BUFFER_SIZE];
+
+ memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
+ background = channel = 0;
+
+ /* Parse command line options */
+ while ((n = getopt(argc, argv, "a:bc:t:h")) != -1) {
+ switch (n) {
+ case 'a': { /* BDADDR */
+ int a0, a1, a2, a3, a4, a5;
+
+ if (sscanf(optarg, "%x:%x:%x:%x:%x:%x",
+ &a5, &a4, &a3, &a2, &a1, &a0) != 6)
+ usage();
+ /* NOT REACHED */
+
+ addr.b[0] = a0 & 0xff;
+ addr.b[1] = a1 & 0xff;
+ addr.b[2] = a2 & 0xff;
+ addr.b[3] = a3 & 0xff;
+ addr.b[4] = a4 & 0xff;
+ addr.b[5] = a5 & 0xff;
+ } break;
+
+ case 'c': /* RFCOMM channel */
+ channel = atoi(optarg);
+ break;
+
+ case 'b': /* Run in background */
+ background = 1;
+ break;
+
+ case 't': /* Slave TTY name */
+ tty = optarg;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ /* NOT REACHED */
+ }
+ }
+
+ /* Check if we have everything we need */
+ if (channel == 0 || tty == NULL ||
+ memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
+ usage();
+ /* NOT REACHED */
+
+ /* Set signal handlers */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sppd_sighandler;
+
+ if (sigaction(SIGTERM, &sa, NULL) < 0)
+ err(1, "Could not sigaction(SIGTERM)");
+
+ if (sigaction(SIGHUP, &sa, NULL) < 0)
+ err(1, "Could not sigaction(SIGHUP)");
+
+ if (sigaction(SIGINT, &sa, NULL) < 0)
+ err(1, "Could not sigaction(SIGINT)");
+
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = SA_NOCLDWAIT;
+
+ if (sigaction(SIGCHLD, &sa, NULL) < 0)
+ err(1, "Could not sigaction(SIGCHLD)");
+
+ /* Open TTYs */
+ if (sppd_ttys_open(tty, &amaster, &aslave) < 0)
+ exit(1);
+
+ /* Open RFCOMM connection */
+ memset(&ra, 0, sizeof(ra));
+ ra.rfcomm_len = sizeof(ra);
+ ra.rfcomm_family = AF_BLUETOOTH;
+
+ s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
+ if (s < 0)
+ err(1, "Could not create socket");
+
+ if (bind(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
+ err(1, "Could not bind socket");
+
+ memcpy(&ra.rfcomm_bdaddr, &addr, sizeof(ra.rfcomm_bdaddr));
+ ra.rfcomm_channel = channel;
+
+ if (connect(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
+ err(1, "Could not connect socket");
+
+ /* Became daemon if required */
+ if (background) {
+ switch (fork()) {
+ case -1:
+ err(1, "Could not fork()");
+ /* NOT REACHED */
+
+ case 0:
+ exit(0);
+ /* NOT REACHED */
+
+ default:
+ if (daemon(0, 0) < 0)
+ err(1, "Could not daemon()");
+ break;
+ }
+ }
+
+ openlog(SPPD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
+ syslog(LOG_INFO, "Starting on %s...", tty);
+
+ for (done = 0; !done; ) {
+ FD_ZERO(&rfd);
+ FD_SET(amaster, &rfd);
+ FD_SET(s, &rfd);
+
+ n = select(max(amaster, s) + 1, &rfd, NULL, NULL, NULL);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+
+ syslog(LOG_ERR, "Could not select(). %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ if (n == 0)
+ continue;
+
+ if (FD_ISSET(amaster, &rfd)) {
+ n = sppd_read(amaster, buf, sizeof(buf));
+ if (n < 0) {
+ syslog(LOG_ERR, "Could not read master pty, " \
+ "fd=%d. %s", amaster, strerror(errno));
+ exit(1);
+ }
+
+ if (n == 0)
+ break; /* XXX */
+
+ if (sppd_write(s, buf, n) < 0) {
+ syslog(LOG_ERR, "Could not write to socket, " \
+ "fd=%d, size=%d. %s",
+ s, n, strerror(errno));
+ exit(1);
+ }
+ }
+
+ if (FD_ISSET(s, &rfd)) {
+ n = sppd_read(s, buf, sizeof(buf));
+ if (n < 0) {
+ syslog(LOG_ERR, "Could not read socket, " \
+ "fd=%d. %s", s, strerror(errno));
+ exit(1);
+ }
+
+ if (n == 0)
+ break;
+
+ if (sppd_write(amaster, buf, n) < 0) {
+ syslog(LOG_ERR, "Could not write to master " \
+ "pty, fd=%d, size=%d. %s",
+ amaster, n, strerror(errno));
+ exit(1);
+ }
+ }
+ }
+
+ syslog(LOG_INFO, "Completed on %s", tty);
+ closelog();
+
+ close(s);
+ close(aslave);
+ close(amaster);
+
+ return (0);
+}
+
+/* Open TTYs */
+static int
+sppd_ttys_open(char const *tty, int *amaster, int *aslave)
+{
+ char pty[PATH_MAX];
+ struct group *gr = NULL;
+ gid_t ttygid;
+ struct termios tio;
+
+ /*
+ * Master PTY
+ */
+
+ strlcpy(pty, tty, sizeof(pty));
+ pty[5] = 'p';
+
+ if (strcmp(pty, tty) == 0) {
+ syslog(LOG_ERR, "Master and slave tty are the same (%s)", tty);
+ return (-1);
+ }
+
+ if ((*amaster = open(pty, O_RDWR, 0)) < 0) {
+ syslog(LOG_ERR, "Could not open(%s). %s", pty, strerror(errno));
+ return (-1);
+ }
+
+ /*
+ * Slave TTY
+ */
+
+ if ((gr = getgrnam("tty")) != NULL)
+ ttygid = gr->gr_gid;
+ else
+ ttygid = -1;
+
+ (void) chown(tty, getuid(), ttygid);
+ (void) chmod(tty, S_IRUSR|S_IWUSR|S_IWGRP);
+ (void) revoke(tty);
+
+ if ((*aslave = open(tty, O_RDWR, 0)) < 0) {
+ syslog(LOG_ERR, "Could not open(%s). %s", tty, strerror(errno));
+ close(*amaster);
+ return (-1);
+ }
+
+ /*
+ * Make slave TTY raw
+ */
+
+ cfmakeraw(&tio);
+
+ if (tcsetattr(*aslave, TCSANOW, &tio) < 0) {
+ syslog(LOG_ERR, "Could not tcsetattr(). %s", strerror(errno));
+ close(*aslave);
+ close(*amaster);
+ return (-1);
+ }
+
+ return (0);
+} /* sppd_ttys_open */
+
+/* Read data */
+static int
+sppd_read(int fd, char *buffer, int size)
+{
+ int n;
+
+again:
+ n = read(fd, buffer, size);
+ if (n < 0) {
+ if (errno == EINTR)
+ goto again;
+
+ return (-1);
+ }
+
+ return (n);
+} /* sppd_read */
+
+/* Write data */
+static int
+sppd_write(int fd, char *buffer, int size)
+{
+ int n, wrote;
+
+ for (wrote = 0; size > 0; ) {
+ n = write(fd, buffer, size);
+ switch (n) {
+ case -1:
+ if (errno != EINTR)
+ return (-1);
+ break;
+
+ case 0:
+ /* XXX can happen? */
+ break;
+
+ default:
+ wrote += n;
+ buffer += n;
+ size -= n;
+ break;
+ }
+ }
+
+ return (wrote);
+} /* sppd_write */
+
+/* Signal handler */
+static void
+sppd_sighandler(int s)
+{
+ syslog(LOG_INFO, "Signal %d received. Total %d signals received\n",
+ s, ++ done);
+} /* sppd_sighandler */
+
+/* Display usage and exit */
+static void
+usage(void)
+{
+ fprintf(stdout,
+"Usage: %s options\n" \
+"Where options are:\n" \
+"\t-a bdaddr BDADDR to connect to (required)\n" \
+"\t-b Run in background\n" \
+"\t-c channel RFCOMM channel to connect to (required)\n" \
+"\t-t tty TTY name\n" \
+"\t-h Display this message\n", SPPD_IDENT);
+
+ exit(255);
+} /* usage */
+