1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> 6 * Copyright (C) 2002-2009 Marcel Holtmann <marcel@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 55static 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 92static 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 119static 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 154static 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 183static 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 231int dun_init(void) 232{ 233 return 0; 234} 235 236int dun_cleanup(void) 237{ 238 return 0; 239} 240 241static 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 261static 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 286int dun_show_connections(void) 287{ 288 for_each_port(show_conn, 0); 289 return 0; 290} 291 292int dun_kill_connection(uint8_t *dst) 293{ 294 for_each_port(kill_conn, (unsigned long) dst); 295 return 0; 296} 297 298int dun_kill_all_connections(void) 299{ 300 for_each_port(kill_conn, 0); 301 return 0; 302} 303 304int 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