ciptool.c revision 1d3715db11f573060cb02a2b7b7c44f06607d337
1/* 2 * 3 * Bluetooth Common ISDN Access Profile (CIP) 4 * 5 * Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 <stdlib.h> 31#include <unistd.h> 32#include <malloc.h> 33#include <getopt.h> 34#include <signal.h> 35#include <sys/poll.h> 36#include <sys/ioctl.h> 37#include <sys/socket.h> 38 39#include <bluetooth/bluetooth.h> 40#include <bluetooth/hci.h> 41#include <bluetooth/hci_lib.h> 42#include <bluetooth/l2cap.h> 43#include <bluetooth/sdp.h> 44#include <bluetooth/sdp_lib.h> 45#include <bluetooth/cmtp.h> 46 47 48static volatile sig_atomic_t __io_canceled = 0; 49 50static void sig_hup(int sig) 51{ 52 return; 53} 54 55static void sig_term(int sig) 56{ 57 __io_canceled = 1; 58} 59 60static char *cmtp_state[] = { 61 "unknown", 62 "connected", 63 "open", 64 "bound", 65 "listening", 66 "connecting", 67 "connecting", 68 "config", 69 "disconnecting", 70 "closed" 71}; 72 73static char *cmtp_flagstostr(uint32_t flags) 74{ 75 static char str[100] = ""; 76 77 strcat(str, "["); 78 79 if (flags & (1 << CMTP_LOOPBACK)) 80 strcat(str, "loopback"); 81 82 strcat(str, "]"); 83 84 return str; 85} 86 87static int get_psm(bdaddr_t *src, bdaddr_t *dst, unsigned short *psm) 88{ 89 sdp_session_t *s; 90 sdp_list_t *srch, *attrs, *rsp; 91 uuid_t svclass; 92 uint16_t attr; 93 int err; 94 95 if (!(s = sdp_connect(src, dst, 0))) 96 return -1; 97 98 sdp_uuid16_create(&svclass, CIP_SVCLASS_ID); 99 srch = sdp_list_append(NULL, &svclass); 100 101 attr = SDP_ATTR_PROTO_DESC_LIST; 102 attrs = sdp_list_append(NULL, &attr); 103 104 err = sdp_service_search_attr_req(s, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp); 105 106 sdp_close(s); 107 108 if (err) 109 return 0; 110 111 for (; rsp; rsp = rsp->next) { 112 sdp_record_t *rec = (sdp_record_t *) rsp->data; 113 sdp_list_t *protos; 114 115 if (!sdp_get_access_protos(rec, &protos)) { 116 unsigned short p = sdp_get_proto_port(protos, L2CAP_UUID); 117 if (p > 0) { 118 *psm = p; 119 return 1; 120 } 121 } 122 } 123 124 return 0; 125} 126 127static int do_connect(int ctl, int dev_id, bdaddr_t *src, bdaddr_t *dst, unsigned short psm, uint32_t flags) 128{ 129 struct cmtp_connadd_req req; 130 struct hci_dev_info di; 131 struct sockaddr_l2 addr; 132 struct l2cap_options opts; 133 int sk, size; 134 135 hci_devinfo(dev_id, &di); 136 if (!(di.link_policy & HCI_LP_RSWITCH)) { 137 printf("Local device is not accepting role switch\n"); 138 } 139 140 if ((sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) { 141 perror("Can't create L2CAP socket"); 142 exit(1); 143 } 144 145 addr.l2_family = AF_BLUETOOTH; 146 bacpy(&addr.l2_bdaddr, src); 147 addr.l2_psm = 0; 148 149 if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 150 perror("Can't bind L2CAP socket"); 151 close(sk); 152 exit(1); 153 } 154 155 size = sizeof(opts); 156 if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) { 157 perror("Can't get L2CAP options"); 158 close(sk); 159 exit(1); 160 } 161 162 opts.imtu = CMTP_DEFAULT_MTU; 163 opts.omtu = CMTP_DEFAULT_MTU; 164 opts.flush_to = 0xffff; 165 166 if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) { 167 perror("Can't set L2CAP options"); 168 close(sk); 169 exit(1); 170 } 171 172 addr.l2_family = AF_BLUETOOTH; 173 bacpy(&addr.l2_bdaddr, dst); 174 addr.l2_psm = htobs(psm); 175 176 if (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 177 perror("Can't connect L2CAP socket"); 178 close(sk); 179 exit(1); 180 } 181 182 req.sock = sk; 183 req.flags = flags; 184 185 if (ioctl(ctl, CMTPCONNADD, &req) < 0) { 186 perror("Can't create connection"); 187 exit(1); 188 } 189 190 return sk; 191} 192 193static void cmd_show(int ctl, bdaddr_t *bdaddr, int argc, char **argv) 194{ 195 struct cmtp_connlist_req req; 196 struct cmtp_conninfo ci[16]; 197 char addr[18]; 198 int i; 199 200 req.cnum = 16; 201 req.ci = ci; 202 203 if (ioctl(ctl, CMTPGETCONNLIST, &req) < 0) { 204 perror("Can't get connection list"); 205 exit(1); 206 } 207 208 for (i = 0; i < req.cnum; i++) { 209 ba2str(&ci[i].bdaddr, addr); 210 printf("%d %s %s %s\n", ci[i].num, addr, 211 cmtp_state[ci[i].state], 212 ci[i].flags ? cmtp_flagstostr(ci[i].flags) : ""); 213 } 214} 215 216static void cmd_search(int ctl, bdaddr_t *bdaddr, int argc, char **argv) 217{ 218 inquiry_info *info = NULL; 219 bdaddr_t src, dst; 220 unsigned short psm; 221 int i, dev_id, num_rsp, length, flags; 222 char addr[18]; 223 uint8_t class[3]; 224 225 ba2str(bdaddr, addr); 226 dev_id = hci_devid(addr); 227 if (dev_id < 0) { 228 dev_id = hci_get_route(NULL); 229 hci_devba(dev_id, &src); 230 } else 231 bacpy(&src, bdaddr); 232 233 length = 8; /* ~10 seconds */ 234 num_rsp = 0; 235 flags = 0; 236 237 printf("Searching ...\n"); 238 239 num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags); 240 241 for (i = 0; i < num_rsp; i++) { 242 memcpy(class, (info+i)->dev_class, 3); 243 if ((class[1] == 2) && ((class[0] / 4) == 5)) { 244 bacpy(&dst, &(info+i)->bdaddr); 245 ba2str(&dst, addr); 246 247 printf("\tChecking service for %s\n", addr); 248 if (!get_psm(&src, &dst, &psm)) 249 continue; 250 251 free(info); 252 253 printf("\tConnecting to device %s\n", addr); 254 do_connect(ctl, dev_id, &src, &dst, psm, 0); 255 return; 256 } 257 } 258 259 free(info); 260 fprintf(stderr, "\tNo devices in range or visible\n"); 261 exit(1); 262} 263 264static void cmd_create(int ctl, bdaddr_t *bdaddr, int argc, char **argv) 265{ 266 bdaddr_t src, dst; 267 unsigned short psm; 268 int dev_id; 269 char addr[18]; 270 271 if (argc < 2) 272 return; 273 274 str2ba(argv[1], &dst); 275 276 ba2str(bdaddr, addr); 277 dev_id = hci_devid(addr); 278 if (dev_id < 0) { 279 dev_id = hci_get_route(&dst); 280 hci_devba(dev_id, &src); 281 } else 282 bacpy(&src, bdaddr); 283 284 if (argc < 3) { 285 if (!get_psm(&src, &dst, &psm)) 286 psm = 4099; 287 } else 288 psm = atoi(argv[2]); 289 290 do_connect(ctl, dev_id, &src, &dst, psm, 0); 291} 292 293static void cmd_release(int ctl, bdaddr_t *bdaddr, int argc, char **argv) 294{ 295 struct cmtp_conndel_req req; 296 struct cmtp_connlist_req cl; 297 struct cmtp_conninfo ci[16]; 298 299 if (argc < 2) { 300 cl.cnum = 16; 301 cl.ci = ci; 302 303 if (ioctl(ctl, CMTPGETCONNLIST, &cl) < 0) { 304 perror("Can't get connection list"); 305 exit(1); 306 } 307 308 if (cl.cnum == 0) 309 return; 310 311 if (cl.cnum != 1) { 312 fprintf(stderr, "You have to specifiy the device address.\n"); 313 exit(1); 314 } 315 316 bacpy(&req.bdaddr, &ci[0].bdaddr); 317 } else 318 str2ba(argv[1], &req.bdaddr); 319 320 if (ioctl(ctl, CMTPCONNDEL, &req) < 0) { 321 perror("Can't release connection"); 322 exit(1); 323 } 324} 325 326static void cmd_loopback(int ctl, bdaddr_t *bdaddr, int argc, char **argv) 327{ 328 struct cmtp_conndel_req req; 329 struct sigaction sa; 330 struct pollfd p; 331 bdaddr_t src, dst; 332 unsigned short psm; 333 int dev_id, sk; 334 char addr[18]; 335 336 if (argc < 2) 337 return; 338 339 str2ba(argv[1], &dst); 340 341 ba2str(bdaddr, addr); 342 dev_id = hci_devid(addr); 343 if (dev_id < 0) { 344 dev_id = hci_get_route(&dst); 345 hci_devba(dev_id, &src); 346 } else 347 bacpy(&src, bdaddr); 348 349 ba2str(&dst, addr); 350 printf("Connecting to %s in loopback mode\n", addr); 351 352 if (argc < 3) { 353 if (!get_psm(&src, &dst, &psm)) 354 psm = 4099; 355 } else 356 psm = atoi(argv[2]); 357 358 sk = do_connect(ctl, dev_id, &src, &dst, psm, (1 << CMTP_LOOPBACK)); 359 360 printf("Press CTRL-C for hangup\n"); 361 362 memset(&sa, 0, sizeof(sa)); 363 sa.sa_flags = SA_NOCLDSTOP; 364 sa.sa_handler = SIG_IGN; 365 sigaction(SIGCHLD, &sa, NULL); 366 sigaction(SIGPIPE, &sa, NULL); 367 368 sa.sa_handler = sig_term; 369 sigaction(SIGTERM, &sa, NULL); 370 sigaction(SIGINT, &sa, NULL); 371 372 sa.sa_handler = sig_hup; 373 sigaction(SIGHUP, &sa, NULL); 374 375 p.fd = sk; 376 p.events = POLLERR | POLLHUP; 377 378 while (!__io_canceled) { 379 p.revents = 0; 380 if (poll(&p, 1, 100)) 381 break; 382 } 383 384 bacpy(&req.bdaddr, &dst); 385 ioctl(ctl, CMTPCONNDEL, &req); 386} 387 388 389static struct { 390 char *cmd; 391 char *alt; 392 void (*func)(int ctl, bdaddr_t *bdaddr, int argc, char **argv); 393 char *opt; 394 char *doc; 395} command[] = { 396 { "show", "list", cmd_show, 0, "Show remote connections" }, 397 { "search", "scan", cmd_search, 0, "Search for a remote device" }, 398 { "connect", "create", cmd_create, "<bdaddr>", "Connect a remote device" }, 399 { "release", "disconnect", cmd_release, "[bdaddr]", "Disconnect the remote device" }, 400 { "loopback", "test", cmd_loopback, "<bdaddr>", "Loopback test of a device" }, 401 { NULL, NULL, NULL, 0, 0 } 402}; 403 404static void usage(void) 405{ 406 int i; 407 408 printf("ciptool - Bluetooth Common ISDN Access Profile (CIP)\n\n"); 409 410 printf("Usage:\n" 411 "\tciptool [options] [command]\n" 412 "\n"); 413 414 printf("Options:\n" 415 "\t-i [hciX|bdaddr] Local HCI device or BD Address\n" 416 "\t-h, --help Display help\n" 417 "\n"); 418 419 printf("Commands:\n"); 420 for (i = 0; command[i].cmd; i++) 421 printf("\t%-8s %-10s\t%s\n", command[i].cmd, 422 command[i].opt ? command[i].opt : " ", 423 command[i].doc); 424 printf("\n"); 425} 426 427static struct option main_options[] = { 428 { "help", 0, 0, 'h' }, 429 { "device", 1, 0, 'i' }, 430 { 0, 0, 0, 0 } 431}; 432 433int main(int argc, char *argv[]) 434{ 435 bdaddr_t bdaddr; 436 int i, opt, ctl; 437 438 bacpy(&bdaddr, BDADDR_ANY); 439 440 while ((opt = getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) { 441 switch(opt) { 442 case 'i': 443 if (!strncmp(optarg, "hci", 3)) 444 hci_devba(atoi(optarg + 3), &bdaddr); 445 else 446 str2ba(optarg, &bdaddr); 447 break; 448 case 'h': 449 usage(); 450 exit(0); 451 default: 452 exit(0); 453 } 454 } 455 456 argc -= optind; 457 argv += optind; 458 optind = 0; 459 460 if (argc < 1) { 461 usage(); 462 return 0; 463 } 464 465 if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_CMTP)) < 0 ) { 466 perror("Can't open CMTP control socket"); 467 exit(1); 468 } 469 470 for (i = 0; command[i].cmd; i++) { 471 if (strncmp(command[i].cmd, argv[0], 4) && strncmp(command[i].alt, argv[0], 4)) 472 continue; 473 command[i].func(ctl, &bdaddr, argc, argv); 474 close(ctl); 475 exit(0); 476 } 477 478 usage(); 479 480 close(ctl); 481 482 return 0; 483} 484