Esempio n. 1
0
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
							gpointer user_data)
{
	struct hog_device *hogdev = user_data;
	uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
	struct uhid_event ev;
	uint16_t vendor_src, vendor, product, version;
	ssize_t vlen;
	int i;

	if (status != 0) {
		error("Report Map read failed: %s", att_ecode2str(status));
		return;
	}

	vlen = dec_read_resp(pdu, plen, value, sizeof(value));
	if (vlen < 0) {
		error("ATT protocol error");
		return;
	}

	DBG("Report MAP:");
	for (i = 0; i < vlen; i++) {
		switch (value[i]) {
		case 0x85:
		case 0x86:
		case 0x87:
			hogdev->prepend_id = TRUE;
		}

		if (i % 2 == 0) {
			if (i + 1 == vlen)
				DBG("\t %02x", value[i]);
			else
				DBG("\t %02x %02x", value[i], value[i + 1]);
		}
	}

	vendor_src = btd_device_get_vendor_src(hogdev->device);
	vendor = btd_device_get_vendor(hogdev->device);
	product = btd_device_get_product(hogdev->device);
	version = btd_device_get_version(hogdev->device);
	DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, "
			"version=0x%X",	vendor_src, vendor, product, version);

	/* create uHID device */
	memset(&ev, 0, sizeof(ev));
	ev.type = UHID_CREATE;
	strcpy((char *) ev.u.create.name, "bluez-hog-device");
	ev.u.create.vendor = vendor;
	ev.u.create.product = product;
	ev.u.create.version = version;
	ev.u.create.country = hogdev->bcountrycode;
	ev.u.create.bus = BUS_BLUETOOTH;
	ev.u.create.rd_data = value;
	ev.u.create.rd_size = vlen;

	if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
		error("Failed to create uHID device: %s", strerror(errno));
}
static struct hog_device *hog_device_new(struct btd_device *device,
        struct gatt_primary *prim)
{
    struct hog_device *dev;
    char name[248];
    uint16_t vendor, product, version;

    if (device_name_known(device))
        device_get_name(device, name, sizeof(name));
    else
        strcpy(name, "bluez-hog-device");

    vendor = btd_device_get_vendor(device);
    product = btd_device_get_product(device);
    version = btd_device_get_version(device);

    DBG("name=%s vendor=0x%X, product=0x%X, version=0x%X", name, vendor,
        product, version);

    dev = new0(struct hog_device, 1);
    dev->device = btd_device_ref(device);
    dev->hog = bt_hog_new_default(name, vendor, product, version, prim);

    /*
     * TODO: Remove attio callback and use .accept once using
     * bt_gatt_client.
     */
    dev->attioid = btd_device_add_attio_callback(device,
                   attio_connected_cb,
                   attio_disconnected_cb,
                   dev);

    if (!devices)
        devices = queue_new();

    queue_push_tail(devices, dev);

