xref: /freebsd/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c (revision 1a63eb31c7fc715c9148a9e1f39a3c9c5fe99288)
11a63eb31SJulian Elischer /*
21a63eb31SJulian Elischer  * rfcomm_pppd.c
31a63eb31SJulian Elischer  *
41a63eb31SJulian Elischer  * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
51a63eb31SJulian Elischer  * All rights reserved.
61a63eb31SJulian Elischer  *
71a63eb31SJulian Elischer  * Redistribution and use in source and binary forms, with or without
81a63eb31SJulian Elischer  * modification, are permitted provided that the following conditions
91a63eb31SJulian Elischer  * are met:
101a63eb31SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
111a63eb31SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
121a63eb31SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
131a63eb31SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
141a63eb31SJulian Elischer  *    documentation and/or other materials provided with the distribution.
151a63eb31SJulian Elischer  *
161a63eb31SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171a63eb31SJulian Elischer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181a63eb31SJulian Elischer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191a63eb31SJulian Elischer  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201a63eb31SJulian Elischer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211a63eb31SJulian Elischer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221a63eb31SJulian Elischer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231a63eb31SJulian Elischer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241a63eb31SJulian Elischer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251a63eb31SJulian Elischer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261a63eb31SJulian Elischer  * SUCH DAMAGE.
271a63eb31SJulian Elischer  *
281a63eb31SJulian Elischer  * $Id: rfcomm_pppd.c,v 1.3 2003/04/26 23:59:49 max Exp $
291a63eb31SJulian Elischer  * $FreeBSD$
301a63eb31SJulian Elischer  */
311a63eb31SJulian Elischer 
321a63eb31SJulian Elischer #include <sys/types.h>
331a63eb31SJulian Elischer #include <sys/socket.h>
341a63eb31SJulian Elischer #include <bitstring.h>
351a63eb31SJulian Elischer #include <errno.h>
361a63eb31SJulian Elischer #include <fcntl.h>
371a63eb31SJulian Elischer #include <ng_hci.h>
381a63eb31SJulian Elischer #include <ng_l2cap.h>
391a63eb31SJulian Elischer #include <ng_btsocket.h>
401a63eb31SJulian Elischer #include <signal.h>
411a63eb31SJulian Elischer #include <stdarg.h>
421a63eb31SJulian Elischer #include <stdio.h>
431a63eb31SJulian Elischer #include <stdlib.h>
441a63eb31SJulian Elischer #include <string.h>
451a63eb31SJulian Elischer #include <syslog.h>
461a63eb31SJulian Elischer #include <unistd.h>
471a63eb31SJulian Elischer 
481a63eb31SJulian Elischer #define RFCOMM_PPPD	"rfcomm_pppd"
491a63eb31SJulian Elischer 
501a63eb31SJulian Elischer static void	exec_ppp	(int s, char *label);
511a63eb31SJulian Elischer static void	sighandler	(int s);
521a63eb31SJulian Elischer static void	usage		(void);
531a63eb31SJulian Elischer 
541a63eb31SJulian Elischer static int	done;
551a63eb31SJulian Elischer 
561a63eb31SJulian Elischer /* Main */
571a63eb31SJulian Elischer int
581a63eb31SJulian Elischer main(int argc, char *argv[])
591a63eb31SJulian Elischer {
601a63eb31SJulian Elischer 	struct sockaddr_rfcomm   sock_addr;
611a63eb31SJulian Elischer 	char			*label = NULL;
621a63eb31SJulian Elischer 	bdaddr_t		 addr;
631a63eb31SJulian Elischer 	int			 s, channel, detach, server;
641a63eb31SJulian Elischer 	pid_t			 pid;
651a63eb31SJulian Elischer 
661a63eb31SJulian Elischer 	memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
671a63eb31SJulian Elischer 	channel = 0;
681a63eb31SJulian Elischer 	detach = 1;
691a63eb31SJulian Elischer 	server = 0;
701a63eb31SJulian Elischer 
711a63eb31SJulian Elischer 	/* Parse command line arguments */
721a63eb31SJulian Elischer 	while ((s = getopt(argc, argv, "a:cC:dhl:s")) != -1) {
731a63eb31SJulian Elischer 		switch (s) {
741a63eb31SJulian Elischer 		case 'a': { /* BDADDR */
751a63eb31SJulian Elischer 			int	a0, a1, a2, a3, a4, a5;
761a63eb31SJulian Elischer 
771a63eb31SJulian Elischer 			if (sscanf(optarg, "%x:%x:%x:%x:%x:%x",
781a63eb31SJulian Elischer 					&a5, &a4, &a3, &a2, &a1, &a0) != 6)
791a63eb31SJulian Elischer 				usage();
801a63eb31SJulian Elischer 				/* NOT REACHED */
811a63eb31SJulian Elischer 
821a63eb31SJulian Elischer 			addr.b[0] = a0 & 0xff;
831a63eb31SJulian Elischer 			addr.b[1] = a1 & 0xff;
841a63eb31SJulian Elischer 			addr.b[2] = a2 & 0xff;
851a63eb31SJulian Elischer 			addr.b[3] = a3 & 0xff;
861a63eb31SJulian Elischer 			addr.b[4] = a4 & 0xff;
871a63eb31SJulian Elischer 			addr.b[5] = a5 & 0xff;
881a63eb31SJulian Elischer 			} break;
891a63eb31SJulian Elischer 
901a63eb31SJulian Elischer 		case 'c': /* client */
911a63eb31SJulian Elischer 			server = 0;
921a63eb31SJulian Elischer 			break;
931a63eb31SJulian Elischer 
941a63eb31SJulian Elischer 		case 'C': /* RFCOMM channel */
951a63eb31SJulian Elischer 			channel = atoi(optarg);
961a63eb31SJulian Elischer 			break;
971a63eb31SJulian Elischer 
981a63eb31SJulian Elischer 		case 'd': /* do not detach */
991a63eb31SJulian Elischer 			detach = 0;
1001a63eb31SJulian Elischer 			break;
1011a63eb31SJulian Elischer 
1021a63eb31SJulian Elischer 		case 'l': /* PPP label */
1031a63eb31SJulian Elischer 			label = optarg;
1041a63eb31SJulian Elischer 			break;
1051a63eb31SJulian Elischer 
1061a63eb31SJulian Elischer 		case 's':
1071a63eb31SJulian Elischer 			server = 1;
1081a63eb31SJulian Elischer 			break;
1091a63eb31SJulian Elischer 
1101a63eb31SJulian Elischer 		case 'h':
1111a63eb31SJulian Elischer 		default:
1121a63eb31SJulian Elischer 			usage();
1131a63eb31SJulian Elischer 			/* NOT REACHED */
1141a63eb31SJulian Elischer 		}
1151a63eb31SJulian Elischer 	}
1161a63eb31SJulian Elischer 
1171a63eb31SJulian Elischer 	/* Check if we got everything we wanted */
1181a63eb31SJulian Elischer 	if ((channel <= 0 || channel > 30) || label == NULL ||
1191a63eb31SJulian Elischer 	    (!server && memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0))
1201a63eb31SJulian Elischer 		usage();
1211a63eb31SJulian Elischer 		/* NOT REACHED */
1221a63eb31SJulian Elischer 
1231a63eb31SJulian Elischer 	openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);
1241a63eb31SJulian Elischer 
1251a63eb31SJulian Elischer 	if (detach) {
1261a63eb31SJulian Elischer 		pid = fork();
1271a63eb31SJulian Elischer 		if (pid == (pid_t) -1) {
1281a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not fork(). %s (%d)",
1291a63eb31SJulian Elischer 				strerror(errno), errno);
1301a63eb31SJulian Elischer 			exit(1);
1311a63eb31SJulian Elischer 		}
1321a63eb31SJulian Elischer 
1331a63eb31SJulian Elischer 		if (pid != 0)
1341a63eb31SJulian Elischer 			exit(0);
1351a63eb31SJulian Elischer 
1361a63eb31SJulian Elischer 		if (daemon(0, 0) < 0) {
1371a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
1381a63eb31SJulian Elischer 				strerror(errno), errno);
1391a63eb31SJulian Elischer 			exit(1);
1401a63eb31SJulian Elischer 		}
1411a63eb31SJulian Elischer 	}
1421a63eb31SJulian Elischer 
1431a63eb31SJulian Elischer 	s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
1441a63eb31SJulian Elischer 	if (s < 0) {
1451a63eb31SJulian Elischer 		syslog(LOG_ERR, "Could not create socket. %s (%d)",
1461a63eb31SJulian Elischer 			strerror(errno), errno);
1471a63eb31SJulian Elischer 		exit(1);
1481a63eb31SJulian Elischer 	}
1491a63eb31SJulian Elischer 
1501a63eb31SJulian Elischer 	if (server) {
1511a63eb31SJulian Elischer 		struct sigaction	sa;
1521a63eb31SJulian Elischer 
1531a63eb31SJulian Elischer 		/* Install signal handler */
1541a63eb31SJulian Elischer 		memset(&sa, 0, sizeof(sa));
1551a63eb31SJulian Elischer 		sa.sa_handler = sighandler;
1561a63eb31SJulian Elischer 
1571a63eb31SJulian Elischer 		if (sigaction(SIGTERM, &sa, NULL) < 0) {
1581a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
1591a63eb31SJulian Elischer 				strerror(errno), errno);
1601a63eb31SJulian Elischer 			exit(1);
1611a63eb31SJulian Elischer 		}
1621a63eb31SJulian Elischer 
1631a63eb31SJulian Elischer 		if (sigaction(SIGHUP, &sa, NULL) < 0) {
1641a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
1651a63eb31SJulian Elischer 				strerror(errno), errno);
1661a63eb31SJulian Elischer 			exit(1);
1671a63eb31SJulian Elischer 		}
1681a63eb31SJulian Elischer 
1691a63eb31SJulian Elischer 		if (sigaction(SIGINT, &sa, NULL) < 0) {
1701a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
1711a63eb31SJulian Elischer 				strerror(errno), errno);
1721a63eb31SJulian Elischer 			exit(1);
1731a63eb31SJulian Elischer 		}
1741a63eb31SJulian Elischer 
1751a63eb31SJulian Elischer 		sa.sa_handler = SIG_IGN;
1761a63eb31SJulian Elischer 		sa.sa_flags = SA_NOCLDWAIT;
1771a63eb31SJulian Elischer 
1781a63eb31SJulian Elischer 		if (sigaction(SIGCHLD, &sa, NULL) < 0) {
1791a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)",
1801a63eb31SJulian Elischer 				strerror(errno), errno);
1811a63eb31SJulian Elischer 			exit(1);
1821a63eb31SJulian Elischer 		}
1831a63eb31SJulian Elischer 
1841a63eb31SJulian Elischer 		/* bind socket and listen for incoming connections */
1851a63eb31SJulian Elischer 		sock_addr.rfcomm_len = sizeof(sock_addr);
1861a63eb31SJulian Elischer 		sock_addr.rfcomm_family = AF_BLUETOOTH;
1871a63eb31SJulian Elischer 		memcpy(&sock_addr.rfcomm_bdaddr, &addr,
1881a63eb31SJulian Elischer 			sizeof(sock_addr.rfcomm_bdaddr));
1891a63eb31SJulian Elischer 		sock_addr.rfcomm_channel = channel;
1901a63eb31SJulian Elischer 
1911a63eb31SJulian Elischer 		if (bind(s, (struct sockaddr *) &sock_addr,
1921a63eb31SJulian Elischer 				sizeof(sock_addr)) < 0) {
1931a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not bind socket. %s (%d)",
1941a63eb31SJulian Elischer 				strerror(errno), errno);
1951a63eb31SJulian Elischer 			exit(1);
1961a63eb31SJulian Elischer 		}
1971a63eb31SJulian Elischer 
1981a63eb31SJulian Elischer 		if (listen(s, 10) < 0) {
1991a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not listen on socket. %s (%d)",
2001a63eb31SJulian Elischer 				strerror(errno), errno);
2011a63eb31SJulian Elischer 			exit(1);
2021a63eb31SJulian Elischer 		}
2031a63eb31SJulian Elischer 
2041a63eb31SJulian Elischer 		for (done = 0; !done; ) {
2051a63eb31SJulian Elischer 			int	len = sizeof(sock_addr);
2061a63eb31SJulian Elischer 			int	s1 = accept(s, (struct sockaddr *) &sock_addr, &len);
2071a63eb31SJulian Elischer 
2081a63eb31SJulian Elischer 			if (s1 < 0) {
2091a63eb31SJulian Elischer 				syslog(LOG_ERR, "Could not accept connection " \
2101a63eb31SJulian Elischer 					"on socket. %s (%d)", strerror(errno),
2111a63eb31SJulian Elischer 					errno);
2121a63eb31SJulian Elischer 				exit(1);
2131a63eb31SJulian Elischer 			}
2141a63eb31SJulian Elischer 
2151a63eb31SJulian Elischer 			pid = fork();
2161a63eb31SJulian Elischer 			if (pid == (pid_t) -1) {
2171a63eb31SJulian Elischer 				syslog(LOG_ERR, "Could not fork(). %s (%d)",
2181a63eb31SJulian Elischer 					strerror(errno), errno);
2191a63eb31SJulian Elischer 				exit(1);
2201a63eb31SJulian Elischer 			}
2211a63eb31SJulian Elischer 
2221a63eb31SJulian Elischer 			if (pid == 0) {
2231a63eb31SJulian Elischer 				close(s);
2241a63eb31SJulian Elischer 
2251a63eb31SJulian Elischer 				/* Reset signal handler */
2261a63eb31SJulian Elischer 				memset(&sa, 0, sizeof(sa));
2271a63eb31SJulian Elischer 				sa.sa_handler = SIG_DFL;
2281a63eb31SJulian Elischer 
2291a63eb31SJulian Elischer 				sigaction(SIGTERM, &sa, NULL);
2301a63eb31SJulian Elischer 				sigaction(SIGHUP, &sa, NULL);
2311a63eb31SJulian Elischer 				sigaction(SIGINT, &sa, NULL);
2321a63eb31SJulian Elischer 				sigaction(SIGCHLD, &sa, NULL);
2331a63eb31SJulian Elischer 
2341a63eb31SJulian Elischer 				/* Become daemon */
2351a63eb31SJulian Elischer 				daemon(0, 0);
2361a63eb31SJulian Elischer 
2371a63eb31SJulian Elischer 				exec_ppp(s1, label);
2381a63eb31SJulian Elischer 			} else
2391a63eb31SJulian Elischer 				close(s1);
2401a63eb31SJulian Elischer 		}
2411a63eb31SJulian Elischer 	} else {
2421a63eb31SJulian Elischer 		sock_addr.rfcomm_len = sizeof(sock_addr);
2431a63eb31SJulian Elischer 		sock_addr.rfcomm_family = AF_BLUETOOTH;
2441a63eb31SJulian Elischer 		memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY,
2451a63eb31SJulian Elischer 			sizeof(sock_addr.rfcomm_bdaddr));
2461a63eb31SJulian Elischer 		sock_addr.rfcomm_channel = 0;
2471a63eb31SJulian Elischer 
2481a63eb31SJulian Elischer 		if (bind(s, (struct sockaddr *) &sock_addr,
2491a63eb31SJulian Elischer 				sizeof(sock_addr)) < 0) {
2501a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not bind socket. %s (%d)",
2511a63eb31SJulian Elischer 				strerror(errno), errno);
2521a63eb31SJulian Elischer 			exit(1);
2531a63eb31SJulian Elischer 		}
2541a63eb31SJulian Elischer 
2551a63eb31SJulian Elischer 		memcpy(&sock_addr.rfcomm_bdaddr, &addr,
2561a63eb31SJulian Elischer 			sizeof(sock_addr.rfcomm_bdaddr));
2571a63eb31SJulian Elischer 		sock_addr.rfcomm_channel = channel;
2581a63eb31SJulian Elischer 
2591a63eb31SJulian Elischer 		if (connect(s, (struct sockaddr *) &sock_addr,
2601a63eb31SJulian Elischer 				sizeof(sock_addr)) < 0) {
2611a63eb31SJulian Elischer 			syslog(LOG_ERR, "Could not connect socket. %s (%d)",
2621a63eb31SJulian Elischer 				strerror(errno), errno);
2631a63eb31SJulian Elischer 			exit(1);
2641a63eb31SJulian Elischer 		}
2651a63eb31SJulian Elischer 
2661a63eb31SJulian Elischer 		exec_ppp(s, label);
2671a63eb31SJulian Elischer 	}
2681a63eb31SJulian Elischer 
2691a63eb31SJulian Elischer 	exit(0);
2701a63eb31SJulian Elischer } /* main */
2711a63eb31SJulian Elischer 
2721a63eb31SJulian Elischer /*
2731a63eb31SJulian Elischer  * Redirects stdin/stdout to s, stderr to /dev/null and exec ppp -direct label.
2741a63eb31SJulian Elischer  * Never retruns.
2751a63eb31SJulian Elischer  */
2761a63eb31SJulian Elischer 
2771a63eb31SJulian Elischer static void
2781a63eb31SJulian Elischer exec_ppp(int s, char *label)
2791a63eb31SJulian Elischer {
2801a63eb31SJulian Elischer 	char	 ppp[] = "/usr/sbin/ppp";
2811a63eb31SJulian Elischer 	char	*ppp_args[] = { ppp, "-direct", NULL, NULL };
2821a63eb31SJulian Elischer 
2831a63eb31SJulian Elischer 	close(0);
2841a63eb31SJulian Elischer 	if (dup(s) < 0) {
2851a63eb31SJulian Elischer 		syslog(LOG_ERR, "Could not dup(0). %s (%d)",
2861a63eb31SJulian Elischer 			strerror(errno), errno);
2871a63eb31SJulian Elischer 		exit(1);
2881a63eb31SJulian Elischer 	}
2891a63eb31SJulian Elischer 
2901a63eb31SJulian Elischer 	close(1);
2911a63eb31SJulian Elischer 	if (dup(s) < 0) {
2921a63eb31SJulian Elischer 		syslog(LOG_ERR, "Could not dup(1). %s (%d)",
2931a63eb31SJulian Elischer 			strerror(errno), errno);
2941a63eb31SJulian Elischer 		exit(1);
2951a63eb31SJulian Elischer 	}
2961a63eb31SJulian Elischer 
2971a63eb31SJulian Elischer 	close(2);
2981a63eb31SJulian Elischer 	open("/dev/null", O_RDWR);
2991a63eb31SJulian Elischer 
3001a63eb31SJulian Elischer 	ppp_args[2] = label;
3011a63eb31SJulian Elischer 	if (execv(ppp, ppp_args) < 0) {
3021a63eb31SJulian Elischer 		syslog(LOG_ERR, "Could not exec(%s -direct %s). %s (%d)",
3031a63eb31SJulian Elischer 			ppp, label, strerror(errno), errno);
3041a63eb31SJulian Elischer 		exit(1);
3051a63eb31SJulian Elischer 	}
3061a63eb31SJulian Elischer } /* run_ppp */
3071a63eb31SJulian Elischer 
3081a63eb31SJulian Elischer /* Signal handler */
3091a63eb31SJulian Elischer static void
3101a63eb31SJulian Elischer sighandler(int s)
3111a63eb31SJulian Elischer {
3121a63eb31SJulian Elischer 	done = 1;
3131a63eb31SJulian Elischer } /* sighandler */
3141a63eb31SJulian Elischer 
3151a63eb31SJulian Elischer /* Display usage and exit */
3161a63eb31SJulian Elischer static void
3171a63eb31SJulian Elischer usage(void)
3181a63eb31SJulian Elischer {
3191a63eb31SJulian Elischer 	fprintf(stdout,
3201a63eb31SJulian Elischer "Usage: %s options\n" \
3211a63eb31SJulian Elischer "Where options are:\n" \
3221a63eb31SJulian Elischer "\t-a bdaddr    BDADDR to listen on or connect to (required for client)\n" \
3231a63eb31SJulian Elischer "\t-c           Act as a clinet (default)\n" \
3241a63eb31SJulian Elischer "\t-C channel   RFCOMM channel to listen on or connect to (required)\n" \
3251a63eb31SJulian Elischer "\t-d           Run in foreground\n" \
3261a63eb31SJulian Elischer "\t-l label     Use PPP label (required)\n" \
3271a63eb31SJulian Elischer "\t-s           Act as a server\n" \
3281a63eb31SJulian Elischer "\t-h           Display this message\n", RFCOMM_PPPD);
3291a63eb31SJulian Elischer 
3301a63eb31SJulian Elischer 	exit(255);
3311a63eb31SJulian Elischer } /* usage */
3321a63eb31SJulian Elischer 
333