All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/2] hog: Fix checking for Report ID item presence
@ 2014-04-29 17:25 Andrzej Kaczmarek
  2014-04-29 17:25 ` [PATCH v2 2/2] hog: Improve report map debugging Andrzej Kaczmarek
  2014-04-30 12:54 ` [PATCH v2 1/2] hog: Fix checking for Report ID item presence Luiz Augusto von Dentz
  0 siblings, 2 replies; 3+ messages in thread
From: Andrzej Kaczmarek @ 2014-04-29 17:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Report ID item in Report Descriptor is now detected by simply looking
for applicable item prefixes anywhere in data and does not take items
structure into consideration. This could lead to false-positive
detections in case value we look for is just part of item data, not an
actual item prefix.

As defined in Device Class Definition for HID (6.2.2.7), Report ID is
a short item with prefix 100001nn (binary) thus we do not need to do
complete parsing of Report Descriptor but only need to check items
prefixes in order to find Report ID items reliably.

This patch checks Report Descriptor item by item looking for item
prefix which matches Report ID, as defined in spec above.
---
v2:
- more verbose commit description
- changed parse_descriptor_item() to get_descriptor_item_info()
- reformatted get_descriptor_item_info() a bit

 profiles/input/hog.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 62 insertions(+), 5 deletions(-)

diff --git a/profiles/input/hog.c b/profiles/input/hog.c
index a11e04e..767bcfa 100644
--- a/profiles/input/hog.c
+++ b/profiles/input/hog.c
@@ -345,6 +345,46 @@ static void external_report_reference_cb(guint8 status, const guint8 *pdu,
 					external_service_char_cb, hogdev);
 }
 
+static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len,
+								bool *is_long)
+{
+	if (!blen)
+		return false;
+
+	*is_long = (buf[0] == 0xfe);
+
+	if (*is_long) {
+		if (blen < 3)
+			return false;
+
+		/*
+		 * long item:
+		 * byte 0 -> 0xFE
+		 * byte 1 -> data size
+		 * byte 2 -> tag
+		 * + data
+		 */
+
+		*len = buf[1] + 3;
+	} else {
+		uint8_t b_size;
+
+		/*
+		 * short item:
+		 * byte 0[1..0] -> data size (=0, 1, 2, 4)
+		 * byte 0[3..2] -> type
+		 * byte 0[7..4] -> tag
+		 * + data
+		 */
+
+		b_size = buf[0] & 0x03;
+		*len = (b_size ? 1 << (b_size - 1) : 0) + 1;
+	}
+
+	/* item length should be no more than input buffer length */
+	return *len <= blen;
+}
+
 static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 							gpointer user_data)
 {
@@ -355,6 +395,7 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	uint16_t vendor_src, vendor, product, version;
 	ssize_t vlen;
 	int i;
+	int next_item = 0;
 
 	if (status != 0) {
 		error("Report Map read failed: %s", att_ecode2str(status));
@@ -369,11 +410,27 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 
 	DBG("Report MAP:");
 	for (i = 0; i < vlen; i++) {
-		switch (value[i]) {
-		case 0x85:
-		case 0x86:
-		case 0x87:
-			hogdev->has_report_id = TRUE;
+		ssize_t ilen = 0;
+		bool long_item = false;
+
+		if (i == next_item) {
+			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;
+
+				next_item += ilen;
+			} else {
+				error("Report Map parsing failed at %d", i);
+
+				/*
+				 * We do not increase next_item here so we won't
+				 * parse subsequent data - this is what we want.
+				 */
+			}
 		}
 
 		if (i % 2 == 0) {
-- 
1.9.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] hog: Improve report map debugging
  2014-04-29 17:25 [PATCH v2 1/2] hog: Fix checking for Report ID item presence Andrzej Kaczmarek
@ 2014-04-29 17:25 ` Andrzej Kaczmarek
  2014-04-30 12:54 ` [PATCH v2 1/2] hog: Fix checking for Report ID item presence Luiz Augusto von Dentz
  1 sibling, 0 replies; 3+ messages in thread
From: Andrzej Kaczmarek @ 2014-04-29 17:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Now that we can split report map into items it's convenient to have it
printed with items structure preserved which makes it more useful for
debugging.

Up to 5 bytes are printed for each item which is enough for short items
and for long items continuation mark ('...') is printed if necessary.
This is because as for now there are no long item tags defined except
for some vendor defined thus we can safely "ignore" them and avoid
overly complicated code.
---
v2:
- simplified debugging code to be called only when debugging is enabled

 profiles/input/hog.c | 64 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 38 insertions(+), 26 deletions(-)

diff --git a/profiles/input/hog.c b/profiles/input/hog.c
index 767bcfa..ae2affd 100644
--- a/profiles/input/hog.c
+++ b/profiles/input/hog.c
@@ -385,6 +385,28 @@ static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len,
 	return *len <= blen;
 }
 
+static char *item2string(char *str, uint8_t *buf, uint8_t len)
+{
+	char *p = str;
+	int i;
+
+	/*
+	 * Since long item tags are not defined except for vendor ones, we
+	 * just ensure that short items are printed properly (up to 5 bytes).
+	 */
+	for (i = 0; i < 6 && i < len; i++)
+		p += sprintf(p, " %02x", buf[i]);
+
+	/*
+	 * If there are some data left, just add continuation mark to indicate
+	 * this.
+	 */
+	if (i < len)
+		sprintf(p, " ...");
+
+	return str;
+}
+
 static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 							gpointer user_data)
 {
@@ -394,8 +416,8 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	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;
-	int next_item = 0;
 
 	if (status != 0) {
 		error("Report Map read failed: %s", att_ecode2str(status));
@@ -409,35 +431,25 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	}
 
 	DBG("Report MAP:");
-	for (i = 0; i < vlen; i++) {
+	for (i = 0; i < vlen;) {
 		ssize_t ilen = 0;
 		bool long_item = false;
 
-		if (i == next_item) {
-			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;
-
-				next_item += ilen;
-			} else {
-				error("Report Map parsing failed at %d", i);
-
-				/*
-				 * We do not increase next_item here so we won't
-				 * parse subsequent data - this is what we want.
-				 */
-			}
-		}
+		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));
 
-		if (i % 2 == 0) {
-			if (i + 1 == vlen)
-				DBG("\t %02x", value[i]);
-			else
-				DBG("\t %02x %02x", value[i], value[i + 1]);
+			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;
 		}
 	}
 
