• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@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 
io_init(void)46 static inline void io_init(void)
47 {
48 	__io_canceled = 0;
49 }
50 
io_cancel(void)51 static inline void io_cancel(void)
52 {
53 	__io_canceled = 1;
54 }
55 
56 /* Signal functions */
sig_hup(int sig)57 static void sig_hup(int sig)
58 {
59 	return;
60 }
61 
sig_term(int sig)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)*/
read_n(int fd,char * buf,int len)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)*/
write_n(int fd,char * buf,int len)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 */
create_connection(bdaddr_t * bdaddr,uint8_t channel)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 */
process_data(int fd)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 
usage(void)202 static void usage(void)
203 {
204 	printf("Usage:\tppporc <bdaddr> [channel]\n");
205 }
206 
main(int argc,char ** argv)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