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 2015/11/20 03:09:59 UTC
incubator-mynewt-larva git commit: att find type value command.
Repository: incubator-mynewt-larva
Updated Branches:
refs/heads/master 0c08cbb69 -> 34a6d69f2
att find type value command.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/34a6d69f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/34a6d69f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/34a6d69f
Branch: refs/heads/master
Commit: 34a6d69f282276e496e45df25bce90081b02a511
Parents: 0c08cbb
Author: Christopher Collins <cc...@gmail.com>
Authored: Thu Nov 19 18:09:39 2015 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Thu Nov 19 18:09:39 2015 -0800
----------------------------------------------------------------------
libs/os/include/os/os_mbuf.h | 4 +
libs/os/src/os_mbuf.c | 86 ++++
net/nimble/host/src/ble_hs_att.c | 538 ++++++++++++++++++-----
net/nimble/host/src/ble_hs_att.h | 2 +
net/nimble/host/src/ble_hs_uuid.c | 10 +-
net/nimble/host/src/ble_hs_uuid.h | 2 +-
net/nimble/host/src/ble_l2cap.c | 56 ++-
net/nimble/host/src/ble_l2cap.h | 3 +-
net/nimble/host/src/test/ble_hs_att_test.c | 331 ++++++++++++--
net/nimble/host/src/test/ble_hs_uuid_test.c | 8 +-
10 files changed, 893 insertions(+), 147 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/libs/os/include/os/os_mbuf.h
----------------------------------------------------------------------
diff --git a/libs/os/include/os/os_mbuf.h b/libs/os/include/os/os_mbuf.h
index a4d4075..289e739 100644
--- a/libs/os/include/os/os_mbuf.h
+++ b/libs/os/include/os/os_mbuf.h
@@ -205,6 +205,8 @@ struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp);
/* Duplicate a mbuf from the pool */
struct os_mbuf *os_mbuf_dup(struct os_mbuf_pool *omp, struct os_mbuf *m);
+struct os_mbuf * os_mbuf_off(struct os_mbuf *om, int off, int *out_off);
+
/* Copy data from an mbuf to a flat buffer. */
int os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst);
@@ -219,6 +221,8 @@ int os_mbuf_free(struct os_mbuf_pool *omp, struct os_mbuf *mb);
int os_mbuf_free_chain(struct os_mbuf_pool *omp, struct os_mbuf *om);
void os_mbuf_adj(struct os_mbuf_pool *omp, struct os_mbuf *mp, int req_len);
+int os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data,
+ int len);
#endif /* _OS_MBUF_H */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/libs/os/src/os_mbuf.c
----------------------------------------------------------------------
diff --git a/libs/os/src/os_mbuf.c b/libs/os/src/os_mbuf.c
index f78d373..75f9074 100644
--- a/libs/os/src/os_mbuf.c
+++ b/libs/os/src/os_mbuf.c
@@ -326,6 +326,37 @@ err:
return (NULL);
}
+/**
+ * Locates the specified absolute offset within an mbuf chain. The offset
+ * can be one past than the total length of the chain, but no greater.
+ *
+ * @param om The start of the mbuf chain to seek within.
+ * @param off The absolute address to find.
+ * @param out_off On success, this points to the relative offset
+ * within the returned mbuf.
+ *
+ * @return The mbuf containing the specified offset on
+ * success.
+ * NULL if the specified offset is out of bounds.
+ */
+struct os_mbuf *
+os_mbuf_off(struct os_mbuf *om, int off, int *out_off)
+{
+ while (1) {
+ if (om == NULL) {
+ return NULL;
+ }
+
+ if (om->om_len >= off) {
+ *out_off = off;
+ return om;
+ }
+
+ off -= om->om_len;
+ om = SLIST_NEXT(om, om_next);
+ }
+}
+
/*
* Copy data from an mbuf chain starting "off" bytes from the beginning,
* continuing for "len" bytes, into the indicated buffer.
@@ -436,6 +467,61 @@ os_mbuf_adj(struct os_mbuf_pool *omp, struct os_mbuf *mp, int req_len)
}
}
+/**
+ * Performs a memory compare of the specified region of an mbuf chain against a
+ * flat buffer.
+ *
+ * @param om The start of the mbuf chain to compare.
+ * @param off The offset within the mbuf chain to start the
+ * comparison.
+ * @param data The flat buffer to compare.
+ * @param len The length of the flat buffer.
+ *
+ * @return 0 if both memory regions are identical;
+ * A memcmp return code if there is a mismatch;
+ * -1 if the mbuf is too short.
+ */
+int
+os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data, int len)
+{
+ int chunk_sz;
+ int data_off;
+ int om_off;
+ int rc;
+
+ if (len <= 0) {
+ return 0;
+ }
+
+ data_off = 0;
+ om = os_mbuf_off((struct os_mbuf *)om, off, &om_off);
+ while (1) {
+ if (om == NULL) {
+ return -1;
+ }
+
+ chunk_sz = min(om->om_len - om_off, len - data_off);
+ if (chunk_sz > 0) {
+ rc = memcmp(om->om_data + om_off, data + data_off, chunk_sz);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+
+ data_off += chunk_sz;
+ if (data_off == len) {
+ return 0;
+ }
+
+ om = SLIST_NEXT(om, om_next);
+ om_off = 0;
+
+ if (om == NULL) {
+ return -1;
+ }
+ }
+}
+
#if 0
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/net/nimble/host/src/ble_hs_att.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_att.c b/net/nimble/host/src/ble_hs_att.c
index 4e17551..02fc2a2 100644
--- a/net/nimble/host/src/ble_hs_att.c
+++ b/net/nimble/host/src/ble_hs_att.c
@@ -26,8 +26,6 @@
#include "ble_hs_att_cmd.h"
#include "ble_hs_att.h"
-static uint8_t *ble_hs_att_tx_buf;
-
typedef int ble_hs_att_rx_fn(struct ble_hs_conn *conn,
struct ble_l2cap_chan *chan,
struct os_mbuf *om);
@@ -43,6 +41,9 @@ static int ble_hs_att_rx_mtu_req(struct ble_hs_conn *conn,
static int ble_hs_att_rx_find_info_req(struct ble_hs_conn *conn,
struct ble_l2cap_chan *chan,
struct os_mbuf *om);
+static int ble_hs_att_rx_find_type_value_req(struct ble_hs_conn *conn,
+ struct ble_l2cap_chan *chan,
+ struct os_mbuf *om);
static int ble_hs_att_rx_read_req(struct ble_hs_conn *conn,
struct ble_l2cap_chan *chan,
struct os_mbuf *om);
@@ -51,10 +52,11 @@ static int ble_hs_att_rx_write_req(struct ble_hs_conn *conn,
struct os_mbuf *om);
static struct ble_hs_att_rx_dispatch_entry ble_hs_att_rx_dispatch[] = {
- { BLE_HS_ATT_OP_MTU_REQ, ble_hs_att_rx_mtu_req },
- { BLE_HS_ATT_OP_FIND_INFO_REQ, ble_hs_att_rx_find_info_req },
- { BLE_HS_ATT_OP_READ_REQ, ble_hs_att_rx_read_req },
- { BLE_HS_ATT_OP_WRITE_REQ, ble_hs_att_rx_write_req },
+ { BLE_HS_ATT_OP_MTU_REQ, ble_hs_att_rx_mtu_req },
+ { BLE_HS_ATT_OP_FIND_INFO_REQ, ble_hs_att_rx_find_info_req },
+ { BLE_HS_ATT_OP_FIND_TYPE_VALUE_REQ, ble_hs_att_rx_find_type_value_req },
+ { BLE_HS_ATT_OP_READ_REQ, ble_hs_att_rx_read_req },
+ { BLE_HS_ATT_OP_WRITE_REQ, ble_hs_att_rx_write_req },
};
#define BLE_HS_ATT_RX_DISPATCH_SZ \
@@ -313,6 +315,7 @@ ble_hs_att_tx_error_rsp(struct ble_l2cap_chan *chan, uint8_t req_op,
uint16_t handle, uint8_t error_code)
{
struct ble_hs_att_error_rsp rsp;
+ uint8_t buf[BLE_HS_ATT_ERROR_RSP_SZ];
int rc;
rsp.bhaep_op = BLE_HS_ATT_OP_ERROR_RSP;
@@ -320,11 +323,10 @@ ble_hs_att_tx_error_rsp(struct ble_l2cap_chan *chan, uint8_t req_op,
rsp.bhaep_handle = handle;
rsp.bhaep_error_code = error_code;
- rc = ble_hs_att_error_rsp_write(ble_hs_att_tx_buf,
- BLE_HS_ATT_ERROR_RSP_SZ, &rsp);
+ rc = ble_hs_att_error_rsp_write(buf, sizeof buf, &rsp);
assert(rc == 0);
- rc = ble_l2cap_tx(chan, ble_hs_att_tx_buf, BLE_HS_ATT_ERROR_RSP_SZ);
+ rc = ble_l2cap_tx_flat(chan, buf, BLE_HS_ATT_ERROR_RSP_SZ);
if (rc != 0) {
return rc;
}
@@ -336,6 +338,7 @@ static int
ble_hs_att_tx_mtu_cmd(struct ble_l2cap_chan *chan, uint8_t op, uint16_t mtu)
{
struct ble_hs_att_mtu_cmd cmd;
+ uint8_t buf[BLE_HS_ATT_MTU_CMD_SZ];
int rc;
assert(!(chan->blc_flags & BLE_L2CAP_CHAN_F_TXED_MTU));
@@ -345,11 +348,10 @@ ble_hs_att_tx_mtu_cmd(struct ble_l2cap_chan *chan, uint8_t op, uint16_t mtu)
cmd.bhamc_op = op;
cmd.bhamc_mtu = mtu;
- rc = ble_hs_att_mtu_cmd_write(ble_hs_att_tx_buf, BLE_HS_ATT_MTU_MAX,
- &cmd);
+ rc = ble_hs_att_mtu_cmd_write(buf, sizeof buf, &cmd);
assert(rc == 0);
- rc = ble_l2cap_tx(chan, ble_hs_att_tx_buf, BLE_HS_ATT_MTU_CMD_SZ);
+ rc = ble_l2cap_tx_flat(chan, buf, sizeof buf);
if (rc != 0) {
return rc;
}
@@ -364,6 +366,7 @@ ble_hs_att_rx_mtu_req(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
struct os_mbuf *om)
{
struct ble_hs_att_mtu_cmd cmd;
+ uint8_t buf[BLE_HS_ATT_MTU_CMD_SZ];
int rc;
/* We should only receive this command as a server. */
@@ -372,11 +375,10 @@ ble_hs_att_rx_mtu_req(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
return EINVAL;
}
- rc = os_mbuf_copydata(om, 0, BLE_HS_ATT_MTU_CMD_SZ, ble_hs_att_tx_buf);
+ rc = os_mbuf_copydata(om, 0, sizeof buf, buf);
assert(rc == 0);
- rc = ble_hs_att_mtu_cmd_parse(ble_hs_att_tx_buf, BLE_HS_ATT_MTU_CMD_SZ,
- &cmd);
+ rc = ble_hs_att_mtu_cmd_parse(buf, sizeof buf, &cmd);
assert(rc == 0);
if (cmd.bhamc_mtu < BLE_HS_ATT_MTU_DFLT) {
@@ -394,16 +396,14 @@ ble_hs_att_rx_mtu_req(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
}
/**
- * Fills the static ATT transmit buffer with the variable length Information
- * Data field of a Find Information ATT response.
+ * Fills the supplied mbuf with the variable length Information Data field of a
+ * Find Information ATT response.
*
* @param req The Find Information request being responded
* to.
- * @param buf The destination buffer where the Information
+ * @param om The destination mbuf where the Information
* Data field gets written.
- * @param buf_sz The maximum size of the output data.
- * @param rsp_sz On success, the number of bytes written gets
- * stored here.
+ * @param mtu The ATT L2CAP channel MTU.
* @param format On success, the format field of the response
* gets stored here. One of:
* o BLE_HS_ATT_FIND_INFO_RSP_FORMAT_16BIT
@@ -412,27 +412,32 @@ ble_hs_att_rx_mtu_req(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
* @return 0 on success; an ATT error code on failure.
*/
static int
-ble_hs_att_fill_info(struct ble_hs_att_find_info_req *req, uint8_t *buf,
- int buf_sz, int *rsp_sz, uint8_t *format)
+ble_hs_att_fill_info(struct ble_hs_att_find_info_req *req, struct os_mbuf *om,
+ uint16_t mtu, uint8_t *format)
{
struct ble_hs_att_entry *ha;
- int new_rsp_sz;
- int uuid16;
+ uint16_t handle_id;
+ uint16_t uuid16;
+ int num_entries;
+ int rsp_sz;
+ int rc;
*format = 0;
- *rsp_sz = 0;
+ num_entries = 0;
+ rc = 0;
ble_hs_att_list_lock();
STAILQ_FOREACH(ha, &g_ble_hs_att_list, ha_next) {
if (ha->ha_handle_id > req->bhafq_end_handle) {
+ rc = 0;
goto done;
}
if (ha->ha_handle_id >= req->bhafq_start_handle) {
uuid16 = ble_hs_uuid_16bit(ha->ha_uuid);
if (*format == 0) {
- if (uuid16 != -1) {
+ if (uuid16 != 0) {
*format = BLE_HS_ATT_FIND_INFO_RSP_FORMAT_16BIT;
} else {
*format = BLE_HS_ATT_FIND_INFO_RSP_FORMAT_128BIT;
@@ -441,69 +446,97 @@ ble_hs_att_fill_info(struct ble_hs_att_find_info_req *req, uint8_t *buf,
switch (*format) {
case BLE_HS_ATT_FIND_INFO_RSP_FORMAT_16BIT:
- if (uuid16 == -1) {
+ if (uuid16 == 0) {
+ rc = 0;
+ goto done;
+ }
+
+ rsp_sz = OS_MBUF_PKTHDR(om)->omp_len + 4;
+ if (rsp_sz > mtu) {
+ rc = 0;
goto done;
}
- new_rsp_sz = *rsp_sz + 4;
- if (new_rsp_sz > buf_sz) {
+ htole16(&handle_id, ha->ha_handle_id);
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, om, &handle_id, 2);
+ if (rc != 0) {
goto done;
}
- htole16(buf + *rsp_sz, ha->ha_handle_id);
- htole16(buf + *rsp_sz + 2, uuid16);
- *rsp_sz = new_rsp_sz;
+ htole16(&uuid16, uuid16);
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, om, &uuid16, 2);
+ if (rc != 0) {
+ goto done;
+ }
break;
case BLE_HS_ATT_FIND_INFO_RSP_FORMAT_128BIT:
- if (uuid16 != -1) {
+ if (uuid16 != 0) {
+ rc = 0;
+ goto done;
+ }
+
+ rsp_sz = OS_MBUF_PKTHDR(om)->omp_len + 18;
+ if (rsp_sz > mtu) {
+ rc = 0;
goto done;
}
- new_rsp_sz = *rsp_sz + 18;
- if (new_rsp_sz > buf_sz) {
+ htole16(&handle_id, ha->ha_handle_id);
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, om, &handle_id, 2);
+ if (rc != 0) {
goto done;
}
- htole16(buf + *rsp_sz, ha->ha_handle_id);
- memcpy(buf + *rsp_sz + 2, ha->ha_uuid, 16);
- *rsp_sz = new_rsp_sz;
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, om, &ha->ha_uuid,
+ 16);
+ if (rc != 0) {
+ goto done;
+ }
break;
default:
assert(0);
break;
}
+
+ num_entries++;
}
}
done:
ble_hs_att_list_unlock();
- if (*rsp_sz == 0) {
+
+ if (rc == 0 && num_entries == 0) {
return ENOENT;
} else {
- return 0;
+ return rc;
}
}
static int
ble_hs_att_rx_find_info_req(struct ble_hs_conn *conn,
struct ble_l2cap_chan *chan,
- struct os_mbuf *om)
+ struct os_mbuf *rxom)
{
struct ble_hs_att_find_info_req req;
struct ble_hs_att_find_info_rsp rsp;
- int rsp_sz;
+ struct os_mbuf *txom;
+ uint8_t buf[max(BLE_HS_ATT_FIND_INFO_REQ_SZ,
+ BLE_HS_ATT_FIND_INFO_RSP_MIN_SZ)];
int rc;
- rc = os_mbuf_copydata(om, 0, BLE_HS_ATT_FIND_INFO_REQ_SZ,
- ble_hs_att_tx_buf);
+ txom = NULL;
+
+ rc = os_mbuf_copydata(rxom, 0, BLE_HS_ATT_FIND_INFO_REQ_SZ, buf);
if (rc != 0) {
- return rc;
+ req.bhafq_start_handle = 0;
+ rc = BLE_HS_ATT_ERR_INVALID_PDU;
+ goto err;
}
- rc = ble_hs_att_find_info_req_parse(ble_hs_att_tx_buf,
- BLE_HS_ATT_FIND_INFO_REQ_SZ, &req);
+ rc = ble_hs_att_find_info_req_parse(buf, BLE_HS_ATT_FIND_INFO_REQ_SZ,
+ &req);
assert(rc == 0);
/* Tx error response if start handle is greater than end handle or is equal
@@ -512,59 +545,358 @@ ble_hs_att_rx_find_info_req(struct ble_hs_conn *conn,
if (req.bhafq_start_handle > req.bhafq_end_handle ||
req.bhafq_start_handle == 0) {
- ble_hs_att_tx_error_rsp(chan, BLE_HS_ATT_OP_FIND_INFO_REQ,
- req.bhafq_start_handle,
- BLE_HS_ATT_ERR_INVALID_HANDLE);
- return EINVAL;
+ rc = BLE_HS_ATT_ERR_INVALID_HANDLE;
+ goto err;
}
- /* Write the variable length Information Data field, reserving room for the
- * response base at the start of the buffer.
- */
- rc = ble_hs_att_fill_info(
- &req,
- ble_hs_att_tx_buf + BLE_HS_ATT_FIND_INFO_RSP_MIN_SZ,
- ble_l2cap_chan_mtu(chan) - BLE_HS_ATT_FIND_INFO_RSP_MIN_SZ,
- &rsp_sz,
- &rsp.bhafp_format);
- if (rc != 0) {
- ble_hs_att_tx_error_rsp(chan, BLE_HS_ATT_OP_FIND_INFO_REQ,
- req.bhafq_start_handle,
- BLE_HS_ATT_ERR_ATTR_NOT_FOUND);
- return rc;
-
+ txom = os_mbuf_get_pkthdr(&ble_l2cap_mbuf_pool);
+ if (txom == NULL) {
+ rc = BLE_HS_ATT_ERR_INSUFFICIENT_RES;
+ goto err;
}
- /* Now that the value of the format field is known, write the response base
- * at the start of the buffer.
+ /* Write the response base at the start of the buffer. The format field is
+ * unknown at this point; it will be filled in later.
*/
rsp.bhafp_op = BLE_HS_ATT_OP_FIND_INFO_RSP;
- rc = ble_hs_att_find_info_rsp_write(ble_hs_att_tx_buf,
- BLE_HS_ATT_FIND_INFO_RSP_MIN_SZ,
+ rc = ble_hs_att_find_info_rsp_write(buf, BLE_HS_ATT_FIND_INFO_RSP_MIN_SZ,
&rsp);
assert(rc == 0);
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, txom, buf,
+ BLE_HS_ATT_FIND_INFO_RSP_MIN_SZ);
+ if (rc != 0) {
+ rc = BLE_HS_ATT_ERR_INSUFFICIENT_RES;
+ goto err;
+ }
+
+ /* Write the variable length Information Data field, populating the format
+ * field as appropriate.
+ */
+ rc = ble_hs_att_fill_info(&req, txom, ble_l2cap_chan_mtu(chan),
+ txom->om_data + 1);
+ if (rc != 0) {
+ rc = BLE_HS_ATT_ERR_ATTR_NOT_FOUND;
+ goto err;
+ }
+
+ rc = ble_l2cap_tx(chan, txom);
+ txom = NULL;
+ if (rc != 0) {
+ goto err;
+ }
+
+ return 0;
+
+err:
+ os_mbuf_free_chain(&ble_l2cap_mbuf_pool, txom);
+ ble_hs_att_tx_error_rsp(chan, BLE_HS_ATT_OP_FIND_INFO_REQ,
+ req.bhafq_start_handle, rc);
+
+ return rc;
+}
+
+/**
+ * Processes a single non-matching attribute entry while filling a
+ * Find-By-Type-Value-Response.
+ *
+ * @param om The response mbuf.
+ * @param first Pointer to the first matching handle ID in the
+ * current group of IDs. 0 if there is not a
+ * current group.
+ * @param prev Pointer to the most recent matching handle ID
+ * in the current group of IDs. 0 if there is
+ * not a current group.
+ * @param mtu The ATT L2CAP channel MTU.
+ *
+ * @return 0 if the response should be sent;
+ * EAGAIN if the entry was successfully processed
+ * and subsequent entries can be inspected.
+ * Other nonzero on error.
+ */
+static int
+ble_hs_att_fill_type_value_no_match(struct os_mbuf *om, uint16_t *first,
+ uint16_t *prev, int mtu)
+{
+ uint16_t u16;
+ int rsp_sz;
+ int rc;
+
+ /* If there is no current group, then there is nothing to do. */
+ if (*first == 0) {
+ return EAGAIN;
+ }
+
+ rsp_sz = OS_MBUF_PKTHDR(om)->omp_len + 4;
+ if (rsp_sz > mtu) {
+ return 0;
+ }
+
+ u16 = *first;
+ htole16(&u16, u16);
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, om, &u16, 2);
+ if (rc != 0) {
+ return ENOMEM;
+ }
- rc = ble_l2cap_tx(chan, ble_hs_att_tx_buf,
- BLE_HS_ATT_FIND_INFO_RSP_MIN_SZ + rsp_sz);
+ u16 = *prev;
+ htole16(&u16, u16);
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, om, &u16, 2);
if (rc != 0) {
+ return ENOMEM;
+ }
+
+ *first = 0;
+ *prev = 0;
+
+ return EAGAIN;
+}
+
+/**
+ * Processes a single matching attribute entry while filling a
+ * Find-By-Type-Value-Response.
+ *
+ * @param om The response mbuf.
+ * @param first Pointer to the first matching handle ID in the
+ * current group of IDs. 0 if there is not a
+ * current group.
+ * @param prev Pointer to the most recent matching handle ID
+ * in the current group of IDs. 0 if there is
+ * not a current group.
+ * @param handle_id The matching handle ID to process.
+ * @param mtu The ATT L2CAP channel MTU.
+ *
+ * @return 0 if the response should be sent;
+ * EAGAIN if the entry was successfully processed
+ * and subsequent entries can be inspected.
+ * Other nonzero on error.
+ */
+static int
+ble_hs_att_fill_type_value_match(struct os_mbuf *om, uint16_t *first,
+ uint16_t *prev, uint16_t handle_id, int mtu)
+{
+ int rc;
+
+ /* If this is the start of a group, record it as the first ID and keep
+ * searching.
+ */
+ if (*first == 0) {
+ *first = handle_id;
+ *prev = handle_id;
+ return EAGAIN;
+ }
+
+ /* If this is the continuation of a group, keep searching. */
+ if (handle_id == *prev + 1) {
+ *prev = handle_id;
+ return EAGAIN;
+ }
+
+ /* Otherwise, this handle is not a part of the previous group. Write the
+ * previous group to the response, and remember this ID as the start of the
+ * next group.
+ */
+ rc = ble_hs_att_fill_type_value_no_match(om, first, prev, mtu);
+ *first = handle_id;
+ *prev = handle_id;
+ return rc;
+}
+
+/**
+ * Fills the supplied mbuf with the variable length Handles-Information-List
+ * field of a Find-By-Type-Value ATT response.
+ *
+ * @param req The Find-By-Type-Value-Request being responded
+ * to.
+ * @param rxom The mbuf containing the received request.
+ * @param txom The destination mbuf where the
+ * Handles-Information-List field gets
+ * written.
+ * @param mtu The ATT L2CAP channel MTU.
+ *
+ * @return 0 on success; an ATT error code on failure.
+ */
+static int
+ble_hs_att_fill_type_value(struct ble_hs_att_find_type_value_req *req,
+ struct os_mbuf *rxom, struct os_mbuf *txom,
+ uint16_t mtu)
+{
+ union ble_hs_att_handle_arg arg;
+ struct ble_hs_att_entry *ha;
+ uint16_t uuid16;
+ uint16_t first;
+ uint16_t prev;
+ int any_entries;
+ int match;
+ int rc;
+
+ first = 0;
+ prev = 0;
+ rc = 0;
+
+ ble_hs_att_list_lock();
+
+ /* Iterate through the attribute list, keeping track of the current
+ * matching group. For each attribute entry, determine if data needs to be
+ * written to the response.
+ */
+ STAILQ_FOREACH(ha, &g_ble_hs_att_list, ha_next) {
+ match = 0;
+
+ if (ha->ha_handle_id > req->bhavq_end_handle) {
+ break;
+ }
+
+ if (ha->ha_handle_id >= req->bhavq_start_handle) {
+ /* Compare the attribute type and value to the request fields to
+ * determine if this attribute matches.
+ */
+ uuid16 = ble_hs_uuid_16bit(ha->ha_uuid);
+ if (uuid16 == req->bhavq_attr_type) {
+ rc = ha->ha_fn(ha, BLE_HS_ATT_OP_READ_REQ, &arg);
+ if (rc != 0) {
+ rc = BLE_HS_ATT_ERR_UNLIKELY;
+ goto done;
+ }
+ rc = os_mbuf_memcmp(rxom,
+ BLE_HS_ATT_FIND_TYPE_VALUE_REQ_MIN_SZ,
+ arg.aha_read.attr_data,
+ arg.aha_read.attr_len);
+ if (rc == 0) {
+ match = 1;
+ }
+ }
+ }
+
+ if (match) {
+ rc = ble_hs_att_fill_type_value_match(txom, &first, &prev,
+ ha->ha_handle_id, mtu);
+ } else {
+ rc = ble_hs_att_fill_type_value_no_match(txom, &first, &prev, mtu);
+ }
+
+ if (rc == 0) {
+ goto done;
+ }
+ if (rc != EAGAIN) {
+ rc = BLE_HS_ATT_ERR_UNLIKELY;
+ goto done;
+ }
+ }
+
+ /* Process one last non-matching ID in case a group was in progress when
+ * the end of the attribute list was reached.
+ */
+ rc = ble_hs_att_fill_type_value_no_match(txom, &first, &prev, mtu);
+ if (rc == EAGAIN) {
+ rc = 0;
+ } else if (rc != 0) {
+ rc = BLE_HS_ATT_ERR_UNLIKELY;
+ }
+
+done:
+ ble_hs_att_list_unlock();
+
+ any_entries = OS_MBUF_PKTHDR(txom)->omp_len >
+ BLE_HS_ATT_FIND_TYPE_VALUE_RSP_MIN_SZ;
+ if (rc == 0 && !any_entries) {
+ return BLE_HS_ATT_ERR_ATTR_NOT_FOUND;
+ } else {
return rc;
}
+}
+
+static int
+ble_hs_att_rx_find_type_value_req(struct ble_hs_conn *conn,
+ struct ble_l2cap_chan *chan,
+ struct os_mbuf *rxom)
+{
+ struct ble_hs_att_find_type_value_req req;
+ struct os_mbuf *txom;
+ uint8_t buf[max(BLE_HS_ATT_FIND_TYPE_VALUE_REQ_MIN_SZ,
+ BLE_HS_ATT_FIND_TYPE_VALUE_RSP_MIN_SZ)];
+ int rc;
+
+ txom = NULL;
+
+ rc = os_mbuf_copydata(rxom, 0, BLE_HS_ATT_FIND_TYPE_VALUE_REQ_MIN_SZ, buf);
+ if (rc != 0) {
+ req.bhavq_start_handle = 0;
+ rc = BLE_HS_ATT_ERR_INVALID_PDU;
+ goto err;
+ }
+
+ rc = ble_hs_att_find_type_value_req_parse(
+ buf, BLE_HS_ATT_FIND_TYPE_VALUE_REQ_MIN_SZ, &req);
+ assert(rc == 0);
+
+ /* Tx error response if start handle is greater than end handle or is equal
+ * to 0 (Vol. 3, Part F, 3.4.3.3).
+ */
+ if (req.bhavq_start_handle > req.bhavq_end_handle ||
+ req.bhavq_start_handle == 0) {
+
+ rc = BLE_HS_ATT_ERR_INVALID_HANDLE;
+ goto err;
+ }
+
+ txom = os_mbuf_get_pkthdr(&ble_l2cap_mbuf_pool);
+ if (txom == NULL) {
+ rc = BLE_HS_ATT_ERR_INSUFFICIENT_RES;
+ goto err;
+ }
+
+ /* Write the response base at the start of the buffer. */
+ buf[0] = BLE_HS_ATT_OP_FIND_TYPE_VALUE_RSP;
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, txom, buf,
+ BLE_HS_ATT_FIND_TYPE_VALUE_RSP_MIN_SZ);
+ if (rc != 0) {
+ rc = BLE_HS_ATT_ERR_INSUFFICIENT_RES;
+ goto err;
+ }
+
+ /* Write the variable length Information Data field. */
+ rc = ble_hs_att_fill_type_value(&req, rxom, txom,
+ ble_l2cap_chan_mtu(chan));
+ if (rc != 0) {
+ goto err;
+ }
+
+ rc = ble_l2cap_tx(chan, txom);
+ txom = NULL;
+ if (rc != 0) {
+ rc = BLE_HS_ATT_ERR_UNLIKELY;
+ goto err;
+ }
return 0;
+
+err:
+ os_mbuf_free_chain(&ble_l2cap_mbuf_pool, txom);
+ ble_hs_att_tx_error_rsp(chan, BLE_HS_ATT_OP_FIND_TYPE_VALUE_REQ,
+ req.bhavq_start_handle, rc);
+ return rc;
}
static int
ble_hs_att_tx_read_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
void *attr_data, int attr_len)
{
+ struct os_mbuf *txom;
uint16_t data_len;
uint8_t op;
int rc;
+ txom = os_mbuf_get_pkthdr(&ble_l2cap_mbuf_pool);
+ if (txom == NULL) {
+ rc = BLE_HS_ATT_ERR_INSUFFICIENT_RES;
+ goto err;
+ }
+
op = BLE_HS_ATT_OP_READ_RSP;
- rc = ble_l2cap_tx(chan, &op, 1);
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, txom, &op, 1);
if (rc != 0) {
- return rc;
+ rc = BLE_HS_ATT_ERR_INSUFFICIENT_RES;
+ goto err;
}
/* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */
@@ -574,14 +906,23 @@ ble_hs_att_tx_read_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
data_len = attr_len;
}
- rc = ble_l2cap_tx(chan, attr_data, data_len);
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, txom, attr_data, data_len);
if (rc != 0) {
- return rc;
+ rc = BLE_HS_ATT_ERR_INSUFFICIENT_RES;
+ goto err;
}
- /* XXX: Kick L2CAP. */
+ rc = ble_l2cap_tx(chan, txom);
+ if (rc != 0) {
+ rc = BLE_HS_ATT_ERR_UNLIKELY;
+ goto err;
+ }
return 0;
+
+err:
+ os_mbuf_free_chain(&ble_l2cap_mbuf_pool, txom);
+ return rc;
}
static int
@@ -591,43 +932,45 @@ ble_hs_att_rx_read_req(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
union ble_hs_att_handle_arg arg;
struct ble_hs_att_read_req req;
struct ble_hs_att_entry *entry;
+ uint8_t buf[BLE_HS_ATT_READ_REQ_SZ];
int rc;
- rc = os_mbuf_copydata(om, 0, BLE_HS_ATT_READ_REQ_SZ, ble_hs_att_tx_buf);
+ rc = os_mbuf_copydata(om, 0, sizeof buf, buf);
if (rc != 0) {
- return rc;
+ req.bharq_handle = 0;
+ rc = BLE_HS_ATT_ERR_INVALID_PDU;
+ goto err;
}
- rc = ble_hs_att_read_req_parse(ble_hs_att_tx_buf, BLE_HS_ATT_READ_REQ_SZ,
- &req);
+ rc = ble_hs_att_read_req_parse(buf, sizeof buf, &req);
assert(rc == 0);
rc = ble_hs_att_find_by_handle(req.bharq_handle, &entry);
if (rc != 0) {
rc = BLE_HS_ATT_ERR_INVALID_HANDLE;
- goto send_err;
+ goto err;
}
if (entry->ha_fn == NULL) {
rc = BLE_ERR_UNSPECIFIED;
- goto send_err;
+ goto err;
}
rc = entry->ha_fn(entry, BLE_HS_ATT_OP_READ_REQ, &arg);
if (rc != 0) {
rc = BLE_ERR_UNSPECIFIED;
- goto send_err;
+ goto err;
}
rc = ble_hs_att_tx_read_rsp(conn, chan, arg.aha_read.attr_data,
arg.aha_read.attr_len);
if (rc != 0) {
- goto send_err;
+ goto err;
}
return 0;
-send_err:
+err:
ble_hs_att_tx_error_rsp(chan, BLE_HS_ATT_OP_READ_REQ,
req.bharq_handle, rc);
return rc;
@@ -640,13 +983,11 @@ ble_hs_att_tx_write_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan)
int rc;
op = BLE_HS_ATT_OP_WRITE_RSP;
- rc = ble_l2cap_tx(chan, &op, 1);
+ rc = ble_l2cap_tx_flat(chan, &op, 1);
if (rc != 0) {
return rc;
}
- /* XXX: Kick L2CAP. */
-
return 0;
}
@@ -657,16 +998,15 @@ ble_hs_att_rx_write_req(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
union ble_hs_att_handle_arg arg;
struct ble_hs_att_write_req req;
struct ble_hs_att_entry *entry;
+ uint8_t buf[BLE_HS_ATT_WRITE_REQ_MIN_SZ];
int rc;
- rc = os_mbuf_copydata(om, 0, BLE_HS_ATT_WRITE_REQ_MIN_SZ,
- ble_hs_att_tx_buf);
+ rc = os_mbuf_copydata(om, 0, sizeof buf, buf);
if (rc != 0) {
return rc;
}
- rc = ble_hs_att_write_req_parse(ble_hs_att_tx_buf,
- BLE_HS_ATT_WRITE_REQ_MIN_SZ, &req);
+ rc = ble_hs_att_write_req_parse(buf, sizeof buf, &req);
assert(rc == 0);
rc = ble_hs_att_find_by_handle(req.bhawq_handle, &entry);
@@ -772,21 +1112,11 @@ ble_hs_att_init(void)
goto err;
}
- free(ble_hs_att_tx_buf);
- ble_hs_att_tx_buf = malloc(BLE_HS_ATT_MTU_MAX);
- if (ble_hs_att_tx_buf == NULL) {
- rc = ENOMEM;
- goto err;
- }
-
return 0;
err:
free(ble_hs_att_entry_mem);
ble_hs_att_entry_mem = NULL;
- free(ble_hs_att_tx_buf);
- ble_hs_att_tx_buf = NULL;
-
return rc;
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/net/nimble/host/src/ble_hs_att.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_att.h b/net/nimble/host/src/ble_hs_att.h
index b8b5fe4..c782ea0 100644
--- a/net/nimble/host/src/ble_hs_att.h
+++ b/net/nimble/host/src/ble_hs_att.h
@@ -21,8 +21,10 @@
#define BLE_HS_ATT_MTU_MAX 256 /* XXX: I'm making this up! */
#define BLE_HS_ATT_ERR_INVALID_HANDLE 0x01
+#define BLE_HS_ATT_ERR_INVALID_PDU 0x04
#define BLE_HS_ATT_ERR_REQ_NOT_SUPPORTED 0x06
#define BLE_HS_ATT_ERR_ATTR_NOT_FOUND 0x0a
+#define BLE_HS_ATT_ERR_UNLIKELY 0x0e
#define BLE_HS_ATT_ERR_INSUFFICIENT_RES 0x11
struct ble_hs_att_entry;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/net/nimble/host/src/ble_hs_uuid.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_uuid.c b/net/nimble/host/src/ble_hs_uuid.c
index f905159..7a48569 100644
--- a/net/nimble/host/src/ble_hs_uuid.c
+++ b/net/nimble/host/src/ble_hs_uuid.c
@@ -29,9 +29,9 @@ static uint8_t ble_hs_uuid_base[16] = {
*
* @return Positive 16-bit unsigned integer on
* success;
- * -1 if the UUID could not be converted.
+ * 0 if the UUID could not be converted.
*/
-int
+uint16_t
ble_hs_uuid_16bit(uint8_t *uuid128)
{
uint16_t uuid16;
@@ -43,17 +43,17 @@ ble_hs_uuid_16bit(uint8_t *uuid128)
rc = memcmp(uuid128 + 4, ble_hs_uuid_base + 4,
sizeof ble_hs_uuid_base - 4);
if (rc != 0) {
- return -1;
+ return 0;
}
if (uuid128[0] != 0 || uuid128[1] != 0) {
/* This UUID has a 32-bit form, but not a 16-bit form. */
- return -1;
+ return 0;
}
uuid16 = (uuid128[2] << 8) + uuid128[3];
if (uuid16 == 0) {
- return -1;
+ return 0;
}
return uuid16;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/net/nimble/host/src/ble_hs_uuid.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_uuid.h b/net/nimble/host/src/ble_hs_uuid.h
index 013b5cb..8604457 100644
--- a/net/nimble/host/src/ble_hs_uuid.h
+++ b/net/nimble/host/src/ble_hs_uuid.h
@@ -17,6 +17,6 @@
#ifndef H_BLE_HS_UUID_
#define H_BLE_HS_UUID_
-int ble_hs_uuid_16bit(uint8_t *uuid128);
+uint16_t ble_hs_uuid_16bit(uint8_t *uuid128);
#endif /* _BLE_HOST_UUID_H */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/net/nimble/host/src/ble_l2cap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap.c b/net/nimble/host/src/ble_l2cap.c
index 07d0bef..b7ac4c6 100644
--- a/net/nimble/host/src/ble_l2cap.c
+++ b/net/nimble/host/src/ble_l2cap.c
@@ -221,23 +221,65 @@ ble_l2cap_rx(struct ble_hs_conn *conn,
return 0;
}
+/**
+ * Transmits the L2CAP payload contained in the specified mbuf. The supplied
+ * mbuf is consumed, regardless of the outcome of the function call.
+ *
+ * @param chan The L2CAP channel to transmit over.
+ * @param om The data to transmit.
+ *
+ * @return 0 on success; nonzero on error.
+ */
int
-ble_l2cap_tx(struct ble_l2cap_chan *chan, void *payload, int len)
+ble_l2cap_tx(struct ble_l2cap_chan *chan, struct os_mbuf *om)
{
+ /* XXX Enqueue mbuf. */
+ if (chan->blc_tx_buf != NULL) {
+ os_mbuf_free_chain(&ble_l2cap_mbuf_pool, chan->blc_tx_buf);
+ }
+
+ chan->blc_tx_buf = om;
+
+ return 0;
+}
+
+/**
+ * Transmits the L2CAP payload contained in the specified flat buffer.
+ *
+ * @param chan The L2CAP channel to transmit over.
+ * @param payload The data to transmit.
+ * @param len The number of data bytes to send.
+ *
+ * @return 0 on success; nonzero on error.
+ */
+int
+ble_l2cap_tx_flat(struct ble_l2cap_chan *chan, void *payload, int len)
+{
+ struct os_mbuf *om;
int rc;
- rc = ble_l2cap_ensure_buf(&chan->blc_tx_buf);
+ om = os_mbuf_get_pkthdr(&ble_l2cap_mbuf_pool);
+ if (om == NULL) {
+ rc = ENOMEM;
+ goto done;
+ }
+
+ rc = os_mbuf_append(&ble_l2cap_mbuf_pool, om, payload, len);
if (rc != 0) {
- /* XXX Need to deal with this in a way that prevents starvation. */
- return ENOMEM;
+ goto done;
}
- rc = os_mbuf_append(&ble_l2cap_mbuf_pool, chan->blc_tx_buf, payload, len);
+ rc = ble_l2cap_tx(chan, om);
+ om = NULL;
if (rc != 0) {
- return rc;
+ goto done;
}
- return 0;
+ rc = 0;
+
+done:
+ os_mbuf_free_chain(&ble_l2cap_mbuf_pool, om);
+ return rc;
}
int
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/net/nimble/host/src/ble_l2cap.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap.h b/net/nimble/host/src/ble_l2cap.h
index 0cad13f..b6b1c1c 100644
--- a/net/nimble/host/src/ble_l2cap.h
+++ b/net/nimble/host/src/ble_l2cap.h
@@ -79,7 +79,8 @@ int ble_l2cap_rx_payload(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
int ble_l2cap_rx(struct ble_hs_conn *connection,
struct hci_data_hdr *hci_hdr,
void *pkt);
-int ble_l2cap_tx(struct ble_l2cap_chan *chan, void *payload, int len);
+int ble_l2cap_tx(struct ble_l2cap_chan *chan, struct os_mbuf *om);
+int ble_l2cap_tx_flat(struct ble_l2cap_chan *chan, void *payload, int len);
int ble_l2cap_init(void);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/net/nimble/host/src/test/ble_hs_att_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_att_test.c b/net/nimble/host/src/test/ble_hs_att_test.c
index 82fab92..ad05f8d 100644
--- a/net/nimble/host/src/test/ble_hs_att_test.c
+++ b/net/nimble/host/src/test/ble_hs_att_test.c
@@ -27,11 +27,13 @@
#include "ble_hs_att.h"
#include "ble_hs_att_cmd.h"
-static uint8_t *ble_hs_att_test_attr_1;
-static int ble_hs_att_test_attr_1_len;
+static uint8_t *ble_hs_att_test_attr_r_1;
+static int ble_hs_att_test_attr_r_1_len;
+static uint8_t *ble_hs_att_test_attr_r_2;
+static int ble_hs_att_test_attr_r_2_len;
-static uint8_t ble_hs_att_test_attr_2[1024];
-static int ble_hs_att_test_attr_2_len;
+static uint8_t ble_hs_att_test_attr_w_1[1024];
+static int ble_hs_att_test_attr_w_1_len;
static void
ble_hs_att_test_misc_init(struct ble_hs_conn **conn,
@@ -51,13 +53,13 @@ ble_hs_att_test_misc_init(struct ble_hs_conn **conn,
}
static int
-ble_hs_att_test_misc_attr_fn_1(struct ble_hs_att_entry *entry,
- uint8_t op, union ble_hs_att_handle_arg *arg)
+ble_hs_att_test_misc_attr_fn_r_1(struct ble_hs_att_entry *entry,
+ uint8_t op, union ble_hs_att_handle_arg *arg)
{
switch (op) {
case BLE_HS_ATT_OP_READ_REQ:
- arg->aha_read.attr_data = ble_hs_att_test_attr_1;
- arg->aha_read.attr_len = ble_hs_att_test_attr_1_len;
+ arg->aha_read.attr_data = ble_hs_att_test_attr_r_1;
+ arg->aha_read.attr_len = ble_hs_att_test_attr_r_1_len;
return 0;
default:
@@ -66,8 +68,23 @@ ble_hs_att_test_misc_attr_fn_1(struct ble_hs_att_entry *entry,
}
static int
-ble_hs_att_test_misc_attr_fn_2(struct ble_hs_att_entry *entry,
- uint8_t op, union ble_hs_att_handle_arg *arg)
+ble_hs_att_test_misc_attr_fn_r_2(struct ble_hs_att_entry *entry,
+ uint8_t op, union ble_hs_att_handle_arg *arg)
+{
+ switch (op) {
+ case BLE_HS_ATT_OP_READ_REQ:
+ arg->aha_read.attr_data = ble_hs_att_test_attr_r_2;
+ arg->aha_read.attr_len = ble_hs_att_test_attr_r_2_len;
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+static int
+ble_hs_att_test_misc_attr_fn_w_1(struct ble_hs_att_entry *entry,
+ uint8_t op, union ble_hs_att_handle_arg *arg)
{
struct os_mbuf_pkthdr *omp;
int rc;
@@ -76,9 +93,9 @@ ble_hs_att_test_misc_attr_fn_2(struct ble_hs_att_entry *entry,
case BLE_HS_ATT_OP_WRITE_REQ:
omp = OS_MBUF_PKTHDR(arg->aha_write.om);
rc = os_mbuf_copydata(arg->aha_write.om, 0, arg->aha_write.attr_len,
- ble_hs_att_test_attr_2);
+ ble_hs_att_test_attr_w_1);
TEST_ASSERT(rc == 0);
- ble_hs_att_test_attr_2_len = arg->aha_write.attr_len;
+ ble_hs_att_test_attr_w_1_len = arg->aha_write.attr_len;
return 0;
default:
@@ -232,7 +249,55 @@ ble_hs_att_test_misc_verify_tx_find_info_rsp(
}
}
- /* Remove the error response from the buffer. */
+ /* Ensure there is no extra data in the response. */
+ TEST_ASSERT(off == OS_MBUF_PKTHDR(chan->blc_tx_buf)->omp_len);
+
+ /* Remove the response from the buffer. */
+ os_mbuf_adj(&ble_l2cap_mbuf_pool, chan->blc_tx_buf, off);
+}
+
+struct ble_hs_att_test_type_value_entry {
+ uint16_t first; /* 0 on last entry */
+ uint16_t last;
+};
+
+static void
+ble_hs_att_test_misc_verify_tx_find_type_value_rsp(
+ struct ble_l2cap_chan *chan,
+ struct ble_hs_att_test_type_value_entry *entries)
+{
+ struct ble_hs_att_test_type_value_entry *entry;
+ uint16_t u16;
+ uint8_t op;
+ int off;
+ int rc;
+
+ off = 0;
+
+ rc = os_mbuf_copydata(chan->blc_tx_buf, off, 1, &op);
+ TEST_ASSERT(rc == 0);
+ off += 1;
+
+ TEST_ASSERT(op == BLE_HS_ATT_OP_FIND_TYPE_VALUE_RSP);
+
+ for (entry = entries; entry->first != 0; entry++) {
+ rc = os_mbuf_copydata(chan->blc_tx_buf, off, 2, &u16);
+ TEST_ASSERT(rc == 0);
+ htole16(&u16, u16);
+ TEST_ASSERT(u16 == entry->first);
+ off += 2;
+
+ rc = os_mbuf_copydata(chan->blc_tx_buf, off, 2, &u16);
+ TEST_ASSERT(rc == 0);
+ htole16(&u16, u16);
+ TEST_ASSERT(u16 == entry->last);
+ off += 2;
+ }
+
+ /* Ensure there is no extra data in the response. */
+ TEST_ASSERT(off == OS_MBUF_PKTHDR(chan->blc_tx_buf)->omp_len);
+
+ /* Remove the response from the buffer. */
os_mbuf_adj(&ble_l2cap_mbuf_pool, chan->blc_tx_buf, off);
}
@@ -305,10 +370,10 @@ TEST_CASE(ble_hs_att_test_read)
BLE_HS_ATT_ERR_INVALID_HANDLE);
/*** Successful read. */
- ble_hs_att_test_attr_1 = (uint8_t[]){0,1,2,3,4,5,6,7};
- ble_hs_att_test_attr_1_len = 8;
+ ble_hs_att_test_attr_r_1 = (uint8_t[]){0,1,2,3,4,5,6,7};
+ ble_hs_att_test_attr_r_1_len = 8;
rc = ble_hs_att_register(uuid, 0, &req.bharq_handle,
- ble_hs_att_test_misc_attr_fn_1);
+ ble_hs_att_test_misc_attr_fn_r_1);
TEST_ASSERT(rc == 0);
rc = ble_hs_att_read_req_write(buf, sizeof buf, &req);
@@ -317,15 +382,15 @@ TEST_CASE(ble_hs_att_test_read)
rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
TEST_ASSERT(rc == 0);
- ble_hs_att_test_misc_verify_tx_read_rsp(chan, ble_hs_att_test_attr_1,
- ble_hs_att_test_attr_1_len);
+ ble_hs_att_test_misc_verify_tx_read_rsp(chan, ble_hs_att_test_attr_r_1,
+ ble_hs_att_test_attr_r_1_len);
/*** Partial read. */
- ble_hs_att_test_attr_1 =
+ ble_hs_att_test_attr_r_1 =
(uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,
22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39};
- ble_hs_att_test_attr_1_len = 40;
+ ble_hs_att_test_attr_r_1_len = 40;
rc = ble_hs_att_read_req_write(buf, sizeof buf, &req);
TEST_ASSERT(rc == 0);
@@ -333,7 +398,7 @@ TEST_CASE(ble_hs_att_test_read)
rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
TEST_ASSERT(rc == 0);
- ble_hs_att_test_misc_verify_tx_read_rsp(chan, ble_hs_att_test_attr_1,
+ ble_hs_att_test_misc_verify_tx_read_rsp(chan, ble_hs_att_test_attr_r_1,
BLE_HS_ATT_MTU_DFLT - 1);
}
@@ -362,7 +427,7 @@ TEST_CASE(ble_hs_att_test_write)
/*** Successful write. */
rc = ble_hs_att_register(uuid, 0, &req.bhawq_handle,
- ble_hs_att_test_misc_attr_fn_2);
+ ble_hs_att_test_misc_attr_fn_w_1);
TEST_ASSERT(rc == 0);
rc = ble_hs_att_write_req_write(buf, sizeof buf, &req);
@@ -442,7 +507,7 @@ TEST_CASE(ble_hs_att_test_find_info)
/*** Range too late. */
rc = ble_hs_att_register(uuid1, 0, &handle1,
- ble_hs_att_test_misc_attr_fn_1);
+ ble_hs_att_test_misc_attr_fn_r_1);
TEST_ASSERT(rc == 0);
req.bhafq_start_handle = 200;
@@ -477,7 +542,7 @@ TEST_CASE(ble_hs_att_test_find_info)
/*** Two 128-bit entries. */
rc = ble_hs_att_register(uuid2, 0,
- &handle2, ble_hs_att_test_misc_attr_fn_1);
+ &handle2, ble_hs_att_test_misc_attr_fn_r_1);
TEST_ASSERT(rc == 0);
req.bhafq_start_handle = handle1;
@@ -502,7 +567,7 @@ TEST_CASE(ble_hs_att_test_find_info)
/*** Two 128-bit entries; 16-bit entry doesn't get sent. */
rc = ble_hs_att_register(uuid3, 0,
- &handle3, ble_hs_att_test_misc_attr_fn_1);
+ &handle3, ble_hs_att_test_misc_attr_fn_r_1);
TEST_ASSERT(rc == 0);
req.bhafq_start_handle = handle1;
@@ -544,12 +609,228 @@ TEST_CASE(ble_hs_att_test_find_info)
} }));
}
+TEST_CASE(ble_hs_att_test_find_type_value)
+{
+ struct ble_hs_att_find_type_value_req req;
+ struct ble_l2cap_chan *chan;
+ struct ble_hs_conn *conn;
+ uint8_t buf[BLE_HS_ATT_FIND_TYPE_VALUE_REQ_MIN_SZ + 2];
+ uint16_t handle1;
+ uint16_t handle2;
+ uint16_t handle3;
+ uint16_t handle4;
+ uint16_t handle5;
+ uint8_t uuid1[16] = {
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+ };
+ uint8_t uuid2[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
+ uint8_t uuid3[16] = {
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+ };
+ int rc;
+
+ ble_hs_att_test_misc_init(&conn, &chan);
+
+ /* Increase the MTU to 128 bytes to allow testing of long responses. */
+ chan->blc_my_mtu = 128;
+ chan->blc_peer_mtu = 128;
+ chan->blc_flags |= BLE_L2CAP_CHAN_F_TXED_MTU;
+
+ /* One-time write of the attribute value at the end of the request. */
+ ble_hs_att_test_attr_r_1 = (uint8_t[]){0x99, 0x99};
+ ble_hs_att_test_attr_r_1_len = 2;
+ memcpy(buf + BLE_HS_ATT_FIND_TYPE_VALUE_REQ_MIN_SZ, ble_hs_att_test_attr_r_1,
+ ble_hs_att_test_attr_r_1_len);
+
+ /*** Start handle of 0. */
+ req.bhavq_op = BLE_HS_ATT_OP_FIND_TYPE_VALUE_REQ;
+ req.bhavq_start_handle = 0;
+ req.bhavq_end_handle = 0;
+ req.bhavq_attr_type = 0x0001;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc != 0);
+
+ ble_hs_att_test_misc_verify_tx_err_rsp(
+ chan, BLE_HS_ATT_OP_FIND_TYPE_VALUE_REQ, 0,
+ BLE_HS_ATT_ERR_INVALID_HANDLE);
+
+ /*** Start handle > end handle. */
+ req.bhavq_start_handle = 101;
+ req.bhavq_end_handle = 100;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc != 0);
+
+ ble_hs_att_test_misc_verify_tx_err_rsp(
+ chan, BLE_HS_ATT_OP_FIND_TYPE_VALUE_REQ, 101,
+ BLE_HS_ATT_ERR_INVALID_HANDLE);
+
+ /*** No attributes. */
+ req.bhavq_start_handle = 200;
+ req.bhavq_end_handle = 300;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc != 0);
+
+ ble_hs_att_test_misc_verify_tx_err_rsp(
+ chan, BLE_HS_ATT_OP_FIND_TYPE_VALUE_REQ, 200,
+ BLE_HS_ATT_ERR_ATTR_NOT_FOUND);
+
+ /*** Range too late. */
+ rc = ble_hs_att_register(uuid1, 0, &handle1,
+ ble_hs_att_test_misc_attr_fn_r_1);
+ TEST_ASSERT(rc == 0);
+
+ req.bhavq_start_handle = 200;
+ req.bhavq_end_handle = 300;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc != 0);
+
+ ble_hs_att_test_misc_verify_tx_err_rsp(
+ chan, BLE_HS_ATT_OP_FIND_TYPE_VALUE_REQ, 200,
+ BLE_HS_ATT_ERR_ATTR_NOT_FOUND);
+
+ /*** One entry, one attribute. */
+ req.bhavq_start_handle = handle1;
+ req.bhavq_end_handle = handle1;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc == 0);
+
+ ble_hs_att_test_misc_verify_tx_find_type_value_rsp(chan,
+ ((struct ble_hs_att_test_type_value_entry[]) { {
+ .first = handle1,
+ .last = handle1,
+ }, {
+ .first = 0,
+ } }));
+
+ /*** One entry, two attributes. */
+ rc = ble_hs_att_register(uuid1, 0,
+ &handle2, ble_hs_att_test_misc_attr_fn_r_1);
+ TEST_ASSERT(rc == 0);
+
+ req.bhavq_start_handle = handle1;
+ req.bhavq_end_handle = handle2;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc == 0);
+
+ ble_hs_att_test_misc_verify_tx_find_type_value_rsp(chan,
+ ((struct ble_hs_att_test_type_value_entry[]) { {
+ .first = handle1,
+ .last = handle2,
+ }, {
+ .first = 0,
+ } }));
+
+ /*** Entry 1: two attributes; entry 2: one attribute. */
+ rc = ble_hs_att_register(uuid2, 0, &handle3,
+ ble_hs_att_test_misc_attr_fn_r_2);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_hs_att_register(uuid1, 0, &handle4,
+ ble_hs_att_test_misc_attr_fn_r_1);
+ TEST_ASSERT(rc == 0);
+
+ req.bhavq_start_handle = 0x0001;
+ req.bhavq_end_handle = 0xffff;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc == 0);
+
+ ble_hs_att_test_misc_verify_tx_find_type_value_rsp(chan,
+ ((struct ble_hs_att_test_type_value_entry[]) { {
+ .first = handle1,
+ .last = handle2,
+ }, {
+ .first = handle4,
+ .last = handle4,
+ }, {
+ .first = 0,
+ } }));
+
+ /*** Ensure attribute with wrong value is not included. */
+ ble_hs_att_test_attr_r_2 = (uint8_t[]){0x00, 0x00};
+ ble_hs_att_test_attr_r_2_len = 2;
+
+ req.bhavq_start_handle = 0x0001;
+ req.bhavq_end_handle = 0xffff;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc == 0);
+
+ ble_hs_att_test_misc_verify_tx_find_type_value_rsp(chan,
+ ((struct ble_hs_att_test_type_value_entry[]) { {
+ .first = handle1,
+ .last = handle2,
+ }, {
+ .first = handle4,
+ .last = handle4,
+ }, {
+ .first = 0,
+ } }));
+
+ /*** Ensure attribute with wrong type is not included. */
+ rc = ble_hs_att_register(uuid3, 0, &handle5,
+ ble_hs_att_test_misc_attr_fn_r_1);
+
+ req.bhavq_start_handle = 0x0001;
+ req.bhavq_end_handle = 0xffff;
+
+ rc = ble_hs_att_find_type_value_req_write(buf, sizeof buf, &req);
+ TEST_ASSERT(rc == 0);
+
+ rc = ble_l2cap_rx_payload(conn, chan, buf, sizeof buf);
+ TEST_ASSERT(rc == 0);
+
+ ble_hs_att_test_misc_verify_tx_find_type_value_rsp(chan,
+ ((struct ble_hs_att_test_type_value_entry[]) { {
+ .first = handle1,
+ .last = handle2,
+ }, {
+ .first = handle4,
+ .last = handle4,
+ }, {
+ .first = 0,
+ } }));
+}
+
TEST_SUITE(att_suite)
{
ble_hs_att_test_mtu();
ble_hs_att_test_read();
ble_hs_att_test_write();
ble_hs_att_test_find_info();
+ ble_hs_att_test_find_type_value();
}
int
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/34a6d69f/net/nimble/host/src/test/ble_hs_uuid_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_uuid_test.c b/net/nimble/host/src/test/ble_hs_uuid_test.c
index fa1dfcd..698aa32 100644
--- a/net/nimble/host/src/test/ble_hs_uuid_test.c
+++ b/net/nimble/host/src/test/ble_hs_uuid_test.c
@@ -22,7 +22,7 @@
TEST_CASE(ble_hs_uuid_test_128_to_16)
{
- int uuid16;
+ uint16_t uuid16;
/*** RFCOMM */
uuid16 = ble_hs_uuid_16bit(((uint8_t[]) {
@@ -52,19 +52,19 @@ TEST_CASE(ble_hs_uuid_test_128_to_16)
uuid16 = ble_hs_uuid_16bit(((uint8_t[]) {
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5f, 0x9c, 0x34, 0xfb}));
- TEST_ASSERT(uuid16 == -1);
+ TEST_ASSERT(uuid16 == 0);
/*** Invalid prefix. */
uuid16 = ble_hs_uuid_16bit(((uint8_t[]) {
0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}));
- TEST_ASSERT(uuid16 == -1);
+ TEST_ASSERT(uuid16 == 0);
/*** 16-bit UUID of 0. */
uuid16 = ble_hs_uuid_16bit(((uint8_t[]) {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}));
- TEST_ASSERT(uuid16 == -1);
+ TEST_ASSERT(uuid16 == 0);
}
TEST_SUITE(ble_hs_uuid_test_suite)