-- 
1.9.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2 1/2] hog: Fix checking for Report ID item presence
  2014-04-29 17:25 [PATCH v2 1/2] hog: Fix checking for Report ID item presence Andrzej Kaczmarek
  2014-04-29 17:25 ` [PATCH v2 2/2] hog: Improve report map debugging Andrzej Kaczmarek
@ 2014-04-30 12:54 ` Luiz Augusto von Dentz
  1 sibling, 0 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2014-04-30 12:54 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth

Hi Andrzej,

On Tue, Apr 29, 2014 at 8:25 PM, Andrzej Kaczmarek
<andrzej.kaczmarek@tieto.com> wrote:
> Report ID item in Report Descriptor is now detected by simply looking
> for applicable item prefixes anywhere in data and does not take items
> structure into consideration. This could lead to false-positive
> detections in case value we look for is just part of item data, not an
> actual item prefix.
>
> As defined in Device Class Definition for HID (6.2.2.7), Report ID is
> a short item with prefix 100001nn (binary) thus we do not need to do
> complete parsing of Report Descriptor but only need to check items
> prefixes in order to find Report ID items reliably.
>
> This patch checks Report Descriptor item by item looking for item
> prefix which matches Report ID, as defined in spec above.
> ---
> v2:
> - more verbose commit description
> - changed parse_descriptor_item() to get_descriptor_item_info()
> - reformatted get_descriptor_item_info() a bit
>
>  profiles/input/hog.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 62 insertions(+), 5 deletions(-)
>
> diff --git a/profiles/input/hog.c b/profiles/input/hog.c
> index a11e04e..767bcfa 100644
> --- a/profiles/input/hog.c
> +++ b/profiles/input/hog.c
> @@ -345,6 +345,46 @@ static void external_report_reference_cb(guint8 status, const guint8 *pdu,
>                                         external_service_char_cb, hogdev);
>  }
>
> +static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len,
> +                                                               bool *is_long)
> +{
> +       if (!blen)
> +               return false;
> +
> +       *is_long = (buf[0] == 0xfe);
> +
> +       if (*is_long) {
> +               if (blen < 3)
> +                       return false;
> +
> +               /*
> +                * long item:
> +                * byte 0 -> 0xFE
> +                * byte 1 -> data size
> +                * byte 2 -> tag
> +                * + data
> +                */
> +
> +               *len = buf[1] + 3;
> +       } else {
> +               uint8_t b_size;
> +
> +               /*
> +                * short item:
> +                * byte 0[1..0] -> data size (=0, 1, 2, 4)
> +                * byte 0[3..2] -> type
> +                * byte 0[7..4] -> tag
> +                * + data
> +                */
> +
> +               b_size = buf[0] & 0x03;
> +               *len = (b_size ? 1 << (b_size - 1) : 0) + 1;
> +       }
> +
> +       /* item length should be no more than input buffer length */
> +       return *len <= blen;
> +}
> +
>  static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
>                                                         gpointer user_data)
>  {
> @@ -355,6 +395,7 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
>         uint16_t vendor_src, vendor, product, version;
>         ssize_t vlen;
>         int i;
> +       int next_item = 0;
>
>         if (status != 0) {
>                 error("Report Map read failed: %s", att_ecode2str(status));
> @@ -369,11 +410,27 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
>
>         DBG("Report MAP:");
>         for (i = 0; i < vlen; i++) {
> -               switch (value[i]) {
> -               case 0x85:
> -               case 0x86:
> -               case 0x87:
> -                       hogdev->has_report_id = TRUE;
> +               ssize_t ilen = 0;
> +               bool long_item = false;
> +
> +               if (i == next_item) {
> +                       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;
> +
> +                               next_item += ilen;
> +                       } else {
> +                               error("Report Map parsing failed at %d", i);
> +
> +                               /*
> +                                * We do not increase next_item here so we won't
> +                                * parse subsequent data - this is what we want.
> +                                */
> +                       }
>                 }
>
>                 if (i % 2 == 0) {
> --
> 1.9.2

Applied, thanks.


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-04-30 12:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-29 17:25 [PATCH v2 1/2] hog: Fix checking for Report ID item presence Andrzej Kaczmarek
2014-04-29 17:25 ` [PATCH v2 2/2] hog: Improve report map debugging Andrzej Kaczmarek
2014-04-30 12:54 ` [PATCH v2 1/2] hog: Fix checking for Report ID item presence Luiz Augusto von Dentz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.