summaryrefslogtreecommitdiffstats
path: root/usr.bin/bluetooth/rfcomm_sppd
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2003-05-10 21:44:42 +0000
committerjulian <julian@FreeBSD.org>2003-05-10 21:44:42 +0000
commitdc5734d94b071df224b65d45b95d9ae7c5d563ab (patch)
treeed7d8caf163274b56933e0b801c52beb10b3260d /usr.bin/bluetooth/rfcomm_sppd
parent9e09746efa5431d5af0baf849575917d37cfdb76 (diff)
downloadFreeBSD-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/rfcomm_sppd')
-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
3 files changed, 505 insertions, 0 deletions
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 */
+
OpenPOWER on IntegriCloud