You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/07/23 02:47:35 UTC
[08/11] incubator-mynewt-core git commit: BLE Host - Use mbufs
instead of flat bufs.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_att_svr.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_svr.c b/net/nimble/host/src/ble_att_svr.c
index 18a2523..a1ec715 100644
--- a/net/nimble/host/src/ble_att_svr.c
+++ b/net/nimble/host/src/ble_att_svr.c
@@ -202,7 +202,7 @@ ble_att_svr_pullup_req_base(struct os_mbuf **om, int base_len,
uint8_t att_err;
int rc;
- rc = ble_hs_misc_pullup_base(om, base_len);
+ rc = ble_hs_mbuf_pullup_base(om, base_len);
if (rc == BLE_HS_ENOMEM) {
att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
} else {
@@ -287,27 +287,11 @@ ble_att_svr_check_security(uint16_t conn_handle, int is_read,
return 0;
}
-static uint16_t
-ble_att_max_read_len(uint16_t conn_handle)
-{
- uint16_t mtu;
-
- if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
- /* The application is reading from itself; no MTU. */
- mtu = BLE_ATT_MTU_MAX;
- } else {
- mtu = ble_att_mtu(conn_handle);
- }
-
- /* Subtract one to account for the att-read-response header. */
- BLE_HS_DBG_ASSERT(mtu > 0);
- return mtu - 1;
-}
-
static int
ble_att_svr_read(uint16_t conn_handle,
struct ble_att_svr_entry *entry,
- struct ble_att_svr_access_ctxt *ctxt,
+ uint16_t offset,
+ struct os_mbuf *om,
uint8_t *out_att_err)
{
uint8_t att_err;
@@ -328,17 +312,9 @@ ble_att_svr_read(uint16_t conn_handle,
}
}
- /* Give the application access to the ATT flat buffer in case it needs
- * to generate the read response dynamically.
- */
- ctxt->read.buf = ble_att_get_flat_buf();
- ctxt->read.data = ctxt->read.buf;
- ctxt->read.max_data_len = ble_att_max_read_len(conn_handle);
-
BLE_HS_DBG_ASSERT(entry->ha_cb != NULL);
rc = entry->ha_cb(conn_handle, entry->ha_handle_id,
- entry->ha_uuid, BLE_ATT_ACCESS_OP_READ, ctxt,
- entry->ha_cb_arg);
+ BLE_ATT_ACCESS_OP_READ, offset, &om, entry->ha_cb_arg);
if (rc != 0) {
att_err = rc;
rc = BLE_HS_EAPP;
@@ -354,9 +330,51 @@ err:
return rc;
}
+static int
+ble_att_svr_read_flat(uint16_t conn_handle,
+ struct ble_att_svr_entry *entry,
+ uint16_t offset,
+ uint16_t max_len,
+ void *dst,
+ uint16_t *out_len,
+ uint8_t *out_att_err)
+{
+ struct os_mbuf *om;
+ uint16_t len;
+ int rc;
+
+ om = ble_hs_mbuf_l2cap_pkt();
+ if (om == NULL) {
+ rc = BLE_HS_ENOMEM;
+ goto done;
+ }
+
+ rc = ble_att_svr_read(conn_handle, entry, offset, om, out_att_err);
+ if (rc != 0) {
+ goto done;
+ }
+
+ len = OS_MBUF_PKTLEN(om);
+ if (len > max_len) {
+ rc = BLE_HS_EMSGSIZE;
+ *out_att_err = BLE_ATT_ERR_UNLIKELY;
+ goto done;
+ }
+
+ rc = os_mbuf_copydata(om, 0, len, dst);
+ BLE_HS_DBG_ASSERT(rc == 0);
+
+ *out_len = len;
+ rc = 0;
+
+done:
+ os_mbuf_free_chain(om);
+ return rc;
+}
+
int
ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
- struct ble_att_svr_access_ctxt *ctxt,
+ uint16_t offset, struct os_mbuf *om,
uint8_t *out_att_err)
{
struct ble_att_svr_entry *entry;
@@ -370,7 +388,7 @@ ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
return BLE_HS_ENOENT;
}
- rc = ble_att_svr_read(conn_handle, entry, ctxt, out_att_err);
+ rc = ble_att_svr_read(conn_handle, entry, offset, om, out_att_err);
if (rc != 0) {
return rc;
}
@@ -384,41 +402,45 @@ ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
* performed by calling the registered GATT access callback.
*
* @param attr_handle The 16-bit handle of the attribute to read.
- * @param out_data On success, this points to the attribute data
- * just read.
- * @param out_attr_len On success, this points to the number of bytes
- * of attribute data just read.
+ * @param out_om On success, this is made to point to a
+ * newly-allocated mbuf containing the
+ * attribute data read.
*
- * @return 0 on success
+ * @return 0 on success;
* NimBLE host ATT return code if the attribute
* access callback reports failure;
* NimBLE host core return code on unexpected
* error.
*/
int
-ble_att_svr_read_local(uint16_t attr_handle, const void **out_data,
- uint16_t *out_attr_len)
+ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om)
{
- struct ble_att_svr_access_ctxt ctxt;
+ struct os_mbuf *om;
int rc;
- ctxt.read.offset = 0;
+ om = ble_hs_mbuf_bare_pkt();
+ if (om == NULL) {
+ rc = BLE_HS_ENOMEM;
+ goto err;
+ }
- rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, &ctxt,
+ rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, 0, om,
NULL);
if (rc != 0) {
- return rc;
+ goto err;
}
- *out_attr_len = ctxt.read.len;
- *out_data = ctxt.read.data;
-
+ *out_om = om;
return 0;
+
+err:
+ os_mbuf_free_chain(om);
+ return rc;
}
static int
ble_att_svr_write(uint16_t conn_handle, struct ble_att_svr_entry *entry,
- struct ble_att_svr_access_ctxt *ctxt, uint8_t *out_att_err)
+ uint16_t offset, struct os_mbuf **om, uint8_t *out_att_err)
{
uint8_t att_err;
int rc;
@@ -429,28 +451,25 @@ ble_att_svr_write(uint16_t conn_handle, struct ble_att_svr_entry *entry,
if (!(entry->ha_flags & BLE_ATT_F_WRITE)) {
att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED;
rc = BLE_HS_ENOTSUP;
- goto err;
+ goto done;
}
rc = ble_att_svr_check_security(conn_handle, 0, entry, &att_err);
if (rc != 0) {
- goto err;
+ goto done;
}
}
BLE_HS_DBG_ASSERT(entry->ha_cb != NULL);
rc = entry->ha_cb(conn_handle, entry->ha_handle_id,
- entry->ha_uuid, BLE_ATT_ACCESS_OP_WRITE, ctxt,
- entry->ha_cb_arg);
+ BLE_ATT_ACCESS_OP_WRITE, offset, om, entry->ha_cb_arg);
if (rc != 0) {
att_err = rc;
rc = BLE_HS_EAPP;
- goto err;
+ goto done;
}
- return 0;
-
-err:
+done:
if (out_att_err != NULL) {
*out_att_err = att_err;
}
@@ -459,7 +478,7 @@ err:
static int
ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle,
- struct ble_att_svr_access_ctxt *ctxt,
+ uint16_t offset, struct os_mbuf **om,
uint8_t *out_att_err)
{
struct ble_att_svr_entry *entry;
@@ -471,7 +490,7 @@ ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle,
return BLE_HS_ENOENT;
}
- rc = ble_att_svr_write(conn_handle, entry, ctxt, out_att_err);
+ rc = ble_att_svr_write(conn_handle, entry, offset, om, out_att_err);
if (rc != 0) {
return rc;
}
@@ -481,25 +500,19 @@ ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle,
static int
ble_att_svr_tx_error_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
- uint8_t req_op, uint16_t handle, uint8_t error_code)
+ struct os_mbuf **om, uint8_t req_op,
+ uint16_t handle, uint8_t error_code)
{
struct ble_att_error_rsp rsp;
- struct os_mbuf *txom;
void *dst;
int rc;
BLE_HS_DBG_ASSERT(error_code != 0);
+ BLE_HS_DBG_ASSERT(OS_MBUF_PKTLEN(*om) == 0);
- txom = ble_hs_misc_pkthdr();
- if (txom == NULL) {
- rc = BLE_HS_ENOMEM;
- goto err;
- }
-
- dst = os_mbuf_extend(txom, BLE_ATT_ERROR_RSP_SZ);
+ dst = os_mbuf_extend(*om, BLE_ATT_ERROR_RSP_SZ);
if (dst == NULL) {
- rc = BLE_HS_ENOMEM;
- goto err;
+ return BLE_HS_ENOMEM;
}
rsp.baep_req_op = req_op;
@@ -510,17 +523,12 @@ ble_att_svr_tx_error_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
BLE_ATT_LOG_CMD(1, "error rsp", conn->bhc_handle,
ble_att_error_rsp_log, &rsp);
- rc = ble_l2cap_tx(conn, chan, txom);
- txom = NULL;
+ rc = ble_l2cap_tx(conn, chan, om);
if (rc != 0) {
- goto err;
+ return rc;
}
return 0;
-
-err:
- os_mbuf_free_chain(txom);
- return rc;
}
/**
@@ -547,13 +555,15 @@ err:
* field.
*/
static int
-ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom,
+ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf **om,
uint8_t att_op, uint8_t err_status, uint16_t err_handle)
{
struct ble_l2cap_chan *chan;
struct ble_hs_conn *conn;
int do_tx;
+ BLE_HS_DBG_ASSERT(om != NULL);
+
if (rc == BLE_HS_ENOTCONN) {
/* No connection; tx is not possible. */
do_tx = 0;
@@ -572,10 +582,11 @@ ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom,
rc = BLE_HS_ENOTCONN;
} else {
if (rc == 0) {
- BLE_HS_DBG_ASSERT(txom != NULL);
- ble_att_inc_tx_stat(txom->om_data[0]);
- rc = ble_l2cap_tx(conn, chan, txom);
- txom = NULL;
+ BLE_HS_DBG_ASSERT(*om != NULL);
+
+ ble_att_inc_tx_stat((*om)->om_data[0]);
+ ble_att_truncate_to_mtu(chan, *om);
+ rc = ble_l2cap_tx(conn, chan, om);
if (rc != 0) {
err_status = BLE_ATT_ERR_UNLIKELY;
}
@@ -583,16 +594,24 @@ ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom,
if (rc != 0) {
STATS_INC(ble_att_stats, error_rsp_tx);
- ble_att_svr_tx_error_rsp(conn, chan, att_op,
- err_handle, err_status);
+
+ /* Reuse om for error response. */
+ if (*om == NULL) {
+ *om = ble_hs_mbuf_l2cap_pkt();
+ } else {
+ /* Remove response from mbuf. */
+ os_mbuf_adj(*om, OS_MBUF_PKTLEN(*om));
+ }
+ if (om != NULL) {
+ ble_att_svr_tx_error_rsp(conn, chan, om, att_op,
+ err_handle, err_status);
+ }
}
}
ble_hs_unlock();
}
- os_mbuf_free_chain(txom);
-
return rc;
}
@@ -621,7 +640,7 @@ ble_att_svr_build_mtu_rsp(uint16_t conn_handle, struct os_mbuf **out_txom,
goto done;
}
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
@@ -648,7 +667,7 @@ done:
}
int
-ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om)
+ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom)
{
struct ble_att_mtu_cmd cmd;
struct ble_l2cap_chan *chan;
@@ -659,12 +678,12 @@ ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om)
txom = NULL;
- rc = ble_att_svr_pullup_req_base(om, BLE_ATT_MTU_CMD_SZ, &att_err);
+ rc = ble_att_svr_pullup_req_base(rxom, BLE_ATT_MTU_CMD_SZ, &att_err);
if (rc != 0) {
goto done;
}
- ble_att_mtu_cmd_parse((*om)->om_data, (*om)->om_len, &cmd);
+ ble_att_mtu_cmd_parse((*rxom)->om_data, (*rxom)->om_len, &cmd);
BLE_ATT_LOG_CMD(0, "mtu req", conn_handle, ble_att_mtu_cmd_log, &cmd);
rc = ble_att_svr_build_mtu_rsp(conn_handle, &txom, &att_err);
@@ -675,8 +694,10 @@ ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om)
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_MTU_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_MTU_REQ,
att_err, 0);
+ os_mbuf_free_chain(txom);
+
if (rc == 0) {
ble_hs_lock();
ble_att_conn_chan_find(conn_handle, &conn, &chan);
@@ -806,7 +827,7 @@ ble_att_svr_build_find_info_rsp(uint16_t conn_handle,
goto done;
}
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
@@ -893,8 +914,9 @@ ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom)
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_FIND_INFO_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_FIND_INFO_REQ,
att_err, err_handle);
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -1033,8 +1055,9 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
struct os_mbuf *rxom, struct os_mbuf *txom,
uint16_t mtu, uint8_t *out_att_err)
{
- struct ble_att_svr_access_ctxt ctxt;
struct ble_att_svr_entry *ha;
+ uint8_t buf[16];
+ uint16_t attr_len;
uint16_t uuid16;
uint16_t first;
uint16_t prev;
@@ -1063,13 +1086,13 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
*/
uuid16 = ble_uuid_128_to_16(ha->ha_uuid);
if (uuid16 == req->bavq_attr_type) {
- ctxt.read.offset = 0;
- rc = ble_att_svr_read(conn_handle, ha, &ctxt, out_att_err);
+ rc = ble_att_svr_read_flat(conn_handle, ha, 0, sizeof buf, buf,
+ &attr_len, out_att_err);
if (rc != 0) {
goto done;
}
- rc = os_mbuf_memcmp(rxom, BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ,
- ctxt.read.data, ctxt.read.len);
+ rc = os_mbuf_cmpf(rxom, BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ,
+ buf, attr_len);
if (rc == 0) {
match = 1;
}
@@ -1122,7 +1145,7 @@ ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle,
uint8_t *buf;
int rc;
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
*out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
@@ -1211,9 +1234,10 @@ ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom)
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom,
BLE_ATT_OP_FIND_TYPE_VALUE_REQ, att_err,
err_handle);
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -1225,16 +1249,16 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
uint8_t *att_err,
uint16_t *err_handle)
{
- struct ble_att_svr_access_ctxt ctxt;
struct ble_att_read_type_rsp rsp;
struct ble_att_svr_entry *entry;
struct os_mbuf *txom;
+ uint16_t attr_len;
uint16_t mtu;
+ uint8_t buf[19];
uint8_t *dptr;
int entry_written;
int txomlen;
int prev_attr_len;
- int attr_len;
int rc;
*att_err = 0; /* Silence unnecessary warning. */
@@ -1248,7 +1272,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
return BLE_HS_ENOTCONN;
}
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
*err_handle = 0;
@@ -1277,17 +1301,15 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
}
if (entry->ha_handle_id >= req->batq_start_handle) {
- ctxt.read.offset = 0;
- rc = ble_att_svr_read(conn_handle, entry, &ctxt, att_err);
+ rc = ble_att_svr_read_flat(conn_handle, entry, 0, sizeof buf, buf,
+ &attr_len, att_err);
if (rc != 0) {
*err_handle = entry->ha_handle_id;
goto done;
}
- if (ctxt.read.len > mtu - 4) {
+ if (attr_len > mtu - 4) {
attr_len = mtu - 4;
- } else {
- attr_len = ctxt.read.len;
}
if (prev_attr_len == 0) {
@@ -1310,7 +1332,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
}
htole16(dptr + 0, entry->ha_handle_id);
- memcpy(dptr + 2, ctxt.read.data, attr_len);
+ memcpy(dptr + 2, buf, attr_len);
entry_written = 1;
}
}
@@ -1341,6 +1363,7 @@ done:
return rc;
}
+int yourmom;
int
ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
{
@@ -1378,6 +1401,11 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
BLE_ATT_LOG_CMD(0, "read type req", conn_handle, ble_att_read_type_req_log,
&req);
+
+ if (req.batq_start_handle == 29) {
+ yourmom++;
+ }
+
if (req.batq_start_handle > req.batq_end_handle ||
req.batq_start_handle == 0) {
@@ -1419,67 +1447,9 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_TYPE_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_READ_TYPE_REQ,
att_err, err_handle);
- return rc;
-}
-
-/**
- * @return 0 on success; nonzero on failure.
- */
-static int
-ble_att_svr_build_read_rsp(uint16_t conn_handle, const void *attr_data,
- int attr_len, struct os_mbuf **out_txom,
- uint8_t *att_err)
-{
- struct os_mbuf *txom;
- uint16_t data_len;
- uint16_t mtu;
- uint8_t op;
- int rc;
-
- txom = NULL;
-
- mtu = ble_att_mtu(conn_handle);
- if (mtu == 0) {
- rc = BLE_HS_ENOTCONN;
- goto done;
- }
-
- txom = ble_hs_misc_pkthdr();
- if (txom == NULL) {
- *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
- rc = BLE_HS_ENOMEM;
- goto done;
- }
-
- op = BLE_ATT_OP_READ_RSP;
- rc = os_mbuf_append(txom, &op, 1);
- if (rc != 0) {
- *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
- rc = BLE_HS_ENOMEM;
- goto done;
- }
-
- /* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */
- if (attr_len > mtu - 1) {
- data_len = mtu - 1;
- } else {
- data_len = attr_len;
- }
-
- rc = os_mbuf_append(txom, attr_data, data_len);
- if (rc != 0) {
- *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
- rc = BLE_HS_ENOMEM;
- goto done;
- }
-
- BLE_ATT_LOG_EMPTY_CMD(1, "read rsp", conn_handle);
- rc = 0;
-
-done:
- *out_txom = txom;
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -1490,11 +1460,11 @@ ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
return BLE_HS_ENOTSUP;
#endif
- struct ble_att_svr_access_ctxt ctxt;
struct ble_att_read_req req;
struct os_mbuf *txom;
uint16_t err_handle;
uint8_t att_err;
+ uint8_t *dptr;
int rc;
/* Initialize some values in case of early error. */
@@ -1511,75 +1481,32 @@ ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
ble_att_read_req_parse((*rxom)->om_data, (*rxom)->om_len, &req);
BLE_ATT_LOG_CMD(0, "read req", conn_handle, ble_att_read_req_log, &req);
- ctxt.read.offset = 0;
- rc = ble_att_svr_read_handle(conn_handle, req.barq_handle, &ctxt,
- &att_err);
- if (rc != 0) {
- err_handle = req.barq_handle;
- goto done;
- }
-
- rc = ble_att_svr_build_read_rsp(conn_handle, ctxt.read.data, ctxt.read.len,
- &txom, &att_err);
- if (rc != 0) {
- err_handle = req.barq_handle;
- goto done;
- }
-
- rc = 0;
-
-done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_REQ,
- att_err, err_handle);
- return rc;
-}
-
-/**
- * @return 0 on success; nonzero on failure.
- */
-static int
-ble_att_svr_build_read_blob_rsp(const void *attr_data, int attr_len,
- uint16_t mtu, struct os_mbuf **out_txom,
- uint8_t *att_err)
-{
- struct os_mbuf *txom;
- uint16_t data_len;
- uint8_t op;
- int rc;
-
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
- *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+ att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
goto done;
}
- op = BLE_ATT_OP_READ_BLOB_RSP;
- rc = os_mbuf_append(txom, &op, 1);
- if (rc != 0) {
- *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+ dptr = os_mbuf_extend(txom, 1);
+ if (dptr == NULL) {
+ att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
goto done;
}
+ *dptr = BLE_ATT_OP_READ_RSP;
- /* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */
- if (attr_len > mtu - 1) {
- data_len = mtu - 1;
- } else {
- data_len = attr_len;
- }
-
- rc = os_mbuf_append(txom, attr_data, data_len);
+ rc = ble_att_svr_read_handle(conn_handle, req.barq_handle, 0, txom,
+ &att_err);
if (rc != 0) {
- *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
- rc = BLE_HS_ENOMEM;
+ err_handle = req.barq_handle;
goto done;
}
- rc = 0;
-
done:
- *out_txom = txom;
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_READ_REQ,
+ att_err, err_handle);
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -1590,11 +1517,11 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
return BLE_HS_ENOTSUP;
#endif
- struct ble_att_svr_access_ctxt ctxt;
struct ble_att_read_blob_req req;
struct os_mbuf *txom;
uint16_t err_handle;
uint16_t mtu;
+ uint8_t *dptr;
uint8_t att_err;
int rc;
@@ -1619,34 +1546,36 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
BLE_ATT_LOG_CMD(0, "read blob req", conn_handle, ble_att_read_blob_req_log,
&req);
- ctxt.read.offset = req.babq_offset;
- rc = ble_att_svr_read_handle(conn_handle, req.babq_handle, &ctxt,
- &att_err);
- if (rc != 0) {
- err_handle = req.babq_handle;
+ txom = ble_hs_mbuf_l2cap_pkt();
+ if (txom == NULL) {
+ att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+ rc = BLE_HS_ENOMEM;
goto done;
}
- if (ctxt.read.offset + ctxt.read.len <= mtu - 3) {
- att_err = BLE_ATT_ERR_ATTR_NOT_LONG;
- err_handle = req.babq_handle;
- rc = BLE_HS_ENOTSUP;
+ dptr = os_mbuf_extend(txom, 1);
+ if (dptr == NULL) {
+ att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+ rc = BLE_HS_ENOMEM;
goto done;
}
+ *dptr = BLE_ATT_OP_READ_BLOB_RSP;
- rc = ble_att_svr_build_read_blob_rsp(ctxt.read.data, ctxt.read.len, mtu,
- &txom, &att_err);
+ rc = ble_att_svr_read_handle(conn_handle, req.babq_handle, req.babq_offset,
+ txom, &att_err);
if (rc != 0) {
err_handle = req.babq_handle;
goto done;
}
+
BLE_ATT_LOG_EMPTY_CMD(1, "read blob rsp", conn_handle);
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_BLOB_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_READ_BLOB_REQ,
att_err, err_handle);
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -1657,10 +1586,7 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
uint8_t *att_err,
uint16_t *err_handle)
{
- struct ble_att_svr_access_ctxt ctxt;
struct os_mbuf *txom;
- uint16_t chunk_sz;
- uint16_t tx_space;
uint16_t handle;
uint16_t mtu;
uint8_t *dptr;
@@ -1674,7 +1600,7 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
goto done;
}
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
*err_handle = 0;
@@ -1691,13 +1617,11 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
}
ble_att_read_mult_rsp_write(dptr, BLE_ATT_READ_MULT_RSP_BASE_SZ);
- tx_space = mtu - OS_MBUF_PKTLEN(txom);
-
/* 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 && tx_space > 0) {
+ 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.
*/
@@ -1713,28 +1637,11 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
handle = le16toh((*rxom)->om_data);
os_mbuf_adj(*rxom, 2);
- ctxt.read.offset = 0;
- rc = ble_att_svr_read_handle(conn_handle, handle, &ctxt, att_err);
- if (rc != 0) {
- *err_handle = handle;
- goto done;
- }
-
- if (ctxt.read.len > tx_space) {
- chunk_sz = tx_space;
- } else {
- chunk_sz = ctxt.read.len;
- }
-
- rc = os_mbuf_append(txom, ctxt.read.data, chunk_sz);
+ rc = ble_att_svr_read_handle(conn_handle, handle, 0, txom, att_err);
if (rc != 0) {
- *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
*err_handle = handle;
- rc = BLE_HS_ENOMEM;
goto done;
}
-
- tx_space -= chunk_sz;
}
BLE_ATT_LOG_EMPTY_CMD(1, "read mult rsp", conn_handle);
@@ -1785,8 +1692,9 @@ ble_att_svr_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom)
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_MULT_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_READ_MULT_REQ,
att_err, err_handle);
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -1805,23 +1713,22 @@ static int
ble_att_svr_service_uuid(struct ble_att_svr_entry *entry, uint16_t *uuid16,
uint8_t *uuid128)
{
- struct ble_att_svr_access_ctxt ctxt;
+ uint16_t attr_len;
int rc;
- ctxt.read.offset = 0;
- rc = ble_att_svr_read(BLE_HS_CONN_HANDLE_NONE, entry, &ctxt, NULL);
+ rc = ble_att_svr_read_flat(BLE_HS_CONN_HANDLE_NONE, entry, 0, 16, uuid128,
+ &attr_len, NULL);
if (rc != 0) {
return rc;
}
- switch (ctxt.read.len) {
+ switch (attr_len) {
case 16:
*uuid16 = 0;
- memcpy(uuid128, ctxt.read.data, 16);
return 0;
case 2:
- *uuid16 = le16toh(ctxt.read.data);
+ *uuid16 = le16toh(uuid128);
if (*uuid16 == 0) {
return BLE_HS_EINVAL;
}
@@ -1905,7 +1812,7 @@ ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle,
goto done;
}
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
@@ -2123,9 +2030,10 @@ ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom)
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom,
BLE_ATT_OP_READ_GROUP_TYPE_REQ, att_err,
err_handle);
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -2136,7 +2044,7 @@ ble_att_svr_build_write_rsp(struct os_mbuf **out_txom, uint8_t *att_err)
uint8_t *dst;
int rc;
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
@@ -2166,10 +2074,8 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
return BLE_HS_ENOTSUP;
#endif
- struct ble_att_svr_access_ctxt ctxt;
struct ble_att_write_req req;
struct os_mbuf *txom;
- void *buf;
uint16_t err_handle;
uint8_t att_err;
int rc;
@@ -2193,12 +2099,7 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
/* Strip the request base from the front of the mbuf. */
os_mbuf_adj(*rxom, BLE_ATT_WRITE_REQ_BASE_SZ);
- buf = ble_att_get_flat_buf();
- ctxt.write.len = OS_MBUF_PKTLEN(*rxom);
- ctxt.write.data = buf;
- os_mbuf_copydata(*rxom, 0, ctxt.write.len, buf);
-
- rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, &ctxt,
+ rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, 0, rxom,
&att_err);
if (rc != 0) {
err_handle = req.bawq_handle;
@@ -2215,8 +2116,9 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_WRITE_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_WRITE_REQ,
att_err, err_handle);
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -2227,10 +2129,8 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom)
return BLE_HS_ENOTSUP;
#endif
- struct ble_att_svr_access_ctxt ctxt;
struct ble_att_write_req req;
uint8_t att_err;
- void *buf;
int rc;
rc = ble_att_svr_pullup_req_base(rxom, BLE_ATT_WRITE_REQ_BASE_SZ,
@@ -2246,12 +2146,7 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom)
/* Strip the request base from the front of the mbuf. */
os_mbuf_adj(*rxom, BLE_ATT_WRITE_REQ_BASE_SZ);
- buf = ble_att_get_flat_buf();
- ctxt.write.len = OS_MBUF_PKTLEN(*rxom);
- ctxt.write.data = buf;
- os_mbuf_copydata(*rxom, 0, ctxt.write.len, buf);
-
- rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, &ctxt,
+ rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, 0, rxom,
&att_err);
if (rc != 0) {
return rc;
@@ -2261,34 +2156,33 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom)
}
/**
- * Writes a locally registered attribute. If the specified attribute handle
+ * Writes a locally registered attribute. This function consumes the supplied
+ * mbuf regardless of the outcome. If the specified attribute handle
* coresponds to a GATT characteristic value or descriptor, the write is
* performed by calling the registered GATT access callback.
*
* @param attr_handle The 16-bit handle of the attribute to write.
- * @param data Buffer containing the data to write to the
- * attribute.
- * @param data_len The number of bytes to write.
+ * @param om The value to write to the attribute. Double
+ * indirection is used to effect a transfer of
+ * ownership from the caller.
*
- * @return 0 on success
+ * @return 0 on success;
* NimBLE host ATT return code if the attribute
* access callback reports failure;
* NimBLE host core return code on unexpected
* error.
*/
int
-ble_att_svr_write_local(uint16_t attr_handle, const void *data,
- uint16_t data_len)
+ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf **om)
{
- struct ble_att_svr_access_ctxt ctxt;
int rc;
- ctxt.write.data = data;
- ctxt.write.len = data_len;
- ctxt.write.offset = 0;
+ rc = ble_att_svr_write_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, 0,
+ om, NULL);
- rc = ble_att_svr_write_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, &ctxt,
- NULL);
+ /* Free the mbuf in case it wasn't consumed (i.e., something failed). */
+ os_mbuf_free_chain(*om);
+ *om = NULL;
return rc;
}
@@ -2311,7 +2205,7 @@ ble_att_svr_prep_alloc(void)
}
memset(entry, 0, sizeof *entry);
- entry->bape_value = ble_hs_misc_pkthdr();
+ entry->bape_value = ble_hs_mbuf_l2cap_pkt();
if (entry->bape_value == NULL) {
ble_att_svr_prep_free(entry);
return NULL;
@@ -2395,6 +2289,42 @@ ble_att_svr_prep_validate(struct ble_att_prep_entry_list *prep_list,
return 0;
}
+static void
+ble_att_svr_prep_extract(struct ble_att_prep_entry_list *prep_list,
+ uint16_t *out_attr_handle,
+ struct os_mbuf **out_om)
+{
+ struct ble_att_prep_entry *entry;
+ struct ble_att_prep_entry *first;
+ struct os_mbuf *om;
+ uint16_t attr_handle;
+
+ BLE_HS_DBG_ASSERT(!SLIST_EMPTY(prep_list));
+
+ first = SLIST_FIRST(prep_list);
+ attr_handle = first->bape_handle;
+ om = NULL;
+
+ while ((entry = SLIST_FIRST(prep_list)) != NULL) {
+ if (entry->bape_handle != attr_handle) {
+ break;
+ }
+
+ if (om == NULL) {
+ om = entry->bape_value;
+ } else {
+ os_mbuf_concat(om, entry->bape_value);
+ }
+ entry->bape_value = NULL;
+
+ SLIST_REMOVE_HEAD(prep_list, bape_next);
+ ble_att_svr_prep_free(entry);
+ }
+
+ *out_attr_handle = attr_handle;
+ *out_om = om;
+}
+
/**
* @return 0 on success; ATT error code on failure.
*/
@@ -2403,13 +2333,10 @@ ble_att_svr_prep_write(uint16_t conn_handle,
struct ble_att_prep_entry_list *prep_list,
uint16_t *err_handle)
{
- struct ble_att_svr_access_ctxt ctxt;
- struct ble_att_prep_entry *entry;
- struct ble_att_prep_entry *next;
struct ble_att_svr_entry *attr;
- uint8_t *flat_buf;
+ struct os_mbuf *om;
+ uint16_t attr_handle;
uint8_t att_err;
- int buf_off;
int rc;
*err_handle = 0; /* Silence unnecessary warning. */
@@ -2420,40 +2347,19 @@ ble_att_svr_prep_write(uint16_t conn_handle,
return rc;
}
- flat_buf = ble_att_get_flat_buf();
-
/* Contents are valid; perform the writes. */
- buf_off = 0;
- entry = SLIST_FIRST(prep_list);
- while (entry != NULL) {
- next = SLIST_NEXT(entry, bape_next);
-
- rc = os_mbuf_copydata(entry->bape_value, 0,
- OS_MBUF_PKTLEN(entry->bape_value),
- flat_buf + buf_off);
- BLE_HS_DBG_ASSERT_EVAL(rc == 0);
- buf_off += OS_MBUF_PKTLEN(entry->bape_value);
-
- /* If this is the last entry for this attribute, perform the write. */
- if (next == NULL || entry->bape_handle != next->bape_handle) {
- attr = ble_att_svr_find_by_handle(entry->bape_handle);
- if (attr == NULL) {
- *err_handle = entry->bape_handle;
- return BLE_ATT_ERR_INVALID_HANDLE;
- }
+ while (!SLIST_EMPTY(prep_list)) {
+ ble_att_svr_prep_extract(prep_list, &attr_handle, &om);
- ctxt.write.data = flat_buf;
- ctxt.write.len = buf_off;
- rc = ble_att_svr_write(conn_handle, attr, &ctxt, &att_err);
- if (rc != 0) {
- *err_handle = entry->bape_handle;
- return att_err;
- }
-
- buf_off = 0;
+ attr = ble_att_svr_find_by_handle(attr_handle);
+ if (attr == NULL) {
+ rc = BLE_ATT_ERR_INVALID_HANDLE;
+ *err_handle = attr_handle;
+ } else {
+ rc = ble_att_svr_write(conn_handle, attr, 0, &om, &att_err);
}
- entry = next;
+ os_mbuf_free_chain(om);
}
return 0;
@@ -2474,6 +2380,7 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
struct os_mbuf *srcom;
struct os_mbuf *txom;
uint16_t err_handle;
+ uint8_t *buf;
uint8_t att_err;
int rc;
@@ -2493,6 +2400,7 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
ble_att_prep_write_req_parse((*rxom)->om_data, (*rxom)->om_len, &req);
BLE_ATT_LOG_CMD(0, "prep write req", conn_handle,
ble_att_prep_write_cmd_log, &req);
+ err_handle = req.bapc_handle;
/* Strip the request base from the front of the mbuf. */
os_mbuf_adj(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
@@ -2501,14 +2409,12 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
if (attr_entry == NULL) {
rc = BLE_HS_ENOENT;
att_err = BLE_ATT_ERR_INVALID_HANDLE;
- err_handle = req.bapc_handle;
goto done;
}
prep_entry = ble_att_svr_prep_alloc();
if (prep_entry == NULL) {
att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL;
- err_handle = req.bapc_handle;
rc = BLE_HS_ENOMEM;
goto done;
}
@@ -2540,7 +2446,6 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
srcom->om_len);
if (rc != 0) {
att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL;
- err_handle = req.bapc_handle;
break;
}
}
@@ -2552,20 +2457,28 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
goto done;
}
- /* The receive buffer now contains the attribute value. Repurpose this
- * buffer for the response. Prepend a response header.
- */
- *rxom = os_mbuf_prepend(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
- if (*rxom == NULL) {
+ txom = ble_hs_mbuf_l2cap_pkt();
+ if (txom == NULL) {
+ att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+ rc = BLE_HS_ENOMEM;
+ goto done;
+ }
+
+ buf = os_mbuf_extend(txom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
+ if (buf == NULL) {
+ att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+ rc = BLE_HS_ENOMEM;
+ goto done;
+ }
+ ble_att_prep_write_rsp_write(buf, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, &req);
+
+ rc = os_mbuf_appendfrom(txom, *rxom, 0, OS_MBUF_PKTLEN(*rxom));
+ if (rc != 0) {
att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
- err_handle = req.bapc_handle;
rc = BLE_HS_ENOMEM;
goto done;
}
- txom = *rxom;
- ble_att_prep_write_rsp_write(txom->om_data, BLE_ATT_PREP_WRITE_CMD_BASE_SZ,
- &req);
BLE_ATT_LOG_CMD(1, "prep write rsp", conn_handle,
ble_att_prep_write_cmd_log, &req);
@@ -2595,13 +2508,10 @@ done:
ble_hs_unlock();
}
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_PREP_WRITE_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_PREP_WRITE_REQ,
att_err, err_handle);
+ os_mbuf_free_chain(txom);
- /* Make sure the receive buffer doesn't get freed since we are using it for
- * the response.
- */
- *rxom = NULL;
return rc;
}
@@ -2615,7 +2525,7 @@ ble_att_svr_build_exec_write_rsp(struct os_mbuf **out_txom, uint8_t *att_err)
uint8_t *dst;
int rc;
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
@@ -2707,8 +2617,9 @@ done:
}
}
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_EXEC_WRITE_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_EXEC_WRITE_REQ,
att_err, err_handle);
+ os_mbuf_free_chain(txom);
return rc;
}
@@ -2720,8 +2631,6 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom)
#endif
struct ble_att_notify_req req;
- uint16_t attr_len;
- void *attr_data;
int rc;
if (OS_MBUF_PKTLEN(*rxom) < BLE_ATT_NOTIFY_REQ_BASE_SZ) {
@@ -2744,11 +2653,8 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom)
/* Strip the request base from the front of the mbuf. */
os_mbuf_adj(*rxom, BLE_ATT_NOTIFY_REQ_BASE_SZ);
- attr_data = ble_att_get_flat_buf();
- attr_len = OS_MBUF_PKTLEN(*rxom);
- os_mbuf_copydata(*rxom, 0, attr_len, attr_data);
-
- ble_gap_notify_rx_event(conn_handle, req.banq_handle, attr_data, attr_len, 0);
+ ble_gap_notify_rx_event(conn_handle, req.banq_handle, *rxom, 0);
+ *rxom = NULL;
return 0;
}
@@ -2763,7 +2669,7 @@ ble_att_svr_build_indicate_rsp(struct os_mbuf **out_txom)
uint8_t *dst;
int rc;
- txom = ble_hs_misc_pkthdr();
+ txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
rc = BLE_HS_ENOMEM;
goto done;
@@ -2793,8 +2699,6 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
struct ble_att_indicate_req req;
struct os_mbuf *txom;
- uint16_t attr_len;
- void *attr_data;
int rc;
/* Initialize some values in case of early error. */
@@ -2822,11 +2726,8 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
/* Strip the request base from the front of the mbuf. */
os_mbuf_adj(*rxom, BLE_ATT_INDICATE_REQ_BASE_SZ);
- attr_data = ble_att_get_flat_buf();
- attr_len = OS_MBUF_PKTLEN(*rxom);
- os_mbuf_copydata(*rxom, 0, attr_len, attr_data);
-
- ble_gap_notify_rx_event(conn_handle, req.baiq_handle, attr_data, attr_len, 1);
+ ble_gap_notify_rx_event(conn_handle, req.baiq_handle, *rxom, 1);
+ *rxom = NULL;
rc = ble_att_svr_build_indicate_rsp(&txom);
if (rc != 0) {
@@ -2837,8 +2738,9 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
rc = 0;
done:
- rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_INDICATE_REQ,
+ rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_INDICATE_REQ,
0, 0);
+ os_mbuf_free_chain(txom);
return rc;
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_gap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap.c b/net/nimble/host/src/ble_gap.c
index 18c4122..c8d0383 100644
--- a/net/nimble/host/src/ble_gap.c
+++ b/net/nimble/host/src/ble_gap.c
@@ -2806,7 +2806,7 @@ ble_gap_conn_rssi(uint16_t conn_handle, int8_t *out_rssi)
void
ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,
- void *attr_data, uint16_t attr_len, int is_indication)
+ struct os_mbuf *om, int is_indication)
{
#if !NIMBLE_OPT(GATT_NOTIFY) && !NIMBLE_OPT(GATT_INDICATE)
return;
@@ -2818,10 +2818,11 @@ ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,
event.type = BLE_GAP_EVENT_NOTIFY_RX;
event.notify_rx.conn_handle = conn_handle;
event.notify_rx.attr_handle = attr_handle;
- event.notify_rx.attr_data = attr_data;
- event.notify_rx.attr_len = attr_len;
+ event.notify_rx.om = om;
event.notify_rx.indication = is_indication;
ble_gap_call_conn_event_cb(&event, conn_handle);
+
+ os_mbuf_free_chain(event.notify_rx.om);
}
void
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_gap_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap_priv.h b/net/nimble/host/src/ble_gap_priv.h
index 69d9538..449a4b0 100644
--- a/net/nimble/host/src/ble_gap_priv.h
+++ b/net/nimble/host/src/ble_gap_priv.h
@@ -83,8 +83,7 @@ void ble_gap_enc_event(uint16_t conn_handle, int status,
void ble_gap_passkey_event(uint16_t conn_handle,
struct ble_gap_passkey_params *passkey_params);
void ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,
- void *attr_data, uint16_t attr_len,
- int is_indication);
+ struct os_mbuf *om, int is_indication);
void ble_gap_notify_tx_event(int status, uint16_t conn_handle,
uint16_t attr_handle, int is_indication);
void ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle,
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_gatt_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gatt_priv.h b/net/nimble/host/src/ble_gatt_priv.h
index 73907b7..c33d5c6 100644
--- a/net/nimble/host/src/ble_gatt_priv.h
+++ b/net/nimble/host/src/ble_gatt_priv.h
@@ -95,21 +95,19 @@ struct ble_gatts_conn {
/*** @client. */
int ble_gattc_locked_by_cur_task(void);
-int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle);
void ble_gatts_indicate_fail_notconn(uint16_t conn_handle);
-int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle);
void ble_gattc_rx_err(uint16_t conn_handle, struct ble_att_error_rsp *rsp);
void ble_gattc_rx_mtu(uint16_t conn_handle, int status, uint16_t chan_mtu);
void ble_gattc_rx_read_type_adata(uint16_t conn_handle,
struct ble_att_read_type_adata *adata);
void ble_gattc_rx_read_type_complete(uint16_t conn_handle, int status);
-void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value,
- int value_len);
+void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status,
+ struct os_mbuf **om);
void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status,
- void *value, int value_len);
+ struct os_mbuf **om);
void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status,
- void *value, int value_len);
+ struct os_mbuf **om);
void ble_gattc_rx_read_group_type_adata(
uint16_t conn_handle, struct ble_att_read_group_type_adata *adata);
void ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int rc);
@@ -119,7 +117,7 @@ void ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, int status);
void ble_gattc_rx_write_rsp(uint16_t conn_handle);
void ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status,
struct ble_att_prep_write_cmd *rsp,
- void *attr_data, uint16_t attr_data_len);
+ struct os_mbuf **om);
void ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, int status);
void ble_gattc_rx_indicate_rsp(uint16_t conn_handle);
void ble_gattc_rx_find_info_idata(uint16_t conn_handle,
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_gattc.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gattc.c b/net/nimble/host/src/ble_gattc.c
index c4ba96b..323c7f2 100644
--- a/net/nimble/host/src/ble_gattc.c
+++ b/net/nimble/host/src/ble_gattc.c
@@ -182,9 +182,10 @@ struct ble_gattc_proc {
} write_long;
struct {
- const struct ble_gatt_attr *attrs;
- int num_attrs;
- int cur_attr;
+ struct ble_gatt_attr attrs[NIMBLE_OPT(GATT_WRITE_MAX_ATTRS)];
+ uint8_t num_attrs;
+ uint8_t cur_attr;
+ uint16_t length;
ble_gatt_reliable_attr_fn *cb;
void *cb_arg;
} write_reliable;
@@ -246,10 +247,10 @@ typedef int ble_gattc_rx_adata_fn(struct ble_gattc_proc *proc,
typedef int ble_gattc_rx_prep_fn(struct ble_gattc_proc *proc, int status,
struct ble_att_prep_write_cmd *rsp,
- void *attr_data, uint16_t attr_len);
+ struct os_mbuf **om);
typedef int ble_gattc_rx_attr_fn(struct ble_gattc_proc *proc, int status,
- void *value, int value_len);
+ struct os_mbuf **om);
typedef int ble_gattc_rx_complete_fn(struct ble_gattc_proc *proc, int status);
typedef int ble_gattc_rx_exec_fn(struct ble_gattc_proc *proc, int status);
@@ -516,7 +517,8 @@ ble_gattc_log_write_long(struct ble_gattc_proc *proc)
{
ble_gattc_log_proc_init("write long; ");
BLE_HS_LOG(INFO, "att_handle=%d len=%d\n",
- proc->write_long.attr.handle, proc->write_long.attr.value_len);
+ proc->write_long.attr.handle,
+ OS_MBUF_PKTLEN(proc->write_long.attr.om));
}
static void
@@ -601,10 +603,26 @@ static void
ble_gattc_proc_free(struct ble_gattc_proc *proc)
{
int rc;
+ int i;
if (proc != NULL) {
ble_gattc_dbg_assert_proc_not_inserted(proc);
+ switch (proc->op) {
+ case BLE_GATT_OP_WRITE_LONG:
+ os_mbuf_free_chain(proc->write_long.attr.om);
+ break;
+
+ case BLE_GATT_OP_WRITE_RELIABLE:
+ for (i = 0; i < proc->write_reliable.num_attrs; i++) {
+ os_mbuf_free_chain(proc->write_reliable.attrs[i].om);
+ }
+ break;
+
+ default:
+ break;
+ }
+
rc = os_memblock_put(&ble_gattc_proc_pool, proc);
BLE_HS_DBG_ASSERT_EVAL(rc == 0);
}
@@ -1577,13 +1595,24 @@ ble_gattc_find_inc_svcs_err(struct ble_gattc_proc *proc, int status,
*/
static int
ble_gattc_find_inc_svcs_rx_read_rsp(struct ble_gattc_proc *proc, int status,
- void *value, int value_len)
+ struct os_mbuf **om)
{
struct ble_gatt_svc service;
+ uint16_t om_len;
int rc;
ble_gattc_dbg_assert_proc_not_inserted(proc);
+ rc = ble_hs_mbuf_to_flat(*om, service.uuid128, 16, &om_len);
+ os_mbuf_free_chain(*om);
+ *om = NULL;
+
+ if (rc != 0 || om_len != 16) {
+ /* Invalid UUID. */
+ rc = BLE_HS_EBADDATA;
+ goto err;
+ }
+
if (proc->find_inc_svcs.cur_start == 0) {
/* Unexpected read response; terminate procedure. */
rc = BLE_HS_EBADDATA;
@@ -1595,16 +1624,9 @@ ble_gattc_find_inc_svcs_rx_read_rsp(struct ble_gattc_proc *proc, int status,
goto err;
}
- if (value_len != 16) {
- /* Invalid UUID. */
- rc = BLE_HS_EBADDATA;
- goto err;
- }
-
/* Report discovered service to application. */
service.start_handle = proc->find_inc_svcs.cur_start;
service.end_handle = proc->find_inc_svcs.cur_end;
- memcpy(service.uuid128, value, 16);
rc = ble_gattc_find_inc_svcs_cb(proc, 0, 0, &service);
if (rc != 0) {
/* Application has indicated that the procedure should be aborted. */
@@ -2529,7 +2551,7 @@ ble_gattc_read_err(struct ble_gattc_proc *proc, int status,
*/
static int
ble_gattc_read_rx_read_rsp(struct ble_gattc_proc *proc, int status,
- void *value, int value_len)
+ struct os_mbuf **om)
{
struct ble_gatt_attr attr;
@@ -2537,11 +2559,13 @@ ble_gattc_read_rx_read_rsp(struct ble_gattc_proc *proc, int status,
attr.handle = proc->read.handle;
attr.offset = 0;
- attr.value_len = value_len;
- attr.value = value;
+ attr.om = *om;
ble_gattc_read_cb(proc, status, 0, &attr);
+ /* Indicate to the caller whether the application consumed the mbuf. */
+ *om = attr.om;
+
/* The read operation only has a single request / response exchange. */
return BLE_HS_EDONE;
}
@@ -2670,10 +2694,18 @@ ble_gattc_read_uuid_rx_adata(struct ble_gattc_proc *proc,
attr.handle = adata->att_handle;
attr.offset = 0;
- attr.value_len = adata->value_len;
- attr.value = adata->value;
+ attr.om = ble_hs_mbuf_from_flat(adata->value, adata->value_len);
+ if (attr.om == NULL) {
+ rc = BLE_HS_ENOMEM;
+ } else {
+ rc = 0;
+ }
+
+ rc = ble_gattc_read_uuid_cb(proc, rc, 0, &attr);
+
+ /* Free the attribute mbuf if the application has not consumed it. */
+ os_mbuf_free_chain(attr.om);
- rc = ble_gattc_read_uuid_cb(proc, 0, 0, &attr);
if (rc != 0) {
return BLE_HS_EDONE;
}
@@ -2847,21 +2879,27 @@ ble_gattc_read_long_err(struct ble_gattc_proc *proc, int status,
*/
static int
ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status,
- void *value, int value_len)
+ struct os_mbuf **om)
{
struct ble_gatt_attr attr;
+ uint16_t data_len;
uint16_t mtu;
int rc;
ble_gattc_dbg_assert_proc_not_inserted(proc);
+ data_len = OS_MBUF_PKTLEN(*om);
+
attr.handle = proc->read_long.handle;
attr.offset = proc->read_long.offset;
- attr.value_len = value_len;
- attr.value = value;
+ attr.om = *om;
/* Report partial payload to application. */
rc = ble_gattc_read_long_cb(proc, status, 0, &attr);
+
+ /* Indicate to the caller whether the application consumed the mbuf. */
+ *om = attr.om;
+
if (rc != 0 || status != 0) {
return BLE_HS_EDONE;
}
@@ -2873,14 +2911,14 @@ ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status,
return BLE_HS_EDONE;
}
- if (value_len < mtu - 1) {
+ if (data_len < mtu - 1) {
/* Response shorter than maximum allowed; read complete. */
ble_gattc_read_long_cb(proc, BLE_HS_EDONE, 0, NULL);
return BLE_HS_EDONE;
}
/* Send follow-up request. */
- proc->read_long.offset += value_len;
+ proc->read_long.offset += data_len;
rc = ble_gattc_read_long_go(proc, 1);
if (rc != 0) {
return BLE_HS_EDONE;
@@ -2957,39 +2995,40 @@ done:
*/
static int
ble_gattc_read_mult_cb(struct ble_gattc_proc *proc, int status,
- uint16_t att_handle, uint8_t *attr_data,
- uint16_t attr_data_len)
+ uint16_t att_handle, struct os_mbuf **om)
{
- struct ble_gatt_attr *attrp;
struct ble_gatt_attr attr;
int rc;
BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
- BLE_HS_DBG_ASSERT(attr_data != NULL || status != 0);
+ BLE_HS_DBG_ASSERT(om != NULL || status != 0);
ble_gattc_dbg_assert_proc_not_inserted(proc);
if (status != 0 && status != BLE_HS_EDONE) {
STATS_INC(ble_gattc_stats, read_mult_fail);
}
+ attr.handle = 0;
+ attr.offset = 0;
+ if (om == NULL) {
+ attr.om = NULL;
+ } else {
+ attr.om = *om;
+ }
+
if (proc->read_mult.cb == NULL) {
rc = 0;
} else {
- if (status != 0) {
- attrp = NULL;
- } else {
- attrp = &attr;
- attr.handle = 0;
- attr.offset = 0;
- attr.value_len = attr_data_len;
- attr.value = attr_data;
- }
-
rc = proc->read_mult.cb(proc->conn_handle,
- ble_gattc_error(status, att_handle), attrp,
+ ble_gattc_error(status, att_handle), &attr,
proc->read_mult.cb_arg);
}
+ /* Indicate to the caller whether the application consumed the mbuf. */
+ if (om != NULL) {
+ *om = attr.om;
+ }
+
return rc;
}
@@ -3002,7 +3041,7 @@ ble_gattc_read_mult_err(struct ble_gattc_proc *proc, int status,
uint16_t att_handle)
{
ble_gattc_dbg_assert_proc_not_inserted(proc);
- ble_gattc_read_mult_cb(proc, status, att_handle, NULL, 0);
+ ble_gattc_read_mult_cb(proc, status, att_handle, NULL);
}
/**
@@ -3065,20 +3104,22 @@ done:
*****************************************************************************/
/**
- * Initiates GATT procedure: Write Without Response.
+ * Initiates GATT procedure: Write Without Response. This function consumes
+ * the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
- * @param value The value to write to the characteristic.
- * @param value_len The number of bytes to write.
+ * @param txom The value to write to the characteristic.
+ * Double indirection is used to effect a
+ * transfer of ownership from the caller.
*
* @return 0 on success; nonzero on failure.
*/
int
ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
- const void *value, uint16_t value_len)
+ struct os_mbuf **txom)
{
#if !NIMBLE_OPT(GATT_WRITE_NO_RSP)
return BLE_HS_ENOTSUP;
@@ -3089,17 +3130,54 @@ ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
STATS_INC(ble_gattc_stats, write_no_rsp);
- ble_gattc_log_write(attr_handle, value_len, 0);
+ ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(*txom), 0);
req.bawq_handle = attr_handle;
- rc = ble_att_clt_tx_write_cmd(conn_handle, &req, value, value_len);
+ rc = ble_att_clt_tx_write_cmd(conn_handle, &req, txom);
if (rc != 0) {
STATS_INC(ble_gattc_stats, write);
}
+ /* Free the mbuf in case the send failed. */
+ os_mbuf_free_chain(*txom);
+ *txom = NULL;
+
return rc;
}
+/**
+ * Initiates GATT procedure: Write Without Response. This function consumes
+ * the supplied mbuf regardless of the outcome.
+ *
+ * @param conn_handle The connection over which to execute the
+ * procedure.
+ * @param attr_handle The handle of the characteristic value to write
+ * to.
+ * @param value The value to write to the characteristic.
+ * @param value_len The number of bytes to write.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+int
+ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle,
+ const void *data, uint16_t data_len)
+{
+ struct os_mbuf *om;
+ int rc;
+
+ om = ble_hs_mbuf_from_flat(data, data_len);
+ if (om == NULL) {
+ return BLE_HS_ENOMEM;
+ }
+
+ rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, &om);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
/*****************************************************************************
* $write *
*****************************************************************************/
@@ -3151,14 +3229,16 @@ ble_gattc_write_err(struct ble_gattc_proc *proc, int status,
}
/**
- * Initiates GATT procedure: Write Characteristic Value.
+ * Initiates GATT procedure: Write Characteristic Value. This function
+ * consumes the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
- * @param value The value to write to the characteristic.
- * @param value_len The number of bytes to write.
+ * @param txom The value to write to the characteristic.
+ * Double indirection is used to effect a
+ * transfer of ownership from the caller.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
@@ -3167,8 +3247,8 @@ ble_gattc_write_err(struct ble_gattc_proc *proc, int status,
* @return 0 on success; nonzero on failure.
*/
int
-ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, const void *value,
- uint16_t value_len, ble_gatt_attr_fn *cb, void *cb_arg)
+ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle,
+ struct os_mbuf **txom, ble_gatt_attr_fn *cb, void *cb_arg)
{
#if !NIMBLE_OPT(GATT_WRITE)
return BLE_HS_ENOTSUP;
@@ -3192,10 +3272,10 @@ ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, const void *value,
proc->write.cb = cb;
proc->write.cb_arg = cb_arg;
- ble_gattc_log_write(attr_handle, value_len, 1);
+ ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(*txom), 1);
req.bawq_handle = attr_handle;
- rc = ble_att_clt_tx_write_req(conn_handle, &req, value, value_len);
+ rc = ble_att_clt_tx_write_req(conn_handle, &req, txom);
if (rc != 0) {
goto done;
}
@@ -3205,10 +3285,51 @@ done:
STATS_INC(ble_gattc_stats, write_fail);
}
+ /* Free the mbuf in case the send failed. */
+ os_mbuf_free_chain(*txom);
+ *txom = NULL;
+
ble_gattc_process_status(proc, rc);
return rc;
}
+/**
+ * Initiates GATT procedure: Write Characteristic Value (flat buffer version).
+ *
+ * @param conn_handle The connection over which to execute the
+ * procedure.
+ * @param attr_handle The handle of the characteristic value to write
+ * to.
+ * @param value The value to write to the characteristic.
+ * @param value_len The number of bytes to write.
+ * @param cb The function to call to report procedure status
+ * updates; null for no callback.
+ * @param cb_arg The optional argument to pass to the callback
+ * function.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+int
+ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle,
+ const void *data, uint16_t data_len,
+ ble_gatt_attr_fn *cb, void *cb_arg)
+{
+ struct os_mbuf *om;
+ int rc;
+
+ om = ble_hs_mbuf_from_flat(data, data_len);
+ if (om == NULL) {
+ return BLE_HS_ENOMEM;
+ }
+
+ rc = ble_gattc_write(conn_handle, attr_handle, &om, cb, cb_arg);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
/*****************************************************************************
* $write long *
*****************************************************************************/
@@ -3254,48 +3375,65 @@ ble_gattc_write_long_go(struct ble_gattc_proc *proc, int cb_on_err)
{
struct ble_att_prep_write_cmd prep_req;
struct ble_att_exec_write_req exec_req;
- const void *value;
+ struct os_mbuf *om;
int max_sz;
int rc;
ble_gattc_dbg_assert_proc_not_inserted(proc);
- if (proc->write_long.attr.offset < proc->write_long.attr.value_len) {
- max_sz = ble_att_mtu(proc->conn_handle) -
- BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
- if (max_sz == 0) {
- /* Not connected. */
- rc = BLE_HS_ENOTCONN;
- } else {
- if (proc->write_long.attr.offset + max_sz >
- proc->write_long.attr.value_len) {
+ om = NULL;
- proc->write_long.length = proc->write_long.attr.value_len -
- proc->write_long.attr.offset;
- } else {
- proc->write_long.length = max_sz;
- }
+ if (proc->write_long.attr.offset +
+ OS_MBUF_PKTLEN(proc->write_long.attr.om) <= 0) {
- prep_req.bapc_handle = proc->write_long.attr.handle;
- prep_req.bapc_offset = proc->write_long.attr.offset;
- value = proc->write_long.attr.value + proc->write_long.attr.offset;
- rc = ble_att_clt_tx_prep_write(proc->conn_handle,
- &prep_req, value,
- proc->write_long.length);
- }
- } else {
exec_req.baeq_flags = BLE_ATT_EXEC_WRITE_F_CONFIRM;
rc = ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req);
+ goto done;
}
+ max_sz = ble_att_mtu(proc->conn_handle) -
+ BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
+ if (max_sz <= 0) {
+ /* Not connected. */
+ rc = BLE_HS_ENOTCONN;
+ goto done;
+ }
+
+ proc->write_long.length =
+ min(max_sz,
+ OS_MBUF_PKTLEN(proc->write_long.attr.om) -
+ proc->write_long.attr.offset);
+
+ om = ble_hs_mbuf_att_pkt();
+ if (om == NULL) {
+ rc = BLE_HS_ENOMEM;
+ goto done;
+ }
+
+ rc = os_mbuf_appendfrom(om, proc->write_long.attr.om,
+ proc->write_long.attr.offset,
+ proc->write_long.length);
if (rc != 0) {
- if (cb_on_err) {
- ble_gattc_write_long_cb(proc, rc, 0);
- }
- return rc;
+ rc = BLE_HS_ENOMEM;
+ goto done;
}
- return 0;
+ prep_req.bapc_handle = proc->write_long.attr.handle;
+ prep_req.bapc_offset = proc->write_long.attr.offset;
+
+ rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req, &om);
+ if (rc != 0) {
+ goto done;
+ }
+
+done:
+ os_mbuf_free_chain(om);
+
+ if (rc != 0 && cb_on_err) {
+ ble_gattc_write_long_cb(proc, rc, 0);
+ }
+
+ return rc;
}
/**
@@ -3314,7 +3452,8 @@ ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status,
* we could send the execute write command, then erase all queued data.
*/
if (proc->write_long.attr.offset > 0 &&
- proc->write_long.attr.offset < proc->write_long.attr.value_len) {
+ proc->write_long.attr.offset <
+ OS_MBUF_PKTLEN(proc->write_long.attr.om)) {
exec_req.baeq_flags = 0;
ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req);
@@ -3331,12 +3470,16 @@ ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status,
static int
ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc,
int status, struct ble_att_prep_write_cmd *rsp,
- void *attr_data, uint16_t attr_len)
+ struct os_mbuf **rxom)
{
+ struct os_mbuf *om;
int rc;
ble_gattc_dbg_assert_proc_not_inserted(proc);
+ /* Let the caller free the mbuf. */
+ om = *rxom;
+
if (status != 0) {
rc = status;
goto err;
@@ -3351,22 +3494,26 @@ ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc,
rc = BLE_HS_EBADDATA;
goto err;
}
- if (rsp->bapc_offset + attr_len > proc->write_long.attr.value_len) {
+ if (rsp->bapc_offset + OS_MBUF_PKTLEN(om) >
+ OS_MBUF_PKTLEN(proc->write_long.attr.om)) {
+
rc = BLE_HS_EBADDATA;
goto err;
}
- if (attr_len != proc->write_long.length) {
+ if (OS_MBUF_PKTLEN(om) != proc->write_long.length) {
rc = BLE_HS_EBADDATA;
goto err;
}
- if (memcmp(attr_data, proc->write_long.attr.value + rsp->bapc_offset,
- attr_len) != 0) {
+ if (os_mbuf_cmpm(om, 0,
+ proc->write_long.attr.om, rsp->bapc_offset,
+ proc->write_long.length) != 0) {
+
rc = BLE_HS_EBADDATA;
goto err;
}
/* Send follow-up request. */
- proc->write_long.attr.offset += attr_len;
+ proc->write_long.attr.offset += OS_MBUF_PKTLEN(om);
rc = ble_gattc_write_long_go(proc, 1);
if (rc != 0) {
goto err;
@@ -3393,14 +3540,16 @@ ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc, int status)
}
/**
- * Initiates GATT procedure: Write Long Characteristic Values.
+ * Initiates GATT procedure: Write Long Characteristic Values. This function
+ * consumes the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
- * @param value The value to write to the characteristic.
- * @param value_len The number of bytes to write.
+ * @param txom The value to write to the characteristic.
+ * Double indirection is used to effect a
+ * transfer of ownership from the caller.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
@@ -3410,8 +3559,7 @@ ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc, int status)
*/
int
ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
- const void *value, uint16_t value_len,
- ble_gatt_attr_fn *cb, void *cb_arg)
+ struct os_mbuf **txom, ble_gatt_attr_fn *cb, void *cb_arg)
{
#if !NIMBLE_OPT(GATT_WRITE_LONG)
return BLE_HS_ENOTSUP;
@@ -3432,11 +3580,13 @@ ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
proc->conn_handle = conn_handle;
proc->write_long.attr.handle = attr_handle;
proc->write_long.attr.offset = 0;
- proc->write_long.attr.value = value;
- proc->write_long.attr.value_len = value_len;
+ proc->write_long.attr.om = *txom;
proc->write_long.cb = cb;
proc->write_long.cb_arg = cb_arg;
+ /* The mbuf is consumed by the procedure. */
+ *txom = NULL;
+
ble_gattc_log_write_long(proc);
rc = ble_gattc_write_long_go(proc, 0);
@@ -3449,6 +3599,10 @@ done:
STATS_INC(ble_gattc_stats, write_long_fail);
}
+ /* Free the mbuf in case of failure. */
+ os_mbuf_free_chain(*txom);
+ *txom = NULL;
+
ble_gattc_process_status(proc, rc);
return rc;
}
@@ -3499,32 +3653,65 @@ ble_gattc_write_reliable_go(struct ble_gattc_proc *proc, int cb_on_err)
{
struct ble_att_prep_write_cmd prep_req;
struct ble_att_exec_write_req exec_req;
- const struct ble_gatt_attr *attr;
+ struct ble_gatt_attr *attr;
+ struct os_mbuf *om;
+ uint16_t max_sz;
int attr_idx;
int rc;
ble_gattc_dbg_assert_proc_not_inserted(proc);
+ om = NULL;
+
attr_idx = proc->write_reliable.cur_attr;
- if (attr_idx < proc->write_reliable.num_attrs) {
- attr = proc->write_reliable.attrs + attr_idx;
- prep_req.bapc_handle = attr->handle;
- prep_req.bapc_offset = 0;
- rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req,
- attr->value, attr->value_len);
- } else {
+
+ if (attr_idx >= proc->write_reliable.num_attrs) {
exec_req.baeq_flags = BLE_ATT_EXEC_WRITE_F_CONFIRM;
rc = ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req);
+ goto done;
+ }
+
+ attr = proc->write_reliable.attrs + attr_idx;
+
+ max_sz = ble_att_mtu(proc->conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
+ if (max_sz <= 0) {
+ /* Not connected. */
+ rc = BLE_HS_ENOTCONN;
+ goto done;
+ }
+
+ proc->write_reliable.length =
+ min(max_sz, OS_MBUF_PKTLEN(attr->om) - attr->offset);
+
+ om = ble_hs_mbuf_att_pkt();
+ if (om == NULL) {
+ rc = BLE_HS_ENOMEM;
+ goto done;
}
+ rc = os_mbuf_appendfrom(om, attr->om, attr->offset,
+ proc->write_reliable.length);
if (rc != 0) {
- if (cb_on_err) {
- ble_gattc_write_reliable_cb(proc, rc, 0);
- }
- return rc;
+ rc = BLE_HS_ENOMEM;
+ goto done;
}
- return 0;
+ prep_req.bapc_handle = attr->handle;
+ prep_req.bapc_offset = attr->offset;
+
+ rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req, &om);
+ if (rc != 0) {
+ goto done;
+ }
+
+done:
+ os_mbuf_free_chain(om);
+
+ if (rc != 0 && cb_on_err) {
+ ble_gattc_write_reliable_cb(proc, rc, 0);
+ }
+
+ return rc;
}
/**
@@ -3559,19 +3746,24 @@ static int
ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc,
int status,
struct ble_att_prep_write_cmd *rsp,
- void *attr_data, uint16_t attr_len)
+ struct os_mbuf **rxom)
{
- const struct ble_gatt_attr *attr;
+ struct ble_gatt_attr *attr;
+ struct os_mbuf *om;
int rc;
ble_gattc_dbg_assert_proc_not_inserted(proc);
+ /* Let the caller free the mbuf. */
+ om = *rxom;
+
if (status != 0) {
rc = status;
goto err;
}
if (proc->write_reliable.cur_attr >= proc->write_reliable.num_attrs) {
+ /* Expecting an execute write response, not a prepare write response. */
rc = BLE_HS_EBADDATA;
goto err;
}
@@ -3582,21 +3774,23 @@ ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc,
rc = BLE_HS_EBADDATA;
goto err;
}
- if (rsp->bapc_offset != 0) {
- rc = BLE_HS_EBADDATA;
- goto err;
- }
- if (attr_len != attr->value_len) {
+ if (rsp->bapc_offset != attr->offset) {
rc = BLE_HS_EBADDATA;
goto err;
}
- if (memcmp(attr_data, attr->value, attr_len) != 0) {
+ if (os_mbuf_cmpm(attr->om, rsp->bapc_offset, om, 0,
+ proc->write_reliable.length) != 0) {
+
rc = BLE_HS_EBADDATA;
goto err;
}
/* Send follow-up request. */
- proc->write_reliable.cur_attr++;
+ attr->offset += proc->write_reliable.length;
+ if (attr->offset >= OS_MBUF_PKTLEN(attr->om)) {
+ attr->offset = 0;
+ proc->write_reliable.cur_attr++;
+ }
rc = ble_gattc_write_reliable_go(proc, 1);
if (rc != 0) {
goto err;
@@ -3623,13 +3817,16 @@ ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc *proc, int status)
}
/**
- * Initiates GATT procedure: Reliable Writes.
+ * Initiates GATT procedure: Reliable Writes. This function consumes the
+ * supplied mbufs regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attrs An array of attribute descriptors; specifies
* which characteristics to write to and what
- * data to write to them.
+ * data to write to them. The mbuf pointer in
+ * each attribute is set to NULL by this
+ * function.
* @param num_attrs The number of characteristics to write; equal
* to the number of elements in the 'attrs'
* array.
@@ -3640,9 +3837,9 @@ ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc *proc, int status)
*/
int
ble_gattc_write_reliable(uint16_t conn_handle,
- const struct ble_gatt_attr *attrs,
- int num_attrs, ble_gatt_reliable_attr_fn *cb,
- void *cb_arg)
+ struct ble_gatt_attr *attrs,
+ int num_attrs,
+ ble_gatt_reliable_attr_fn *cb, void *cb_arg)
{
#if !NIMBLE_OPT(GATT_WRITE_RELIABLE)
return BLE_HS_ENOTSUP;
@@ -3650,9 +3847,17 @@ ble_gattc_write_reliable(uint16_t conn_handle,
struct ble_gattc_proc *proc;
int rc;
+ int i;
+
+ proc = NULL;
STATS_INC(ble_gattc_stats, write_reliable);
+ if (num_attrs > NIMBLE_OPT(GATT_WRITE_MAX_ATTRS)) {
+ rc = BLE_HS_EINVAL;
+ goto done;
+ }
+
proc = ble_gattc_proc_alloc();
if (proc == NULL) {
rc = BLE_HS_ENOMEM;
@@ -3661,12 +3866,19 @@ ble_gattc_write_reliable(uint16_t conn_handle,
proc->op = BLE_GATT_OP_WRITE_RELIABLE;
proc->conn_handle = conn_handle;
- proc->write_reliable.attrs = attrs;
proc->write_reliable.num_attrs = num_attrs;
proc->write_reliable.cur_attr = 0;
proc->write_reliable.cb = cb;
proc->write_reliable.cb_arg = cb_arg;
+ for (i = 0; i < num_attrs; i++) {
+ proc->write_reliable.attrs[i] = attrs[i];
+ proc->write_reliable.attrs[i].offset = 0;
+
+ /* Consume mbuf from caller. */
+ attrs[i].om = NULL;
+ }
+
ble_gattc_log_write_reliable(proc);
rc = ble_gattc_write_reliable_go(proc, 1);
@@ -3679,6 +3891,12 @@ done:
STATS_INC(ble_gattc_stats, write_reliable_fail);
}
+ /* Free supplied mbufs in case something failed. */
+ for (i = 0; i < num_attrs; i++) {
+ os_mbuf_free_chain(attrs[i].om);
+ attrs[i].om = NULL;
+ }
+
ble_gattc_process_status(proc, rc);
return rc;
}
@@ -3688,54 +3906,59 @@ done:
*****************************************************************************/
/**
- * Sends a "free-form" characteristic notification. The content of the message
- * is specified in the attr parameter.
+ * Sends a "free-form" characteristic notification. This function consumes the
+ * supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The attribute handle to indicate in the
* outgoing notification.
- * @param attr_data The characteristic value to include in the
- * outgoing notification.
- * @param attr_data_len The number of bytes of attribute data to include
- * in the notification.
+ * @param txom The value to write to the characteristic.
+ * Double indirection is used to effect a
+ * transfer of ownership from the caller.
*
* @return 0 on success; nonzero on failure.
*/
int
ble_gattc_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle,
- const void *attr_data, uint16_t attr_data_len)
+ struct os_mbuf **txom)
{
#if !NIMBLE_OPT(GATT_NOTIFY)
return BLE_HS_ENOTSUP;
#endif
- struct ble_att_svr_access_ctxt ctxt;
struct ble_att_notify_req req;
+ struct os_mbuf *om;
int rc;
STATS_INC(ble_gattc_stats, notify);
ble_gattc_log_notify(chr_val_handle);
- if (attr_data == NULL) {
+ if (txom != NULL) {
+ /* Consume mbuf from caller. */
+ om = *txom;
+ *txom = NULL;
+ } else {
/* No custom attribute data; read the value from the specified
* attribute.
*/
+ om = ble_hs_mbuf_att_pkt();
+ if (om == NULL) {
+ rc = BLE_HS_ENOMEM;
+ goto done;
+ }
rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE,
- chr_val_handle, &ctxt, NULL);
+ chr_val_handle, 0, om, NULL);
if (rc != 0) {
/* Fatal error; application disallowed attribute read. */
rc = BLE_HS_EAPP;
goto done;
}
-
- attr_data = ctxt.read.data;
- attr_data_len = ctxt.read.len;
}
req.banq_handle = chr_val_handle;
- rc = ble_att_clt_tx_notify(conn_handle, &req, attr_data, attr_data_len);
+ rc = ble_att_clt_tx_notify(conn_handle, &req, &om);
if (rc != 0) {
goto done;
}
@@ -3747,12 +3970,14 @@ done:
STATS_INC(ble_gattc_stats, notify_fail);
}
+ os_mbuf_free_chain(om);
+
return rc;
}
/**
- * Sends a characteristic notification. The content of the message is read from
- * the specified characteristic.
+ * Sends a characteristic notification. The content of the message is read
+ * from the specified characteristic.
*
* @param conn_handle The connection over which to execute the
* procedure.
@@ -3771,7 +3996,7 @@ ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle)
int rc;
- rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, NULL, 0);
+ rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, NULL);
/* Tell the application that a notification transmission was attempted. */
ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 0);
@@ -3867,10 +4092,10 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle)
return BLE_HS_ENOTSUP;
#endif
- struct ble_att_svr_access_ctxt ctxt;
struct ble_att_indicate_req req;
struct ble_gattc_proc *proc;
struct ble_hs_conn *conn;
+ struct os_mbuf *om;
int rc;
STATS_INC(ble_gattc_stats, indicate);
@@ -3887,8 +4112,14 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle)
ble_gattc_log_indicate(chr_val_handle);
- rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, chr_val_handle,
- &ctxt, NULL);
+ om = ble_hs_mbuf_att_pkt();
+ if (om == NULL) {
+ rc = BLE_HS_ENOMEM;
+ goto done;
+ }
+
+ rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, chr_val_handle, 0,
+ om, NULL);
if (rc != 0) {
/* Fatal error; application disallowed attribute read. */
BLE_HS_DBG_ASSERT(0);
@@ -3897,9 +4128,7 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle)
}
req.baiq_handle = chr_val_handle;
- rc = ble_att_clt_tx_indicate(conn_handle, &req,
- ctxt.read.data, ctxt.read.len);
-
+ rc = ble_att_clt_tx_indicate(conn_handle, &req, &om);
if (rc != 0) {
goto done;
}
@@ -3922,6 +4151,7 @@ done:
ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 1);
ble_gattc_process_status(proc, rc);
+ os_mbuf_free_chain(om);
return rc;
}
@@ -4149,8 +4379,7 @@ ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int status)
* procedure.
*/
void
-ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value,
- int value_len)
+ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, struct os_mbuf **om)
{
#if !NIMBLE_OPT(ATT_CLT_READ)
return;
@@ -4164,7 +4393,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value,
ble_gattc_rx_read_rsp_entries,
&rx_entry);
if (proc != NULL) {
- rc = rx_entry->cb(proc, status, value, value_len);
+ rc = rx_entry->cb(proc, status, om);
ble_gattc_process_status(proc, rc);
}
}
@@ -4175,7 +4404,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value,
*/
void
ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status,
- void *value, int value_len)
+ struct os_mbuf **om)
{
#if !NIMBLE_OPT(ATT_CLT_READ_BLOB)
return;
@@ -4186,7 +4415,7 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status,
proc = ble_gattc_extract(conn_handle, BLE_GATT_OP_READ_LONG);
if (proc != NULL) {
- rc = ble_gattc_read_long_rx_read_rsp(proc, status, value, value_len);
+ rc = ble_gattc_read_long_rx_read_rsp(proc, status, om);
ble_gattc_process_status(proc, rc);
}
}
@@ -4197,7 +4426,7 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status,
*/
void
ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status,
- void *value, int value_len)
+ struct os_mbuf **om)
{
#if !NIMBLE_OPT(ATT_CLT_READ_MULT)
return;
@@ -4207,7 +4436,7 @@ ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status,
proc = ble_gattc_extract(conn_handle, BLE_GATT_OP_READ_MULT);
if (proc != NULL) {
- ble_gattc_read_mult_cb(proc, status, 0, value, value_len);
+ ble_gattc_read_mult_cb(proc, status, 0, om);
ble_gattc_process_status(proc, BLE_HS_EDONE);
}
}
@@ -4239,7 +4468,7 @@ ble_gattc_rx_write_rsp(uint16_t conn_handle)
void
ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status,
struct ble_att_prep_write_cmd *rsp,
- void *attr_data, uint16_t attr_data_len)
+ struct os_mbuf **om)
{
#if !NIMBLE_OPT(ATT_CLT_PREP_WRITE)
return;
@@ -4253,7 +4482,7 @@ ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status,
ble_gattc_rx_prep_entries,
&rx_entry);
if (proc != NULL) {
- rc = rx_entry->cb(proc, status, rsp, attr_data, attr_data_len);
+ rc = rx_entry->cb(proc, status, rsp, om);
ble_gattc_process_status(proc, rc);
}
}