Blame profiles/input/device.c

Packit 34410b
/*
Packit 34410b
 *
Packit 34410b
 *  BlueZ - Bluetooth protocol stack for Linux
Packit 34410b
 *
Packit 34410b
 *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
Packit 34410b
 *  Copyright (C) 2014       Google Inc.
Packit 34410b
 *
Packit 34410b
 *
Packit 34410b
 *  This program is free software; you can redistribute it and/or modify
Packit 34410b
 *  it under the terms of the GNU General Public License as published by
Packit 34410b
 *  the Free Software Foundation; either version 2 of the License, or
Packit 34410b
 *  (at your option) any later version.
Packit 34410b
 *
Packit 34410b
 *  This program is distributed in the hope that it will be useful,
Packit 34410b
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 34410b
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 34410b
 *  GNU General Public License for more details.
Packit 34410b
 *
Packit 34410b
 *  You should have received a copy of the GNU General Public License
Packit 34410b
 *  along with this program; if not, write to the Free Software
Packit 34410b
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 34410b
 *
Packit 34410b
 */
Packit 34410b
Packit 34410b
#ifdef HAVE_CONFIG_H
Packit 34410b
#include <config.h>
Packit 34410b
#endif
Packit 34410b
Packit 34410b
#define _GNU_SOURCE
Packit 34410b
#include <stdlib.h>
Packit 34410b
#include <stdbool.h>
Packit 34410b
#include <errno.h>
Packit 34410b
#include <fcntl.h>
Packit 34410b
#include <unistd.h>
Packit 34410b
#include <sys/ioctl.h>
Packit 34410b
Packit 34410b
#include "lib/bluetooth.h"
Packit 34410b
#include "lib/hidp.h"
Packit 34410b
#include "lib/sdp.h"
Packit 34410b
#include "lib/sdp_lib.h"
Packit 34410b
#include "lib/uuid.h"
Packit 34410b
Packit 34410b
#include "gdbus/gdbus.h"
Packit 34410b
Packit 34410b
#include "btio/btio.h"
Packit 34410b
#include "src/log.h"
Packit 34410b
#include "src/adapter.h"
Packit 34410b
#include "src/device.h"
Packit 34410b
#include "src/profile.h"
Packit 34410b
#include "src/service.h"
Packit 34410b
#include "src/storage.h"
Packit 34410b
#include "src/dbus-common.h"
Packit 34410b
#include "src/error.h"
Packit 34410b
#include "src/sdp-client.h"
Packit 34410b
#include "src/shared/uhid.h"
Packit 34410b
Packit 34410b
#include "device.h"
Packit 34410b
#include "hidp_defs.h"
Packit 34410b
Packit 34410b
#define INPUT_INTERFACE "org.bluez.Input1"
Packit 34410b
Packit 34410b
enum reconnect_mode_t {
Packit 34410b
	RECONNECT_NONE = 0,
Packit 34410b
	RECONNECT_DEVICE,
Packit 34410b
	RECONNECT_HOST,
Packit 34410b
	RECONNECT_ANY
Packit 34410b
};
Packit 34410b
Packit 34410b
struct input_device {
Packit 34410b
	struct btd_service	*service;
Packit 34410b
	struct btd_device	*device;
Packit 34410b
	char			*path;
Packit 34410b
	bdaddr_t		src;
Packit 34410b
	bdaddr_t		dst;
Packit 34410b
	uint32_t		handle;
Packit 34410b
	GIOChannel		*ctrl_io;
Packit 34410b
	GIOChannel		*intr_io;
Packit 34410b
	guint			ctrl_watch;
Packit 34410b
	guint			intr_watch;
Packit 34410b
	guint			sec_watch;
Packit 34410b
	struct hidp_connadd_req *req;
Packit 34410b
	bool			disable_sdp;
Packit 34410b
	enum reconnect_mode_t	reconnect_mode;
Packit 34410b
	guint			reconnect_timer;
Packit 34410b
	uint32_t		reconnect_attempt;
Packit 34410b
	struct bt_uhid		*uhid;
Packit 34410b
	bool			uhid_created;
Packit 34410b
	uint8_t			report_req_pending;
Packit 34410b
	guint			report_req_timer;
Packit 34410b
	uint32_t		report_rsp_id;
Packit 34410b
};
Packit 34410b
Packit 34410b
static int idle_timeout = 0;
Packit 34410b
static bool uhid_enabled = false;
rpm-build 95ab10
static bool classic_bonded_only = false;
Packit 34410b
Packit 34410b
void input_set_idle_timeout(int timeout)
Packit 34410b
{
Packit 34410b
	idle_timeout = timeout;
Packit 34410b
}
Packit 34410b
Packit 34410b
void input_enable_userspace_hid(bool state)
Packit 34410b
{
Packit 34410b
	uhid_enabled = state;
Packit 34410b
}
Packit 34410b
rpm-build 95ab10
void input_set_classic_bonded_only(bool state)
rpm-build 95ab10
{
rpm-build 95ab10
	classic_bonded_only = state;
rpm-build 95ab10
}
rpm-build 95ab10
Packit 34410b
static void input_device_enter_reconnect_mode(struct input_device *idev);
Packit 34410b
static int connection_disconnect(struct input_device *idev, uint32_t flags);
Packit 34410b
Packit 34410b
static void input_device_free(struct input_device *idev)
Packit 34410b
{
Packit 34410b
	bt_uhid_unref(idev->uhid);
Packit 34410b
	btd_service_unref(idev->service);
Packit 34410b
	btd_device_unref(idev->device);
Packit 34410b
	g_free(idev->path);
Packit 34410b
Packit 34410b
	if (idev->ctrl_watch > 0)
Packit 34410b
		g_source_remove(idev->ctrl_watch);
Packit 34410b
Packit 34410b
	if (idev->intr_watch > 0)
Packit 34410b
		g_source_remove(idev->intr_watch);
Packit 34410b
Packit 34410b
	if (idev->sec_watch > 0)
Packit 34410b
		g_source_remove(idev->sec_watch);
Packit 34410b
Packit 34410b
	if (idev->intr_io)
Packit 34410b
		g_io_channel_unref(idev->intr_io);
Packit 34410b
Packit 34410b
	if (idev->ctrl_io)
Packit 34410b
		g_io_channel_unref(idev->ctrl_io);
Packit 34410b
Packit 34410b
	if (idev->req) {
Packit 34410b
		g_free(idev->req->rd_data);
Packit 34410b
		g_free(idev->req);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (idev->reconnect_timer > 0)
Packit 34410b
		g_source_remove(idev->reconnect_timer);
Packit 34410b
Packit 34410b
	if (idev->report_req_timer > 0)
Packit 34410b
		g_source_remove(idev->report_req_timer);
Packit 34410b
Packit 34410b
	g_free(idev);
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool hidp_send_message(GIOChannel *chan, uint8_t hdr,
Packit 34410b
					const uint8_t *data, size_t size)
Packit 34410b
{
Packit 34410b
	int fd;
Packit 34410b
	ssize_t len;
Packit 34410b
	uint8_t msg[size + 1];
Packit 34410b
Packit 34410b
	if (!chan) {
Packit 34410b
		error("BT socket not connected");
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (data == NULL)
Packit 34410b
		size = 0;
Packit 34410b
Packit 34410b
	msg[0] = hdr;
Packit 34410b
	if (size > 0)
Packit 34410b
		memcpy(&msg[1], data, size);
Packit 34410b
	++size;
Packit 34410b
Packit 34410b
	fd = g_io_channel_unix_get_fd(chan);
Packit 34410b
Packit 34410b
	len = write(fd, msg, size);
Packit 34410b
	if (len < 0) {
Packit 34410b
		error("BT socket write error: %s (%d)", strerror(errno), errno);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if ((size_t) len < size) {
Packit 34410b
		error("BT socket write error: partial write (%zd of %zu bytes)",
Packit 34410b
								len, size);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool hidp_send_ctrl_message(struct input_device *idev, uint8_t hdr,
Packit 34410b
					const uint8_t *data, size_t size)
Packit 34410b
{
Packit 34410b
	return hidp_send_message(idev->ctrl_io, hdr, data, size);
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool hidp_send_intr_message(struct input_device *idev, uint8_t hdr,
Packit 34410b
					const uint8_t *data, size_t size)
Packit 34410b
{
Packit 34410b
	return hidp_send_message(idev->intr_io, hdr, data, size);
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool uhid_send_feature_answer(struct input_device *idev,
Packit 34410b
					const uint8_t *data, size_t size,
Packit 34410b
					uint32_t id, uint16_t err)
Packit 34410b
{
Packit 34410b
	struct uhid_event ev;
Packit 34410b
	int ret;
Packit 34410b
Packit 34410b
	if (data == NULL)
Packit 34410b
		size = 0;
Packit 34410b
Packit 34410b
	if (size > sizeof(ev.u.feature_answer.data))
Packit 34410b
		size = sizeof(ev.u.feature_answer.data);
Packit 34410b
Packit 34410b
	if (!idev->uhid_created) {
Packit 34410b
		DBG("HID report (%zu bytes) dropped", size);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	memset(&ev, 0, sizeof(ev));
Packit 34410b
	ev.type = UHID_FEATURE_ANSWER;
Packit 34410b
	ev.u.feature_answer.id = id;
Packit 34410b
	ev.u.feature_answer.err = err;
Packit 34410b
	ev.u.feature_answer.size = size;
Packit 34410b
Packit 34410b
	if (size > 0)
Packit 34410b
		memcpy(ev.u.feature_answer.data, data, size);
Packit 34410b
Packit 34410b
	ret = bt_uhid_send(idev->uhid, &ev;;
Packit 34410b
	if (ret < 0) {
Packit 34410b
		error("bt_uhid_send: %s (%d)", strerror(-ret), -ret);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	DBG("HID report (%zu bytes)", size);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool uhid_send_input_report(struct input_device *idev,
Packit 34410b
					const uint8_t *data, size_t size)
Packit 34410b
{
Packit 34410b
	struct uhid_event ev;
Packit 34410b
	int err;
Packit 34410b
Packit 34410b
	if (data == NULL)
Packit 34410b
		size = 0;
Packit 34410b
Packit 34410b
	if (size > sizeof(ev.u.input.data))
Packit 34410b
		size = sizeof(ev.u.input.data);
Packit 34410b
Packit 34410b
	if (!idev->uhid_created) {
Packit 34410b
		DBG("HID report (%zu bytes) dropped", size);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	memset(&ev, 0, sizeof(ev));
Packit 34410b
	ev.type = UHID_INPUT;
Packit 34410b
	ev.u.input.size = size;
Packit 34410b
Packit 34410b
	if (size > 0)
Packit 34410b
		memcpy(ev.u.input.data, data, size);
Packit 34410b
Packit 34410b
	err = bt_uhid_send(idev->uhid, &ev;;
Packit 34410b
	if (err < 0) {
Packit 34410b
		error("bt_uhid_send: %s (%d)", strerror(-err), -err);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	DBG("HID report (%zu bytes)", size);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool hidp_recv_intr_data(GIOChannel *chan, struct input_device *idev)
Packit 34410b
{
Packit 34410b
	int fd;
Packit 34410b
	ssize_t len;
Packit 34410b
	uint8_t hdr;
Packit 34410b
	uint8_t data[UHID_DATA_MAX + 1];
Packit 34410b
Packit 34410b
	fd = g_io_channel_unix_get_fd(chan);
Packit 34410b
Packit 34410b
	len = read(fd, data, sizeof(data));
Packit 34410b
	if (len < 0) {
Packit 34410b
		error("BT socket read error: %s (%d)", strerror(errno), errno);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (len == 0) {
Packit 34410b
		DBG("BT socket read returned 0 bytes");
Packit 34410b
		return true;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	hdr = data[0];
Packit 34410b
	if (hdr != (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
Packit 34410b
		DBG("unsupported HIDP protocol header 0x%02x", hdr);
Packit 34410b
		return true;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (len < 2) {
Packit 34410b
		DBG("received empty HID report");
Packit 34410b
		return true;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	uhid_send_input_report(idev, data + 1, len - 1);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = data;
Packit 34410b
	char address[18];
Packit 34410b
Packit 34410b
	if (cond & G_IO_IN) {
Packit 34410b
		if (hidp_recv_intr_data(chan, idev) && (cond == G_IO_IN))
Packit 34410b
			return TRUE;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	ba2str(&idev->dst, address);
Packit 34410b
Packit 34410b
	DBG("Device %s disconnected", address);
Packit 34410b
Packit 34410b
	/* Checking for ctrl_watch avoids a double g_io_channel_shutdown since
Packit 34410b
	 * it's likely that ctrl_watch_cb has been queued for dispatching in
Packit 34410b
	 * this mainloop iteration */
Packit 34410b
	if ((cond & (G_IO_HUP | G_IO_ERR)) && idev->ctrl_watch)
Packit 34410b
		g_io_channel_shutdown(chan, TRUE, NULL);
Packit 34410b
Packit 34410b
	idev->intr_watch = 0;
Packit 34410b
Packit 34410b
	if (idev->intr_io) {
Packit 34410b
		g_io_channel_unref(idev->intr_io);
Packit 34410b
		idev->intr_io = NULL;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* Close control channel */
Packit 34410b
	if (idev->ctrl_io && !(cond & G_IO_NVAL))
Packit 34410b
		g_io_channel_shutdown(idev->ctrl_io, TRUE, NULL);
Packit 34410b
Packit 34410b
	btd_service_disconnecting_complete(idev->service, 0);
Packit 34410b
Packit 34410b
	/* Enter the auto-reconnect mode if needed */
Packit 34410b
	input_device_enter_reconnect_mode(idev);
Packit 34410b
Packit 34410b
	return FALSE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void hidp_recv_ctrl_handshake(struct input_device *idev, uint8_t param)
Packit 34410b
{
Packit 34410b
	bool pending_req_complete = false;
Packit 34410b
	uint8_t pending_req_type;
Packit 34410b
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	pending_req_type = idev->report_req_pending & HIDP_HEADER_TRANS_MASK;
Packit 34410b
Packit 34410b
	switch (param) {
Packit 34410b
	case HIDP_HSHK_SUCCESSFUL:
Packit 34410b
		if (pending_req_type == HIDP_TRANS_SET_REPORT) {
Packit 34410b
			DBG("SET_REPORT successful");
Packit 34410b
			pending_req_complete = true;
Packit 34410b
		} else
Packit 34410b
			DBG("Spurious HIDP_HSHK_SUCCESSFUL");
Packit 34410b
		break;
Packit 34410b
Packit 34410b
	case HIDP_HSHK_NOT_READY:
Packit 34410b
	case HIDP_HSHK_ERR_INVALID_REPORT_ID:
Packit 34410b
	case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
Packit 34410b
	case HIDP_HSHK_ERR_INVALID_PARAMETER:
Packit 34410b
	case HIDP_HSHK_ERR_UNKNOWN:
Packit 34410b
	case HIDP_HSHK_ERR_FATAL:
Packit 34410b
		if (pending_req_type == HIDP_TRANS_GET_REPORT) {
Packit 34410b
			DBG("GET_REPORT failed (%u)", param);
Packit 34410b
			uhid_send_feature_answer(idev, NULL, 0,
Packit 34410b
						idev->report_rsp_id, EIO);
Packit 34410b
			pending_req_complete = true;
Packit 34410b
		} else if (pending_req_type == HIDP_TRANS_SET_REPORT) {
Packit 34410b
			DBG("SET_REPORT failed (%u)", param);
Packit 34410b
			pending_req_complete = true;
Packit 34410b
		} else
Packit 34410b
			DBG("Spurious HIDP_HSHK_ERR");
Packit 34410b
Packit 34410b
		if (param == HIDP_HSHK_ERR_FATAL)
Packit 34410b
			hidp_send_ctrl_message(idev, HIDP_TRANS_HID_CONTROL |
Packit 34410b
						HIDP_CTRL_SOFT_RESET, NULL, 0);
Packit 34410b
		break;
Packit 34410b
Packit 34410b
	default:
Packit 34410b
		hidp_send_ctrl_message(idev, HIDP_TRANS_HANDSHAKE |
Packit 34410b
				HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
Packit 34410b
		break;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (pending_req_complete) {
Packit 34410b
		idev->report_req_pending = 0;
Packit 34410b
		if (idev->report_req_timer > 0) {
Packit 34410b
			g_source_remove(idev->report_req_timer);
Packit 34410b
			idev->report_req_timer = 0;
Packit 34410b
		}
Packit 34410b
		idev->report_rsp_id = 0;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static void hidp_recv_ctrl_hid_control(struct input_device *idev, uint8_t param)
Packit 34410b
{
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG)
Packit 34410b
		connection_disconnect(idev, 0);
Packit 34410b
}
Packit 34410b
Packit 34410b
static void hidp_recv_ctrl_data(struct input_device *idev, uint8_t param,
Packit 34410b
					const uint8_t *data, size_t size)
Packit 34410b
{
Packit 34410b
	uint8_t pending_req_type;
Packit 34410b
	uint8_t pending_req_param;
Packit 34410b
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	pending_req_type = idev->report_req_pending & HIDP_HEADER_TRANS_MASK;
Packit 34410b
	if (pending_req_type != HIDP_TRANS_GET_REPORT) {
Packit 34410b
		DBG("Spurious DATA on control channel");
Packit 34410b
		return;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	pending_req_param = idev->report_req_pending & HIDP_HEADER_PARAM_MASK;
Packit 34410b
	if (pending_req_param != param) {
Packit 34410b
		DBG("Received DATA RTYPE doesn't match pending request RTYPE");
Packit 34410b
		return;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	switch (param) {
Packit 34410b
	case HIDP_DATA_RTYPE_FEATURE:
Packit 34410b
	case HIDP_DATA_RTYPE_INPUT:
Packit 34410b
	case HIDP_DATA_RTYPE_OUPUT:
Packit 34410b
		uhid_send_feature_answer(idev, data + 1, size - 1,
Packit 34410b
							idev->report_rsp_id, 0);
Packit 34410b
		break;
Packit 34410b
Packit 34410b
	case HIDP_DATA_RTYPE_OTHER:
Packit 34410b
		DBG("Received DATA_RTYPE_OTHER");
Packit 34410b
		break;
Packit 34410b
Packit 34410b
	default:
Packit 34410b
		hidp_send_ctrl_message(idev, HIDP_TRANS_HANDSHAKE |
Packit 34410b
				HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
Packit 34410b
		break;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	idev->report_req_pending = 0;
Packit 34410b
	if (idev->report_req_timer > 0) {
Packit 34410b
		g_source_remove(idev->report_req_timer);
Packit 34410b
		idev->report_req_timer = 0;
Packit 34410b
	}
Packit 34410b
	idev->report_rsp_id = 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool hidp_recv_ctrl_message(GIOChannel *chan, struct input_device *idev)
Packit 34410b
{
Packit 34410b
	int fd;
Packit 34410b
	ssize_t len;
Packit 34410b
	uint8_t hdr, type, param;
Packit 34410b
	uint8_t data[UHID_DATA_MAX + 1];
Packit 34410b
Packit 34410b
	fd = g_io_channel_unix_get_fd(chan);
Packit 34410b
Packit 34410b
	len = read(fd, data, sizeof(data));
Packit 34410b
	if (len < 0) {
Packit 34410b
		error("BT socket read error: %s (%d)", strerror(errno), errno);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (len == 0) {
Packit 34410b
		DBG("BT socket read returned 0 bytes");
Packit 34410b
		return true;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	hdr = data[0];
Packit 34410b
	type = hdr & HIDP_HEADER_TRANS_MASK;
Packit 34410b
	param = hdr & HIDP_HEADER_PARAM_MASK;
Packit 34410b
Packit 34410b
	switch (type) {
Packit 34410b
	case HIDP_TRANS_HANDSHAKE:
Packit 34410b
		hidp_recv_ctrl_handshake(idev, param);
Packit 34410b
		break;
Packit 34410b
	case HIDP_TRANS_HID_CONTROL:
Packit 34410b
		hidp_recv_ctrl_hid_control(idev, param);
Packit 34410b
		break;
Packit 34410b
	case HIDP_TRANS_DATA:
Packit 34410b
		hidp_recv_ctrl_data(idev, param, data, len);
Packit 34410b
		break;
Packit 34410b
	default:
Packit 34410b
		error("unsupported HIDP control message");
Packit 34410b
		hidp_send_ctrl_message(idev, HIDP_TRANS_HANDSHAKE |
Packit 34410b
				HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
Packit 34410b
		break;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = data;
Packit 34410b
	char address[18];
Packit 34410b
Packit 34410b
	if (cond & G_IO_IN) {
Packit 34410b
		if (hidp_recv_ctrl_message(chan, idev) && (cond == G_IO_IN))
Packit 34410b
			return TRUE;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	ba2str(&idev->dst, address);
Packit 34410b
Packit 34410b
	DBG("Device %s disconnected", address);
Packit 34410b
Packit 34410b
	/* Checking for intr_watch avoids a double g_io_channel_shutdown since
Packit 34410b
	 * it's likely that intr_watch_cb has been queued for dispatching in
Packit 34410b
	 * this mainloop iteration */
Packit 34410b
	if ((cond & (G_IO_HUP | G_IO_ERR)) && idev->intr_watch)
Packit 34410b
		g_io_channel_shutdown(chan, TRUE, NULL);
Packit 34410b
Packit 34410b
	idev->ctrl_watch = 0;
Packit 34410b
Packit 34410b
	if (idev->ctrl_io) {
Packit 34410b
		g_io_channel_unref(idev->ctrl_io);
Packit 34410b
		idev->ctrl_io = NULL;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* Close interrupt channel */
Packit 34410b
	if (idev->intr_io && !(cond & G_IO_NVAL))
Packit 34410b
		g_io_channel_shutdown(idev->intr_io, TRUE, NULL);
Packit 34410b
Packit 34410b
	return FALSE;
Packit 34410b
}
Packit 34410b
Packit 34410b
#define REPORT_REQ_TIMEOUT  3
Packit 34410b
Packit 34410b
static gboolean hidp_report_req_timeout(gpointer data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = data;
Packit 34410b
	uint8_t pending_req_type;
Packit 34410b
	const char *req_type_str;
Packit 34410b
	char address[18];
Packit 34410b
Packit 34410b
	ba2str(&idev->dst, address);
Packit 34410b
	pending_req_type = idev->report_req_pending & HIDP_HEADER_TRANS_MASK;
Packit 34410b
Packit 34410b
	switch (pending_req_type) {
Packit 34410b
	case HIDP_TRANS_GET_REPORT:
Packit 34410b
		req_type_str = "GET_REPORT";
Packit 34410b
		break;
Packit 34410b
	case HIDP_TRANS_SET_REPORT:
Packit 34410b
		req_type_str = "SET_REPORT";
Packit 34410b
		break;
Packit 34410b
	default:
Packit 34410b
		/* Should never happen */
Packit 34410b
		req_type_str = "OTHER_TRANS";
Packit 34410b
		break;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	DBG("Device %s HIDP %s request timed out", address, req_type_str);
Packit 34410b
Packit 34410b
	idev->report_req_pending = 0;
Packit 34410b
	idev->report_req_timer = 0;
Packit 34410b
	idev->report_rsp_id = 0;
Packit 34410b
Packit 34410b
	return FALSE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void hidp_send_set_report(struct uhid_event *ev, void *user_data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = user_data;
Packit 34410b
	uint8_t hdr;
Packit 34410b
	bool sent;
Packit 34410b
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	switch (ev->u.output.rtype) {
Packit 34410b
	case UHID_FEATURE_REPORT:
Packit 34410b
		/* Send SET_REPORT on control channel */
Packit 34410b
		if (idev->report_req_pending) {
Packit 34410b
			DBG("Old GET_REPORT or SET_REPORT still pending");
Packit 34410b
			return;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		hdr = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
Packit 34410b
		sent = hidp_send_ctrl_message(idev, hdr, ev->u.output.data,
Packit 34410b
							ev->u.output.size);
Packit 34410b
		if (sent) {
Packit 34410b
			idev->report_req_pending = hdr;
Packit 34410b
			idev->report_req_timer =
Packit 34410b
				g_timeout_add_seconds(REPORT_REQ_TIMEOUT,
Packit 34410b
						hidp_report_req_timeout, idev);
Packit 34410b
		}
Packit 34410b
		break;
Packit 34410b
	case UHID_OUTPUT_REPORT:
Packit 34410b
		/* Send DATA on interrupt channel */
Packit 34410b
		hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
Packit 34410b
		hidp_send_intr_message(idev, hdr, ev->u.output.data,
Packit 34410b
							ev->u.output.size);
Packit 34410b
		break;
Packit 34410b
	default:
Packit 34410b
		DBG("Unsupported HID report type %u", ev->u.output.rtype);
Packit 34410b
		return;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static void hidp_send_get_report(struct uhid_event *ev, void *user_data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = user_data;
Packit 34410b
	uint8_t hdr;
Packit 34410b
	bool sent;
Packit 34410b
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	if (idev->report_req_pending) {
Packit 34410b
		DBG("Old GET_REPORT or SET_REPORT still pending");
Packit 34410b
		uhid_send_feature_answer(idev, NULL, 0, ev->u.feature.id,
Packit 34410b
									EBUSY);
Packit 34410b
		return;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* Send GET_REPORT on control channel */
Packit 34410b
	switch (ev->u.feature.rtype) {
Packit 34410b
	case UHID_FEATURE_REPORT:
Packit 34410b
		hdr = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
Packit 34410b
		break;
Packit 34410b
	case UHID_INPUT_REPORT:
Packit 34410b
		hdr = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT;
Packit 34410b
		break;
Packit 34410b
	case UHID_OUTPUT_REPORT:
Packit 34410b
		hdr = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Packit 34410b
		break;
Packit 34410b
	default:
Packit 34410b
		DBG("Unsupported HID report type %u", ev->u.feature.rtype);
Packit 34410b
		return;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	sent = hidp_send_ctrl_message(idev, hdr, &ev->u.feature.rnum,
Packit 34410b
						sizeof(ev->u.feature.rnum));
Packit 34410b
	if (sent) {
Packit 34410b
		idev->report_req_pending = hdr;
Packit 34410b
		idev->report_req_timer =
Packit 34410b
			g_timeout_add_seconds(REPORT_REQ_TIMEOUT,
Packit 34410b
						hidp_report_req_timeout, idev);
Packit 34410b
		idev->report_rsp_id = ev->u.feature.id;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static void epox_endian_quirk(unsigned char *data, int size)
Packit 34410b
{
Packit 34410b
	/* USAGE_PAGE (Keyboard)	05 07
Packit 34410b
	 * USAGE_MINIMUM (0)		19 00
Packit 34410b
	 * USAGE_MAXIMUM (65280)	2A 00 FF   <= must be FF 00
Packit 34410b
	 * LOGICAL_MINIMUM (0)		15 00
Packit 34410b
	 * LOGICAL_MAXIMUM (65280)	26 00 FF   <= must be FF 00
Packit 34410b
	 */
Packit 34410b
	unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff,
Packit 34410b
						0x15, 0x00, 0x26, 0x00, 0xff };
Packit 34410b
	unsigned int i;
Packit 34410b
Packit 34410b
	if (!data)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	for (i = 0; i < size - sizeof(pattern); i++) {
Packit 34410b
		if (!memcmp(data + i, pattern, sizeof(pattern))) {
Packit 34410b
			data[i + 5] = 0xff;
Packit 34410b
			data[i + 6] = 0x00;
Packit 34410b
			data[i + 10] = 0xff;
Packit 34410b
			data[i + 11] = 0x00;
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static int create_hid_dev_name(sdp_record_t *rec, struct hidp_connadd_req *req)
Packit 34410b
{
Packit 34410b
	char sdesc[sizeof(req->name) / 2];
Packit 34410b
Packit 34410b
	if (sdp_get_service_desc(rec, sdesc, sizeof(sdesc)) == 0) {
Packit 34410b
		char pname[sizeof(req->name) / 2];
Packit 34410b
Packit 34410b
		if (sdp_get_provider_name(rec, pname, sizeof(pname)) == 0 &&
Packit 34410b
						strncmp(sdesc, pname, 5) != 0)
Packit 34410b
			snprintf(req->name, sizeof(req->name), "%s %s",
Packit 34410b
								pname, sdesc);
Packit 34410b
		else
Packit 34410b
			snprintf(req->name, sizeof(req->name), "%s", sdesc);
Packit 34410b
	} else {
Packit 34410b
		return sdp_get_service_name(rec, req->name, sizeof(req->name));
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
/* See HID profile specification v1.0, "7.11.6 HIDDescriptorList" for details
Packit 34410b
 * on the attribute format. */
Packit 34410b
static int extract_hid_desc_data(sdp_record_t *rec,
Packit 34410b
						struct hidp_connadd_req *req)
Packit 34410b
{
Packit 34410b
	sdp_data_t *d;
Packit 34410b
Packit 34410b
	d = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);
Packit 34410b
	if (!d)
Packit 34410b
		goto invalid_desc;
Packit 34410b
Packit 34410b
	if (!SDP_IS_SEQ(d->dtd))
Packit 34410b
		goto invalid_desc;
Packit 34410b
Packit 34410b
	/* First HIDDescriptor */
Packit 34410b
	d = d->val.dataseq;
Packit 34410b
	if (!SDP_IS_SEQ(d->dtd))
Packit 34410b
		goto invalid_desc;
Packit 34410b
Packit 34410b
	/* ClassDescriptorType */
Packit 34410b
	d = d->val.dataseq;
Packit 34410b
	if (d->dtd != SDP_UINT8)
Packit 34410b
		goto invalid_desc;
Packit 34410b
Packit 34410b
	/* ClassDescriptorData */
Packit 34410b
	d = d->next;
Packit 34410b
	if (!d || !SDP_IS_TEXT_STR(d->dtd))
Packit 34410b
		goto invalid_desc;
Packit 34410b
Packit 34410b
	req->rd_data = g_try_malloc0(d->unitSize);
Packit 34410b
	if (req->rd_data) {
Packit 34410b
		memcpy(req->rd_data, d->val.str, d->unitSize);
Packit 34410b
		req->rd_size = d->unitSize;
Packit 34410b
		epox_endian_quirk(req->rd_data, req->rd_size);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
Packit 34410b
invalid_desc:
Packit 34410b
	error("Missing or invalid HIDDescriptorList SDP attribute");
Packit 34410b
	return -EINVAL;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
Packit 34410b
{
Packit 34410b
	sdp_data_t *pdlist;
Packit 34410b
	uint8_t attr_val;
Packit 34410b
	int err;
Packit 34410b
Packit 34410b
	err = create_hid_dev_name(rec, req);
Packit 34410b
	if (err < 0)
Packit 34410b
		DBG("No valid Service Name or Service Description found");
Packit 34410b
Packit 34410b
	pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);
Packit 34410b
	req->parser = pdlist ? pdlist->val.uint16 : 0x0100;
Packit 34410b
Packit 34410b
	pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
Packit 34410b
	req->subclass = pdlist ? pdlist->val.uint8 : 0;
Packit 34410b
Packit 34410b
	pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
Packit 34410b
	req->country = pdlist ? pdlist->val.uint8 : 0;
Packit 34410b
Packit 34410b
	pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);
Packit 34410b
	attr_val = pdlist ? pdlist->val.uint8 : 0;
Packit 34410b
	if (attr_val)
Packit 34410b
		req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);
Packit 34410b
Packit 34410b
	pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
Packit 34410b
	attr_val = pdlist ? pdlist->val.uint8 : 0;
Packit 34410b
	if (attr_val)
Packit 34410b
		req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
Packit 34410b
Packit 34410b
	err = extract_hid_desc_data(rec, req);
Packit 34410b
	if (err < 0)
Packit 34410b
		return err;
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int ioctl_connadd(struct hidp_connadd_req *req)
Packit 34410b
{
Packit 34410b
	int ctl, err = 0;
Packit 34410b
Packit 34410b
	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
Packit 34410b
	if (ctl < 0)
Packit 34410b
		return -errno;
Packit 34410b
Packit 34410b
	if (ioctl(ctl, HIDPCONNADD, req) < 0)
Packit 34410b
		err = -errno;
Packit 34410b
Packit 34410b
	close(ctl);
Packit 34410b
Packit 34410b
	return err;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool ioctl_is_connected(struct input_device *idev)
Packit 34410b
{
Packit 34410b
	struct hidp_conninfo ci;
Packit 34410b
	int ctl;
Packit 34410b
Packit 34410b
	/* Standard HID */
Packit 34410b
	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
Packit 34410b
	if (ctl < 0) {
Packit 34410b
		error("Can't open HIDP control socket");
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	memset(&ci, 0, sizeof(ci));
Packit 34410b
	bacpy(&ci.bdaddr, &idev->dst);
Packit 34410b
	if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) {
Packit 34410b
		error("Can't get HIDP connection info");
Packit 34410b
		close(ctl);
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	close(ctl);
Packit 34410b
Packit 34410b
	if (ci.state != BT_CONNECTED)
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int ioctl_disconnect(struct input_device *idev, uint32_t flags)
Packit 34410b
{
Packit 34410b
	struct hidp_conndel_req req;
Packit 34410b
	struct hidp_conninfo ci;
Packit 34410b
	int ctl, err = 0;
Packit 34410b
Packit 34410b
	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
Packit 34410b
	if (ctl < 0) {
Packit 34410b
		error("Can't open HIDP control socket");
Packit 34410b
		return -errno;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	memset(&ci, 0, sizeof(ci));
Packit 34410b
	bacpy(&ci.bdaddr, &idev->dst);
Packit 34410b
	if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) ||
Packit 34410b
						(ci.state != BT_CONNECTED)) {
Packit 34410b
		close(ctl);
Packit 34410b
		return -ENOTCONN;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	memset(&req, 0, sizeof(req));
Packit 34410b
	bacpy(&req.bdaddr, &idev->dst);
Packit 34410b
	req.flags = flags;
Packit 34410b
	if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
Packit 34410b
		err = -errno;
Packit 34410b
		error("Can't delete the HID device: %s (%d)",
Packit 34410b
							strerror(-err), -err);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	close(ctl);
Packit 34410b
Packit 34410b
	return err;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int uhid_connadd(struct input_device *idev, struct hidp_connadd_req *req)
Packit 34410b
{
Packit 34410b
	int err;
Packit 34410b
	struct uhid_event ev;
Packit 34410b
Packit 34410b
	if (idev->uhid_created)
Packit 34410b
		return 0;
Packit 34410b
Packit 34410b
	/* create uHID device */
Packit 34410b
	memset(&ev, 0, sizeof(ev));
Packit 34410b
	ev.type = UHID_CREATE;
Packit 34410b
	strncpy((char *) ev.u.create.name, req->name, sizeof(ev.u.create.name));
Packit 34410b
	ba2str(&idev->src, (char *) ev.u.create.phys);
Packit 34410b
	ba2str(&idev->dst, (char *) ev.u.create.uniq);
Packit 34410b
	ev.u.create.vendor = req->vendor;
Packit 34410b
	ev.u.create.product = req->product;
Packit 34410b
	ev.u.create.version = req->version;
Packit 34410b
	ev.u.create.country = req->country;
Packit 34410b
	ev.u.create.bus = BUS_BLUETOOTH;
Packit 34410b
	ev.u.create.rd_data = req->rd_data;
Packit 34410b
	ev.u.create.rd_size = req->rd_size;
Packit 34410b
Packit 34410b
	err = bt_uhid_send(idev->uhid, &ev;;
Packit 34410b
	if (err < 0) {
Packit 34410b
		error("bt_uhid_send: %s", strerror(-err));
Packit 34410b
		return err;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	bt_uhid_register(idev->uhid, UHID_OUTPUT, hidp_send_set_report, idev);
Packit 34410b
	bt_uhid_register(idev->uhid, UHID_FEATURE, hidp_send_get_report, idev);
Packit 34410b
Packit 34410b
	idev->uhid_created = true;
Packit 34410b
Packit 34410b
	return err;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean encrypt_notify(GIOChannel *io, GIOCondition condition,
Packit 34410b
								gpointer data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = data;
Packit 34410b
	int err;
Packit 34410b
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	if (idev->uhid)
Packit 34410b
		err = uhid_connadd(idev, idev->req);
Packit 34410b
	else
Packit 34410b
		err = ioctl_connadd(idev->req);
Packit 34410b
Packit 34410b
	if (err < 0) {
Packit 34410b
		error("ioctl_connadd(): %s (%d)", strerror(-err), -err);
Packit 34410b
Packit 34410b
		if (idev->ctrl_io) {
Packit 34410b
			g_io_channel_shutdown(idev->ctrl_io, FALSE, NULL);
Packit 34410b
			g_io_channel_unref(idev->ctrl_io);
Packit 34410b
			idev->ctrl_io = NULL;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		if (idev->intr_io) {
Packit 34410b
			g_io_channel_shutdown(idev->intr_io, FALSE, NULL);
Packit 34410b
			g_io_channel_unref(idev->intr_io);
Packit 34410b
			idev->intr_io = NULL;
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	idev->sec_watch = 0;
Packit 34410b
Packit 34410b
	g_free(idev->req->rd_data);
Packit 34410b
	g_free(idev->req);
Packit 34410b
	idev->req = NULL;
Packit 34410b
Packit 34410b
	return FALSE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int hidp_add_connection(struct input_device *idev)
Packit 34410b
{
Packit 34410b
	struct hidp_connadd_req *req;
Packit 34410b
	sdp_record_t *rec;
Packit 34410b
	char src_addr[18], dst_addr[18];
Packit 34410b
	char filename[PATH_MAX];
Packit 34410b
	GKeyFile *key_file;
Packit 34410b
	char handle[11], *str;
Packit 34410b
	GError *gerr = NULL;
Packit 34410b
	int err;
Packit 34410b
Packit 34410b
	req = g_new0(struct hidp_connadd_req, 1);
Packit 34410b
	req->ctrl_sock = g_io_channel_unix_get_fd(idev->ctrl_io);
Packit 34410b
	req->intr_sock = g_io_channel_unix_get_fd(idev->intr_io);
Packit 34410b
	req->flags     = 0;
Packit 34410b
	req->idle_to   = idle_timeout;
Packit 34410b
Packit 34410b
	ba2str(&idev->src, src_addr);
Packit 34410b
	ba2str(&idev->dst, dst_addr);
Packit 34410b
Packit 34410b
	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", src_addr,
Packit 34410b
								dst_addr);
Packit 34410b
	sprintf(handle, "0x%8.8X", idev->handle);
Packit 34410b
Packit 34410b
	key_file = g_key_file_new();
Packit 34410b
	g_key_file_load_from_file(key_file, filename, 0, NULL);
Packit 34410b
	str = g_key_file_get_string(key_file, "ServiceRecords", handle, NULL);
Packit 34410b
	g_key_file_free(key_file);
Packit 34410b
Packit 34410b
	if (!str) {
Packit 34410b
		error("Rejected connection from unknown device %s", dst_addr);
Packit 34410b
		err = -EPERM;
Packit 34410b
		goto cleanup;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	rec = record_from_string(str);
Packit 34410b
	g_free(str);
Packit 34410b
Packit 34410b
	err = extract_hid_record(rec, req);
Packit 34410b
	sdp_record_free(rec);
Packit 34410b
	if (err < 0) {
Packit 34410b
		error("Could not parse HID SDP record: %s (%d)", strerror(-err),
Packit 34410b
									-err);
Packit 34410b
		goto cleanup;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	req->vendor = btd_device_get_vendor(idev->device);
Packit 34410b
	req->product = btd_device_get_product(idev->device);
Packit 34410b
	req->version = btd_device_get_version(idev->device);
Packit 34410b
Packit 34410b
	if (device_name_known(idev->device))
Packit 34410b
		device_get_name(idev->device, req->name, sizeof(req->name));
Packit 34410b
rpm-build 95ab10
	/* Make sure the device is bonded if required */
rpm-build 95ab10
	if (classic_bonded_only && !device_is_bonded(idev->device,
rpm-build 95ab10
				btd_device_get_bdaddr_type(idev->device))) {
rpm-build 95ab10
		error("Rejected connection from !bonded device %s", dst_addr);
rpm-build 95ab10
		goto cleanup;
rpm-build 95ab10
	}
rpm-build 95ab10
Packit 34410b
	/* Encryption is mandatory for keyboards */
rpm-build 95ab10
	/* Some platforms may choose to require encryption for all devices */
rpm-build 95ab10
	/* Note that this only matters for pre 2.1 devices as otherwise the */
rpm-build 95ab10
	/* device is encrypted by default by the lower layers */
rpm-build 95ab10
	if (classic_bonded_only || req->subclass & 0x40) {
Packit 34410b
		if (!bt_io_set(idev->intr_io, &gerr,
Packit 34410b
					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
Packit 34410b
					BT_IO_OPT_INVALID)) {
Packit 34410b
			error("btio: %s", gerr->message);
Packit 34410b
			g_error_free(gerr);
Packit 34410b
			err = -EFAULT;
Packit 34410b
			goto cleanup;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		idev->req = req;
Packit 34410b
		idev->sec_watch = g_io_add_watch(idev->intr_io, G_IO_OUT,
Packit 34410b
							encrypt_notify, idev);
Packit 34410b
Packit 34410b
		return 0;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (idev->uhid)
Packit 34410b
		err = uhid_connadd(idev, req);
Packit 34410b
	else
Packit 34410b
		err = ioctl_connadd(req);
Packit 34410b
Packit 34410b
cleanup:
Packit 34410b
	g_free(req->rd_data);
Packit 34410b
	g_free(req);
Packit 34410b
Packit 34410b
	return err;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool is_connected(struct input_device *idev)
Packit 34410b
{
Packit 34410b
	if (idev->uhid)
Packit 34410b
		return (idev->intr_io != NULL && idev->ctrl_io != NULL);
Packit 34410b
	else
Packit 34410b
		return ioctl_is_connected(idev);
Packit 34410b
}
Packit 34410b
Packit 34410b
static int connection_disconnect(struct input_device *idev, uint32_t flags)
Packit 34410b
{
Packit 34410b
	if (!is_connected(idev))
Packit 34410b
		return -ENOTCONN;
Packit 34410b
Packit 34410b
	/* Standard HID disconnect */
Packit 34410b
	if (idev->intr_io)
Packit 34410b
		g_io_channel_shutdown(idev->intr_io, TRUE, NULL);
Packit 34410b
	if (idev->ctrl_io)
Packit 34410b
		g_io_channel_shutdown(idev->ctrl_io, TRUE, NULL);
Packit 34410b
Packit 34410b
	if (idev->uhid)
Packit 34410b
		return 0;
Packit 34410b
	else
Packit 34410b
		return ioctl_disconnect(idev, flags);
Packit 34410b
}
Packit 34410b
Packit 34410b
static int input_device_connected(struct input_device *idev)
Packit 34410b
{
Packit 34410b
	int err;
Packit 34410b
Packit 34410b
	if (idev->intr_io == NULL || idev->ctrl_io == NULL)
Packit 34410b
		return -ENOTCONN;
Packit 34410b
Packit 34410b
	err = hidp_add_connection(idev);
Packit 34410b
	if (err < 0)
Packit 34410b
		return err;
Packit 34410b
Packit 34410b
	btd_service_connecting_complete(idev->service, 0);
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void interrupt_connect_cb(GIOChannel *chan, GError *conn_err,
Packit 34410b
							gpointer user_data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = user_data;
Packit 34410b
	GIOCondition cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
Packit 34410b
	int err;
Packit 34410b
Packit 34410b
	if (conn_err) {
Packit 34410b
		err = -EIO;
Packit 34410b
		goto failed;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	err = input_device_connected(idev);
Packit 34410b
	if (err < 0)
Packit 34410b
		goto failed;
Packit 34410b
Packit 34410b
	if (idev->uhid)
Packit 34410b
		cond |= G_IO_IN;
Packit 34410b
Packit 34410b
	idev->intr_watch = g_io_add_watch(idev->intr_io, cond, intr_watch_cb,
Packit 34410b
									idev);
Packit 34410b
Packit 34410b
	return;
Packit 34410b
Packit 34410b
failed:
Packit 34410b
	btd_service_connecting_complete(idev->service, err);
Packit 34410b
Packit 34410b
	/* So we guarantee the interrupt channel is closed before the
Packit 34410b
	 * control channel (if we only do unref GLib will close it only
Packit 34410b
	 * after returning control to the mainloop */
Packit 34410b
	if (!conn_err)
Packit 34410b
		g_io_channel_shutdown(idev->intr_io, FALSE, NULL);
Packit 34410b
Packit 34410b
	g_io_channel_unref(idev->intr_io);
Packit 34410b
	idev->intr_io = NULL;
Packit 34410b
Packit 34410b
	if (idev->ctrl_io) {
Packit 34410b
		g_io_channel_unref(idev->ctrl_io);
Packit 34410b
		idev->ctrl_io = NULL;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static void control_connect_cb(GIOChannel *chan, GError *conn_err,
Packit 34410b
							gpointer user_data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = user_data;
Packit 34410b
	GIOCondition cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
Packit 34410b
	GIOChannel *io;
Packit 34410b
	GError *err = NULL;
Packit 34410b
Packit 34410b
	if (conn_err) {
Packit 34410b
		error("%s", conn_err->message);
Packit 34410b
		goto failed;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* Connect to the HID interrupt channel */
Packit 34410b
	io = bt_io_connect(interrupt_connect_cb, idev,
Packit 34410b
				NULL, &err,
Packit 34410b
				BT_IO_OPT_SOURCE_BDADDR, &idev->src,
Packit 34410b
				BT_IO_OPT_DEST_BDADDR, &idev->dst,
Packit 34410b
				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
Packit 34410b
				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
Packit 34410b
				BT_IO_OPT_INVALID);
Packit 34410b
	if (!io) {
Packit 34410b
		error("%s", err->message);
Packit 34410b
		g_error_free(err);
Packit 34410b
		goto failed;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	idev->intr_io = io;
Packit 34410b
Packit 34410b
	if (idev->uhid)
Packit 34410b
		cond |= G_IO_IN;
Packit 34410b
Packit 34410b
	idev->ctrl_watch = g_io_add_watch(idev->ctrl_io, cond, ctrl_watch_cb,
Packit 34410b
									idev);
Packit 34410b
Packit 34410b
	return;
Packit 34410b
Packit 34410b
failed:
Packit 34410b
	btd_service_connecting_complete(idev->service, -EIO);
Packit 34410b
	g_io_channel_unref(idev->ctrl_io);
Packit 34410b
	idev->ctrl_io = NULL;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int dev_connect(struct input_device *idev)
Packit 34410b
{
Packit 34410b
	GError *err = NULL;
Packit 34410b
	GIOChannel *io;
Packit 34410b
Packit 34410b
	if (idev->disable_sdp)
Packit 34410b
		bt_clear_cached_session(&idev->src, &idev->dst);
Packit 34410b
Packit 34410b
	io = bt_io_connect(control_connect_cb, idev,
Packit 34410b
				NULL, &err,
Packit 34410b
				BT_IO_OPT_SOURCE_BDADDR, &idev->src,
Packit 34410b
				BT_IO_OPT_DEST_BDADDR, &idev->dst,
Packit 34410b
				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
Packit 34410b
				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
Packit 34410b
				BT_IO_OPT_INVALID);
Packit 34410b
	idev->ctrl_io = io;
Packit 34410b
Packit 34410b
	if (err == NULL)
Packit 34410b
		return 0;
Packit 34410b
Packit 34410b
	error("%s", err->message);
Packit 34410b
	g_error_free(err);
Packit 34410b
Packit 34410b
	return -EIO;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean input_device_auto_reconnect(gpointer user_data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = user_data;
Packit 34410b
Packit 34410b
	DBG("path=%s, attempt=%d", idev->path, idev->reconnect_attempt);
Packit 34410b
Packit 34410b
	/* Stop the recurrent reconnection attempts if the device is
Packit 34410b
	 * reconnected or is marked for removal.
Packit 34410b
	 */
Packit 34410b
	if (device_is_temporary(idev->device) ||
Packit 34410b
					btd_device_is_connected(idev->device))
Packit 34410b
		goto bail;
Packit 34410b
Packit 34410b
	/* Only attempt an auto-reconnect for at most 3 minutes (6 * 30s). */
Packit 34410b
	if (idev->reconnect_attempt >= 6)
Packit 34410b
		goto bail;
Packit 34410b
Packit 34410b
	/* Check if the profile is already connected. */
Packit 34410b
	if (idev->ctrl_io)
Packit 34410b
		goto bail;
Packit 34410b
Packit 34410b
	if (is_connected(idev))
Packit 34410b
		goto bail;
Packit 34410b
Packit 34410b
	idev->reconnect_attempt++;
Packit 34410b
	dev_connect(idev);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
Packit 34410b
bail:
Packit 34410b
	idev->reconnect_timer = 0;
Packit 34410b
	return FALSE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static const char * const _reconnect_mode_str[] = {
Packit 34410b
	"none",
Packit 34410b
	"device",
Packit 34410b
	"host",
Packit 34410b
	"any"
Packit 34410b
};
Packit 34410b
Packit 34410b
static const char *reconnect_mode_to_string(const enum reconnect_mode_t mode)
Packit 34410b
{
Packit 34410b
	return _reconnect_mode_str[mode];
Packit 34410b
}
Packit 34410b
Packit 34410b
static void input_device_enter_reconnect_mode(struct input_device *idev)
Packit 34410b
{
Packit 34410b
	DBG("path=%s reconnect_mode=%s", idev->path,
Packit 34410b
				reconnect_mode_to_string(idev->reconnect_mode));
Packit 34410b
rpm-build 95ab10
	/* Make sure the device is bonded if required */
rpm-build 95ab10
	if (classic_bonded_only && !device_is_bonded(idev->device,
rpm-build 95ab10
				btd_device_get_bdaddr_type(idev->device)))
rpm-build 95ab10
		return;
rpm-build 95ab10
Packit 34410b
	/* Only attempt an auto-reconnect when the device is required to
Packit 34410b
	 * accept reconnections from the host.
Packit 34410b
	 */
Packit 34410b
	if (idev->reconnect_mode != RECONNECT_ANY &&
Packit 34410b
				idev->reconnect_mode != RECONNECT_HOST)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	/* If the device is temporary we are not required to reconnect
Packit 34410b
	 * with the device. This is likely the case of a removing device.
Packit 34410b
	 */
Packit 34410b
	if (device_is_temporary(idev->device) ||
Packit 34410b
					btd_device_is_connected(idev->device))
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	if (idev->reconnect_timer > 0)
Packit 34410b
		g_source_remove(idev->reconnect_timer);
Packit 34410b
Packit 34410b
	DBG("registering auto-reconnect");
Packit 34410b
	idev->reconnect_attempt = 0;
Packit 34410b
	idev->reconnect_timer = g_timeout_add_seconds(30,
Packit 34410b
					input_device_auto_reconnect, idev);
Packit 34410b
Packit 34410b
}
Packit 34410b
Packit 34410b
int input_device_connect(struct btd_service *service)
Packit 34410b
{
Packit 34410b
	struct input_device *idev;
Packit 34410b
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	idev = btd_service_get_user_data(service);
Packit 34410b
Packit 34410b
	if (idev->ctrl_io)
Packit 34410b
		return -EBUSY;
Packit 34410b
Packit 34410b
	if (is_connected(idev))
Packit 34410b
		return -EALREADY;
Packit 34410b
Packit 34410b
	return dev_connect(idev);
Packit 34410b
}
Packit 34410b
Packit 34410b
int input_device_disconnect(struct btd_service *service)
Packit 34410b
{
Packit 34410b
	struct input_device *idev;
Packit 34410b
	int err, flags;
Packit 34410b
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	idev = btd_service_get_user_data(service);
Packit 34410b
Packit 34410b
	flags = device_is_temporary(idev->device) ?
Packit 34410b
					(1 << HIDP_VIRTUAL_CABLE_UNPLUG) : 0;
Packit 34410b
Packit 34410b
	err = connection_disconnect(idev, flags);
Packit 34410b
	if (err < 0)
Packit 34410b
		return err;
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool is_device_sdp_disable(const sdp_record_t *rec)
Packit 34410b
{
Packit 34410b
	sdp_data_t *data;
Packit 34410b
Packit 34410b
	data = sdp_data_get(rec, SDP_ATTR_HID_SDP_DISABLE);
Packit 34410b
Packit 34410b
	return data && data->val.uint8;
Packit 34410b
}
Packit 34410b
Packit 34410b
static enum reconnect_mode_t hid_reconnection_mode(bool reconnect_initiate,
Packit 34410b
						bool normally_connectable)
Packit 34410b
{
Packit 34410b
	if (!reconnect_initiate && !normally_connectable)
Packit 34410b
		return RECONNECT_NONE;
Packit 34410b
	else if (!reconnect_initiate && normally_connectable)
Packit 34410b
		return RECONNECT_HOST;
Packit 34410b
	else if (reconnect_initiate && !normally_connectable)
Packit 34410b
		return RECONNECT_DEVICE;
Packit 34410b
	else /* (reconnect_initiate && normally_connectable) */
Packit 34410b
		return RECONNECT_ANY;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void extract_hid_props(struct input_device *idev,
Packit 34410b
					const sdp_record_t *rec)
Packit 34410b
{
Packit 34410b
	/* Extract HID connectability */
Packit 34410b
	bool reconnect_initiate, normally_connectable;
Packit 34410b
	sdp_data_t *pdlist;
Packit 34410b
Packit 34410b
	/* HIDNormallyConnectable is optional and assumed FALSE
Packit 34410b
	* if not present. */
Packit 34410b
	pdlist = sdp_data_get(rec, SDP_ATTR_HID_RECONNECT_INITIATE);
Packit 34410b
	reconnect_initiate = pdlist ? pdlist->val.uint8 : TRUE;
Packit 34410b
Packit 34410b
	pdlist = sdp_data_get(rec, SDP_ATTR_HID_NORMALLY_CONNECTABLE);
Packit 34410b
	normally_connectable = pdlist ? pdlist->val.uint8 : FALSE;
Packit 34410b
Packit 34410b
	/* Update local values */
Packit 34410b
	idev->reconnect_mode =
Packit 34410b
		hid_reconnection_mode(reconnect_initiate, normally_connectable);
Packit 34410b
}
Packit 34410b
Packit 34410b
static struct input_device *input_device_new(struct btd_service *service)
Packit 34410b
{
Packit 34410b
	struct btd_device *device = btd_service_get_device(service);
Packit 34410b
	struct btd_profile *p = btd_service_get_profile(service);
Packit 34410b
	const char *path = device_get_path(device);
Packit 34410b
	const sdp_record_t *rec = btd_device_get_record(device, p->remote_uuid);
Packit 34410b
	struct btd_adapter *adapter = device_get_adapter(device);
Packit 34410b
	struct input_device *idev;
Packit 34410b
Packit 34410b
	if (!rec)
Packit 34410b
		return NULL;
Packit 34410b
Packit 34410b
	idev = g_new0(struct input_device, 1);
Packit 34410b
	bacpy(&idev->src, btd_adapter_get_address(adapter));
Packit 34410b
	bacpy(&idev->dst, device_get_address(device));
Packit 34410b
	idev->service = btd_service_ref(service);
Packit 34410b
	idev->device = btd_device_ref(device);
Packit 34410b
	idev->path = g_strdup(path);
Packit 34410b
	idev->handle = rec->handle;
Packit 34410b
	idev->disable_sdp = is_device_sdp_disable(rec);
Packit 34410b
Packit 34410b
	/* Initialize device properties */
Packit 34410b
	extract_hid_props(idev, rec);
Packit 34410b
Packit 34410b
	return idev;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean property_get_reconnect_mode(
Packit 34410b
					const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = data;
Packit 34410b
	const char *str_mode = reconnect_mode_to_string(idev->reconnect_mode);
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str_mode);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static const GDBusPropertyTable input_properties[] = {
Packit 34410b
	{ "ReconnectMode", "s", property_get_reconnect_mode },
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
int input_device_register(struct btd_service *service)
Packit 34410b
{
Packit 34410b
	struct btd_device *device = btd_service_get_device(service);
Packit 34410b
	const char *path = device_get_path(device);
Packit 34410b
	struct input_device *idev;
Packit 34410b
Packit 34410b
	DBG("%s", path);
Packit 34410b
Packit 34410b
	idev = input_device_new(service);
Packit 34410b
	if (!idev)
Packit 34410b
		return -EINVAL;
Packit 34410b
Packit 34410b
	if (uhid_enabled) {
Packit 34410b
		idev->uhid = bt_uhid_new_default();
Packit 34410b
		if (!idev->uhid) {
Packit 34410b
			error("bt_uhid_new_default: failed");
Packit 34410b
			input_device_free(idev);
Packit 34410b
			return -EIO;
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (g_dbus_register_interface(btd_get_dbus_connection(),
Packit 34410b
					idev->path, INPUT_INTERFACE,
Packit 34410b
					NULL, NULL,
Packit 34410b
					input_properties, idev,
Packit 34410b
					NULL) == FALSE) {
Packit 34410b
		error("Unable to register %s interface", INPUT_INTERFACE);
Packit 34410b
		input_device_free(idev);
Packit 34410b
		return -EINVAL;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	btd_service_set_user_data(service, idev);
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static struct input_device *find_device(const bdaddr_t *src,
Packit 34410b
					const bdaddr_t *dst)
Packit 34410b
{
Packit 34410b
	struct btd_device *device;
Packit 34410b
	struct btd_service *service;
Packit 34410b
Packit 34410b
	device = btd_adapter_find_device(adapter_find(src), dst, BDADDR_BREDR);
Packit 34410b
	if (device == NULL)
Packit 34410b
		return NULL;
Packit 34410b
Packit 34410b
	service = btd_device_get_service(device, HID_UUID);
Packit 34410b
	if (service == NULL)
Packit 34410b
		return NULL;
Packit 34410b
Packit 34410b
	return btd_service_get_user_data(service);
Packit 34410b
}
Packit 34410b
Packit 34410b
void input_device_unregister(struct btd_service *service)
Packit 34410b
{
Packit 34410b
	struct btd_device *device = btd_service_get_device(service);
Packit 34410b
	const char *path = device_get_path(device);
Packit 34410b
	struct input_device *idev = btd_service_get_user_data(service);
Packit 34410b
Packit 34410b
	DBG("%s", path);
Packit 34410b
Packit 34410b
	g_dbus_unregister_interface(btd_get_dbus_connection(),
Packit 34410b
						idev->path, INPUT_INTERFACE);
Packit 34410b
Packit 34410b
	input_device_free(idev);
Packit 34410b
}
Packit 34410b
Packit 34410b
static int input_device_connadd(struct input_device *idev)
Packit 34410b
{
Packit 34410b
	int err;
Packit 34410b
Packit 34410b
	err = input_device_connected(idev);
Packit 34410b
	if (err == 0)
Packit 34410b
		return 0;
Packit 34410b
Packit 34410b
	if (idev->ctrl_io) {
Packit 34410b
		g_io_channel_shutdown(idev->ctrl_io, FALSE, NULL);
Packit 34410b
		g_io_channel_unref(idev->ctrl_io);
Packit 34410b
		idev->ctrl_io = NULL;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (idev->intr_io) {
Packit 34410b
		g_io_channel_shutdown(idev->intr_io, FALSE, NULL);
Packit 34410b
		g_io_channel_unref(idev->intr_io);
Packit 34410b
		idev->intr_io = NULL;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return err;
Packit 34410b
}
Packit 34410b
Packit 34410b
bool input_device_exists(const bdaddr_t *src, const bdaddr_t *dst)
Packit 34410b
{
Packit 34410b
	if (find_device(src, dst))
Packit 34410b
		return true;
Packit 34410b
Packit 34410b
	return false;
Packit 34410b
}
Packit 34410b
Packit 34410b
int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
Packit 34410b
								GIOChannel *io)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = find_device(src, dst);
Packit 34410b
	GIOCondition cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
Packit 34410b
Packit 34410b
	DBG("idev %p psm %d", idev, psm);
Packit 34410b
Packit 34410b
	if (!idev)
Packit 34410b
		return -ENOENT;
Packit 34410b
Packit 34410b
	if (uhid_enabled)
Packit 34410b
		cond |= G_IO_IN;
Packit 34410b
Packit 34410b
	switch (psm) {
Packit 34410b
	case L2CAP_PSM_HIDP_CTRL:
Packit 34410b
		if (idev->ctrl_io)
Packit 34410b
			return -EALREADY;
Packit 34410b
		idev->ctrl_io = g_io_channel_ref(io);
Packit 34410b
		idev->ctrl_watch = g_io_add_watch(idev->ctrl_io, cond,
Packit 34410b
							ctrl_watch_cb, idev);
Packit 34410b
		break;
Packit 34410b
	case L2CAP_PSM_HIDP_INTR:
Packit 34410b
		if (idev->intr_io)
Packit 34410b
			return -EALREADY;
Packit 34410b
		idev->intr_io = g_io_channel_ref(io);
Packit 34410b
		idev->intr_watch = g_io_add_watch(idev->intr_io, cond,
Packit 34410b
							intr_watch_cb, idev);
Packit 34410b
		break;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (idev->intr_io && idev->ctrl_io)
Packit 34410b
		input_device_connadd(idev);
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst)
Packit 34410b
{
Packit 34410b
	struct input_device *idev = find_device(src, dst);
Packit 34410b
Packit 34410b
	if (!idev)
Packit 34410b
		return -ENOENT;
Packit 34410b
Packit 34410b
	if (idev->intr_io)
Packit 34410b
		g_io_channel_shutdown(idev->intr_io, TRUE, NULL);
Packit 34410b
Packit 34410b
	if (idev->ctrl_io)
Packit 34410b
		g_io_channel_shutdown(idev->ctrl_io, TRUE, NULL);
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}