    return dev;
}
static bool dev_is_sixaxis(const bdaddr_t *src, const bdaddr_t *dst)
{
	struct btd_device *device;
	uint16_t vid, pid;

	device = btd_adapter_find_device(adapter_find(src), dst);
	if (!device)
		return false;

	vid = btd_device_get_vendor(device);
	pid = btd_device_get_product(device);

	/* DualShock 3 */
	if (vid == 0x054c && pid == 0x0268)
		return true;

	/* DualShock 4 */
	if (vid == 0x054c && pid == 0x05c4)
		return true;

	return false;
}
Esempio n. 4
0
static ssize_t wii_pincb(struct btd_adapter *adapter, struct btd_device *device,
						char *pinbuf, bool *display,
						unsigned int attempt)
{
	uint16_t vendor, product;
	char addr[18], name[25];
	unsigned int i;

	/* Only try the pin code once per device. If it's not correct then it's
	 * an unknown device. */
	if (attempt > 1)
		return 0;

	ba2str(device_get_address(device), addr);

	vendor = btd_device_get_vendor(device);
	product = btd_device_get_product(device);

	device_get_name(device, name, sizeof(name));
	name[sizeof(name) - 1] = 0;

	for (i = 0; i < G_N_ELEMENTS(wii_ids); ++i) {
		if (vendor == wii_ids[i][0] && product == wii_ids[i][1])
			goto found;
	}

	for (i = 0; i < G_N_ELEMENTS(wii_names); ++i) {
		if (g_str_equal(name, wii_names[i]))
			goto found;
	}

	return 0;

found:
	DBG("Forcing fixed pin on detected wiimote %s", addr);
	memcpy(pinbuf, adapter_get_address(adapter), 6);
	return 6;
}
Esempio n. 5
0
static int hidp_add_connection(struct input_device *idev)
{
    struct hidp_connadd_req *req;
    sdp_record_t *rec;
    char src_addr[18], dst_addr[18];
    char filename[PATH_MAX + 1];
    GKeyFile *key_file;
    char handle[11], *str;
    GError *gerr = NULL;
    int err;

    req = g_new0(struct hidp_connadd_req, 1);
    req->ctrl_sock = g_io_channel_unix_get_fd(idev->ctrl_io);
    req->intr_sock = g_io_channel_unix_get_fd(idev->intr_io);
    req->flags     = 0;
    req->idle_to   = idle_timeout;

    ba2str(&idev->src, src_addr);
    ba2str(&idev->dst, dst_addr);

    snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", src_addr,
             dst_addr);
    filename[PATH_MAX] = '\0';
    sprintf(handle, "0x%8.8X", idev->handle);

    key_file = g_key_file_new();
    g_key_file_load_from_file(key_file, filename, 0, NULL);
    str = g_key_file_get_string(key_file, "ServiceRecords", handle, NULL);
    g_key_file_free(key_file);

    if (!str) {
        error("Rejected connection from unknown device %s", dst_addr);
        err = -EPERM;
        goto cleanup;
    }

    rec = record_from_string(str);
    g_free(str);

    err = extract_hid_record(rec, req);
    sdp_record_free(rec);
    if (err < 0) {
        error("Could not parse HID SDP record: %s (%d)", strerror(-err),
              -err);
        goto cleanup;
    }

    req->vendor = btd_device_get_vendor(idev->device);
    req->product = btd_device_get_product(idev->device);
    req->version = btd_device_get_version(idev->device);

    if (idev->name)
        strncpy(req->name, idev->name, sizeof(req->name) - 1);

    /* Encryption is mandatory for keyboards */
    if (req->subclass & 0x40) {
        if (!bt_io_set(idev->intr_io, &gerr,
                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                       BT_IO_OPT_INVALID)) {
            error("btio: %s", gerr->message);
            g_error_free(gerr);
            err = -EFAULT;
            goto cleanup;
        }

        idev->req = req;
        idev->sec_watch = g_io_add_watch(idev->intr_io, G_IO_OUT,
                                         encrypt_notify, idev);

        return 0;
    }

    err = ioctl_connadd(req);

cleanup:
    g_free(req->rd_data);
    g_free(req);

    return err;
}
Esempio n. 6
0
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
							gpointer user_data)
{
	struct hog_device *hogdev = user_data;
	struct btd_adapter *adapter = device_get_adapter(hogdev->device);
	uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
	struct uhid_event ev;
	uint16_t vendor_src, vendor, product, version;
	ssize_t vlen;
	char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */
	int i, err;

	if (status != 0) {
		error("Report Map read failed: %s", att_ecode2str(status));
		return;
	}

	vlen = dec_read_resp(pdu, plen, value, sizeof(value));
	if (vlen < 0) {
		error("ATT protocol error");
		return;
	}

	DBG("Report MAP:");
	for (i = 0; i < vlen;) {
		ssize_t ilen = 0;
		bool long_item = false;

		if (get_descriptor_item_info(&value[i], vlen - i, &ilen,
								&long_item)) {
			/* Report ID is short item with prefix 100001xx */
			if (!long_item && (value[i] & 0xfc) == 0x84)
				hogdev->has_report_id = TRUE;

			DBG("\t%s", item2string(itemstr, &value[i], ilen));

			i += ilen;
		} else {
			error("Report Map parsing failed at %d", i);

			/* Just print remaining items at once and break */
			DBG("\t%s", item2string(itemstr, &value[i], vlen - i));
			break;
		}
	}

	vendor_src = btd_device_get_vendor_src(hogdev->device);
	vendor = btd_device_get_vendor(hogdev->device);
	product = btd_device_get_product(hogdev->device);
	version = btd_device_get_version(hogdev->device);
	DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, "
			"version=0x%X",	vendor_src, vendor, product, version);

	/* create uHID device */
	memset(&ev, 0, sizeof(ev));
	ev.type = UHID_CREATE;
	if (device_name_known(hogdev->device))
		device_get_name(hogdev->device, (char *) ev.u.create.name,
						sizeof(ev.u.create.name));
	else
		strcpy((char *) ev.u.create.name, "bluez-hog-device");
	ba2str(btd_adapter_get_address(adapter), (char *) ev.u.create.phys);
	ba2str(device_get_address(hogdev->device), (char *) ev.u.create.uniq);
	ev.u.create.vendor = vendor;
	ev.u.create.product = product;
	ev.u.create.version = version;
	ev.u.create.country = hogdev->bcountrycode;
	ev.u.create.bus = BUS_BLUETOOTH;
	ev.u.create.rd_data = value;
	ev.u.create.rd_size = vlen;

	err = bt_uhid_send(hogdev->uhid, &ev);
	if (err < 0) {
		error("bt_uhid_send: %s", strerror(-err));
		return;
	}

	bt_uhid_register(hogdev->uhid, UHID_OUTPUT, forward_report, hogdev);
	bt_uhid_register(hogdev->uhid, UHID_SET_REPORT, set_report, hogdev);
	bt_uhid_register(hogdev->uhid, UHID_GET_REPORT, get_report, hogdev);
}
Esempio n. 7
0
static int hidp_add_connection(struct input_device *idev,
					struct input_conn *iconn)
{
	struct hidp_connadd_req *req;
	struct fake_hid *fake_hid;
	struct fake_input *fake;
	sdp_record_t *rec;
	char src_addr[18], dst_addr[18];
	GError *gerr = NULL;
	int err;

