This is an automated email from the ASF dual-hosted git repository.

kopyscinski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit 0711811c9f002391c7cd3c86dc96be3e411dd816
Author: Ɓukasz Rymanowski <[email protected]>
AuthorDate: Thu Mar 12 13:50:52 2020 +0100

    nimble/gatt: Add support for newt ATT opcodes
    
    This is initial implementation of handling new GATT opcodes.
    Gatt Client supports now:
    ATT multi Variable read req
    receiving ATT multi notifications
    
    Gatt server supports now:
    ATT multi Variable read rsp
---
 nimble/host/include/host/ble_att.h                 |   8 +
 nimble/host/include/host/ble_gatt.h                |  14 ++
 nimble/host/services/gatt/src/ble_svc_gatt.c       |   4 +
 nimble/host/src/ble_att.c                          |   3 +
 nimble/host/src/ble_att_clt.c                      |  21 ++-
 nimble/host/src/ble_att_cmd_priv.h                 |  14 ++
 nimble/host/src/ble_att_priv.h                     |   7 +-
 nimble/host/src/ble_att_svr.c                      | 164 +++++++++++++++++++++
 nimble/host/src/ble_gatt_priv.h                    |   2 +-
 nimble/host/src/ble_gattc.c                        | 144 +++++++++++++++---
 nimble/host/syscfg.yml                             |  11 ++
 nimble/host/test/src/ble_att_clt_test.c            |   4 +-
 nimble/include/nimble/nimble_opt_auto.h            |   4 +
 porting/examples/linux/include/syscfg/syscfg.h     |   8 +
 .../examples/linux_blemesh/include/syscfg/syscfg.h |   8 +
 porting/nimble/include/syscfg/syscfg.h             |   8 +
 porting/npl/riot/include/syscfg/syscfg.h           |   8 +
 17 files changed, 405 insertions(+), 27 deletions(-)

diff --git a/nimble/host/include/host/ble_att.h 
b/nimble/host/include/host/ble_att.h
index cb98eab4..5a3a2a1f 100644
--- a/nimble/host/include/host/ble_att.h
+++ b/nimble/host/include/host/ble_att.h
@@ -195,6 +195,14 @@ struct os_mbuf;
 /** Indicate Response. */
 #define BLE_ATT_OP_INDICATE_RSP             0x1e
 
+/** Read Multiple Variable Lenght Request */
+#define BLE_ATT_OP_READ_MULT_VAR_REQ        0x20
+
+/** Read Multiple Variable Lenght Response */
+#define BLE_ATT_OP_READ_MULT_VAR_RSP        0x21
+
+/** Notify Multiple Request */
+#define BLE_ATT_OP_NOTIFY_MULTI_REQ         0x23
 /** Write Command. */
 #define BLE_ATT_OP_WRITE_CMD                0x52
 
diff --git a/nimble/host/include/host/ble_gatt.h 
b/nimble/host/include/host/ble_gatt.h
index b3bea2bd..b38dd32b 100644
--- a/nimble/host/include/host/ble_gatt.h
+++ b/nimble/host/include/host/ble_gatt.h
@@ -267,6 +267,17 @@ typedef int ble_gatt_attr_fn(uint16_t conn_handle,
                              struct ble_gatt_attr *attr,
                              void *arg);
 
