diff --git a/Makefile.tools b/Makefile.tools
index 7fa4269..eea1a9b 100644
--- a/Makefile.tools
+++ b/Makefile.tools
test/btiotest test/test-textfile \
test/uuidtest test/mpris-player
-test_hciemu_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la
+test_hciemu_LDADD = lib/libbluetooth-private.la
test_l2test_LDADD = lib/libbluetooth-private.la
diff --git a/test/hciemu.c b/test/hciemu.c
index 5526634..ca6a867 100644
--- a/test/hciemu.c
+++ b/test/hciemu.c
#include <stdio.h>
#include <errno.h>
-#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <syslog.h>
#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/poll.h>
-#include <sys/ioctl.h>
+#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/resource.h>
+#include <netdb.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
-#include <netdb.h>
-
-#include <glib.h>
-
#define VHCI_DEV "/dev/vhci"
#define VHCI_MAX_CONN 12
uint8_t eir_data[HCI_MAX_EIR_LENGTH];
uint16_t acl_cnt;
bdaddr_t bdaddr;
- int fd;
+ int dev_fd;
+ int scan_fd;
int dd;
- GIOChannel *scan;
};
struct vhci_conn {
bdaddr_t dest;
uint16_t handle;
- GIOChannel *chan;
+ int fd;
};
struct vhci_link_info {
static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
-static GMainLoop *event_loop;
+#define MAX_EPOLL_EVENTS 10
-static volatile sig_atomic_t __io_canceled;
+static int epoll_fd;
-static inline void io_init(void)
-{
- __io_canceled = 0;
-}
-
-static inline void io_cancel(void)
-{
- __io_canceled = 1;
-}
+static volatile sig_atomic_t __io_canceled = 0;
static void sig_term(int sig)
{
- io_cancel();
- g_main_loop_quit(event_loop);
+ __io_canceled = 1;
}
-static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data);
-static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data);
-static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data);
-
static inline int read_n(int fd, void *buf, int len)
{
register int w, t = 0;
return fd;
}
-static int write_snoop(int fd, int type, int incoming, unsigned char *buf, int len)
+static int write_snoop(int fd, int type, int incoming,
+ unsigned char *buf, int len)
{
struct btsnoop_pkt pkt;
struct timeval tv;
write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
- if (write(vdev.fd, buf, ptr - buf) < 0)
+ if (write(vdev.dev_fd, buf, ptr - buf) < 0)
syslog(LOG_ERR, "Can't send event: %s(%d)",
strerror(errno), errno);
}
write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
- if (write(vdev.fd, buf, ptr - buf) < 0)
+ if (write(vdev.dev_fd, buf, ptr - buf) < 0)
syslog(LOG_ERR, "Can't send event: %s(%d)",
strerror(errno), errno);
}
write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
- if (write(vdev.fd, buf, ptr - buf) < 0)
+ if (write(vdev.dev_fd, buf, ptr - buf) < 0)
syslog(LOG_ERR, "Can't send event: %s (%d)",
strerror(errno), errno);
}
write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
- if (write(vdev.fd, buf, ptr - buf) < 0)
+ if (write(vdev.dev_fd, buf, ptr - buf) < 0)
syslog(LOG_ERR, "Can't send event: %s (%d)",
strerror(errno), errno);
+
+ /* TODO: Add io_acl_data() handling */
}
static void disconn_complete(struct vhci_conn *conn)
write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
- if (write(vdev.fd, buf, ptr - buf) < 0)
+ if (write(vdev.dev_fd, buf, ptr - buf) < 0)
syslog(LOG_ERR, "Can't send event: %s (%d)",
strerror(errno), errno);
write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
- if (write(vdev.fd, buf, ptr - buf) < 0)
+ if (write(vdev.dev_fd, buf, ptr - buf) < 0)
syslog(LOG_ERR, "Can't send event: %s (%d)",
strerror(errno), errno);
}
static int scan_enable(uint8_t *data)
{
+ struct epoll_event scan_event;
struct sockaddr_in sa;
- GIOChannel *sk_io;
bdaddr_t ba;
int sk, opt;
if (!(*data & SCAN_PAGE)) {
- if (vdev.scan) {
- g_io_channel_shutdown(vdev.scan, TRUE, NULL);
- vdev.scan = NULL;
+ if (vdev.scan_fd >= 0) {
+ close(vdev.scan_fd);
+ vdev.scan_fd = -1;
}
return 0;
}
- if (vdev.scan)
+ if (vdev.scan_fd >= 0)
return 0;
if ((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
goto failed;
}
- sk_io = g_io_channel_unix_new(sk);
- g_io_add_watch(sk_io, G_IO_IN | G_IO_NVAL, io_conn_ind, NULL);
- vdev.scan = sk_io;
+ memset(&scan_event, 0, sizeof(scan_event));
+ scan_event.events = EPOLLIN;
+ scan_event.data.fd = sk;
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sk, &scan_event) < 0) {
+ syslog(LOG_ERR, "Failed to setup scan event watch");
+ goto failed;
+ }
+
+ vdev.scan_fd = sk;
return 0;
failed:
return;
connect_complete(conn);
-
- g_io_add_watch(conn->chan, G_IO_IN | G_IO_NVAL | G_IO_HUP,
- io_acl_data, (gpointer) conn);
}
static void close_connection(struct vhci_conn *conn)
syslog(LOG_INFO, "Closing connection %s handle %d",
addr, conn->handle);
- g_io_channel_shutdown(conn->chan, TRUE, NULL);
- g_io_channel_unref(conn->chan);
+ close(conn->fd);
vconn[conn->handle - 1] = NULL;
disconn_complete(conn);
vconn[h] = conn;
conn->handle = h + 1;
- conn->chan = g_io_channel_unix_new(sk);
+ conn->fd = sk;
connect_complete(conn);
- g_io_add_watch(conn->chan, G_IO_IN | G_IO_NVAL | G_IO_HUP,
- io_acl_data, (gpointer) conn);
- return;
}
static void hci_link_control(uint16_t ocf, int plen, uint8_t *data)
hci_acl_hdr *ah = (void *) data;
struct vhci_conn *conn;
uint16_t handle;
- int fd;
handle = acl_handle(btohs(ah->handle));
return;
}
- fd = g_io_channel_unix_get_fd(conn->chan);
- if (write_n(fd, data, btohs(ah->dlen) + HCI_ACL_HDR_SIZE) < 0) {
+ if (write_n(conn->fd, data, btohs(ah->dlen) + HCI_ACL_HDR_SIZE) < 0) {
close_connection(conn);
return;
}
}
}
-static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data)
+#if 0
+static void io_acl_data(void *data)
{
- struct vhci_conn *conn = (struct vhci_conn *) data;
+ struct vhci_conn *conn = data;
unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
hci_acl_hdr *ah;
uint16_t flags;
- int fd, len;
-
- if (cond & G_IO_NVAL) {
- g_io_channel_unref(chan);
- return FALSE;
- }
-
- if (cond & G_IO_HUP) {
- close_connection(conn);
- return FALSE;
- }
-
- fd = g_io_channel_unix_get_fd(chan);
+ int len;
ptr = buf + 1;
- if (read_n(fd, ptr, HCI_ACL_HDR_SIZE) <= 0) {
+ if (read_n(conn->fd, ptr, HCI_ACL_HDR_SIZE) <= 0) {
close_connection(conn);
- return FALSE;
+ return;
}
ah = (void *) ptr;
ptr += HCI_ACL_HDR_SIZE;
len = btohs(ah->dlen);
- if (read_n(fd, ptr, len) <= 0) {
+ if (read_n(conn->fd, ptr, len) <= 0) {
close_connection(conn);
- return FALSE;
+ return;
}
buf[0] = HCI_ACLDATA_PKT;
write_snoop(vdev.dd, HCI_ACLDATA_PKT, 1, buf, len);
- if (write(vdev.fd, buf, len) < 0)
- return FALSE;
-
- return TRUE;
+ if (write(vdev.dev_fd, buf, len) < 0)
+ syslog(LOG_ERR, "ACL data write error");
}
+#endif
-static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data)
+static void io_conn_ind(void)
{
struct vhci_link_info info;
struct vhci_conn *conn;
struct sockaddr_in sa;
socklen_t len;
- int sk, nsk, h;
-
- if (cond & G_IO_NVAL)
- return FALSE;
-
- sk = g_io_channel_unix_get_fd(chan);
+ int nsk, h;
len = sizeof(sa);
- if ((nsk = accept(sk, (struct sockaddr *) &sa, &len)) < 0)
- return TRUE;
+ if ((nsk = accept(vdev.scan_fd, (struct sockaddr *) &sa, &len)) < 0)
+ return;
if (read_n(nsk, &info, sizeof(info)) < 0) {
syslog(LOG_ERR, "Can't read link info");
- return TRUE;
+ return;
}
if (!(conn = malloc(sizeof(*conn)))) {
syslog(LOG_ERR, "Can't alloc new connection");
close(nsk);
- return TRUE;
+ return;
}
bacpy(&conn->dest, &info.bdaddr);
syslog(LOG_ERR, "Too many connections");
free(conn);
close(nsk);
- return TRUE;
+ return;
accepted:
vconn[h] = conn;
conn->handle = h + 1;
- conn->chan = g_io_channel_unix_new(nsk);
+ conn->fd = nsk;
connect_request(conn);
-
- return TRUE;
}
-static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data)
+static void io_hci_data(void)
{
unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
int type;
ssize_t len;
- int fd;
ptr = buf;
- fd = g_io_channel_unix_get_fd(chan);
-
- len = read(fd, buf, sizeof(buf));
+ len = read(vdev.dev_fd, buf, sizeof(buf));
if (len < 0) {
if (errno == EAGAIN)
- return TRUE;
+ return;
syslog(LOG_ERR, "Read failed: %s (%d)", strerror(errno), errno);
- g_io_channel_unref(chan);
- g_main_loop_quit(event_loop);
- return FALSE;
+ __io_canceled = 1;
+ return;
}
type = *ptr++;
syslog(LOG_ERR, "Unknown packet type 0x%2.2x", type);
break;
}
-
- return TRUE;
}
static int getbdaddrbyname(char *str, bdaddr_t *ba)
int main(int argc, char *argv[])
{
+ int exitcode = EXIT_FAILURE;
struct sigaction sa;
- GIOChannel *dev_io;
char *device = NULL, *snoop = NULL;
- int fd, dd, opt, detach = 1;
+ 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) {
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
- io_init();
-
if (!device)
device = strdup(VHCI_DEV);
/* Open and create virtual HCI device */
- fd = open(device, O_RDWR);
- if (fd < 0) {
+ 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);
- exit(1);
+ return exitcode;
}
free(device);
dd = -1;
/* Create event loop */
- event_loop = g_main_loop_new(NULL, FALSE);
+ epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (epoll_fd < 0) {
+ perror("Failed to create epoll descriptor");
+ goto close_device;
+ }
/* Device settings */
vdev.features[0] = 0xff;
vdev.eir_fec = 0x00;
memset(vdev.eir_data, 0, sizeof(vdev.eir_data));
- vdev.fd = fd;
+ vdev.dev_fd = device_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);
+ 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 */
- g_main_loop_run(event_loop);
+ 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;
- close(fd);
+ 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 0;
+ return exitcode;
}