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