Index: stable/10/usr.bin/bluetooth/rfcomm_sppd/Makefile =================================================================== --- stable/10/usr.bin/bluetooth/rfcomm_sppd/Makefile (revision 274181) +++ stable/10/usr.bin/bluetooth/rfcomm_sppd/Makefile (revision 274182) @@ -1,11 +1,11 @@ # $Id: Makefile,v 1.7 2003/09/07 18:15:55 max Exp $ # $FreeBSD$ PROG= rfcomm_sppd SRCS= rfcomm_sppd.c rfcomm_sdp.c WARNS?= 2 DPADD= ${LIBBLUETOOTH} ${LIBSDP} -LDADD= -lbluetooth -lsdp +LDADD= -lbluetooth -lsdp -lutil .include Index: stable/10/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 =================================================================== --- stable/10/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 (revision 274181) +++ stable/10/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 (revision 274182) @@ -1,186 +1,186 @@ .\" Copyright (c) 2001-2003 Maksim Yevmenkin .\" 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.3 2003/09/07 18:15:55 max Exp $ .\" $FreeBSD$ .\" .Dd April 21, 2008 .Dt RFCOMM_SPPD 1 .Os .Sh NAME .Nm rfcomm_sppd .Nd RFCOMM Serial Port Profile daemon .Sh SYNOPSIS .Nm -.Op Fl bhS +.Op Fl bhtS .Fl a Ar address .Fl c Ar channel -.Op Fl t Ar tty .Sh DESCRIPTION The .Nm utility is a Serial Port Profile daemon. It can operate in two modes: client and server. .Pp In client mode, .Nm opens RFCOMM connection to the specified .Ar address server and .Ar channel . Once connection is established, the .Nm utility provides access to the server's remote serial port via stdin/stdout or via -.Xr pty 4 +.Xr pts 4 interface if .Fl t option was specified. .Pp If the .Fl S option is specified, .Nm will operate in server mode and act as RFCOMM server, listening on .Dv ANY address and advertising a virtual serial port via the .Xr sdpd 8 daemon. If .Fl t options was specified, -the server side of the virtual serial port is attached to the pseudo-terminal -.Ar tty . +the server side of the virtual serial port is attached to a pseudo-terminal. Otherwise the virtual serial port is attached to the stdin/stdout. .Nm should be run as root in order to communicate with .Xr sdpd 8 in this case. .Pp The .Nm utility 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 the 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 address In client mode, this required option specifies the address of the remote RFCOMM server. If this option is specified in server mode, .Nm will only accept connections from the .Tn Bluetooth device with address .Ar address . The address can be specified as BD_ADDR or name. If name was specified then .Nm utility will attempt to resolve the name via .Xr bt_gethostbyname 3 . .It Fl b Detach from the controlling terminal, i.e., run in background. .It Fl c Ar channel In both client and server mode, this option specifies the RFCOMM channel to connect to or listen on. In server mode, the channel should be a number between 1 and 30. If not specified, .Nm will try to bind to .Dq wildcard RFCOMM channel number. The actual RFCOMM channel will be obtained via .Xr getsockname 2 call and will be used to register Serial Port service with .Xr sdpd 8 . In client mode, the channel could either be a number between 1 and 30 or a service name. Supported service names are: .Cm DUN (for DialUp Networking service), .Cm FAX (for Fax service), .Cm LAN (for LAN Access Using PPP service) and .Cm SP (for Serial Port service). If channel was not specified then .Nm utility will try to obtain RFCOMM channel for Serial Port service via Service Discovery Protocol from the server. .It Fl h Display usage message and exit. .It Fl S Server mode; see .Sx DESCRIPTION . -.It Fl t Ar tty -Slave pseudo tty name. +.It Fl t +Use slave pseudo tty. If not set stdin/stdout will be used. This option is required if .Fl b option was specified. .El .Sh FILES -.Bl -tag -width ".Pa /dev/tty[p-sP-S][0-9a-v]" -compact -.It Pa /dev/pty[p-sP-S][0-9a-v] -master pseudo terminals -.It Pa /dev/tty[p-sP-S][0-9a-v] +.Bl -tag -width ".Pa /dev/pts/[num]" -compact +.It Pa /dev/pts/[num] slave pseudo terminals .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES -.Dl "rfcomm_sppd -a 00:01:02:03:04:05 -c 1 -t /dev/ttyp1" +.Dl "rfcomm_sppd -a 00:01:02:03:04:05 -c 1 -t" .Pp Will start the .Nm utility and open RFCOMM connection to the server at .Li 00:01:02:03:04:05 and channel .Li 1 . -Once the connection has been established, -.Pa /dev/ttyp1 +Once the connection has been established, a +.Xr pts 4 can be used to talk to the remote serial port on the server. +.Nm +prints the name of the +.Xr pts 4 +to use on stdout. .Sh SEE ALSO .Xr bluetooth 3 , .Xr ng_btsocket 4 , -.Xr pty 4 , +.Xr pts 4 , .Xr rfcomm_pppd 8 , .Xr sdpd 8 .Sh AUTHORS .An Maksim Yevmenkin Aq m_evmenkin@yahoo.com .Sh BUGS Please report if found. Index: stable/10/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c =================================================================== --- stable/10/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c (revision 274181) +++ stable/10/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c (revision 274182) @@ -1,504 +1,459 @@ /* * rfcomm_sppd.c */ /*- * Copyright (c) 2003 Maksim Yevmenkin * 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.4 2003/09/07 18:15:55 max Exp $ * $FreeBSD$ */ #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #define SPPD_IDENT "rfcomm_sppd" #define SPPD_BUFFER_SIZE 1024 #define max(a, b) (((a) > (b))? (a) : (b)) int rfcomm_channel_lookup (bdaddr_t const *local, bdaddr_t const *remote, int service, int *channel, int *error); -static int sppd_ttys_open (char const *tty, int *amaster, int *aslave); +static int sppd_ttys_open (char **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, service, - s, amaster, aslave, fd, doserver; + s, amaster, aslave, fd, doserver, + dopty; fd_set rfd; char *tty = NULL, *ep = NULL, buf[SPPD_BUFFER_SIZE]; memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); background = channel = 0; service = SDP_SERVICE_CLASS_SERIAL_PORT; doserver = 0; + dopty = 0; /* Parse command line options */ - while ((n = getopt(argc, argv, "a:bc:t:hS")) != -1) { + while ((n = getopt(argc, argv, "a:bc:thS")) != -1) { switch (n) { case 'a': /* BDADDR */ if (!bt_aton(optarg, &addr)) { struct hostent *he = NULL; if ((he = bt_gethostbyname(optarg)) == NULL) errx(1, "%s: %s", optarg, hstrerror(h_errno)); memcpy(&addr, he->h_addr, sizeof(addr)); } break; case 'c': /* RFCOMM channel */ channel = strtoul(optarg, &ep, 10); if (*ep != '\0') { channel = 0; switch (tolower(optarg[0])) { case 'd': /* DialUp Networking */ service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; break; case 'f': /* Fax */ service = SDP_SERVICE_CLASS_FAX; break; case 'l': /* LAN */ service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; break; case 's': /* Serial Port */ service = SDP_SERVICE_CLASS_SERIAL_PORT; break; default: errx(1, "Unknown service name: %s", optarg); /* NOT REACHED */ } } break; case 'b': /* Run in background */ background = 1; break; - case 't': /* Slave TTY name */ - if (optarg[0] != '/') - asprintf(&tty, "%s%s", _PATH_DEV, optarg); - else - tty = optarg; + case 't': /* Open pseudo TTY */ + dopty = 1; break; case 'S': doserver = 1; break; case 'h': default: usage(); /* NOT REACHED */ } } /* Check if we have everything we need */ if (!doserver && 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 (tty == NULL) { + if (dopty) { + if (sppd_ttys_open(&tty, &amaster, &aslave) < 0) + exit(1); + + fd = amaster; + } else { if (background) usage(); amaster = STDIN_FILENO; fd = STDOUT_FILENO; - } else { - if (sppd_ttys_open(tty, &amaster, &aslave) < 0) - exit(1); - - fd = amaster; - } + } /* Open RFCOMM connection */ if (doserver) { struct sockaddr_rfcomm ma; bdaddr_t bt_addr_any; sdp_sp_profile_t sp; void *ss; uint32_t sdp_handle; int acceptsock, aaddrlen; acceptsock = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); if (acceptsock < 0) err(1, "Could not create socket"); memcpy(&bt_addr_any, NG_HCI_BDADDR_ANY, sizeof(bt_addr_any)); memset(&ma, 0, sizeof(ma)); ma.rfcomm_len = sizeof(ma); ma.rfcomm_family = AF_BLUETOOTH; memcpy(&ma.rfcomm_bdaddr, &bt_addr_any, sizeof(bt_addr_any)); ma.rfcomm_channel = channel; if (bind(acceptsock, (struct sockaddr *)&ma, sizeof(ma)) < 0) err(1, "Could not bind socket on channel %d", channel); if (listen(acceptsock, 10) != 0) err(1, "Could not listen on socket"); aaddrlen = sizeof(ma); if (getsockname(acceptsock, (struct sockaddr *)&ma, &aaddrlen) < 0) err(1, "Could not get socket name"); channel = ma.rfcomm_channel; ss = sdp_open_local(NULL); if (ss == NULL) errx(1, "Unable to create local SDP session"); if (sdp_error(ss) != 0) errx(1, "Unable to open local SDP session. %s (%d)", strerror(sdp_error(ss)), sdp_error(ss)); memset(&sp, 0, sizeof(sp)); sp.server_channel = channel; if (sdp_register_service(ss, SDP_SERVICE_CLASS_SERIAL_PORT, &bt_addr_any, (void *)&sp, sizeof(sp), &sdp_handle) != 0) { errx(1, "Unable to register LAN service with " "local SDP daemon. %s (%d)", strerror(sdp_error(ss)), sdp_error(ss)); } s = -1; while (s < 0) { aaddrlen = sizeof(ra); s = accept(acceptsock, (struct sockaddr *)&ra, &aaddrlen); if (s < 0) err(1, "Unable to accept()"); if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) && memcmp(&addr, &ra.rfcomm_bdaddr, sizeof(addr))) { warnx("Connect from wrong client"); close(s); s = -1; } } sdp_unregister_service(ss, sdp_handle); sdp_close(ss); close(acceptsock); } else { /* Check channel, if was not set then obtain it via SDP */ if (channel == 0 && service != 0) if (rfcomm_channel_lookup(NULL, &addr, service, &channel, &n) != 0) errc(1, n, "Could not obtain RFCOMM channel"); if (channel <= 0 || channel > 30) errx(1, "Invalid RFCOMM channel number %d", channel); s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); if (s < 0) err(1, "Could not create socket"); memset(&ra, 0, sizeof(ra)); ra.rfcomm_len = sizeof(ra); ra.rfcomm_family = AF_BLUETOOTH; 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 && daemon(0, 0) < 0) err(1, "Could not daemon()"); openlog(SPPD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON); syslog(LOG_INFO, "Starting on %s...", (tty != NULL)? tty : "stdin/stdout"); + /* Print used tty on stdout for wrappers to pick up */ + if (!background) + fprintf(stdout, "%s\n", 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(fd, buf, n) < 0) { syslog(LOG_ERR, "Could not write to master " \ "pty, fd=%d, size=%d. %s", fd, n, strerror(errno)); exit(1); } } } syslog(LOG_INFO, "Completed on %s", (tty != NULL)? tty : "stdin/stdout"); closelog(); close(s); if (tty != NULL) { close(aslave); close(amaster); } return (0); } /* Open TTYs */ static int -sppd_ttys_open(char const *tty, int *amaster, int *aslave) +sppd_ttys_open(char **tty, int *amaster, int *aslave) { - char pty[PATH_MAX], *slash; - struct group *gr = NULL; - gid_t ttygid; + char pty[PATH_MAX]; struct termios tio; - /* - * Construct master PTY name. The slave tty name must be less then - * PATH_MAX characters in length, must contain '/' character and - * must not end with '/'. - */ + cfmakeraw(&tio); - if (strlen(tty) >= sizeof(pty)) { - syslog(LOG_ERR, "Slave tty name is too long"); + if (openpty(amaster, aslave, pty, &tio, NULL) == -1) { + syslog(LOG_ERR, "Could not openpty(). %s", strerror(errno)); return (-1); } - strlcpy(pty, tty, sizeof(pty)); - slash = strrchr(pty, '/'); - if (slash == NULL || slash[1] == '\0') { - syslog(LOG_ERR, "Invalid slave tty name (%s)", tty); - return (-1); - } - - slash[1] = '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_IRGRP|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)); + if ((*tty = strdup(pty)) == NULL) { + syslog(LOG_ERR, "Could not strdup(). %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 address Peer address (required in client mode)\n" \ "\t-b Run in background\n" \ "\t-c channel RFCOMM channel to connect to or listen on\n" \ -"\t-t tty TTY name (required in background mode)\n" \ +"\t-t use slave pseudo tty (required in background mode)\n" \ "\t-S Server mode\n" \ "\t-h Display this message\n", SPPD_IDENT); exit(255); } /* usage */ Index: stable/10 =================================================================== --- stable/10 (revision 274181) +++ stable/10 (revision 274182) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r273548