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