hog-lib: Don't restrict Report MAP size
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 16 Aug 2022 18:56:32 +0000 (11:56 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 15 May 2023 09:25:54 +0000 (14:55 +0530)
Although HIDS spec is quite clear the Report MAP shall be limited to
512 bytes it doesn't seem OS do enforce that on the profile/client side
and since there isn't any qualification test enforcing it either there
are quite many devices which uses Report MAP bigger that 512 bytes
(e.g.: Brydge W-Touch and Lenovo Duet 3 BT Folio).

https://github.com/bluez/bluez/issues/377
Signed-off-by: Manika Shrivastava <manika.sh@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
profiles/input/hog-lib.c

index 436daea..6752280 100755 (executable)
@@ -64,7 +64,6 @@
 #define HOG_PROTO_MODE_BOOT    0
 #define HOG_PROTO_MODE_REPORT  1
 
-#define HOG_REPORT_MAP_MAX_SIZE        512
 #define HID_INFO_SIZE                  4
 #define ATT_NOTIFICATION_HEADER_SIZE   3
 
@@ -103,11 +102,6 @@ struct bt_hog {
        struct queue            *input;
 };
 
-struct report_map {
-       uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
-       size_t  length;
-};
-
 struct report {
        struct bt_hog           *hog;
        bool                    numbered;
@@ -1096,7 +1090,7 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 {
        struct gatt_request *req = user_data;
        struct bt_hog *hog = req->user_data;
-       uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
+       uint8_t *value;
        ssize_t vlen;
 
        remove_gatt_req(req, status);
@@ -1106,10 +1100,12 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
                return;
        }
 
-       vlen = dec_read_resp(pdu, plen, value, sizeof(value));
+       value = new0(uint8_t, plen);
+
+       vlen = dec_read_resp(pdu, plen, value, plen);
        if (vlen < 0) {
                error("ATT protocol error");
-               return;
+               goto done;
        }
 
        uhid_create(hog, value, vlen);
@@ -1120,6 +1116,9 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
                                        NULL, db_report_map_write_value_cb,
                                        NULL);
        }
+
+done:
+       free(value);
 }
 
 static void read_report_map(struct bt_hog *hog)
@@ -1394,7 +1393,7 @@ static void db_report_map_read_value_cb(struct gatt_db_attribute *attrib,
                                                int err, const uint8_t *value,
                                                size_t length, void *user_data)
 {
-       struct report_map *map = user_data;
+       struct iovec *map = user_data;
 
        if (err) {
                error("Error reading report map from gatt db %s",
@@ -1405,8 +1404,9 @@ static void db_report_map_read_value_cb(struct gatt_db_attribute *attrib,
        if (!length)
                return;
 
-       map->length = length < sizeof(map->value) ? length : sizeof(map->value);
-       memcpy(map->value, value, map->length);
+
+       map->iov_len = length;
+       map->iov_base = (void *) value;
 }
 
 static void foreach_hog_chrc(struct gatt_db_attribute *attr, void *user_data)
@@ -1415,7 +1415,7 @@ static void foreach_hog_chrc(struct gatt_db_attribute *attr, void *user_data)
        bt_uuid_t uuid, report_uuid, report_map_uuid, info_uuid;
        bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
        uint16_t handle, value_handle;
-       struct report_map report_map = {0};
+       struct iovec map = {};
 
        gatt_db_attribute_get_char_data(attr, &handle, &value_handle, NULL,
                                        NULL, &uuid);
@@ -1438,14 +1438,14 @@ static void foreach_hog_chrc(struct gatt_db_attribute *attr, void *user_data)
                        gatt_db_attribute_read(hog->report_map_attr, 0,
                                                BT_ATT_OP_READ_REQ, NULL,
                                                db_report_map_read_value_cb,
-                                               &report_map);
+                                               &map);
                }
 
-               if (report_map.length) {
+               if (map.iov_len) {
                        /* Report map found in the cache, straight to creating
                         * UHID to optimize reconnection.
                         */
-                       uhid_create(hog, report_map.value, report_map.length);
+                       uhid_create(hog, map.iov_base, map.iov_len);
                }
 
                gatt_db_service_foreach_desc(attr, foreach_hog_external, hog);