+/**
+ * The host will free the attribute mbuf automatically after the callback is
+ * executed.  The application can take ownership of the mbuf and prevent it
+ * from being freed by assigning NULL to attr->om.
+ */
+typedef int ble_gatt_attr_mult_fn(uint16_t conn_handle,
+                                  const struct ble_gatt_error *error,
+                                  struct ble_gatt_attr *attrs,
+                                  uint8_t num_attrs,
+                                  void *arg);
+
 /**
  * The host will free the attribute mbufs automatically after the callback is
  * executed.  The application can take ownership of the mbufs and prevent them
@@ -489,6 +500,9 @@ int ble_gattc_read_mult(uint16_t conn_handle, const 
uint16_t *handles,
                         uint8_t num_handles, ble_gatt_attr_fn *cb,
                         void *cb_arg);
 
+int ble_gattc_read_mult_var(uint16_t conn_handle, const uint16_t *handles,
+                            uint8_t num_handles, ble_gatt_attr_mult_fn *cb,
+                            void *cb_arg);
 /**
  * Initiates GATT procedure: Write Without Response.  This function consumes
  * the supplied mbuf regardless of the outcome.
diff --git a/nimble/host/services/gatt/src/ble_svc_gatt.c 
b/nimble/host/services/gatt/src/ble_svc_gatt.c
index 961c23fc..501164d5 100644
--- a/nimble/host/services/gatt/src/ble_svc_gatt.c
+++ b/nimble/host/services/gatt/src/ble_svc_gatt.c
@@ -179,4 +179,8 @@ ble_svc_gatt_init(void)
     if (MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0) {
         ble_svc_gatt_cl_sup_feat |= (1 << BLE_SVC_GATT_CLI_SUP_FEAT_EATT_BIT);
     }
+
+    if (MYNEWT_VAL(BLE_ATT_SVR_NOTIFY_MULTI) > 0) {
+        ble_svc_gatt_cl_sup_feat |= (1 << 
BLE_SVC_GATT_CLI_SUP_FEAT_MULT_NTF_BIT);
+    }
 }
diff --git a/nimble/host/src/ble_att.c b/nimble/host/src/ble_att.c
index ae5041f6..3295bc86 100644
--- a/nimble/host/src/ble_att.c
+++ b/nimble/host/src/ble_att.c
@@ -69,6 +69,9 @@ static const struct ble_att_rx_dispatch_entry 
ble_att_rx_dispatch[] = {
     { BLE_ATT_OP_NOTIFY_REQ,           ble_att_svr_rx_notify },
     { BLE_ATT_OP_INDICATE_REQ,         ble_att_svr_rx_indicate },
     { BLE_ATT_OP_INDICATE_RSP,         ble_att_clt_rx_indicate },
+    { BLE_ATT_OP_READ_MULT_VAR_REQ,    ble_att_svr_rx_read_mult_var },
+    { BLE_ATT_OP_READ_MULT_VAR_RSP,    ble_att_clt_rx_read_mult_var },
+    { BLE_ATT_OP_NOTIFY_MULTI_REQ,     ble_att_svr_rx_notify_multi},
     { BLE_ATT_OP_WRITE_CMD,            ble_att_svr_rx_write_no_rsp },
 };
 
diff --git a/nimble/host/src/ble_att_clt.c b/nimble/host/src/ble_att_clt.c
index 7fcccbb9..1bbb32f1 100644
--- a/nimble/host/src/ble_att_clt.c
+++ b/nimble/host/src/ble_att_clt.c
@@ -540,7 +540,7 @@ ble_att_clt_rx_read_blob(uint16_t conn_handle, uint16_t 
cid, struct os_mbuf **rx
  *****************************************************************************/
 int
 ble_att_clt_tx_read_mult(uint16_t conn_handle, uint16_t cid, const uint16_t 
*handles,
-                         int num_handles)
+                         int num_handles, bool variable)
 {
 #if !NIMBLE_BLE_ATT_CLT_READ_MULT
     return BLE_HS_ENOTSUP;
@@ -549,12 +549,15 @@ ble_att_clt_tx_read_mult(uint16_t conn_handle, uint16_t 
cid, const uint16_t *han
     struct ble_att_read_mult_req *req;
     struct os_mbuf *txom;
     int i;
+    uint8_t op;
 
     if (num_handles < 1) {
         return BLE_HS_EINVAL;
     }
 
-    req = ble_att_cmd_get(BLE_ATT_OP_READ_MULT_REQ,
+    op = variable ? BLE_ATT_OP_READ_MULT_VAR_REQ : BLE_ATT_OP_READ_MULT_REQ;
+
+    req = ble_att_cmd_get(op,
                           sizeof(req->handles[0]) * num_handles,
                           &txom);
     if (req == NULL) {
@@ -576,7 +579,19 @@ ble_att_clt_rx_read_mult(uint16_t conn_handle, uint16_t 
cid, struct os_mbuf **rx
 #endif
 
     /* Pass the Attribute Value field to GATT. */
-    ble_gattc_rx_read_mult_rsp(conn_handle, cid, 0, rxom);
+    ble_gattc_rx_read_mult_rsp(conn_handle, cid, 0, rxom, false);
+    return 0;
+}
+
+int
+ble_att_clt_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, struct 
os_mbuf **rxom)
+{
+#if !NIMBLE_BLE_ATT_CLT_READ_MULT_VAR
+    return BLE_HS_ENOTSUP;
+#endif
+
+    /* Pass the Attribute Value field to GATT. */
+    ble_gattc_rx_read_mult_rsp(conn_handle, cid, 0, rxom, true);
     return 0;
 }
 
diff --git a/nimble/host/src/ble_att_cmd_priv.h 
b/nimble/host/src/ble_att_cmd_priv.h
index 7202e0b7..78c60d5e 100644
--- a/nimble/host/src/ble_att_cmd_priv.h
+++ b/nimble/host/src/ble_att_cmd_priv.h
@@ -309,6 +309,20 @@ struct ble_att_exec_write_req {
  */
 #define BLE_ATT_EXEC_WRITE_RSP_SZ       1
 
+/**
+ * | Parameter                                     | Size (octets)     |
+ * +-----------------------------------------------+-------------------+
+ * | Attribute Opcode                              | 1                 |
+ * | Attribute Handle Length Value Tuple List      | 8 to (ATT_MTU-1)  |
+ */
+#define BLE_ATT_NOTIFY_MULTI_REQ_BASE_SZ      9
+
+struct ble_att_tuple_list {
+    uint16_t handle;
+    uint16_t value_len;
+    uint8_t data[0];
+} __attribute__((packed));
+
 /**
  * | Parameter                          | Size (octets)     |
  * +------------------------------------+-------------------+
diff --git a/nimble/host/src/ble_att_priv.h b/nimble/host/src/ble_att_priv.h
index f596cf91..ac65250f 100644
--- a/nimble/host/src/ble_att_priv.h
+++ b/nimble/host/src/ble_att_priv.h
@@ -198,6 +198,8 @@ int ble_att_svr_rx_read_blob(uint16_t conn_handle, uint16_t 
cid,
                              struct os_mbuf **rxom);
 int ble_att_svr_rx_read_mult(uint16_t conn_handle, uint16_t cid,
                              struct os_mbuf **rxom);
+int ble_att_svr_rx_read_mult_var(uint16_t conn_handle, uint16_t cid,
+                                 struct os_mbuf **rxom);
 int ble_att_svr_rx_write(uint16_t conn_handle, uint16_t cid,
                          struct os_mbuf **rxom);
 int ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, uint16_t cid, struct 
os_mbuf **rxom);
@@ -207,6 +209,8 @@ int ble_att_svr_rx_exec_write(uint16_t conn_handle, 
uint16_t cid,
                               struct os_mbuf **rxom);
 int ble_att_svr_rx_notify(uint16_t conn_handle, uint16_t cid,
                           struct os_mbuf **rxom);
+int ble_att_svr_rx_notify_multi(uint16_t conn_handle, uint16_t cid,
+                                struct os_mbuf **rxom);
 int ble_att_svr_rx_indicate(uint16_t conn_handle, uint16_t cid,
                             struct os_mbuf **rxom);
 void ble_att_svr_prep_clear(struct ble_att_prep_entry_list *prep_list);
@@ -261,8 +265,9 @@ int ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t 
cid, uint16_t handle
                              uint16_t offset);
 int ble_att_clt_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct 
os_mbuf **rxom);
 int ble_att_clt_tx_read_mult(uint16_t conn_handle, uint16_t cid,
-                             const uint16_t *handles, int num_handles);
+                             const uint16_t *handles, int num_handles, bool 
variable);
 int ble_att_clt_rx_read_mult(uint16_t conn_handle, uint16_t cid, struct 
os_mbuf **rxom);
+int ble_att_clt_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, struct 
os_mbuf **rxom);
 int ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t cid, uint16_t 
start_handle,
                              uint16_t end_handle, const ble_uuid_t *uuid);
 int ble_att_clt_rx_read_type(uint16_t conn_handle, uint16_t cid, struct 
os_mbuf **rxom);
diff --git a/nimble/host/src/ble_att_svr.c b/nimble/host/src/ble_att_svr.c
index 7cdcd1db..eb91e3e1 100644
--- a/nimble/host/src/ble_att_svr.c
+++ b/nimble/host/src/ble_att_svr.c
@@ -1629,6 +1629,113 @@ ble_att_svr_rx_read_mult(uint16_t conn_handle, uint16_t 
cid, struct os_mbuf **rx
                               att_err, err_handle);
 }
 
+static int
+ble_att_svr_build_read_mult_rsp_var(uint16_t conn_handle, uint16_t cid,
+                                    struct os_mbuf **rxom,
+                                    struct os_mbuf **out_txom,
+                                    uint8_t *att_err,
+                                    uint16_t *err_handle)
+{
+    struct os_mbuf *txom;
+    uint16_t handle;
+    uint16_t mtu;
+    uint16_t tuple_len;
+    struct os_mbuf *tmp = NULL;
+    int rc;
+
+    mtu = ble_att_mtu_by_cid(conn_handle, cid);
+
+    rc = ble_att_svr_pkt(rxom, &txom, att_err);
+    if (rc != 0) {
+        *err_handle = 0;
+        goto done;
+    }
+
+    if (ble_att_cmd_prepare(BLE_ATT_OP_READ_MULT_VAR_RSP, 0, txom) == NULL) {
+        *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+        *err_handle = 0;
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+
+    tmp = os_msys_get_pkthdr(2, 0);
+
+    /* Iterate through requested handles, reading the corresponding attribute
+     * for each.  Stop when there are no more handles to process, or the
+     * response is full.
+     */
+    while (OS_MBUF_PKTLEN(*rxom) >= 2 && OS_MBUF_PKTLEN(txom) < mtu) {
+        /* Ensure the full 16-bit handle is contiguous at the start of the
+         * mbuf.
+         */
+        rc = ble_att_svr_pullup_req_base(rxom, 2, att_err);
+        if (rc != 0) {
+            *err_handle = 0;
+            goto done;
+        }
+
+        /* Extract the 16-bit handle and strip it from the front of the
+         * mbuf.
+         */
+        handle = get_le16((*rxom)->om_data);
+        os_mbuf_adj(*rxom, 2);
+
+        rc = ble_att_svr_read_handle(conn_handle, handle, 0, tmp, att_err);
+        if (rc != 0) {
+            *err_handle = handle;
+            goto done;
+        }
+        tuple_len = OS_MBUF_PKTLEN(tmp);
+        rc = os_mbuf_append(txom, &tuple_len, sizeof(tuple_len));
+        if (rc != 0) {
+            *err_handle = handle;
+            goto done;
+        }
+        if (tuple_len != 0) {
+            rc = os_mbuf_appendfrom(txom, tmp, 0, tuple_len);
+            if (rc != 0) {
+                *err_handle = handle;
+                goto done;
+            }
+            os_mbuf_adj(tmp, tuple_len);
+        }
+    }
+    rc = 0;
+
+done:
+
+    if (tmp) {
+        os_mbuf_free_chain(tmp);
+    }
+    *out_txom = txom;
+    return rc;
+}
+
+int
+ble_att_svr_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, struct 
os_mbuf **rxom)
+{
+#if (!MYNEWT_VAL(BLE_ATT_SVR_READ_MULT) || (MYNEWT_VAL(BLE_VERSION) < 52))
+    return BLE_HS_ENOTSUP;
+#endif
+
+    struct os_mbuf *txom;
+    uint16_t err_handle;
+    uint8_t att_err;
+    int rc;
+
+    /* Initialize some values in case of early error. */
+    txom = NULL;
+    err_handle = 0;
+    att_err = 0;
+
+    rc = ble_att_svr_build_read_mult_rsp_var(conn_handle, cid, rxom, &txom, 
&att_err,
+                                         &err_handle);
+
+    return ble_att_svr_tx_rsp(conn_handle, cid, rc, txom,
+                              BLE_ATT_OP_READ_MULT_VAR_REQ,
+                              att_err, err_handle);
+}
+
 static int
 ble_att_svr_is_valid_read_group_type(const ble_uuid_t *uuid)
 {
@@ -2504,6 +2611,63 @@ ble_att_svr_rx_notify(uint16_t conn_handle, uint16_t 
cid, struct os_mbuf **rxom)
     return 0;
 }
 
+int
+ble_att_svr_rx_notify_multi(uint16_t conn_handle, uint16_t cid, struct os_mbuf 
**rxom)
+{
+#if !MYNEWT_VAL(BLE_ATT_SVR_NOTIFY_MULTI)
+    return BLE_HS_ENOTSUP;
+#endif
+
+    struct ble_att_tuple_list *req;
+    uint16_t handle;
+    int rc;
+    uint16_t pkt_len;
+    struct os_mbuf *tmp;
+    uint16_t attr_len;
+
+    pkt_len = OS_MBUF_PKTLEN(*rxom);
+    while (pkt_len > 0) {
+        rc = ble_att_svr_pullup_req_base(rxom, sizeof(struct 
ble_att_tuple_list), NULL);
+        if (rc != 0) {
+            return BLE_HS_ENOMEM;
+        }
+
+        req = (struct ble_att_tuple_list *)(*rxom)->om_data;
+
+        handle = le16toh(req->handle);
+        attr_len = le16toh(req->value_len);
+
+        os_mbuf_adj(*rxom, 4);
+
+        if (attr_len > BLE_ATT_ATTR_MAX_LEN) {
+            /*TODO Figure out what to do here */
+            break;
+        }
+
+        tmp = os_msys_get_pkthdr(attr_len, 0);
+        if (!tmp) {
+            /*TODO Figure out what to do here */
+            break;
+        }
+
+        rc = os_mbuf_appendfrom(tmp, *rxom, 0, attr_len);
+        if (rc) {
+            /*TODO Figure out what to do here */
+            break;
+        }
+
+        ble_gap_notify_rx_event(conn_handle, handle, tmp, 0);
+
+        os_mbuf_adj(*rxom, attr_len);
+        pkt_len = OS_MBUF_PKTLEN(*rxom);
+    }
+
+    os_mbuf_free_chain(*rxom);
+    *rxom = NULL;
+
+    return 0;
+}
+
 /**
  * @return                      0 on success; nonzero on failure.
  */
diff --git a/nimble/host/src/ble_gatt_priv.h b/nimble/host/src/ble_gatt_priv.h
index 595a813d..f77c78ad 100644
--- a/nimble/host/src/ble_gatt_priv.h
+++ b/nimble/host/src/ble_gatt_priv.h
@@ -113,7 +113,7 @@ void ble_gattc_rx_read_rsp(uint16_t conn_handle, uint16_t 
cid, int status,
 void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, uint16_t cid, int status,
                                 struct os_mbuf **rxom);
 void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, uint16_t cid, int status,
-                                struct os_mbuf **rxom);
+                                struct os_mbuf **rxom, bool variable);
 void ble_gattc_rx_read_group_type_adata(uint16_t conn_handle, uint16_t cid,
                                         struct ble_att_read_group_type_adata 
*adata);
 void ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, uint16_t cid, 
