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