1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk (at) qualcomm.com> 6 * Copyright (C) 2002-2009 Marcel Holtmann <marcel (at) holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include <config.h> 27 #endif 28 29 #include <stdio.h> 30 #include <errno.h> 31 #include <ctype.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <syslog.h> 36 #include <dirent.h> 37 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <sys/wait.h> 41 #include <sys/param.h> 42 #include <sys/ioctl.h> 43 #include <sys/socket.h> 44 45 #include <netinet/in.h> 46 47 #include <bluetooth/bluetooth.h> 48 #include <bluetooth/rfcomm.h> 49 50 #include "dund.h" 51 #include "lib.h" 52 53 #define PROC_BASE "/proc" 54 55 static int for_each_port(int (*func)(struct rfcomm_dev_info *, unsigned long), unsigned long arg) 56 { 57 struct rfcomm_dev_list_req *dl; 58 struct rfcomm_dev_info *di; 59 long r = 0; 60 int sk, i; 61 62 sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM); 63 if (sk < 0 ) { 64 perror("Can't open RFCOMM control socket"); 65 exit(1); 66 } 67 68 dl = malloc(sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di)); 69 if (!dl) { 70 perror("Can't allocate request memory"); 71 close(sk); 72 exit(1); 73 } 74 75 dl->dev_num = RFCOMM_MAX_DEV; 76 di = dl->dev_info; 77 78 if (ioctl(sk, RFCOMMGETDEVLIST, (void *) dl) < 0) { 79 perror("Can't get device list"); 80 exit(1); 81 } 82 83 for (i = 0; i < dl->dev_num; i++) { 84 r = func(di + i, arg); 85 if (r) break; 86 } 87 88 close(sk); 89 return r; 90 } 91 92 static int uses_rfcomm(char *path, char *dev) 93 { 94 struct dirent *de; 95 DIR *dir; 96 97 dir = opendir(path); 98 if (!dir) 99 return 0; 100 101 if (chdir(path) < 0) 102 return 0; 103 104 while ((de = readdir(dir)) != NULL) { 105 char link[PATH_MAX + 1]; 106 int len = readlink(de->d_name, link, sizeof(link)); 107 if (len > 0) { 108 link[len] = 0; 109 if (strstr(link, dev)) 110 return 1; 111 } 112 } 113 114 closedir(dir); 115 116 return 0; 117 } 118 119 static int find_pppd(int id, pid_t *pid) 120 { 121 struct dirent *de; 122 char path[PATH_MAX + 1]; 123 char dev[10]; 124 int empty = 1; 125 DIR *dir; 126 127 dir = opendir(PROC_BASE); 128 if (!dir) { 129 perror(PROC_BASE); 130 return -1; 131 } 132 133 sprintf(dev, "rfcomm%d", id); 134 135 *pid = 0; 136 while ((de = readdir(dir)) != NULL) { 137 empty = 0; 138 if (isdigit(de->d_name[0])) { 139 sprintf(path, "%s/%s/fd", PROC_BASE, de->d_name); 140 if (uses_rfcomm(path, dev)) { 141 *pid = atoi(de->d_name); 142 break; 143 } 144 } 145 } 146 closedir(dir); 147 148 if (empty) 149 fprintf(stderr, "%s is empty (not mounted ?)\n", PROC_BASE); 150 151 return *pid != 0; 152 } 153 154 static int dun_exec(char *tty, char *prog, char **args) 155 { 156 int pid = fork(); 157 int fd; 158 159 switch (pid) { 160 case -1: 161 return -1; 162 163 case 0: 164 break; 165 166 default: 167 return pid; 168 } 169 170 setsid(); 171 172 /* Close all FDs */ 173 for (fd = 3; fd < 20; fd++) 174 close(fd); 175 176 execvp(prog, args); 177 178 syslog(LOG_ERR, "Error while executing %s", prog); 179 180 exit(1); 181 } 182 183 static int dun_create_tty(int sk, char *tty, int size) 184 { 185 struct sockaddr_rc sa; 186 struct stat st; 187 socklen_t alen; 188 int id, try = 30; 189 190 struct rfcomm_dev_req req = { 191 flags: (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP), 192 dev_id: -1 193 }; 194 195 alen = sizeof(sa); 196 if (getpeername(sk, (struct sockaddr *) &sa, &alen) < 0) 197 return -1; 198 bacpy(&req.dst, &sa.rc_bdaddr); 199 200 alen = sizeof(sa); 201 if (getsockname(sk, (struct sockaddr *) &sa, &alen) < 0) 202 return -1; 203 bacpy(&req.src, &sa.rc_bdaddr); 204 req.channel = sa.rc_channel; 205 206 id = ioctl(sk, RFCOMMCREATEDEV, &req); 207 if (id < 0) 208 return id; 209 210 snprintf(tty, size, "/dev/rfcomm%d", id); 211 while (stat(tty, &st) < 0) { 212 snprintf(tty, size, "/dev/bluetooth/rfcomm/%d", id); 213 if (stat(tty, &st) < 0) { 214 snprintf(tty, size, "/dev/rfcomm%d", id); 215 if (try--) { 216 usleep(100 * 1000); 217 continue; 218 } 219 220 memset(&req, 0, sizeof(req)); 221 req.dev_id = id; 222 ioctl(sk, RFCOMMRELEASEDEV, &req); 223 224 return -1; 225 } 226 } 227 228 return id; 229 } 230 231 int dun_init(void) 232 { 233 return 0; 234 } 235 236 int dun_cleanup(void) 237 { 238 return 0; 239 } 240 241 static int show_conn(struct rfcomm_dev_info *di, unsigned long arg) 242 { 243 pid_t pid; 244 245 if (di->state == BT_CONNECTED && 246 (di->flags & (1<<RFCOMM_REUSE_DLC)) && 247 (di->flags & (1<<RFCOMM_TTY_ATTACHED)) && 248 (di->flags & (1<<RFCOMM_RELEASE_ONHUP))) { 249 250 if (find_pppd(di->id, &pid)) { 251 char dst[18]; 252 ba2str(&di->dst, dst); 253 254 printf("rfcomm%d: %s channel %d pppd pid %d\n", 255 di->id, dst, di->channel, pid); 256 } 257 } 258 return 0; 259 } 260 261 static int kill_conn(struct rfcomm_dev_info *di, unsigned long arg) 262 { 263 bdaddr_t *dst = (bdaddr_t *) arg; 264 pid_t pid; 265 266 if (di->state == BT_CONNECTED && 267 (di->flags & (1<<RFCOMM_REUSE_DLC)) && 268 (di->flags & (1<<RFCOMM_TTY_ATTACHED)) && 269 (di->flags & (1<<RFCOMM_RELEASE_ONHUP))) { 270 271 if (dst && bacmp(&di->dst, dst)) 272 return 0; 273 274 if (find_pppd(di->id, &pid)) { 275 if (kill(pid, SIGINT) < 0) 276 perror("Kill"); 277 278 if (!dst) 279 return 0; 280 return 1; 281 } 282 } 283 return 0; 284 } 285 286 int dun_show_connections(void) 287 { 288 for_each_port(show_conn, 0); 289 return 0; 290 } 291 292 int dun_kill_connection(uint8_t *dst) 293 { 294 for_each_port(kill_conn, (unsigned long) dst); 295 return 0; 296 } 297 298 int dun_kill_all_connections(void) 299 { 300 for_each_port(kill_conn, 0); 301 return 0; 302 } 303 304 int dun_open_connection(int sk, char *pppd, char **args, int wait) 305 { 306 char tty[100]; 307 int pid; 308 309 if (dun_create_tty(sk, tty, sizeof(tty) - 1) < 0) { 310 syslog(LOG_ERR, "RFCOMM TTY creation failed. %s(%d)", strerror(errno), errno); 311 return -1; 312 } 313 314 args[0] = "pppd"; 315 args[1] = tty; 316 args[2] = "nodetach"; 317 318 pid = dun_exec(tty, pppd, args); 319 if (pid < 0) { 320 syslog(LOG_ERR, "Exec failed. %s(%d)", strerror(errno), errno); 321 return -1; 322 } 323 324 if (wait) { 325 int status; 326 waitpid(pid, &status, 0); 327 /* FIXME: Check for waitpid errors */ 328 } 329 330 return 0; 331 } 332