int rc);
diff --git a/nimble/host/src/ble_gattc.c b/nimble/host/src/ble_gattc.c
index 7467ff60..17f302cd 100644
--- a/nimble/host/src/ble_gattc.c
+++ b/nimble/host/src/ble_gattc.c
@@ -93,11 +93,12 @@
 #define BLE_GATT_OP_READ_UUID                   8
 #define BLE_GATT_OP_READ_LONG                   9
 #define BLE_GATT_OP_READ_MULT                   10
-#define BLE_GATT_OP_WRITE                       11
-#define BLE_GATT_OP_WRITE_LONG                  12
-#define BLE_GATT_OP_WRITE_RELIABLE              13
-#define BLE_GATT_OP_INDICATE                    14
-#define BLE_GATT_OP_CNT                         15
+#define BLE_GATT_OP_READ_MULT_VAR               11
+#define BLE_GATT_OP_WRITE                       12
+#define BLE_GATT_OP_WRITE_LONG                  13
+#define BLE_GATT_OP_WRITE_RELIABLE              14
+#define BLE_GATT_OP_INDICATE                    15
+#define BLE_GATT_OP_CNT                         16
 
 /** Procedure stalled due to resource exhaustion. */
 #define BLE_GATTC_PROC_F_STALLED                0x01
