diff options
Diffstat (limited to 'input/server.c')
-rw-r--r-- | input/server.c | 200 |
1 files changed, 35 insertions, 165 deletions
diff --git a/input/server.c b/input/server.c index 2a9e08d4..0f04b06a 100644 --- a/input/server.c +++ b/input/server.c @@ -42,103 +42,12 @@ #include "logging.h" #include "dbus.h" +#include "device.h" #include "server.h" #include "storage.h" -struct session_data { - bdaddr_t src; - bdaddr_t dst; - int ctrl_sk; - int intr_sk; -}; - -static GSList *sessions = NULL; static DBusConnection *connection = NULL; -static struct session_data *find_session(bdaddr_t *src, bdaddr_t *dst) -{ - GSList *list; - - for (list = sessions; list != NULL; list = list->next) { - struct session_data *session = list->data; - - if (!bacmp(&session->src, src) && !bacmp(&session->dst, dst)) - return session; - } - - return NULL; -} - -static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data) -{ - if (cond & G_IO_NVAL) - return FALSE; - - if (cond & (G_IO_HUP | G_IO_ERR)) { - g_io_channel_close(chan); - return FALSE; - } - - return TRUE; -} - -static void create_device(struct session_data *session) -{ - struct hidp_connadd_req req; - char addr[18]; - int ctl, err, timeout = 30; - - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) { - error("Can't open HIDP interface"); - goto cleanup; - } - - ba2str(&session->dst, addr); - - memset(&req, 0, sizeof(req)); - req.ctrl_sock = session->ctrl_sk; - req.intr_sock = session->intr_sk; - req.flags = 0; - req.idle_to = timeout * 60; - - if (get_stored_device_info(&session->src, &session->dst, &req) < 0) { - error("Rejected connection from unknown device %s", addr); - goto cleanup; - } - - if (req.subclass & 0x40) { - err = encrypt_link(&session->src, &session->dst); - if (err < 0 && err != -ENOKEY) { - if (req.rd_data) - free(req.rd_data); - goto cleanup; - } - } - - info("New input device %s (%s)", addr, req.name); - - if (req.vendor == 0x054c && req.product == 0x0268) { - unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 }; - err = write(session->ctrl_sk, buf, sizeof(buf)); - } - - err = ioctl(ctl, HIDPCONNADD, &req); - - close(ctl); - - if (req.rd_data) - free(req.rd_data); - -cleanup: - sessions = g_slist_remove(sessions, session); - - close(session->intr_sk); - close(session->ctrl_sk); - - g_free(session); -} - static void cancel_authorization(const char *addr) { DBusMessage *msg; @@ -160,38 +69,39 @@ static void cancel_authorization(const char *addr) send_message_and_unref(connection, msg); } +struct authorization_data { + bdaddr_t src; + bdaddr_t dst; +}; + static void authorization_callback(DBusPendingCall *pcall, void *data) { - struct session_data *session = data; + struct authorization_data *auth = data; DBusMessage *reply = dbus_pending_call_steal_reply(pcall); DBusError derr; dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - error("Access denied: %s", derr.message); - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { - char addr[18]; - memset(addr, 0, sizeof(addr)); - ba2str(&session->dst, addr); - cancel_authorization(addr); - } - dbus_error_free(&derr); - - sessions = g_slist_remove(sessions, session); - - close(session->intr_sk); - close(session->ctrl_sk); - - g_free(session); - } else { - create_device(session); + if (dbus_set_error_from_message(&derr, reply) != TRUE) { + dbus_message_unref(reply); + input_device_connadd(&auth->src, &auth->dst); + return; + } + + error("Authorization denied: %s", derr.message); + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { + char addr[18]; + memset(addr, 0, sizeof(addr)); + ba2str(&auth->dst, addr); + cancel_authorization(addr); } + dbus_error_free(&derr); dbus_message_unref(reply); } -static int authorize_device(struct session_data *session) +static int authorize_device(bdaddr_t *src, bdaddr_t *dst) { + struct authorization_data *auth; DBusMessage *msg; DBusPendingCall *pending; char addr[18]; @@ -206,7 +116,7 @@ static int authorize_device(struct session_data *session) } memset(addr, 0, sizeof(addr)); - ba2str(&session->dst, addr); + ba2str(dst, addr); dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr, DBUS_TYPE_STRING, &uuid, @@ -216,28 +126,18 @@ static int authorize_device(struct session_data *session) msg, &pending, -1) == FALSE) return -EACCES; - dbus_pending_call_set_notify(pending, authorization_callback, session, NULL); + auth = g_new0(struct authorization_data, 1); + bacpy(&auth->src, src); + bacpy(&auth->dst, dst); + dbus_pending_call_set_notify(pending, authorization_callback, auth, g_free); dbus_pending_call_unref(pending); dbus_message_unref(msg); return 0; } -static void create_watch(int sk, struct session_data *session) -{ - GIOChannel *io; - - io = g_io_channel_unix_new(sk); - - g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - session_event, session); - - g_io_channel_unref(io); -} - static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data) { - struct session_data *session; struct sockaddr_l2 addr; socklen_t addrlen; bdaddr_t src, dst; @@ -268,44 +168,14 @@ static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data debug("Incoming connection on PSM %d", psm); - session = find_session(&src, &dst); - if (session) { - if (psm == 19) { - session->intr_sk = nsk; - if (authorize_device(session) < 0) { - error("Authorization request failed"); - sessions = g_slist_remove(sessions, session); - - close(session->intr_sk); - close(session->ctrl_sk); - - g_free(session); - - return TRUE; - } - debug("Waiting authorization ..."); - } else { - error("Control channel already established"); - close(nsk); - } - } else { - if (psm == 17) { - session = g_new0(struct session_data, 1); - - bacpy(&session->src, &src); - bacpy(&session->dst, &dst); - session->ctrl_sk = nsk; - session->intr_sk = -1; - - sessions = g_slist_append(sessions, session); - - create_watch(nsk, session); - } else { - error("No control channel available"); - close(nsk); - } + if (input_device_set_channel(&src, &dst, psm, nsk) < 0) { + input_device_close_channels(&src, &dst); + return TRUE; } + if ((psm == L2CAP_PSM_HIDP_INTR) && (authorize_device(&src, &dst) < 0)) + input_device_close_channels(&src, &dst); + return TRUE; } @@ -347,14 +217,14 @@ static GIOChannel *intr_io = NULL; int server_start(DBusConnection *conn) { - ctrl_io = setup_l2cap(17); + ctrl_io = setup_l2cap(L2CAP_PSM_HIDP_CTRL); if (!ctrl_io) { error("Failed to listen on control channel"); return -1; } g_io_channel_set_close_on_unref(ctrl_io, TRUE); - intr_io = setup_l2cap(19); + intr_io = setup_l2cap(L2CAP_PSM_HIDP_INTR); if (!intr_io) { error("Failed to listen on interrupt channel"); g_io_channel_unref(ctrl_io); |