summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--input/device.c37
-rw-r--r--src/device.c18
-rw-r--r--src/device.h2
-rw-r--r--src/storage.c54
-rw-r--r--src/storage.h5
5 files changed, 98 insertions, 18 deletions
diff --git a/input/device.c b/input/device.c
index d2ca1fdf..8391326e 100644
--- a/input/device.c
+++ b/input/device.c
@@ -598,8 +598,9 @@ cleanup:
g_free(req);
}
-static int hidp_add_connection(const bdaddr_t *src, const bdaddr_t *dst, int ctrl_sk,
- int intr_sk, int timeout, const char *name, const uint32_t handle)
+static int hidp_add_connection(const struct input_device *idev,
+ const struct input_conn *iconn)
+
{
struct hidp_connadd_req *req;
struct fake_hid *fake_hid;
@@ -609,15 +610,15 @@ static int hidp_add_connection(const bdaddr_t *src, const bdaddr_t *dst, int ctr
int err;
req = g_new0(struct hidp_connadd_req, 1);
- req->ctrl_sock = ctrl_sk;
- req->intr_sock = intr_sk;
+ req->ctrl_sock = iconn->ctrl_sk;
+ req->intr_sock = iconn->intr_sk;
req->flags = 0;
- req->idle_to = timeout;
+ req->idle_to = iconn->timeout;
- ba2str(src, src_addr);
- ba2str(dst, dst_addr);
+ ba2str(&idev->src, src_addr);
+ ba2str(&idev->dst, dst_addr);
- rec = fetch_record(src_addr, dst_addr, handle);
+ rec = fetch_record(src_addr, dst_addr, idev->handle);
if (!rec) {
error("Rejected connection from unknown device %s", dst_addr);
err = -EPERM;
@@ -627,22 +628,25 @@ static int hidp_add_connection(const bdaddr_t *src, const bdaddr_t *dst, int ctr
extract_hid_record(rec, req);
sdp_record_free(rec);
+ read_pnp(src_addr, dst_addr, &req->vendor, &req->product,
+ &req->version);
+
fake_hid = get_fake_hid(req->vendor, req->product);
if (fake_hid) {
fake = g_new0(struct fake_input, 1);
fake->connect = fake_hid_connect;
fake->disconnect = fake_hid_disconnect;
fake->priv = fake_hid;
- err = fake_hid_connadd(fake, intr_sk, fake_hid);
+ err = fake_hid_connadd(fake, iconn->intr_sk, fake_hid);
goto cleanup;
}
- if (name)
- strncpy(req->name, name, 128);
+ if (idev->name)
+ strncpy(req->name, idev->name, 128);
/* Encryption is mandatory for keyboards */
if (req->subclass & 0x40) {
- err = bt_acl_encrypt(src, dst, encrypt_completed, req);
+ err = bt_acl_encrypt(&idev->src, &idev->dst, encrypt_completed, req);
if (err == 0) {
/* Waiting async encryption */
return 0;
@@ -657,7 +661,7 @@ static int hidp_add_connection(const bdaddr_t *src, const bdaddr_t *dst, int ctr
if (req->vendor == 0x054c && req->product == 0x0268) {
unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 };
- err = write(ctrl_sk, buf, sizeof(buf));
+ err = write(iconn->ctrl_sk, buf, sizeof(buf));
}
err = ioctl_connadd(req);
@@ -683,9 +687,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
}
iconn->intr_sk = g_io_channel_unix_get_fd(chan);
- err = hidp_add_connection(&idev->src, &idev->dst,
- iconn->ctrl_sk, iconn->intr_sk,
- iconn->timeout, idev->name, idev->handle);
+ err = hidp_add_connection(idev, iconn);
if (err < 0)
goto failed;
@@ -1202,8 +1204,7 @@ int input_device_connadd(const bdaddr_t *src, const bdaddr_t *dst)
if (!iconn)
return -ENOENT;
- err = hidp_add_connection(src, dst, iconn->ctrl_sk, iconn->intr_sk,
- iconn->timeout, idev->name, idev->handle);
+ err = hidp_add_connection(idev, iconn);
if (err < 0)
goto error;
diff --git a/src/device.c b/src/device.c
index a1d1575e..eadc9d51 100644
--- a/src/device.c
+++ b/src/device.c
@@ -830,6 +830,24 @@ static void update_services(struct browse_req *req, sdp_list_t *recs)
if (!uuid_str)
continue;
+ if (!strcasecmp(uuid_str, PNP_UUID)) {
+ uint16_t vendor, product, version;
+ sdp_data_t *pdlist;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
+ vendor = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
+ product = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
+ version = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ if (vendor || product || version)
+ store_pnp(srcaddr, dstaddr, vendor, product,
+ version);
+ }
+
/* Driver uuid found */
l = g_slist_find_custom(req->uuids, uuid_str,
(GCompareFunc) strcasecmp);
diff --git a/src/device.h b/src/device.h
index d2331173..21f7ffaa 100644
--- a/src/device.h
+++ b/src/device.h
@@ -45,6 +45,8 @@ uint8_t device_get_auth(struct btd_device *device);
#define BTD_UUIDS(args...) ((const char *[]) { args, NULL } )
+#define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb"
+
struct btd_device_driver {
const char *name;
const char **uuids;
diff --git a/src/storage.c b/src/storage.c
index 0690fc1a..559c3b12 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -810,3 +810,57 @@ int delete_record(const gchar *src, const gchar *dst, const uint32_t handle)
return textfile_del(filename, key);
}
+
+int store_pnp(const gchar *src, const gchar *dst, const uint16_t vendor,
+ const uint16_t product, const uint16_t version)
+{
+ char filename[PATH_MAX + 1], str[15];
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src, "pnp");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ snprintf(str, sizeof(str), "%04X %04X %04X", vendor, product, version);
+
+ return textfile_put(filename, dst, str);
+}
+
+int read_pnp(const gchar *src, const gchar *dst, uint32_t *vendor,
+ uint16_t *product, uint16_t *version)
+{
+ char filename[PATH_MAX + 1];
+ char *str, *product_str, *version_str;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src, "pnp");
+
+ str = textfile_get(filename, dst);
+
+ if (!str)
+ return -ENOENT;
+
+ product_str = strchr(str, ' ');
+ if (!product_str) {
+ free(str);
+ return -ENOENT;
+ }
+ *(product_str++) = 0;
+
+ version_str = strchr(product_str, ' ');
+ if (!version_str) {
+ free(str);
+ return -ENOENT;
+ }
+ *(version_str++) = 0;
+
+ if (vendor)
+ *vendor = (uint16_t) strtol(str, NULL, 16);
+
+ if (product)
+ *product = (uint16_t) strtol(product_str, NULL, 16);
+
+ if (version)
+ *version = (uint16_t) strtol(version_str, NULL, 16);
+
+ free(str);
+ return 0;
+}
diff --git a/src/storage.h b/src/storage.h
index 7f89ef19..a4eb82da 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -59,3 +59,8 @@ int delete_entry(bdaddr_t *src, const char *storage, const char *key);
int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec);
sdp_record_t *fetch_record(const gchar *src, const gchar *dst, const uint32_t handle);
int delete_record(const gchar *src, const gchar *dst, const uint32_t handle);
+
+int store_pnp(const gchar *src, const gchar *dst, const uint16_t vendor,
+ const uint16_t product, const uint16_t version);
+int read_pnp(const gchar *src, const gchar *dst, uint32_t *vendor,
+ uint16_t *product, uint16_t *version);