	DBG("idev %p", idev);

	req = g_new0(struct hidp_connadd_req, 1);
	req->ctrl_sock = g_io_channel_unix_get_fd(iconn->ctrl_io);
	req->intr_sock = g_io_channel_unix_get_fd(iconn->intr_io);
	req->flags     = 0;
	req->idle_to   = iconn->timeout;

	ba2str(&idev->src, src_addr);
	ba2str(&idev->dst, dst_addr);

	rec = fetch_record(src_addr, dst_addr, idev->handle);
	if (!rec) {
		error("Rejected connection from unknown device %s", dst_addr);
		err = -EPERM;
		goto cleanup;
	}

	extract_hid_record(rec, req);
	extract_hid_props(idev, rec);
	sdp_record_free(rec);

	req->vendor = btd_device_get_vendor(idev->device);
	req->product = btd_device_get_product(idev->device);
	req->version = btd_device_get_version(idev->device);

	fake_hid = get_fake_hid(req->vendor, req->product);
	if (fake_hid) {
		err = 0;
		fake = g_new0(struct fake_input, 1);
		fake->connect = fake_hid_connect;
		fake->disconnect = fake_hid_disconnect;
		fake->priv = fake_hid;
		fake->idev = idev;
		fake = fake_hid_connadd(fake, iconn->intr_io, fake_hid);
		if (fake == NULL)
			err = -ENOMEM;
		else
			fake->flags |= FI_FLAG_CONNECTED;
		goto cleanup;
	}

	if (idev->name)
		strncpy(req->name, idev->name, sizeof(req->name) - 1);

	/* Encryption is mandatory for keyboards */
	if (req->subclass & 0x40) {
		struct btd_adapter *adapter = device_get_adapter(idev->device);

		err = btd_adapter_encrypt_link(adapter, (bdaddr_t *) &idev->dst,
						encrypt_completed, req);
		if (err == 0) {
			/* Waiting async encryption */
			return 0;
		}

		if (err == -ENOSYS)
			goto nosys;

		if (err != -EALREADY) {
			error("encrypt_link: %s (%d)", strerror(-err), -err);
			goto cleanup;
		}
	}

	err = ioctl_connadd(req);

cleanup:
	free(req->rd_data);
	g_free(req);

	return err;

nosys:
	if (!bt_io_set(iconn->intr_io, BT_IO_L2CAP, &gerr,
				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
				BT_IO_OPT_INVALID)) {
		error("btio: %s", gerr->message);
		g_error_free(gerr);
		goto cleanup;
	}

	iconn->req = req;
	iconn->sec_watch = g_io_add_watch(iconn->intr_io, G_IO_OUT,
							encrypt_notify, iconn);
	return 0;
}