diff options
author | julian <julian@FreeBSD.org> | 2003-05-10 21:44:42 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 2003-05-10 21:44:42 +0000 |
commit | dc5734d94b071df224b65d45b95d9ae7c5d563ab (patch) | |
tree | ed7d8caf163274b56933e0b801c52beb10b3260d /usr.bin/bluetooth | |
parent | 9e09746efa5431d5af0baf849575917d37cfdb76 (diff) | |
download | FreeBSD-src-dc5734d94b071df224b65d45b95d9ae7c5d563ab.zip FreeBSD-src-dc5734d94b071df224b65d45b95d9ae7c5d563ab.tar.gz |
Part one of undating the bluetooth code to the newest version
Submitted by: Maksim Yevmenkin <m_evmenkin@yahoo.com>
Approved by: re@
Diffstat (limited to 'usr.bin/bluetooth')
-rw-r--r-- | usr.bin/bluetooth/Makefile | 5 | ||||
-rw-r--r-- | usr.bin/bluetooth/btsockstat/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/bluetooth/btsockstat/btsockstat.1 | 35 | ||||
-rw-r--r-- | usr.bin/bluetooth/btsockstat/btsockstat.c | 196 | ||||
-rw-r--r-- | usr.bin/bluetooth/rfcomm_sppd/Makefile | 15 | ||||
-rw-r--r-- | usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 | 107 | ||||
-rw-r--r-- | usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c | 383 |
7 files changed, 716 insertions, 31 deletions
diff --git a/usr.bin/bluetooth/Makefile b/usr.bin/bluetooth/Makefile index 1da9ef2..be3146e 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 ea78892..7614881 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 357edd2..608958d 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 d123502..7911f40 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 0000000..53d9f31 --- /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 0000000..8c244d6 --- /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 0000000..dbb2032 --- /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 */ + |