int main(int argc, char *argv[]) { struct sigaction sa; GIOChannel *dev_io; char *device = NULL, *snoop = NULL; bdaddr_t bdaddr; int fd, dd, opt, detach = 1, dev = -1; bacpy(&bdaddr, BDADDR_ANY); while ((opt=getopt_long(argc, argv, "d:b:s:nh", main_options, NULL)) != EOF) { switch(opt) { case 'd': device = strdup(optarg); break; case 'b': str2ba(optarg, &bdaddr); break; case 's': snoop = strdup(optarg); break; case 'n': detach = 0; break; case 'h': default: usage(); exit(0); } } argc -= optind; argv += optind; optind = 0; if (argc < 1) { usage(); exit(1); } if (strlen(argv[0]) > 3 && !strncasecmp(argv[0], "hci", 3)) { dev = hci_devid(argv[0]); if (dev < 0) { perror("Invalid device"); exit(1); } } else { if (getbdaddrbyname(argv[0], &vdev.bdaddr) < 0) exit(1); } if (detach) { if (daemon(0, 0)) { perror("Can't start daemon"); exit(1); } } /* Start logging to syslog and stderr */ openlog("hciemu", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); syslog(LOG_INFO, "HCI emulation daemon ver %s started", VERSION); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); io_init(); if (!device && dev >= 0) device = strdup(GHCI_DEV); /* Open and create virtual HCI device */ if (device) { fd = open(device, O_RDWR); if (fd < 0) { syslog(LOG_ERR, "Can't open device %s: %s (%d)", device, strerror(errno), errno); free(device); exit(1); } free(device); } else { fd = open(VHCI_DEV, O_RDWR); if (fd < 0) { fd = open(VHCI_UDEV, O_RDWR); if (fd < 0) { syslog(LOG_ERR, "Can't open device %s: %s (%d)", VHCI_DEV, strerror(errno), errno); exit(1); } } } /* Create snoop file */ if (snoop) { dd = create_snoop(snoop); if (dd < 0) syslog(LOG_ERR, "Can't create snoop file %s: %s (%d)", snoop, strerror(errno), errno); free(snoop); } else dd = -1; /* Create event loop */ event_loop = g_main_loop_new(NULL, FALSE); if (dev >= 0) return run_proxy(fd, dev, &bdaddr); /* Device settings */ vdev.features[0] = 0xff; vdev.features[1] = 0xff; vdev.features[2] = 0x8f; vdev.features[3] = 0xfe; vdev.features[4] = 0x9b; vdev.features[5] = 0xf9; vdev.features[6] = 0x01; vdev.features[7] = 0x80; memset(vdev.name, 0, sizeof(vdev.name)); strncpy((char *) vdev.name, "BlueZ (Virtual HCI)", sizeof(vdev.name) - 1); vdev.dev_class[0] = 0x00; vdev.dev_class[1] = 0x00; vdev.dev_class[2] = 0x00; vdev.inq_mode = 0x00; vdev.eir_fec = 0x00; memset(vdev.eir_data, 0, sizeof(vdev.eir_data)); vdev.fd = fd; vdev.dd = dd; dev_io = g_io_channel_unix_new(fd); g_io_add_watch(dev_io, G_IO_IN, io_hci_data, NULL); setpriority(PRIO_PROCESS, 0, -19); /* Start event processor */ g_main_loop_run(event_loop); close(fd); if (dd >= 0) close(dd); syslog(LOG_INFO, "Exit"); return 0; }
int main(int argc, char *argv[]) { int exitcode = EXIT_FAILURE; struct sigaction sa; char *device = NULL, *snoop = NULL; int device_fd; struct epoll_event device_event; int dd, opt, detach = 1; while ((opt=getopt_long(argc, argv, "d:s:nh", options, NULL)) != EOF) { switch(opt) { case 'd': device = strdup(optarg); break; case 's': snoop = strdup(optarg); break; case 'n': detach = 0; break; case 'h': usage(); exit(0); default: usage(); exit(1); } } argc -= optind; argv += optind; optind = 0; if (argc < 1) { usage(); exit(1); } if (getbdaddrbyname(argv[0], &vdev.bdaddr) < 0) exit(1); if (detach) { if (daemon(0, 0)) { perror("Can't start daemon"); exit(1); } } /* Start logging to syslog and stderr */ openlog("hciemu", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); syslog(LOG_INFO, "HCI emulation daemon ver %s started", VERSION); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); if (!device) device = strdup(VHCI_DEV); /* Open and create virtual HCI device */ device_fd = open(device, O_RDWR); if (device_fd < 0) { syslog(LOG_ERR, "Can't open device %s: %s (%d)", device, strerror(errno), errno); free(device); return exitcode; } free(device); /* Create snoop file */ if (snoop) { dd = create_snoop(snoop); if (dd < 0) syslog(LOG_ERR, "Can't create snoop file %s: %s (%d)", snoop, strerror(errno), errno); free(snoop); } else dd = -1; /* Create event loop */ epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (epoll_fd < 0) { perror("Failed to create epoll descriptor"); goto close_device; } reset_vdev(); vdev.dev_fd = device_fd; vdev.dd = dd; memset(&device_event, 0, sizeof(device_event)); device_event.events = EPOLLIN; device_event.data.fd = device_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, device_fd, &device_event) < 0) { perror("Failed to setup device event watch"); goto close_device; } setpriority(PRIO_PROCESS, 0, -19); /* Start event processor */ for (;;) { struct epoll_event events[MAX_EPOLL_EVENTS]; int n, nfds; if (__io_canceled) break; nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1); if (nfds < 0) continue; for (n = 0; n < nfds; n++) { if (events[n].data.fd == vdev.dev_fd) io_hci_data(); else if (events[n].data.fd == vdev.scan_fd) io_conn_ind(); } } exitcode = EXIT_SUCCESS; epoll_ctl(epoll_fd, EPOLL_CTL_DEL, device_fd, NULL); close_device: close(device_fd); if (dd >= 0) close(dd); close(epoll_fd); syslog(LOG_INFO, "Exit"); return exitcode; }