@@ -189,7 +190,9 @@ struct ble_gattc_proc {
         struct {
             uint16_t handles[MYNEWT_VAL(BLE_GATT_READ_MAX_ATTRS)];
             uint8_t num_handles;
+            bool variable;
             ble_gatt_attr_fn *cb;
+            ble_gatt_attr_mult_fn *cb_mult;
             void *cb_arg;
         } read_mult;
 
@@ -584,7 +587,7 @@ ble_gattc_log_read_long(struct ble_gattc_proc *proc)
 }
 
 static void
-ble_gattc_log_read_mult(const uint16_t *handles, uint8_t num_handles)
+ble_gattc_log_read_mult(const uint16_t *handles, uint8_t num_handles, bool 
variable)
 {
     int i;
 
@@ -3324,8 +3327,74 @@ done:
 }
 
 /*****************************************************************************
- * $read multiple                                                            *
- *****************************************************************************/
+* $read multiple                                                             *
+*****************************************************************************/
+
+static int
+ble_gattc_read_mult_cb_var(struct ble_gattc_proc *proc, int status,
+                           uint16_t att_handle, struct os_mbuf **om)
+{
+    struct ble_gatt_attr attr[proc->read_mult.num_handles];
+    int rc;
+    int i;
+    uint16_t attr_len;
+
+    if (proc->read_mult.cb_mult == NULL) {
+        return 0;
+    }
+
+    memset(attr, 0, sizeof(*attr));
+
+    for (i = 0; i < proc->read_mult.num_handles; i++) {
+        attr[i].handle = proc->read_mult.handles[i];
+        attr[i].offset = 0;
+        if (om == NULL || OS_MBUF_PKTLEN(*om) == 0) {
+            continue;
+        }
+
+        *om = os_mbuf_pullup(*om, 2);
+        assert(*om);
+
+        attr_len = get_le16((*om)->om_data);
+
+        os_mbuf_adj(*om, 2);
+
+        if (attr_len > BLE_ATT_ATTR_MAX_LEN) {
+            /*TODO Figure out what to do here */
+            break;
+        }
+
+        attr[i].om = os_msys_get_pkthdr(attr_len, 0);
+        if (!attr[i].om) {
+            /*TODO Figure out what to do here */
+            break;
+        }
+
+        rc = os_mbuf_appendfrom(attr[i].om, *om, 0, attr_len);
+        if (rc) {
+            /*TODO Figure out what to do here */
+            break;
+        }
+
+        os_mbuf_adj(*om, attr_len);
+    }
+
+    /*FIXME Testing assert */
+    assert(i == proc->read_mult.num_handles);
+
+    proc->read_mult.cb_mult(proc->conn_handle,
+                    ble_gattc_error(status, att_handle), &attr[0],
+                    i,
+                    proc->read_mult.cb_arg);
+
+    for (i = 0; i < proc->read_mult.num_handles; i++) {
+        if (attr[i].om != NULL) {
+            os_mbuf_free_chain(attr[i].om);
+        }
+    }
+
+    return 0;
+}
 
 /**
  * Calls a read-multiple-characteristics proc's callback with the specified
@@ -3349,6 +3418,10 @@ ble_gattc_read_mult_cb(struct ble_gattc_proc *proc, int 
status,
         STATS_INC(ble_gattc_stats, read_mult_fail);
     }
 
+    if (proc->read_mult.variable) {
+        return ble_gattc_read_mult_cb_var(proc, status, att_handle, om);
+    }
+
     attr.handle = 0;
     attr.offset = 0;
     if (om == NULL) {
@@ -3400,7 +3473,7 @@ ble_gattc_read_mult_tx(struct ble_gattc_proc *proc)
     int rc;
 
     rc = ble_att_clt_tx_read_mult(proc->conn_handle, proc->cid, 
proc->read_mult.handles,
-                                  proc->read_mult.num_handles);
+                                  proc->read_mult.num_handles, 
proc->read_mult.variable);
     if (rc != 0) {
         return rc;
     }
@@ -3409,10 +3482,11 @@ ble_gattc_read_mult_tx(struct ble_gattc_proc *proc)
 }
 
 
-int
-ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles,
-                    uint8_t num_handles, ble_gatt_attr_fn *cb,
-                    void *cb_arg)
+static int
+ble_gattc_read_mult_internal(uint16_t conn_handle, const uint16_t *handles,
+                             uint8_t num_handles, bool variable, 
ble_gatt_attr_fn *cb,
+                             ble_gatt_attr_mult_fn *cb_mult,
+                             void *cb_arg)
 {
 #if !MYNEWT_VAL(BLE_GATT_READ_MULT)
     return BLE_HS_ENOTSUP;
@@ -3436,14 +3510,20 @@ ble_gattc_read_mult(uint16_t conn_handle, const 
uint16_t *handles,
         goto done;
     }
 
-    ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_READ_MULT);
+    if (variable) {
+        ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_READ_MULT_VAR);
+    } else {
+        ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_READ_MULT);
+    }
 
     memcpy(proc->read_mult.handles, handles, num_handles * sizeof *handles);
     proc->read_mult.num_handles = num_handles;
+    proc->read_mult.variable = variable;
     proc->read_mult.cb = cb;
+    proc->read_mult.cb_mult = cb_mult;
     proc->read_mult.cb_arg = cb_arg;
 
-    ble_gattc_log_read_mult(handles, num_handles);
+    ble_gattc_log_read_mult(handles, num_handles, variable);
     rc = ble_gattc_read_mult_tx(proc);
     if (rc != 0) {
         goto done;
@@ -3458,9 +3538,31 @@ done:
     return rc;
 }
 
+int
+ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles,
+                    uint8_t num_handles, ble_gatt_attr_fn *cb,
+                    void *cb_arg)
+{
+    return ble_gattc_read_mult_internal(conn_handle, handles,
+                                        num_handles, false, cb, NULL, cb_arg);
+}
+
+int
+ble_gattc_read_mult_var(uint16_t conn_handle, const uint16_t *handles,
+                        uint8_t num_handles, ble_gatt_attr_mult_fn *cb,
+                        void *cb_arg)
+{
+#if MYNEWT_VAL(BLE_GATT_READ_MULT_VAR)
+    return ble_gattc_read_mult_internal(conn_handle, handles, num_handles,
+                                        true, NULL, cb, cb_arg);
+#else
+    return BLE_HS_ENOTSUP;
+#endif
+}
+
 /*****************************************************************************
- * $write no response                                                        *
- *****************************************************************************/
+* $write no response                                                        *
+*****************************************************************************/
 
 int
 ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
