Home | History | Annotate | Download | only in tools
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2002-2009  Marcel Holtmann <marcel (at) holtmann.org>
      6  *
      7  *
      8  *  This program is free software; you can redistribute it and/or modify
      9  *  it under the terms of the GNU General Public License as published by
     10  *  the Free Software Foundation; either version 2 of the License, or
     11  *  (at your option) any later version.
     12  *
     13  *  This program is distributed in the hope that it will be useful,
     14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *  GNU General Public License for more details.
     17  *
     18  *  You should have received a copy of the GNU General Public License
     19  *  along with this program; if not, write to the Free Software
     20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     21  *
     22  */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include <config.h>
     26 #endif
     27 
     28 #include <stdio.h>
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #include <unistd.h>
     32 #include <stdlib.h>
     33 #include <signal.h>
     34 #include <syslog.h>
     35 #include <getopt.h>
     36 #include <sys/poll.h>
     37 #include <sys/ioctl.h>
     38 #include <sys/socket.h>
     39 
     40 #include <bluetooth/bluetooth.h>
     41 #include <bluetooth/rfcomm.h>
     42 
     43 /* IO cancelation */
     44 static volatile sig_atomic_t __io_canceled;
     45 
     46 static inline void io_init(void)
     47 {
     48 	__io_canceled = 0;
     49 }
     50 
     51 static inline void io_cancel(void)
     52 {
     53 	__io_canceled = 1;
     54 }
     55 
     56 /* Signal functions */
     57 static void sig_hup(int sig)
     58 {
     59 	return;
     60 }
     61 
     62 static void sig_term(int sig)
     63 {
     64 	syslog(LOG_INFO, "Closing RFCOMM channel");
     65 	io_cancel();
     66 }
     67 
     68 /* Read exactly len bytes (Signal safe)*/
     69 static inline int read_n(int fd, char *buf, int len)
     70 {
     71 	register int t = 0, w;
     72 
     73 	while (!__io_canceled && len > 0) {
     74 		if ((w = read(fd, buf, len)) < 0) {
     75 			if (errno == EINTR || errno == EAGAIN)
     76 				continue;
     77 			return -1;
     78 		}
     79 		if (!w)
     80 			return 0;
     81 		len -= w;
     82 		buf += w;
     83 		t += w;
     84 	}
     85 
     86 	return t;
     87 }
     88 
     89 /* Write exactly len bytes (Signal safe)*/
     90 static inline int write_n(int fd, char *buf, int len)
     91 {
     92 	register int t = 0, w;
     93 
     94 	while (!__io_canceled && len > 0) {
     95 		if ((w = write(fd, buf, len)) < 0) {
     96 			if (errno == EINTR || errno == EAGAIN)
     97 				continue;
     98 			return -1;
     99 		}
    100 		if (!w)
    101 			return 0;
    102 		len -= w;
    103 		buf += w;
    104 		t += w;
    105 	}
    106 
    107 	return t;
    108 }
    109 
    110 /* Create the RFCOMM connection */
    111 static int create_connection(bdaddr_t *bdaddr, uint8_t channel)
    112 {
    113 	struct sockaddr_rc remote_addr, local_addr;
    114 	int fd, err;
    115 
    116 	if ((fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0)
    117 		return fd;
    118 
    119 	memset(&local_addr, 0, sizeof(local_addr));
    120 	local_addr.rc_family = AF_BLUETOOTH;
    121 	bacpy(&local_addr.rc_bdaddr, BDADDR_ANY);
    122 	if ((err = bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr))) < 0) {
    123 		close(fd);
    124 		return err;
    125 	}
    126 
    127 	memset(&remote_addr, 0, sizeof(remote_addr));
    128 	remote_addr.rc_family = AF_BLUETOOTH;
    129 	bacpy(&remote_addr.rc_bdaddr, bdaddr);
    130 	remote_addr.rc_channel = channel;
    131 	if ((err = connect(fd, (struct sockaddr *)&remote_addr, sizeof(remote_addr))) < 0) {
    132 		close(fd);
    133 		return err;
    134 	}
    135 
    136 	syslog(LOG_INFO, "RFCOMM channel %d connected", channel);
    137 
    138 	return fd;
    139 }
    140 
    141 /* Process the data from socket and pseudo tty */
    142 static int process_data(int fd)
    143 {
    144 	struct pollfd p[2];
    145 	char buf[1024];
    146 	int err, r;
    147 
    148 	p[0].fd = 0;
    149 	p[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
    150 
    151 	p[1].fd = fd;
    152 	p[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
    153 
    154 	err = 0;
    155 
    156 	while (!__io_canceled) {
    157 		p[0].revents = 0;
    158 		p[1].revents = 0;
    159 
    160 		err = poll(p, 2, -1);
    161 		if (err < 0)
    162 			break;
    163 
    164 		err = 0;
    165 
    166 		if (p[0].revents) {
    167 			if (p[0].revents & (POLLERR | POLLHUP | POLLNVAL))
    168 			  break;
    169 			r = read(0, buf, sizeof(buf));
    170 			if (r < 0) {
    171 				if (errno != EINTR && errno != EAGAIN) {
    172 					err = r;
    173 					break;
    174 				}
    175 			}
    176 
    177 			err = write_n(fd, buf, r);
    178 			if (err < 0)
    179 				break;
    180 		}
    181 
    182 		if (p[1].revents) {
    183 			if (p[1].revents & (POLLERR | POLLHUP | POLLNVAL))
    184 				break;
    185 			r = read(fd, buf, sizeof(buf));
    186 			if (r < 0) {
    187 				if (errno != EINTR && errno != EAGAIN) {
    188 					err = r;
    189 					break;
    190 				}
    191 			}
    192 
    193 			err = write_n(1, buf, r);
    194 			if (err < 0)
    195 				break;
    196 		}
    197 	}
    198 
    199 	return err;
    200 }
    201 
    202 static void usage(void)
    203 {
    204 	printf("Usage:\tppporc <bdaddr> [channel]\n");
    205 }
    206 
    207 int main(int argc, char** argv)
    208 {
    209 	struct sigaction sa;
    210 	int fd, err, opt;
    211 
    212 	bdaddr_t bdaddr;
    213 	uint8_t channel;
    214 
    215 	/* Parse command line options */
    216 	while ((opt = getopt(argc, argv, "h")) != EOF) {
    217 		switch(opt) {
    218 		case 'h':
    219 			usage();
    220 			exit(0);
    221 		}
    222 	}
    223 
    224 	argc -= optind;
    225 	argv += optind;
    226 
    227 	switch (argc) {
    228 	case 1:
    229 		str2ba(argv[0], &bdaddr);
    230 		channel = 1;
    231 		break;
    232 	case 2:
    233 		str2ba(argv[0], &bdaddr);
    234 		channel = atoi(argv[1]);
    235 		break;
    236 	default:
    237 		usage();
    238 		exit(0);
    239 	}
    240 
    241 	/* Initialize syslog */
    242 	openlog("ppporc", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
    243 	syslog(LOG_INFO, "PPP over RFCOMM");
    244 
    245 	/* Initialize signals */
    246 	memset(&sa, 0, sizeof(sa));
    247 	sa.sa_flags   = SA_NOCLDSTOP;
    248 	sa.sa_handler = SIG_IGN;
    249 	sigaction(SIGCHLD, &sa, NULL);
    250 	sigaction(SIGPIPE, &sa, NULL);
    251 
    252 	sa.sa_handler = sig_term;
    253 	sigaction(SIGTERM, &sa, NULL);
    254 	sigaction(SIGINT,  &sa, NULL);
    255 
    256 	sa.sa_handler = sig_hup;
    257 	sigaction(SIGHUP, &sa, NULL);
    258 
    259 	syslog(LOG_INFO, "Connecting to %s", argv[0]);
    260 
    261 	if ((fd = create_connection(&bdaddr, channel)) < 0) {
    262 		syslog(LOG_ERR, "Can't connect to remote device (%s)", strerror(errno));
    263 		return fd;
    264 	}
    265 
    266 	err = process_data(fd);
    267 
    268 	close(fd);
    269 
    270 	return err;
    271 }
    272