shared/gatt-client: Add support for Read Multiple Variable Length
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 3 Jun 2019 13:21:19 +0000 (16:21 +0300)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 12 Apr 2021 09:00:48 +0000 (14:30 +0530)
The Read Multiple Variable Length Request is used to request that the
server read two or more values of a set of attributes that have a
variable or unknown value length and return their values in a
Read Multiple Variable Length Response.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
src/shared/gatt-client.c

index 654a782..14e6a6a 100644 (file)
@@ -2937,7 +2937,9 @@ static void read_multiple_cb(uint8_t opcode, const void *pdu, uint16_t length,
        uint8_t att_ecode;
        bool success;
 
-       if (opcode != BT_ATT_OP_READ_MULT_RSP || (!pdu && length)) {
+       if ((opcode != BT_ATT_OP_READ_MULT_RSP &&
+                       opcode != BT_ATT_OP_READ_MULT_VL_RSP) ||
+                       (!pdu && length)) {
                success = false;
 
                if (opcode == BT_ATT_OP_ERROR_RSP)
@@ -2952,8 +2954,36 @@ static void read_multiple_cb(uint8_t opcode, const void *pdu, uint16_t length,
                att_ecode = 0;
        }
 
-       if (op->callback)
+       if (!op->callback)
+               return;
+
+       if (opcode == BT_ATT_OP_READ_MULT_RSP || att_ecode) {
                op->callback(success, att_ecode, pdu, length, op->user_data);
+               return;
+       }
+
+       if (length < 2) {
+               op->callback(success, att_ecode, pdu, length, op->user_data);
+               return;
+       }
+
+       /* Parse response */
+       while (length >= 2) {
+               uint16_t len;
+
+               len = get_le16(pdu);
+               length -= 2;
+               pdu += 2;
+
+               /* The Length Value Tuple List may be truncated within the
+                * first two octets of a tuple due to the size limits of the
+                * current ATT_MTU.
+                */
+               if (len > length)
+                       length = len;
+
+               op->callback(success, att_ecode, pdu, len, op->user_data);
+       }
 }
 
 unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client,
@@ -2965,6 +2995,7 @@ unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client,
        uint8_t pdu[num_handles * 2];
        struct request *req;
        struct read_op *op;
+       uint8_t opcode;
        int i;
 
        if (!client)
@@ -2994,8 +3025,11 @@ unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client,
        for (i = 0; i < num_handles; i++)
                put_le16(handles[i], pdu + (2 * i));
 
-       req->att_id = bt_att_send(client->att, BT_ATT_OP_READ_MULT_REQ,
-                                                       pdu, sizeof(pdu),
+       opcode = bt_gatt_client_get_features(client) &
+               BT_GATT_CHRC_CLI_FEAT_EATT ? BT_ATT_OP_READ_MULT_VL_REQ :
+               BT_ATT_OP_READ_MULT_REQ;
+
+       req->att_id = bt_att_send(client->att, opcode, pdu, sizeof(pdu),
                                                        read_multiple_cb, req,
                                                        request_unref);
        if (!req->att_id) {