@@ -4762,16 +4864,18 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, 
uint16_t cid, int status,
  */
 void
 ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, uint16_t cid, int status,
-                           struct os_mbuf **om)
+                           struct os_mbuf **om, bool variable)
 {
 #if !NIMBLE_BLE_ATT_CLT_READ_MULT
     return;
 #endif
 
     struct ble_gattc_proc *proc;
+    uint8_t op;
 
-    proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid,
-                                              BLE_GATT_OP_READ_MULT);
+    op = variable ? BLE_GATT_OP_READ_MULT_VAR : BLE_GATT_OP_READ_MULT;
+
+    proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, op);
     if (proc != NULL) {
         ble_gattc_read_mult_cb(proc, status, 0, om);
         ble_gattc_process_status(proc, BLE_HS_EDONE);
diff --git a/nimble/host/syscfg.yml b/nimble/host/syscfg.yml
index bfe38192..f94111c6 100644
--- a/nimble/host/syscfg.yml
+++ b/nimble/host/syscfg.yml
@@ -244,6 +244,11 @@ syscfg.defs:
             Enables the Read Multiple Characteristic Values GATT procedure.
             (0/1)
         value: MYNEWT_VAL_BLE_ROLE_CENTRAL
+    BLE_GATT_READ_MULT_VAR:
+        description: >
+            Enables the Read Multiple Variable Characteristic Values GATT 
procedure.
+            (0/1)
+        value: MYNEWT_VAL_BLE_ROLE_CENTRAL && (MYNEWT_VAL_BLE_VERSION >= 52)
     BLE_GATT_WRITE_NO_RSP:
         description: >
             Enables the Write Without Response GATT procedure. (0/1)
@@ -362,6 +367,12 @@ syscfg.defs:
             Enables processing of incoming Handle Value Notification ATT
             commands. (0/1)
         value: 1
+    BLE_ATT_SVR_NOTIFY_MULTI:
+        description: >
+            Enables processing of incoming Multi Handle Value Notification ATT
+            commands. (0/1)
+        value: MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && (MYNEWT_VAL_BLE_VERSION >= 52)
+
     BLE_ATT_SVR_INDICATE:
         description: >
             Enables processing of incoming Handle Value Indication ATT
diff --git a/nimble/host/test/src/ble_att_clt_test.c 
b/nimble/host/test/src/ble_att_clt_test.c
index 7d41371e..a944f6ee 100644
--- a/nimble/host/test/src/ble_att_clt_test.c
+++ b/nimble/host/test/src/ble_att_clt_test.c
@@ -380,7 +380,7 @@ TEST_CASE_SELF(ble_att_clt_test_tx_read_mult)
     conn_handle = ble_att_clt_test_misc_init();
 
     /*** Success. */
-    rc = ble_att_clt_tx_read_mult(conn_handle, BLE_L2CAP_CID_ATT, 
((uint16_t[]){ 1, 2 }), 2);
+    rc = ble_att_clt_tx_read_mult(conn_handle, BLE_L2CAP_CID_ATT, 
((uint16_t[]) { 1, 2 }), 2, false);
     TEST_ASSERT(rc == 0);
 
     om = ble_hs_test_util_prev_tx_dequeue_pullup();
@@ -392,7 +392,7 @@ TEST_CASE_SELF(ble_att_clt_test_tx_read_mult)
     TEST_ASSERT(get_le16(om->om_data + BLE_ATT_READ_MULT_REQ_BASE_SZ + 2) == 
2);
 
     /*** Error: no handles. */
-    rc = ble_att_clt_tx_read_mult(conn_handle, BLE_L2CAP_CID_ATT, NULL, 0);
+    rc = ble_att_clt_tx_read_mult(conn_handle, BLE_L2CAP_CID_ATT, NULL, 0, 
false);
     TEST_ASSERT(rc == BLE_HS_EINVAL);
 
     ble_hs_test_util_assert_mbufs_freed(NULL);
diff --git a/nimble/include/nimble/nimble_opt_auto.h 
b/nimble/include/nimble/nimble_opt_auto.h
index 33a1e2aa..55f62199 100644
--- a/nimble/include/nimble/nimble_opt_auto.h
+++ b/nimble/include/nimble/nimble_opt_auto.h
@@ -77,6 +77,10 @@ extern "C" {
 #define NIMBLE_BLE_ATT_CLT_READ_MULT            \
     (MYNEWT_VAL(BLE_GATT_READ_MULT))
 
+#undef NIMBLE_BLE_ATT_CLT_READ_MULT_VAR
+#define NIMBLE_BLE_ATT_CLT_READ_MULT_VAR            \
+    (MYNEWT_VAL(BLE_GATT_READ_MULT_VAR))
+
 #undef NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE
 #define NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE      \
     (MYNEWT_VAL(BLE_GATT_DISC_ALL_SVCS))
diff --git a/porting/examples/linux/include/syscfg/syscfg.h 
b/porting/examples/linux/include/syscfg/syscfg.h
index c262ff8a..04438c21 100644
--- a/porting/examples/linux/include/syscfg/syscfg.h
+++ b/porting/examples/linux/include/syscfg/syscfg.h
@@ -531,6 +531,10 @@
 #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI
+#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && 
(MYNEWT_VAL_BLE_VERSION >= 52))
+#endif
+
 #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE
 #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1)
 #endif
@@ -643,6 +647,10 @@
 #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR
+#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && 
(MYNEWT_VAL_BLE_VERSION >= 52))
+#endif
+
 #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID
 #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL)
 #endif
