16b5c5d0dSHasso Tepper /* $NetBSD: rfcomm_sppd.c,v 1.8 2007/04/21 10:39:30 dsl Exp $ */
26b5c5d0dSHasso Tepper
36b5c5d0dSHasso Tepper /*-
46b5c5d0dSHasso Tepper * Copyright (c) 2006 Itronix Inc.
56b5c5d0dSHasso Tepper * All rights reserved.
66b5c5d0dSHasso Tepper *
76b5c5d0dSHasso Tepper * Redistribution and use in source and binary forms, with or without
86b5c5d0dSHasso Tepper * modification, are permitted provided that the following conditions
96b5c5d0dSHasso Tepper * are met:
106b5c5d0dSHasso Tepper * 1. Redistributions of source code must retain the above copyright
116b5c5d0dSHasso Tepper * notice, this list of conditions and the following disclaimer.
126b5c5d0dSHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright
136b5c5d0dSHasso Tepper * notice, this list of conditions and the following disclaimer in the
146b5c5d0dSHasso Tepper * documentation and/or other materials provided with the distribution.
156b5c5d0dSHasso Tepper * 3. The name of Itronix Inc. may not be used to endorse
166b5c5d0dSHasso Tepper * or promote products derived from this software without specific
176b5c5d0dSHasso Tepper * prior written permission.
186b5c5d0dSHasso Tepper *
196b5c5d0dSHasso Tepper * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
206b5c5d0dSHasso Tepper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216b5c5d0dSHasso Tepper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226b5c5d0dSHasso Tepper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
236b5c5d0dSHasso Tepper * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
246b5c5d0dSHasso Tepper * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
256b5c5d0dSHasso Tepper * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
266b5c5d0dSHasso Tepper * ON ANY THEORY OF LIABILITY, WHETHER IN
276b5c5d0dSHasso Tepper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286b5c5d0dSHasso Tepper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296b5c5d0dSHasso Tepper * POSSIBILITY OF SUCH DAMAGE.
306b5c5d0dSHasso Tepper */
316b5c5d0dSHasso Tepper /*
326b5c5d0dSHasso Tepper * rfcomm_sppd.c
336b5c5d0dSHasso Tepper *
346b5c5d0dSHasso Tepper * Copyright (c) 2007 Iain Hibbert
356b5c5d0dSHasso Tepper * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
366b5c5d0dSHasso Tepper * All rights reserved.
376b5c5d0dSHasso Tepper *
386b5c5d0dSHasso Tepper * Redistribution and use in source and binary forms, with or without
396b5c5d0dSHasso Tepper * modification, are permitted provided that the following conditions
406b5c5d0dSHasso Tepper * are met:
416b5c5d0dSHasso Tepper * 1. Redistributions of source code must retain the above copyright
426b5c5d0dSHasso Tepper * notice, this list of conditions and the following disclaimer.
436b5c5d0dSHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright
446b5c5d0dSHasso Tepper * notice, this list of conditions and the following disclaimer in the
456b5c5d0dSHasso Tepper * documentation and/or other materials provided with the distribution.
466b5c5d0dSHasso Tepper *
476b5c5d0dSHasso Tepper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
486b5c5d0dSHasso Tepper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
496b5c5d0dSHasso Tepper * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
506b5c5d0dSHasso Tepper * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
516b5c5d0dSHasso Tepper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
526b5c5d0dSHasso Tepper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
536b5c5d0dSHasso Tepper * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
546b5c5d0dSHasso Tepper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
556b5c5d0dSHasso Tepper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
566b5c5d0dSHasso Tepper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
576b5c5d0dSHasso Tepper * SUCH DAMAGE.
586b5c5d0dSHasso Tepper */
596b5c5d0dSHasso Tepper
606b5c5d0dSHasso Tepper #include <bluetooth.h>
616b5c5d0dSHasso Tepper #include <ctype.h>
626b5c5d0dSHasso Tepper #include <err.h>
636b5c5d0dSHasso Tepper #include <errno.h>
646b5c5d0dSHasso Tepper #include <fcntl.h>
656b5c5d0dSHasso Tepper #include <grp.h>
666b5c5d0dSHasso Tepper #include <limits.h>
676b5c5d0dSHasso Tepper #include <paths.h>
686b5c5d0dSHasso Tepper #include <sdp.h>
696b5c5d0dSHasso Tepper #include <signal.h>
706b5c5d0dSHasso Tepper #include <stdarg.h>
716b5c5d0dSHasso Tepper #include <stdio.h>
726b5c5d0dSHasso Tepper #include <stdlib.h>
736b5c5d0dSHasso Tepper #include <string.h>
746b5c5d0dSHasso Tepper #include <syslog.h>
756b5c5d0dSHasso Tepper #include <termios.h>
766b5c5d0dSHasso Tepper #include <unistd.h>
776b5c5d0dSHasso Tepper #include <sys/stat.h>
786b5c5d0dSHasso Tepper
796b5c5d0dSHasso Tepper #include <netbt/rfcomm.h>
806b5c5d0dSHasso Tepper
816b5c5d0dSHasso Tepper #include "rfcomm_sdp.h"
826b5c5d0dSHasso Tepper
836b5c5d0dSHasso Tepper #define max(a, b) ((a) > (b) ? (a) : (b))
846b5c5d0dSHasso Tepper
856b5c5d0dSHasso Tepper int open_tty(const char *);
866b5c5d0dSHasso Tepper int open_client(bdaddr_t *, bdaddr_t *, int, const char *);
876b5c5d0dSHasso Tepper int open_server(bdaddr_t *, uint8_t, int, const char *);
886b5c5d0dSHasso Tepper void copy_data(int, int);
896b5c5d0dSHasso Tepper void sighandler(int);
90*6d08986dSSascha Wildner void usage(void) __dead2;
916b5c5d0dSHasso Tepper void reset_tio(void);
926b5c5d0dSHasso Tepper
936b5c5d0dSHasso Tepper int done; /* got a signal */
946b5c5d0dSHasso Tepper struct termios tio; /* stored termios for reset on exit */
956b5c5d0dSHasso Tepper
966b5c5d0dSHasso Tepper struct service {
976b5c5d0dSHasso Tepper const char *name;
986b5c5d0dSHasso Tepper const char *description;
996b5c5d0dSHasso Tepper uint16_t class;
1006b5c5d0dSHasso Tepper int pdulen;
1016b5c5d0dSHasso Tepper } services[] = {
1026b5c5d0dSHasso Tepper { "DUN", "Dialup Networking",
1036b5c5d0dSHasso Tepper SDP_SERVICE_CLASS_DIALUP_NETWORKING,
1046b5c5d0dSHasso Tepper sizeof(struct sdp_dun_profile)
1056b5c5d0dSHasso Tepper },
1066b5c5d0dSHasso Tepper { "LAN", "Lan access using PPP",
1076b5c5d0dSHasso Tepper SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
1086b5c5d0dSHasso Tepper sizeof(struct sdp_lan_profile)
1096b5c5d0dSHasso Tepper },
1106b5c5d0dSHasso Tepper { "SP", "Serial Port",
1116b5c5d0dSHasso Tepper SDP_SERVICE_CLASS_SERIAL_PORT,
1126b5c5d0dSHasso Tepper sizeof(struct sdp_sp_profile)
1136b5c5d0dSHasso Tepper },
1146b5c5d0dSHasso Tepper { NULL, NULL,
1156b5c5d0dSHasso Tepper 0,
1166b5c5d0dSHasso Tepper 0
1176b5c5d0dSHasso Tepper }
1186b5c5d0dSHasso Tepper };
1196b5c5d0dSHasso Tepper
1206b5c5d0dSHasso Tepper int
main(int argc,char * argv[])1216b5c5d0dSHasso Tepper main(int argc, char *argv[])
1226b5c5d0dSHasso Tepper {
1236b5c5d0dSHasso Tepper struct termios t;
1246b5c5d0dSHasso Tepper bdaddr_t laddr, raddr;
1256b5c5d0dSHasso Tepper fd_set rdset;
1266b5c5d0dSHasso Tepper const char *service;
1276b5c5d0dSHasso Tepper char *ep, *tty;
1286b5c5d0dSHasso Tepper int lm, n, rfcomm, tty_in, tty_out;
1296b5c5d0dSHasso Tepper uint8_t channel;
1306b5c5d0dSHasso Tepper
1316b5c5d0dSHasso Tepper bdaddr_copy(&laddr, BDADDR_ANY);
1326b5c5d0dSHasso Tepper bdaddr_copy(&raddr, BDADDR_ANY);
1336b5c5d0dSHasso Tepper service = "SP";
1346b5c5d0dSHasso Tepper tty = NULL;
1356b5c5d0dSHasso Tepper channel = 0;
1366b5c5d0dSHasso Tepper lm = 0;
1376b5c5d0dSHasso Tepper
1386b5c5d0dSHasso Tepper /* Parse command line options */
1396b5c5d0dSHasso Tepper while ((n = getopt(argc, argv, "a:c:d:hm:s:t:")) != -1) {
1406b5c5d0dSHasso Tepper switch (n) {
1416b5c5d0dSHasso Tepper case 'a': /* remote device address */
1426b5c5d0dSHasso Tepper if (!bt_aton(optarg, &raddr)) {
1436b5c5d0dSHasso Tepper struct hostent *he = NULL;
1446b5c5d0dSHasso Tepper
1456b5c5d0dSHasso Tepper if ((he = bt_gethostbyname(optarg)) == NULL)
1466b5c5d0dSHasso Tepper errx(EXIT_FAILURE, "%s: %s", optarg,
1476b5c5d0dSHasso Tepper hstrerror(h_errno));
1486b5c5d0dSHasso Tepper
1496b5c5d0dSHasso Tepper bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
1506b5c5d0dSHasso Tepper }
1516b5c5d0dSHasso Tepper break;
1526b5c5d0dSHasso Tepper
1536b5c5d0dSHasso Tepper case 'c': /* RFCOMM channel */
1546b5c5d0dSHasso Tepper channel = strtoul(optarg, &ep, 10);
1556b5c5d0dSHasso Tepper if (*ep != '\0' || channel < 1 || channel > 30)
1566b5c5d0dSHasso Tepper errx(EXIT_FAILURE, "Invalid channel: %s", optarg);
1576b5c5d0dSHasso Tepper
1586b5c5d0dSHasso Tepper break;
1596b5c5d0dSHasso Tepper
1606b5c5d0dSHasso Tepper case 'd': /* local device address */
1616b5c5d0dSHasso Tepper if (!bt_devaddr(optarg, &laddr))
1626b5c5d0dSHasso Tepper err(EXIT_FAILURE, "%s", optarg);
1636b5c5d0dSHasso Tepper
1646b5c5d0dSHasso Tepper break;
1656b5c5d0dSHasso Tepper
1666b5c5d0dSHasso Tepper case 'm': /* Link Mode */
1676b5c5d0dSHasso Tepper if (strcasecmp(optarg, "auth") == 0)
1686b5c5d0dSHasso Tepper lm = RFCOMM_LM_AUTH;
1696b5c5d0dSHasso Tepper else if (strcasecmp(optarg, "encrypt") == 0)
1706b5c5d0dSHasso Tepper lm = RFCOMM_LM_ENCRYPT;
1716b5c5d0dSHasso Tepper else if (strcasecmp(optarg, "secure") == 0)
1726b5c5d0dSHasso Tepper lm = RFCOMM_LM_SECURE;
1736b5c5d0dSHasso Tepper else
1746b5c5d0dSHasso Tepper errx(EXIT_FAILURE, "%s: unknown mode", optarg);
1756b5c5d0dSHasso Tepper
1766b5c5d0dSHasso Tepper break;
1776b5c5d0dSHasso Tepper
1786b5c5d0dSHasso Tepper case 's': /* service class */
1796b5c5d0dSHasso Tepper service = optarg;
1806b5c5d0dSHasso Tepper break;
1816b5c5d0dSHasso Tepper
1826b5c5d0dSHasso Tepper case 't': /* Slave TTY name */
1836b5c5d0dSHasso Tepper if (optarg[0] != '/')
1846b5c5d0dSHasso Tepper asprintf(&tty, "%s%s", _PATH_DEV, optarg);
1856b5c5d0dSHasso Tepper else
1866b5c5d0dSHasso Tepper tty = optarg;
1876b5c5d0dSHasso Tepper
1886b5c5d0dSHasso Tepper break;
1896b5c5d0dSHasso Tepper
1906b5c5d0dSHasso Tepper case 'h':
1916b5c5d0dSHasso Tepper default:
1926b5c5d0dSHasso Tepper usage();
1936b5c5d0dSHasso Tepper /* NOT REACHED */
1946b5c5d0dSHasso Tepper }
1956b5c5d0dSHasso Tepper }
1966b5c5d0dSHasso Tepper
1976b5c5d0dSHasso Tepper /*
1986b5c5d0dSHasso Tepper * validate options:
1996b5c5d0dSHasso Tepper * must have channel or remote address but not both
2006b5c5d0dSHasso Tepper */
2016b5c5d0dSHasso Tepper if ((channel == 0 && bdaddr_any(&raddr))
2026b5c5d0dSHasso Tepper || (channel != 0 && !bdaddr_any(&raddr)))
2036b5c5d0dSHasso Tepper usage();
2046b5c5d0dSHasso Tepper
2056b5c5d0dSHasso Tepper /*
2066b5c5d0dSHasso Tepper * grab ttys before we start the bluetooth
2076b5c5d0dSHasso Tepper */
2086b5c5d0dSHasso Tepper if (tty == NULL) {
2096b5c5d0dSHasso Tepper tty_in = STDIN_FILENO;
2106b5c5d0dSHasso Tepper tty_out = STDOUT_FILENO;
2116b5c5d0dSHasso Tepper } else {
2126b5c5d0dSHasso Tepper tty_in = open_tty(tty);
2136b5c5d0dSHasso Tepper tty_out = tty_in;
2146b5c5d0dSHasso Tepper }
2156b5c5d0dSHasso Tepper
2166b5c5d0dSHasso Tepper /* open RFCOMM */
2176b5c5d0dSHasso Tepper if (channel == 0)
2186b5c5d0dSHasso Tepper rfcomm = open_client(&laddr, &raddr, lm, service);
2196b5c5d0dSHasso Tepper else
2206b5c5d0dSHasso Tepper rfcomm = open_server(&laddr, channel, lm, service);
2216b5c5d0dSHasso Tepper
2226b5c5d0dSHasso Tepper /*
2236b5c5d0dSHasso Tepper * now we are ready to go, so either detach or maybe turn
2246b5c5d0dSHasso Tepper * off some input processing, so that rfcomm_sppd can
2256b5c5d0dSHasso Tepper * be used directly with stdio
2266b5c5d0dSHasso Tepper */
2276b5c5d0dSHasso Tepper if (tty == NULL) {
2286b5c5d0dSHasso Tepper if (tcgetattr(tty_in, &t) < 0)
2296b5c5d0dSHasso Tepper err(EXIT_FAILURE, "tcgetattr");
2306b5c5d0dSHasso Tepper
2316b5c5d0dSHasso Tepper memcpy(&tio, &t, sizeof(tio));
2326b5c5d0dSHasso Tepper t.c_lflag &= ~(ECHO | ICANON);
2336b5c5d0dSHasso Tepper t.c_iflag &= ~(ICRNL);
2346b5c5d0dSHasso Tepper
2356b5c5d0dSHasso Tepper if (memcmp(&tio, &t, sizeof(tio))) {
2366b5c5d0dSHasso Tepper if (tcsetattr(tty_in, TCSANOW, &t) < 0)
2376b5c5d0dSHasso Tepper err(EXIT_FAILURE, "tcsetattr");
2386b5c5d0dSHasso Tepper
2396b5c5d0dSHasso Tepper atexit(reset_tio);
2406b5c5d0dSHasso Tepper }
2416b5c5d0dSHasso Tepper } else {
2426b5c5d0dSHasso Tepper if (daemon(0, 0) < 0)
2436b5c5d0dSHasso Tepper err(EXIT_FAILURE, "daemon() failed");
2446b5c5d0dSHasso Tepper }
2456b5c5d0dSHasso Tepper
2466b5c5d0dSHasso Tepper /* catch signals */
2476b5c5d0dSHasso Tepper done = 0;
2486b5c5d0dSHasso Tepper (void)signal(SIGHUP, sighandler);
2496b5c5d0dSHasso Tepper (void)signal(SIGINT, sighandler);
2506b5c5d0dSHasso Tepper (void)signal(SIGPIPE, sighandler);
2516b5c5d0dSHasso Tepper (void)signal(SIGTERM, sighandler);
2526b5c5d0dSHasso Tepper
2536b5c5d0dSHasso Tepper openlog(getprogname(), LOG_PERROR | LOG_PID, LOG_DAEMON);
2546b5c5d0dSHasso Tepper syslog(LOG_INFO, "Starting on %s...", (tty ? tty : "stdio"));
2556b5c5d0dSHasso Tepper
2566b5c5d0dSHasso Tepper n = max(tty_in, rfcomm) + 1;
2576b5c5d0dSHasso Tepper while (!done) {
2586b5c5d0dSHasso Tepper FD_ZERO(&rdset);
2596b5c5d0dSHasso Tepper FD_SET(tty_in, &rdset);
2606b5c5d0dSHasso Tepper FD_SET(rfcomm, &rdset);
2616b5c5d0dSHasso Tepper
2626b5c5d0dSHasso Tepper if (select(n, &rdset, NULL, NULL, NULL) < 0) {
2636b5c5d0dSHasso Tepper if (errno == EINTR)
2646b5c5d0dSHasso Tepper continue;
2656b5c5d0dSHasso Tepper
2666b5c5d0dSHasso Tepper syslog(LOG_ERR, "select error: %m");
2676b5c5d0dSHasso Tepper exit(EXIT_FAILURE);
2686b5c5d0dSHasso Tepper }
2696b5c5d0dSHasso Tepper
2706b5c5d0dSHasso Tepper if (FD_ISSET(tty_in, &rdset))
2716b5c5d0dSHasso Tepper copy_data(tty_in, rfcomm);
2726b5c5d0dSHasso Tepper
2736b5c5d0dSHasso Tepper if (FD_ISSET(rfcomm, &rdset))
2746b5c5d0dSHasso Tepper copy_data(rfcomm, tty_out);
2756b5c5d0dSHasso Tepper }
2766b5c5d0dSHasso Tepper
2776b5c5d0dSHasso Tepper syslog(LOG_INFO, "Completed on %s", (tty ? tty : "stdio"));
2786b5c5d0dSHasso Tepper exit(EXIT_SUCCESS);
2796b5c5d0dSHasso Tepper }
2806b5c5d0dSHasso Tepper
2816b5c5d0dSHasso Tepper int
open_tty(const char * tty)2826b5c5d0dSHasso Tepper open_tty(const char *tty)
2836b5c5d0dSHasso Tepper {
2846b5c5d0dSHasso Tepper char pty[PATH_MAX], *slash;
2856b5c5d0dSHasso Tepper struct group *gr = NULL;
2866b5c5d0dSHasso Tepper gid_t ttygid;
2876b5c5d0dSHasso Tepper int master;
2886b5c5d0dSHasso Tepper
2896b5c5d0dSHasso Tepper /*
2906b5c5d0dSHasso Tepper * Construct master PTY name. The slave tty name must be less then
2916b5c5d0dSHasso Tepper * PATH_MAX characters in length, must contain '/' character and
2926b5c5d0dSHasso Tepper * must not end with '/'.
2936b5c5d0dSHasso Tepper */
2946b5c5d0dSHasso Tepper if (strlen(tty) >= sizeof(pty))
2956b5c5d0dSHasso Tepper errx(EXIT_FAILURE, ": tty name too long");
2966b5c5d0dSHasso Tepper
2976b5c5d0dSHasso Tepper strlcpy(pty, tty, sizeof(pty));
2986b5c5d0dSHasso Tepper slash = strrchr(pty, '/');
2996b5c5d0dSHasso Tepper if (slash == NULL || slash[1] == '\0')
3006b5c5d0dSHasso Tepper errx(EXIT_FAILURE, "%s: invalid tty", tty);
3016b5c5d0dSHasso Tepper
3026b5c5d0dSHasso Tepper slash[1] = 'p';
3036b5c5d0dSHasso Tepper if (strcmp(pty, tty) == 0)
3046b5c5d0dSHasso Tepper errx(EXIT_FAILURE, "Master and slave tty are the same (%s)", tty);
3056b5c5d0dSHasso Tepper
3066b5c5d0dSHasso Tepper if ((master = open(pty, O_RDWR, 0)) < 0)
3076b5c5d0dSHasso Tepper err(EXIT_FAILURE, "%s", pty);
3086b5c5d0dSHasso Tepper
3096b5c5d0dSHasso Tepper /*
3106b5c5d0dSHasso Tepper * Slave TTY
3116b5c5d0dSHasso Tepper */
3126b5c5d0dSHasso Tepper
3136b5c5d0dSHasso Tepper if ((gr = getgrnam("tty")) != NULL)
3146b5c5d0dSHasso Tepper ttygid = gr->gr_gid;
3156b5c5d0dSHasso Tepper else
3166b5c5d0dSHasso Tepper ttygid = (gid_t)-1;
3176b5c5d0dSHasso Tepper
3186b5c5d0dSHasso Tepper (void)chown(tty, getuid(), ttygid);
3196b5c5d0dSHasso Tepper (void)chmod(tty, S_IRUSR | S_IWUSR | S_IWGRP);
3206b5c5d0dSHasso Tepper (void)revoke(tty);
3216b5c5d0dSHasso Tepper
3226b5c5d0dSHasso Tepper return master;
3236b5c5d0dSHasso Tepper }
3246b5c5d0dSHasso Tepper
3256b5c5d0dSHasso Tepper int
open_client(bdaddr_t * laddr,bdaddr_t * raddr,int lm,const char * service)3266b5c5d0dSHasso Tepper open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, const char *service)
3276b5c5d0dSHasso Tepper {
3286b5c5d0dSHasso Tepper struct sockaddr_bt sa;
3296b5c5d0dSHasso Tepper struct service *s;
3306b5c5d0dSHasso Tepper struct linger l;
3316b5c5d0dSHasso Tepper char *ep;
3326b5c5d0dSHasso Tepper int fd;
33344753b81Szrj uint8_t channel = 0; /* avoid gcc warnings */
3346b5c5d0dSHasso Tepper
3356b5c5d0dSHasso Tepper for (s = services ; ; s++) {
3366b5c5d0dSHasso Tepper if (s->name == NULL) {
3376b5c5d0dSHasso Tepper channel = strtoul(service, &ep, 10);
3386b5c5d0dSHasso Tepper if (*ep != '\0' || channel < 1 || channel > 30)
3396b5c5d0dSHasso Tepper errx(EXIT_FAILURE, "Invalid service: %s", service);
3406b5c5d0dSHasso Tepper
3416b5c5d0dSHasso Tepper break;
3426b5c5d0dSHasso Tepper }
3436b5c5d0dSHasso Tepper
3446b5c5d0dSHasso Tepper if (strcasecmp(s->name, service) == 0) {
3456b5c5d0dSHasso Tepper if (rfcomm_channel_lookup(laddr, raddr, s->class, &channel, &errno) < 0)
3466b5c5d0dSHasso Tepper err(EXIT_FAILURE, "%s", s->name);
3476b5c5d0dSHasso Tepper
3486b5c5d0dSHasso Tepper break;
3496b5c5d0dSHasso Tepper }
3506b5c5d0dSHasso Tepper }
3516b5c5d0dSHasso Tepper
3526b5c5d0dSHasso Tepper memset(&sa, 0, sizeof(sa));
3536b5c5d0dSHasso Tepper sa.bt_len = sizeof(sa);
3546b5c5d0dSHasso Tepper sa.bt_family = AF_BLUETOOTH;
3556b5c5d0dSHasso Tepper bdaddr_copy(&sa.bt_bdaddr, laddr);
3566b5c5d0dSHasso Tepper
3576b5c5d0dSHasso Tepper fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
3586b5c5d0dSHasso Tepper if (fd < 0)
3596b5c5d0dSHasso Tepper err(EXIT_FAILURE, "socket()");
3606b5c5d0dSHasso Tepper
3616b5c5d0dSHasso Tepper if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
3626b5c5d0dSHasso Tepper err(EXIT_FAILURE, "bind(%s)", bt_ntoa(laddr, NULL));
3636b5c5d0dSHasso Tepper
3646b5c5d0dSHasso Tepper memset(&l, 0, sizeof(l));
3656b5c5d0dSHasso Tepper l.l_onoff = 1;
3666b5c5d0dSHasso Tepper l.l_linger = 5;
3676b5c5d0dSHasso Tepper if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
3686b5c5d0dSHasso Tepper err(EXIT_FAILURE, "linger()");
3696b5c5d0dSHasso Tepper
3706b5c5d0dSHasso Tepper if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
3716b5c5d0dSHasso Tepper err(EXIT_FAILURE, "link mode");
3726b5c5d0dSHasso Tepper
3736b5c5d0dSHasso Tepper sa.bt_channel = channel;
3746b5c5d0dSHasso Tepper bdaddr_copy(&sa.bt_bdaddr, raddr);
3756b5c5d0dSHasso Tepper
3766b5c5d0dSHasso Tepper if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
3776b5c5d0dSHasso Tepper err(EXIT_FAILURE, "connect(%s, %d)", bt_ntoa(raddr, NULL),
3786b5c5d0dSHasso Tepper channel);
3796b5c5d0dSHasso Tepper
3806b5c5d0dSHasso Tepper return fd;
3816b5c5d0dSHasso Tepper }
3826b5c5d0dSHasso Tepper
3836b5c5d0dSHasso Tepper /*
3846b5c5d0dSHasso Tepper * In all the profiles we currently support registering, the channel
3856b5c5d0dSHasso Tepper * is the first octet in the PDU, and it seems all the rest can be
3866b5c5d0dSHasso Tepper * zero, so we just use an array of uint8_t big enough to store the
3876b5c5d0dSHasso Tepper * largest, currently LAN. See <sdp.h> for definitions..
3886b5c5d0dSHasso Tepper */
3896b5c5d0dSHasso Tepper #define pdu_len sizeof(struct sdp_lan_profile)
3906b5c5d0dSHasso Tepper
3916b5c5d0dSHasso Tepper int
open_server(bdaddr_t * laddr,uint8_t channel,int lm,const char * service)3926b5c5d0dSHasso Tepper open_server(bdaddr_t *laddr, uint8_t channel, int lm, const char *service)
3936b5c5d0dSHasso Tepper {
3946b5c5d0dSHasso Tepper struct sockaddr_bt sa;
3956b5c5d0dSHasso Tepper struct linger l;
3966b5c5d0dSHasso Tepper socklen_t len;
3976b5c5d0dSHasso Tepper void *ss;
3986b5c5d0dSHasso Tepper int sv, fd, n;
3996b5c5d0dSHasso Tepper uint8_t pdu[pdu_len];
4006b5c5d0dSHasso Tepper
4016b5c5d0dSHasso Tepper memset(&sa, 0, sizeof(sa));
4026b5c5d0dSHasso Tepper sa.bt_len = sizeof(sa);
4036b5c5d0dSHasso Tepper sa.bt_family = AF_BLUETOOTH;
4046b5c5d0dSHasso Tepper bdaddr_copy(&sa.bt_bdaddr, laddr);
4056b5c5d0dSHasso Tepper sa.bt_channel = channel;
4066b5c5d0dSHasso Tepper
4076b5c5d0dSHasso Tepper sv = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
4086b5c5d0dSHasso Tepper if (sv < 0)
4096b5c5d0dSHasso Tepper err(EXIT_FAILURE, "socket()");
4106b5c5d0dSHasso Tepper
4116b5c5d0dSHasso Tepper if (bind(sv, (struct sockaddr *)&sa, sizeof(sa)) < 0)
4126b5c5d0dSHasso Tepper err(EXIT_FAILURE, "bind(%s, %d)", bt_ntoa(laddr, NULL),
4136b5c5d0dSHasso Tepper channel);
4146b5c5d0dSHasso Tepper
4156b5c5d0dSHasso Tepper if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
4166b5c5d0dSHasso Tepper err(EXIT_FAILURE, "link mode");
4176b5c5d0dSHasso Tepper
4186b5c5d0dSHasso Tepper if (listen(sv, 1) < 0)
4196b5c5d0dSHasso Tepper err(EXIT_FAILURE, "listen()");
4206b5c5d0dSHasso Tepper
4216b5c5d0dSHasso Tepper /* Register service with SDP server */
4226b5c5d0dSHasso Tepper for (n = 0 ; ; n++) {
4236b5c5d0dSHasso Tepper if (services[n].name == NULL)
4246b5c5d0dSHasso Tepper usage();
4256b5c5d0dSHasso Tepper
4266b5c5d0dSHasso Tepper if (strcasecmp(services[n].name, service) == 0)
4276b5c5d0dSHasso Tepper break;
4286b5c5d0dSHasso Tepper }
4296b5c5d0dSHasso Tepper
4306b5c5d0dSHasso Tepper memset(pdu, 0, pdu_len);
4316b5c5d0dSHasso Tepper pdu[0] = channel;
4326b5c5d0dSHasso Tepper
4336b5c5d0dSHasso Tepper ss = sdp_open_local(NULL);
4346b5c5d0dSHasso Tepper if (ss == NULL || (errno = sdp_error(ss)) != 0)
4356b5c5d0dSHasso Tepper err(EXIT_FAILURE, "sdp_open_local");
4366b5c5d0dSHasso Tepper
4376b5c5d0dSHasso Tepper if (sdp_register_service(ss, services[n].class, laddr,
4386b5c5d0dSHasso Tepper pdu, services[n].pdulen, NULL) != 0) {
4396b5c5d0dSHasso Tepper errno = sdp_error(ss);
4406b5c5d0dSHasso Tepper err(EXIT_FAILURE, "sdp_register_service");
4416b5c5d0dSHasso Tepper }
4426b5c5d0dSHasso Tepper
4436b5c5d0dSHasso Tepper len = sizeof(sa);
4446b5c5d0dSHasso Tepper fd = accept(sv, (struct sockaddr *)&sa, &len);
4456b5c5d0dSHasso Tepper if (fd < 0)
4466b5c5d0dSHasso Tepper err(EXIT_FAILURE, "accept");
4476b5c5d0dSHasso Tepper
4486b5c5d0dSHasso Tepper memset(&l, 0, sizeof(l));
4496b5c5d0dSHasso Tepper l.l_onoff = 1;
4506b5c5d0dSHasso Tepper l.l_linger = 5;
4516b5c5d0dSHasso Tepper if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
4526b5c5d0dSHasso Tepper err(EXIT_FAILURE, "linger()");
4536b5c5d0dSHasso Tepper
4546b5c5d0dSHasso Tepper close(sv);
4556b5c5d0dSHasso Tepper return fd;
4566b5c5d0dSHasso Tepper }
4576b5c5d0dSHasso Tepper
4586b5c5d0dSHasso Tepper void
copy_data(int src,int dst)4596b5c5d0dSHasso Tepper copy_data(int src, int dst)
4606b5c5d0dSHasso Tepper {
4616b5c5d0dSHasso Tepper static char buf[BUFSIZ];
4626b5c5d0dSHasso Tepper ssize_t nr, nw, off;
4636b5c5d0dSHasso Tepper
4646b5c5d0dSHasso Tepper while ((nr = read(src, buf, sizeof(buf))) == -1) {
4656b5c5d0dSHasso Tepper if (errno != EINTR) {
4666b5c5d0dSHasso Tepper syslog(LOG_ERR, "read failed: %m");
4676b5c5d0dSHasso Tepper exit(EXIT_FAILURE);
4686b5c5d0dSHasso Tepper }
4696b5c5d0dSHasso Tepper }
4706b5c5d0dSHasso Tepper
4716b5c5d0dSHasso Tepper if (nr == 0) /* reached EOF */
4726b5c5d0dSHasso Tepper done++;
4736b5c5d0dSHasso Tepper
4746b5c5d0dSHasso Tepper for (off = 0 ; nr ; nr -= nw, off += nw) {
4756b5c5d0dSHasso Tepper if ((nw = write(dst, buf + off, (size_t)nr)) == -1) {
4766b5c5d0dSHasso Tepper syslog(LOG_ERR, "write failed: %m");
4776b5c5d0dSHasso Tepper exit(EXIT_FAILURE);
4786b5c5d0dSHasso Tepper }
4796b5c5d0dSHasso Tepper }
4806b5c5d0dSHasso Tepper }
4816b5c5d0dSHasso Tepper
4826b5c5d0dSHasso Tepper void
sighandler(int s __unused)4831558c73fSSascha Wildner sighandler(int s __unused)
4846b5c5d0dSHasso Tepper {
4856b5c5d0dSHasso Tepper
4866b5c5d0dSHasso Tepper done++;
4876b5c5d0dSHasso Tepper }
4886b5c5d0dSHasso Tepper
4896b5c5d0dSHasso Tepper void
reset_tio(void)4906b5c5d0dSHasso Tepper reset_tio(void)
4916b5c5d0dSHasso Tepper {
4926b5c5d0dSHasso Tepper
4936b5c5d0dSHasso Tepper tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
4946b5c5d0dSHasso Tepper }
4956b5c5d0dSHasso Tepper
4966b5c5d0dSHasso Tepper void
usage(void)4976b5c5d0dSHasso Tepper usage(void)
4986b5c5d0dSHasso Tepper {
4996b5c5d0dSHasso Tepper const char *cmd = getprogname();
5006b5c5d0dSHasso Tepper struct service *s;
5016b5c5d0dSHasso Tepper
5026b5c5d0dSHasso Tepper fprintf(stderr, "Usage: %s [-d device] [-m mode] [-s service] [-t tty]\n"
5036b5c5d0dSHasso Tepper " %*s {-a bdaddr | -c channel}\n"
5046b5c5d0dSHasso Tepper "\n"
5056b5c5d0dSHasso Tepper "Where:\n"
5066b5c5d0dSHasso Tepper "\t-a bdaddr remote device address\n"
5076b5c5d0dSHasso Tepper "\t-c channel local RFCOMM channel\n"
5086b5c5d0dSHasso Tepper "\t-d device local device address\n"
5096b5c5d0dSHasso Tepper "\t-m mode link mode\n"
5106b5c5d0dSHasso Tepper "\t-s service service class\n"
5116b5c5d0dSHasso Tepper "\t-t tty run in background using pty\n"
5126b5c5d0dSHasso Tepper "\n", cmd, (int)strlen(cmd), "");
5136b5c5d0dSHasso Tepper
5146b5c5d0dSHasso Tepper fprintf(stderr, "Known service classes:\n");
5156b5c5d0dSHasso Tepper for (s = services ; s->name != NULL ; s++)
5166b5c5d0dSHasso Tepper fprintf(stderr, "\t%-13s%s\n", s->name, s->description);
5176b5c5d0dSHasso Tepper
5186b5c5d0dSHasso Tepper exit(EXIT_FAILURE);
5196b5c5d0dSHasso Tepper }
520