diff --git a/porting/examples/linux_blemesh/include/syscfg/syscfg.h 
b/porting/examples/linux_blemesh/include/syscfg/syscfg.h
index 2aba7d61..c9fd5411 100644
--- a/porting/examples/linux_blemesh/include/syscfg/syscfg.h
+++ b/porting/examples/linux_blemesh/include/syscfg/syscfg.h
@@ -532,6 +532,10 @@
 #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI
+#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && 
(MYNEWT_VAL_BLE_VERSION >= 52))
+#endif
+
 #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE
 #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1)
 #endif
@@ -644,6 +648,10 @@
 #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR
+#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && 
(MYNEWT_VAL_BLE_VERSION >= 52))
+#endif
+
 #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID
 #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL)
 #endif
diff --git a/porting/nimble/include/syscfg/syscfg.h 
b/porting/nimble/include/syscfg/syscfg.h
index f0732c21..dcea02fd 100644
--- a/porting/nimble/include/syscfg/syscfg.h
+++ b/porting/nimble/include/syscfg/syscfg.h
@@ -530,6 +530,10 @@
 #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI
+#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && 
(MYNEWT_VAL_BLE_VERSION >= 52))
+#endif
+
 #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE
 #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1)
 #endif
@@ -642,6 +646,10 @@
 #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR
+#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && 
(MYNEWT_VAL_BLE_VERSION >= 52))
+#endif
+
 #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID
 #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL)
 #endif
diff --git a/porting/npl/riot/include/syscfg/syscfg.h 
b/porting/npl/riot/include/syscfg/syscfg.h
index b70d7b90..b381d328 100644
--- a/porting/npl/riot/include/syscfg/syscfg.h
+++ b/porting/npl/riot/include/syscfg/syscfg.h
@@ -1394,6 +1394,10 @@
 #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI
+#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && 
(MYNEWT_VAL_BLE_VERSION >= 52))
+#endif
+
 #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE
 #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1)
 #endif
@@ -1506,6 +1510,10 @@
 #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR
+#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && 
(MYNEWT_VAL_BLE_VERSION >= 52))
+#endif
+
 #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID
 #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL)
 #endif

Reply via email to