Repository: incubator-mynewt-larva Updated Branches: refs/heads/master 7c9bc36c3 -> 7b029d814
Ensure connection list never locked during att callback. 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/4980dba7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/4980dba7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/4980dba7 Branch: refs/heads/master Commit: 4980dba7162c94eb493ba4d2d67bbac9d348af57 Parents: 7c9bc36 Author: Christopher Collins <ccollins47...@gmail.com> Authored: Tue Feb 2 11:16:38 2016 -0800 Committer: Christopher Collins <ccollins47...@gmail.com> Committed: Tue Feb 2 14:01:40 2016 -0800 ---------------------------------------------------------------------- net/nimble/host/src/ble_att.c | 26 + net/nimble/host/src/ble_att_priv.h | 3 +- net/nimble/host/src/ble_att_svr.c | 1457 +++++++++++++++---------------- net/nimble/host/src/ble_gattc.c | 6 +- 4 files changed, 747 insertions(+), 745 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/4980dba7/net/nimble/host/src/ble_att.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_att.c b/net/nimble/host/src/ble_att.c index 7567297..a86d96d 100644 --- a/net/nimble/host/src/ble_att.c +++ b/net/nimble/host/src/ble_att.c @@ -94,6 +94,8 @@ int ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn, struct ble_l2cap_chan **out_chan) { + *out_chan = NULL; + *out_conn = ble_hs_conn_find(conn_handle); if (*out_conn == NULL) { return BLE_HS_ENOTCONN; @@ -106,6 +108,30 @@ ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn, } /** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +uint16_t +ble_att_mtu(uint16_t conn_handle) +{ + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + uint16_t mtu; + + ble_hs_conn_lock(); + + ble_att_conn_chan_find(conn_handle, &conn, &chan); + if (chan != NULL) { + mtu = ble_l2cap_chan_mtu(chan); + } else { + mtu = 0; + } + + ble_hs_conn_unlock(); + + return mtu; +} + +/** * Lock restrictions: Caller must lock ble_hs_conn mutex. */ static int http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/4980dba7/net/nimble/host/src/ble_att_priv.h ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_att_priv.h b/net/nimble/host/src/ble_att_priv.h index 879ef47..479e555 100644 --- a/net/nimble/host/src/ble_att_priv.h +++ b/net/nimble/host/src/ble_att_priv.h @@ -91,6 +91,7 @@ SLIST_HEAD(ble_att_clt_entry_list, ble_att_clt_entry); struct ble_l2cap_chan *ble_att_create_chan(void); int ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn, struct ble_l2cap_chan **out_chan); +uint16_t ble_att_mtu(uint16_t conn_handle); void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu); struct os_mbuf *ble_att_get_pkthdr(void); void ble_att_init(void); @@ -128,7 +129,7 @@ int ble_att_svr_rx_notify(uint16_t conn_handle, int ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom); void ble_att_svr_prep_clear(struct ble_att_svr_conn *basc); -int ble_att_svr_read_handle(struct ble_hs_conn *conn, uint16_t attr_handle, +int ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle, struct ble_att_svr_access_ctxt *ctxt, uint8_t *out_att_err); int ble_att_svr_init(void); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/4980dba7/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 e1c80be..43cce25 100644 --- a/net/nimble/host/src/ble_att_svr.c +++ b/net/nimble/host/src/ble_att_svr.c @@ -89,6 +89,9 @@ ble_att_svr_list_unlock(void) assert(rc == 0 || rc == OS_NOT_STARTED); } +/** + * Lock restrictions: None. + */ static struct ble_att_svr_entry * ble_att_svr_entry_alloc(void) { @@ -116,6 +119,8 @@ ble_att_svr_entry_free(struct ble_att_svr_entry *entry) /** * Allocate the next handle id and return it. * + * Lock restrictions: None. + * * @return A new 16-bit handle ID. */ static uint16_t @@ -130,6 +135,8 @@ ble_att_svr_next_id(void) /** * Register a host attribute with the BLE stack. * + * Lock restrictions: None. + * * @param ha A filled out ble_att structure to register * @param handle_id A pointer to a 16-bit handle ID, which will be * the handle that is allocated. @@ -166,6 +173,9 @@ ble_att_svr_register(uint8_t *uuid, uint8_t flags, uint16_t *handle_id, return 0; } +/** + * Lock restrictions: None. + */ int ble_att_svr_register_uuid16(uint16_t uuid16, uint8_t flags, uint16_t *handle_id, ble_att_svr_access_fn *cb, @@ -187,6 +197,9 @@ ble_att_svr_register_uuid16(uint16_t uuid16, uint8_t flags, return 0; } +/** + * Lock restrictions: None. + */ uint16_t ble_att_svr_prev_handle(void) { @@ -198,6 +211,8 @@ ble_att_svr_prev_handle(void) * If walk_func wants to stop iteration, it returns 1. To continue iteration * it returns 0. * + * Lock restrictions: None. + * * @param walk_func The function to call for each element in the * host attribute list. * @param arg The argument to provide to walk_func @@ -245,6 +260,9 @@ done: return rc; } +/** + * Lock restrictions: None. + */ static int ble_att_svr_match_handle(struct ble_att_svr_entry *ha, void *arg) { @@ -259,6 +277,8 @@ ble_att_svr_match_handle(struct ble_att_svr_entry *ha, void *arg) /** * Find a host attribute by handle id. * + * Lock restrictions: None. + * * @param handle_id The handle_id to search for * @param ha_ptr On input: Indicates the starting point of the * walk; null means start at the beginning of @@ -286,6 +306,9 @@ ble_att_svr_find_by_handle(uint16_t handle_id, } } +/** + * Lock restrictions: None. + */ static int ble_att_svr_match_uuid(struct ble_att_svr_entry *ha, void *arg) { @@ -303,6 +326,8 @@ ble_att_svr_match_uuid(struct ble_att_svr_entry *ha, void *arg) /** * Find a host attribute by UUID. * + * Lock restrictions: None. + * * @param uuid The ble_uuid_t to search for * @param ha_ptr On input: Indicates the starting point of the * walk; null means start at the beginning of @@ -329,24 +354,30 @@ ble_att_svr_find_by_uuid(uint8_t *uuid, struct ble_att_svr_entry **ha_ptr) } } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ static int -ble_att_svr_read(struct ble_hs_conn *conn, struct ble_att_svr_entry *entry, +ble_att_svr_read(uint16_t conn_handle, struct ble_att_svr_entry *entry, struct ble_att_svr_access_ctxt *ctxt, uint8_t *out_att_err) { - uint16_t conn_handle; uint8_t att_err; int rc; - if (conn == NULL) { - conn_handle = BLE_HS_CONN_HANDLE_NONE; - } else { - conn_handle = conn->bhc_handle; + assert(!ble_hs_conn_locked_by_cur_task()); - if (!(entry->ha_flags & HA_FLAG_PERM_READ)) { - att_err = BLE_ATT_ERR_READ_NOT_PERMITTED; - rc = BLE_HS_ENOTSUP; - goto err; - } + if (conn_handle != BLE_HS_CONN_HANDLE_NONE && + !(entry->ha_flags & HA_FLAG_PERM_READ)) { + + att_err = BLE_ATT_ERR_READ_NOT_PERMITTED; + rc = BLE_HS_ENOTSUP; + goto err; + } + + if (entry->ha_cb == NULL) { + att_err = BLE_ATT_ERR_UNLIKELY; + rc = BLE_HS_ENOTSUP; + goto err; } /* XXX: Check security. */ @@ -370,8 +401,11 @@ err: return rc; } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ int -ble_att_svr_read_handle(struct ble_hs_conn *conn, uint16_t attr_handle, +ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle, struct ble_att_svr_access_ctxt *ctxt, uint8_t *out_att_err) { @@ -381,10 +415,11 @@ ble_att_svr_read_handle(struct ble_hs_conn *conn, uint16_t attr_handle, entry = NULL; rc = ble_att_svr_find_by_handle(attr_handle, &entry); if (rc != 0) { + *out_att_err = BLE_ATT_ERR_INVALID_HANDLE; return rc; } - rc = ble_att_svr_read(conn, entry, ctxt, out_att_err); + rc = ble_att_svr_read(conn_handle, entry, ctxt, out_att_err); if (rc != 0) { return rc; } @@ -393,15 +428,21 @@ ble_att_svr_read_handle(struct ble_hs_conn *conn, uint16_t attr_handle, } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ static int -ble_att_svr_write(struct ble_hs_conn *conn, struct ble_att_svr_entry *entry, +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 conn_handle; uint8_t att_err; int rc; - if (!(entry->ha_flags & HA_FLAG_PERM_WRITE)) { + assert(!ble_hs_conn_locked_by_cur_task()); + + if (conn_handle != BLE_HS_CONN_HANDLE_NONE && + !(entry->ha_flags & HA_FLAG_PERM_WRITE)) { + att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED; rc = BLE_HS_ENOTSUP; goto err; @@ -409,12 +450,6 @@ ble_att_svr_write(struct ble_hs_conn *conn, struct ble_att_svr_entry *entry, /* XXX: Check security. */ - if (conn == NULL) { - conn_handle = BLE_HS_CONN_HANDLE_NONE; - } else { - conn_handle = conn->bhc_handle; - } - assert(entry->ha_cb != NULL); rc = entry->ha_cb(conn_handle, entry->ha_handle_id, entry->ha_uuid, BLE_ATT_ACCESS_OP_WRITE, ctxt, @@ -435,6 +470,32 @@ err: } static int +ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle, + struct ble_att_svr_access_ctxt *ctxt, + uint8_t *out_att_err) +{ + struct ble_att_svr_entry *entry; + int rc; + + entry = NULL; + rc = ble_att_svr_find_by_handle(attr_handle, &entry); + if (rc != 0) { + *out_att_err = BLE_ATT_ERR_INVALID_HANDLE; + return rc; + } + + rc = ble_att_svr_write(conn_handle, entry, ctxt, out_att_err); + if (rc != 0) { + return rc; + } + + return 0; +} + +/** + * Lock restrictions: Caller must lock ble_hs_conn mutex. + */ +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) { @@ -475,6 +536,69 @@ err: return rc; } +/** + * Transmits a response or error message over the specified connection. + * + * The specified rc value controls what gets sent as follows: + * o If rc == 0: tx an affirmative response. + * o If rc == BLE_HS_ENOTCONN: tx nothing. + * o Else: tx an error response. + * + * In addition, if transmission of an affirmative response fails, an error is + * sent instead. + * + * @param conn_handle The handle of the connection to send over. + * @param rc The status indicating whether to transmit an + * affirmative response or an error. + * @param txom Contains the affirmative response payload. + * @param err_op If an error is transmitted, this is the value + * of the error message's op field. + * @param err_status If an error is transmitted, this is the value + * of the error message's status field. + * @param err_handle If an error is transmitted, this is the value + * of the error message's attribute handle + * field. + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +static int +ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom, + uint8_t err_op, uint8_t err_status, uint16_t err_handle) +{ + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + + if (rc != BLE_HS_ENOTCONN) { + ble_hs_conn_lock(); + + ble_att_conn_chan_find(conn_handle, &conn, &chan); + if (chan == NULL) { + rc = BLE_HS_ENOTCONN; + } else { + if (rc == 0) { + rc = ble_l2cap_tx(conn, chan, txom); + txom = NULL; + if (rc != 0) { + err_status = BLE_ATT_ERR_UNLIKELY; + } + } + + if (rc != 0 && err_status != 0) { + ble_att_svr_tx_error_rsp(conn, chan, err_op, + err_handle, err_status); + } + } + + ble_hs_conn_unlock(); + } + + os_mbuf_free_chain(txom); + + return rc; +} + +/** + * Lock restrictions: Caller must lock ble_hs_conn mutex. + */ static int ble_att_svr_tx_mtu_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, uint8_t op, uint16_t mtu, uint8_t *att_err) @@ -523,6 +647,9 @@ err: return rc; } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ int ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om) { @@ -566,6 +693,8 @@ ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om) * Fills the supplied mbuf with the variable length Information Data field of a * Find Information ATT response. * + * Lock restrictions: None. + * * @param req The Find Information request being responded * to. * @param om The destination mbuf where the Information @@ -680,20 +809,34 @@ done: } } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ static int -ble_att_svr_tx_find_info(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, - struct ble_att_find_info_req *req, uint8_t *att_err) +ble_att_svr_build_find_info_rsp(uint16_t conn_handle, + struct ble_att_find_info_req *req, + struct os_mbuf **out_txom, + uint8_t *att_err) { struct ble_att_find_info_rsp rsp; struct os_mbuf *txom; + uint16_t mtu; void *buf; int rc; + txom = NULL; + + mtu = ble_att_mtu(conn_handle); + if (mtu == 0) { + rc = BLE_HS_ENOTCONN; + goto done; + } + txom = ble_att_get_pkthdr(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } /* Write the response base at the start of the buffer. The format field is @@ -703,7 +846,7 @@ ble_att_svr_tx_find_info(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, if (buf == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_find_info_rsp_write(buf, BLE_ATT_FIND_INFO_RSP_BASE_SZ, &rsp); @@ -712,44 +855,43 @@ ble_att_svr_tx_find_info(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, /* Write the variable length Information Data field, populating the format * field as appropriate. */ - rc = ble_att_svr_fill_info(req, txom, ble_l2cap_chan_mtu(chan), - txom->om_data + 1); + rc = ble_att_svr_fill_info(req, txom, mtu, txom->om_data + 1); if (rc != 0) { *att_err = BLE_ATT_ERR_ATTR_NOT_FOUND; rc = BLE_HS_ENOENT; - goto err; - } - - rc = ble_l2cap_tx(conn, chan, txom); - txom = NULL; - if (rc != 0) { - *att_err = BLE_ATT_ERR_UNLIKELY; - goto err; + goto done; } - return 0; + rc = 0; -err: - os_mbuf_free_chain(txom); +done: + *out_txom = txom; return rc; } -static int -ble_att_svr_rx_find_info_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_find_info_req req; + struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + att_err = 0; + err_handle = 0; + *rxom = os_mbuf_pullup(*rxom, BLE_ATT_MTU_CMD_SZ); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_find_info_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); @@ -764,39 +906,20 @@ ble_att_svr_rx_find_info_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_HANDLE; err_handle = req.bafq_start_handle; rc = BLE_HS_EBADDATA; - goto err; + goto done; } - rc = ble_att_svr_tx_find_info(conn, chan, &req, &att_err); + rc = ble_att_svr_build_find_info_rsp(conn_handle, &req, &txom, &att_err); if (rc != 0) { err_handle = req.bafq_start_handle; - goto err; - } - - return 0; - -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_FIND_INFO_REQ, - err_handle, att_err); - return rc; -} - -int -ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); - - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_find_info_locked(conn, chan, rxom); + goto done; } - ble_hs_conn_unlock(); + rc = 0; +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_FIND_INFO_REQ, + att_err, err_handle); return rc; } @@ -804,6 +927,8 @@ ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom) * Processes a single non-matching attribute entry while filling a * Find-By-Type-Value-Response. * + * Lock restrictions: None. + * * @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 @@ -864,6 +989,8 @@ ble_att_svr_fill_type_value_no_match(struct os_mbuf *om, uint16_t *first, * Processes a single matching attribute entry while filling a * Find-By-Type-Value-Response. * + * Lock restrictions: None. + * * @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 @@ -917,6 +1044,8 @@ ble_att_svr_fill_type_value_match(struct os_mbuf *om, uint16_t *first, * Fills the supplied mbuf with the variable length Handles-Information-List * field of a Find-By-Type-Value ATT response. * + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + * * @param req The Find-By-Type-Value-Request being responded * to. * @param rxom The mbuf containing the received request. @@ -930,7 +1059,7 @@ ble_att_svr_fill_type_value_match(struct os_mbuf *om, uint16_t *first, * BLE_HS_EAPP on other error. */ static int -ble_att_svr_fill_type_value(struct ble_hs_conn *conn, +ble_att_svr_fill_type_value(uint16_t conn_handle, struct ble_att_find_type_value_req *req, struct os_mbuf *rxom, struct os_mbuf *txom, uint16_t mtu, uint8_t *out_att_err) @@ -968,7 +1097,7 @@ ble_att_svr_fill_type_value(struct ble_hs_conn *conn, uuid16 = ble_uuid_128_to_16(ha->ha_uuid); if (uuid16 == req->bavq_attr_type) { ctxt.offset = 0; - rc = ble_att_svr_read(conn, ha, &ctxt, out_att_err); + rc = ble_att_svr_read(conn_handle, ha, &ctxt, out_att_err); if (rc != 0) { goto done; } @@ -1021,14 +1150,18 @@ done: } } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ static int -ble_att_svr_tx_find_type_value(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct ble_att_find_type_value_req *req, - struct os_mbuf *rxom, - uint8_t *out_att_err) +ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle, + struct ble_att_find_type_value_req *req, + struct os_mbuf *rxom, + struct os_mbuf **out_txom, + uint8_t *out_att_err) { struct os_mbuf *txom; + uint16_t mtu; uint8_t *buf; int rc; @@ -1036,7 +1169,7 @@ ble_att_svr_tx_find_type_value(struct ble_hs_conn *conn, if (txom == NULL) { *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } /* Write the response base at the start of the buffer. */ @@ -1044,47 +1177,53 @@ ble_att_svr_tx_find_type_value(struct ble_hs_conn *conn, if (buf == NULL) { *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } buf[0] = BLE_ATT_OP_FIND_TYPE_VALUE_RSP; /* Write the variable length Information Data field. */ - rc = ble_att_svr_fill_type_value(conn, req, rxom, txom, - ble_l2cap_chan_mtu(chan), out_att_err); - if (rc != 0) { - goto err; + mtu = ble_att_mtu(conn_handle); + if (mtu == 0) { + rc = BLE_HS_ENOTCONN; + goto done; } - rc = ble_l2cap_tx(conn, chan, txom); - txom = NULL; + rc = ble_att_svr_fill_type_value(conn_handle, req, rxom, txom, mtu, + out_att_err); if (rc != 0) { - *out_att_err = BLE_ATT_ERR_UNLIKELY; - goto err; + goto done; } - return 0; + rc = 0; -err: - os_mbuf_free_chain(txom); +done: + *out_txom = txom; return rc; } -static int -ble_att_svr_rx_find_type_value_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_find_type_value_req req; + struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + att_err = 0; + err_handle = 0; + *rxom = os_mbuf_pullup(*rxom, BLE_ATT_MTU_CMD_SZ); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_find_type_value_req_parse((*rxom)->om_data, (*rxom)->om_len, @@ -1100,53 +1239,41 @@ ble_att_svr_rx_find_type_value_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_HANDLE; err_handle = req.bavq_start_handle; rc = BLE_HS_EBADDATA; - goto err; + goto done; } - rc = ble_att_svr_tx_find_type_value(conn, chan, &req, *rxom, &att_err); + rc = ble_att_svr_build_find_type_value_rsp(conn_handle, &req, *rxom, + &txom, &att_err); if (rc != 0) { err_handle = req.bavq_start_handle; - goto err; - } - - return 0; - -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_FIND_TYPE_VALUE_REQ, - err_handle, att_err); - return rc; -} - -int -ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); - - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_find_type_value_locked(conn, chan, rxom); + goto done; } - ble_hs_conn_unlock(); + rc = 0; +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, + BLE_ATT_OP_FIND_TYPE_VALUE_REQ, att_err, + err_handle); return rc; } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ static int -ble_att_svr_tx_read_type_rsp(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct ble_att_read_type_req *req, - uint8_t *uuid128, uint8_t *att_err, - uint16_t *err_handle) +ble_att_svr_build_read_type_rsp(uint16_t conn_handle, + struct ble_att_read_type_req *req, + uint8_t *uuid128, + struct os_mbuf **out_txom, + uint8_t *att_err, + uint16_t *err_handle) { struct ble_att_read_type_rsp rsp; struct ble_att_svr_access_ctxt ctxt; struct ble_att_svr_entry *entry; struct os_mbuf *txom; + uint16_t mtu; uint8_t *dptr; int entry_written; int txomlen; @@ -1160,6 +1287,11 @@ ble_att_svr_tx_read_type_rsp(struct ble_hs_conn *conn, entry_written = 0; prev_attr_len = 0; + mtu = ble_att_mtu(conn_handle); + if (mtu == 0) { + return BLE_HS_ENOTCONN; + } + txom = ble_att_get_pkthdr(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; @@ -1197,14 +1329,14 @@ ble_att_svr_tx_read_type_rsp(struct ble_hs_conn *conn, if (entry->ha_handle_id >= req->batq_start_handle) { ctxt.offset = 0; - rc = ble_att_svr_read(conn, entry, &ctxt, att_err); + rc = ble_att_svr_read(conn_handle, entry, &ctxt, att_err); if (rc != 0) { *err_handle = entry->ha_handle_id; goto done; } - if (ctxt.data_len > ble_l2cap_chan_mtu(chan) - 4) { - attr_len = ble_l2cap_chan_mtu(chan) - 4; + if (ctxt.data_len > mtu - 4) { + attr_len = mtu - 4; } else { attr_len = ctxt.data_len; } @@ -1216,7 +1348,7 @@ ble_att_svr_tx_read_type_rsp(struct ble_hs_conn *conn, } txomlen = OS_MBUF_PKTHDR(txom)->omp_len + 2 + attr_len; - if (txomlen > ble_l2cap_chan_mtu(chan)) { + if (txomlen > mtu) { break; } @@ -1244,43 +1376,42 @@ done: } else { /* Send what we can, even if an error was encountered. */ *att_err = 0; + *err_handle = entry->ha_handle_id; /* Fill the response base. */ rsp.batp_length = BLE_ATT_READ_TYPE_ADATA_BASE_SZ + prev_attr_len; rc = ble_att_read_type_rsp_write(txom->om_data, txom->om_len, &rsp); assert(rc == 0); - - /* Transmit the response. */ - rc = ble_l2cap_tx(conn, chan, txom); - txom = NULL; - if (rc != 0) { - *att_err = BLE_ATT_ERR_UNLIKELY; - *err_handle = entry->ha_handle_id; - } } - os_mbuf_free_chain(txom); + *out_txom = txom; + return rc; } -static int -ble_att_svr_rx_read_type_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_read_type_req req; + struct os_mbuf *txom; uint16_t err_handle; uint16_t uuid16; uint8_t uuid128[16]; uint8_t att_err; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + *rxom = os_mbuf_pullup(*rxom, OS_MBUF_PKTLEN(*rxom)); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_read_type_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); @@ -1292,7 +1423,7 @@ ble_att_svr_rx_read_type_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_HANDLE; err_handle = req.batq_start_handle; rc = BLE_HS_EBADDATA; - goto err; + goto done; } switch ((*rxom)->om_len) { @@ -1303,7 +1434,7 @@ ble_att_svr_rx_read_type_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_ATTR_NOT_FOUND; err_handle = 0; rc = BLE_HS_EBADDATA; - goto err; + goto done; } break; @@ -1315,59 +1446,51 @@ ble_att_svr_rx_read_type_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_PDU; err_handle = 0; rc = BLE_HS_EMSGSIZE; - goto err; + goto done; } - rc = ble_att_svr_tx_read_type_rsp(conn, chan, &req, uuid128, &att_err, - &err_handle); + rc = ble_att_svr_build_read_type_rsp(conn_handle, &req, uuid128, + &txom, &att_err, &err_handle); if (rc != 0) { - goto err; + goto done; } - return 0; + rc = 0; -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_READ_TYPE_REQ, - err_handle, att_err); +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_TYPE_REQ, + att_err, err_handle); return rc; } -int -ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + * + * @return 0 on success; nonzero on failure. + */ +static int +ble_att_svr_build_read_rsp(uint16_t conn_handle, void *attr_data, int attr_len, + struct os_mbuf **out_txom, uint8_t *att_err) { - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; + struct os_mbuf *txom; + uint16_t data_len; + uint16_t mtu; + uint8_t op; int rc; - ble_hs_conn_lock(); + txom = NULL; - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_read_type_locked(conn, chan, rxom); + mtu = ble_att_mtu(conn_handle); + if (mtu == 0) { + rc = BLE_HS_ENOTCONN; + goto done; } - ble_hs_conn_unlock(); - - return rc; -} - -/** - * @return 0 on success; nonzero on failure. - */ -static int -ble_att_svr_tx_read_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, - void *attr_data, int attr_len, uint8_t *att_err) -{ - struct os_mbuf *txom; - uint16_t data_len; - uint8_t op; - int rc; - txom = ble_att_get_pkthdr(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } op = BLE_ATT_OP_READ_RSP; @@ -1375,12 +1498,12 @@ ble_att_svr_tx_read_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, if (rc != 0) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } /* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */ - if (attr_len > ble_l2cap_chan_mtu(chan) - 1) { - data_len = ble_l2cap_chan_mtu(chan) - 1; + if (attr_len > mtu - 1) { + data_len = mtu - 1; } else { data_len = attr_len; } @@ -1389,95 +1512,40 @@ ble_att_svr_tx_read_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, if (rc != 0) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; - } - - rc = ble_l2cap_tx(conn, chan, txom); - if (rc != 0) { - *att_err = BLE_ATT_ERR_UNLIKELY; - goto err; + goto done; } - return 0; + rc = 0; -err: - os_mbuf_free_chain(txom); +done: + *out_txom = txom; return rc; } /** - * @return 0 on success; nonzero on failure. + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. */ -static int -ble_att_svr_tx_read_blob_rsp(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, void *attr_data, - int attr_len, uint8_t *att_err) -{ - struct os_mbuf *txom; - uint16_t data_len; - uint8_t op; - int rc; - - txom = ble_att_get_pkthdr(); - if (txom == NULL) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; - rc = BLE_HS_ENOMEM; - goto err; - } - - op = BLE_ATT_OP_READ_BLOB_RSP; - rc = os_mbuf_append(txom, &op, 1); - if (rc != 0) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; - rc = BLE_HS_ENOMEM; - goto err; - } - - /* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */ - if (attr_len > ble_l2cap_chan_mtu(chan) - 1) { - data_len = ble_l2cap_chan_mtu(chan) - 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 err; - } - - rc = ble_l2cap_tx(conn, chan, txom); - if (rc != 0) { - *att_err = BLE_ATT_ERR_UNLIKELY; - goto err; - } - - return 0; - -err: - os_mbuf_free_chain(txom); - return rc; -} - -static int -ble_att_svr_rx_read_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +int +ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_svr_access_ctxt ctxt; - struct ble_att_svr_entry *entry; struct ble_att_read_req req; + struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + att_err = 0; + err_handle = 0; + *rxom = os_mbuf_pullup(*rxom, OS_MBUF_PKTLEN(*rxom)); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_read_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); @@ -1485,85 +1553,113 @@ ble_att_svr_rx_read_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_PDU; err_handle = 0; rc = BLE_HS_EBADDATA; - goto err; - } - - entry = NULL; - rc = ble_att_svr_find_by_handle(req.barq_handle, &entry); - if (rc != 0) { - att_err = BLE_ATT_ERR_INVALID_HANDLE; - err_handle = req.barq_handle; - rc = BLE_HS_ENOENT; - goto err; - } - - if (entry->ha_cb == NULL) { - att_err = BLE_ATT_ERR_UNLIKELY; - err_handle = req.barq_handle; - rc = BLE_HS_ENOTSUP; - goto err; + goto done; } ctxt.offset = 0; - rc = ble_att_svr_read(conn, entry, &ctxt, &att_err); + rc = ble_att_svr_read_handle(conn_handle, req.barq_handle, &ctxt, + &att_err); if (rc != 0) { err_handle = req.barq_handle; - rc = BLE_HS_ENOTSUP; - goto err; + goto done; } - rc = ble_att_svr_tx_read_rsp(conn, chan, ctxt.attr_data, - ctxt.data_len, &att_err); + rc = ble_att_svr_build_read_rsp(conn_handle, ctxt.attr_data, ctxt.data_len, + &txom, &att_err); if (rc != 0) { err_handle = req.barq_handle; - goto err; + goto done; } - return 0; + rc = 0; -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_READ_REQ, - err_handle, att_err); +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_REQ, + att_err, err_handle); return rc; } -int -ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) +/** + * Lock restrictions: None. + * + * @return 0 on success; nonzero on failure. + */ +static int +ble_att_svr_build_read_blob_rsp(void *attr_data, int attr_len, uint16_t mtu, + struct os_mbuf **out_txom, uint8_t *att_err) { - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; + struct os_mbuf *txom; + uint16_t data_len; + uint8_t op; int rc; - ble_hs_conn_lock(); + txom = ble_att_get_pkthdr(); + if (txom == NULL) { + *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + rc = BLE_HS_ENOMEM; + goto done; + } - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_read_locked(conn, chan, rxom); + op = BLE_ATT_OP_READ_BLOB_RSP; + rc = os_mbuf_append(txom, &op, 1); + if (rc != 0) { + *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + rc = BLE_HS_ENOMEM; + goto done; } - ble_hs_conn_unlock(); + /* 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; + } + + rc = 0; +done: + *out_txom = txom; return rc; } -static int -ble_att_svr_rx_read_blob_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_svr_access_ctxt ctxt; - struct ble_att_svr_entry *entry; struct ble_att_read_blob_req req; + struct os_mbuf *txom; uint16_t err_handle; + uint16_t mtu; uint8_t att_err; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + att_err = 0; + err_handle = 0; + + mtu = ble_att_mtu(conn_handle); + if (mtu == 0) { + rc = BLE_HS_ENOTCONN; + goto done; + } + *rxom = os_mbuf_pullup(*rxom, OS_MBUF_PKTLEN(*rxom)); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_read_blob_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); @@ -1571,101 +1667,85 @@ ble_att_svr_rx_read_blob_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_PDU; err_handle = 0; rc = BLE_HS_EBADDATA; - goto err; - } - - entry = NULL; - rc = ble_att_svr_find_by_handle(req.babq_handle, &entry); - if (rc != 0) { - att_err = BLE_ATT_ERR_INVALID_HANDLE; - err_handle = req.babq_handle; - rc = BLE_HS_ENOENT; - goto err; - } - - if (entry->ha_cb == NULL) { - att_err = BLE_ATT_ERR_UNLIKELY; - err_handle = req.babq_handle; - rc = BLE_HS_ENOTSUP; - goto err; + goto done; } ctxt.offset = req.babq_offset; - rc = ble_att_svr_read(conn, entry, &ctxt, &att_err); + rc = ble_att_svr_read_handle(conn_handle, req.babq_handle, &ctxt, + &att_err); if (rc != 0) { err_handle = req.babq_handle; - rc = BLE_HS_ENOTSUP; - goto err; + goto done; } - if (ctxt.offset + ctxt.data_len <= ble_l2cap_chan_mtu(chan) - 3) { + if (ctxt.offset + ctxt.data_len <= mtu - 3) { att_err = BLE_ATT_ERR_ATTR_NOT_LONG; err_handle = req.babq_handle; rc = BLE_HS_ENOTSUP; - goto err; + goto done; } - rc = ble_att_svr_tx_read_blob_rsp(conn, chan, ctxt.attr_data, - ctxt.data_len, &att_err); + rc = ble_att_svr_build_read_blob_rsp(ctxt.attr_data, ctxt.data_len, mtu, + &txom, &att_err); if (rc != 0) { err_handle = req.babq_handle; - goto err; - } - - return 0; - -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_READ_BLOB_REQ, - err_handle, att_err); - return rc; -} - -int -ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); - - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_read_blob_locked(conn, chan, rxom); + goto done; } - ble_hs_conn_unlock(); + rc = 0; +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_BLOB_REQ, + att_err, err_handle); return rc; } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ static int -ble_att_svr_tx_read_mult(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, - struct os_mbuf **rxom, uint8_t *att_err, - uint16_t *err_handle) +ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, + struct os_mbuf **rxom, + struct os_mbuf **out_txom, + uint8_t *att_err, + uint16_t *err_handle) { struct ble_att_svr_access_ctxt ctxt; - struct ble_att_svr_entry *entry; struct os_mbuf *txom; uint16_t chunk_sz; uint16_t tx_space; uint16_t handle; + uint16_t mtu; uint8_t *dptr; int rc; + txom = NULL; + + mtu = ble_att_mtu(conn_handle); + if (mtu == 0) { + rc = BLE_HS_ENOTCONN; + goto done; + } + txom = ble_att_get_pkthdr(); + if (txom == NULL) { + *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + *err_handle = 0; + rc = BLE_HS_ENOMEM; + goto done; + } dptr = os_mbuf_extend(txom, BLE_ATT_READ_MULT_RSP_BASE_SZ); if (dptr == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; *err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_read_mult_rsp_write(dptr, BLE_ATT_READ_MULT_RSP_BASE_SZ); assert(rc == 0); - tx_space = ble_l2cap_chan_mtu(chan) - OS_MBUF_PKTLEN(txom); + 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 @@ -1675,28 +1755,11 @@ ble_att_svr_tx_read_mult(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, handle = le16toh((*rxom)->om_data); os_mbuf_adj(*rxom, 2); - entry = NULL; - rc = ble_att_svr_find_by_handle(handle, &entry); - if (rc != 0) { - *att_err = BLE_ATT_ERR_INVALID_HANDLE; - *err_handle = handle; - rc = BLE_HS_ENOENT; - goto err; - } - - if (entry->ha_cb == NULL) { - *att_err = BLE_ATT_ERR_UNLIKELY; - *err_handle = handle; - rc = BLE_HS_ENOTSUP; - goto err; - } - ctxt.offset = 0; - rc = ble_att_svr_read(conn, entry, &ctxt, att_err); + rc = ble_att_svr_read_handle(conn_handle, handle, &ctxt, att_err); if (rc != 0) { *err_handle = handle; - rc = BLE_HS_ENOTSUP; - goto err; + goto done; } if (ctxt.data_len > tx_space) { @@ -1710,43 +1773,41 @@ ble_att_svr_tx_read_mult(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; *err_handle = handle; rc = BLE_HS_ENOMEM; - goto err; + goto done; } tx_space -= chunk_sz; } - rc = ble_l2cap_tx(conn, chan, txom); - if (rc != 0) { - *att_err = BLE_ATT_ERR_UNLIKELY; - *err_handle = 0; - goto err; - } - - return 0; + rc = 0; -err: - os_mbuf_free_chain(txom); +done: + *out_txom = txom; return rc; } -static int -ble_att_svr_rx_read_mult_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) { + struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; int rc; - err_handle = 0; /* Silence warning. */ + /* Initialize some values in case of early error. */ + txom = NULL; + err_handle = 0; + att_err = 0; *rxom = os_mbuf_pullup(*rxom, OS_MBUF_PKTLEN(*rxom)); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_read_mult_req_parse((*rxom)->om_data, (*rxom)->om_len); @@ -1754,44 +1815,29 @@ ble_att_svr_rx_read_mult_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_PDU; err_handle = 0; rc = BLE_HS_EBADDATA; - goto err; + goto done; } /* Strip opcode from request. */ os_mbuf_adj(*rxom, BLE_ATT_READ_MULT_REQ_BASE_SZ); - rc = ble_att_svr_tx_read_mult(conn, chan, rxom, &att_err, &err_handle); + rc = ble_att_svr_build_read_mult_rsp(conn_handle, rxom, &txom, &att_err, + &err_handle); if (rc != 0) { - goto err; - } - - return 0; - -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_READ_MULT_REQ, - err_handle, att_err); - return rc; -} - -int -ble_att_svr_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); - - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_read_mult_locked(conn, chan, rxom); + goto done; } - ble_hs_conn_unlock(); + rc = 0; +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_MULT_REQ, + att_err, err_handle); return rc; } +/** + * Lock restrictions: None. + */ static int ble_att_svr_is_valid_group_type(uint8_t *uuid128) { @@ -1803,6 +1849,9 @@ ble_att_svr_is_valid_group_type(uint8_t *uuid128) uuid16 == BLE_ATT_UUID_SECONDARY_SERVICE; } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ static int ble_att_svr_service_uuid(struct ble_att_svr_entry *entry, uint16_t *uuid16, uint8_t *uuid128) @@ -1811,7 +1860,7 @@ ble_att_svr_service_uuid(struct ble_att_svr_entry *entry, uint16_t *uuid16, int rc; ctxt.offset = 0; - rc = ble_att_svr_read(NULL, entry, &ctxt, NULL); + rc = ble_att_svr_read(BLE_HS_CONN_HANDLE_NONE, entry, &ctxt, NULL); if (rc != 0) { return rc; } @@ -1834,6 +1883,9 @@ ble_att_svr_service_uuid(struct ble_att_svr_entry *entry, uint16_t *uuid16, } } +/** + * Lock restrictions: None. + */ static int ble_att_svr_read_group_type_entry_write(struct os_mbuf *om, uint16_t mtu, uint16_t start_group_handle, @@ -1870,14 +1922,17 @@ ble_att_svr_read_group_type_entry_write(struct os_mbuf *om, uint16_t mtu, } /** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + * * @return 0 on success; BLE_HS error code on failure. */ static int -ble_att_svr_tx_read_group_type(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct ble_att_read_group_type_req *req, - uint8_t *group_uuid128, uint8_t *att_err, - uint16_t *err_handle) +ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle, + struct ble_att_read_group_type_req *req, + uint8_t *group_uuid128, + struct os_mbuf **out_txom, + uint8_t *att_err, + uint16_t *err_handle) { struct ble_att_read_group_type_rsp rsp; struct ble_att_svr_entry *entry; @@ -1885,6 +1940,7 @@ ble_att_svr_tx_read_group_type(struct ble_hs_conn *conn, uint16_t start_group_handle; uint16_t end_group_handle; uint16_t service_uuid16; + uint16_t mtu; uint8_t service_uuid128[16]; void *rsp_buf; int rc; @@ -1897,9 +1953,18 @@ ble_att_svr_tx_read_group_type(struct ble_hs_conn *conn, *att_err = 0; *err_handle = req->bagq_start_handle; + txom = NULL; + + mtu = ble_att_mtu(conn_handle); + if (mtu == 0) { + rc = BLE_HS_ENOTCONN; + goto done; + } + txom = ble_att_get_pkthdr(); if (txom == NULL) { - rc = BLE_ATT_ERR_INSUFFICIENT_RES; + *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + rc = BLE_HS_ENOMEM; goto done; } @@ -1933,8 +1998,7 @@ ble_att_svr_tx_read_group_type(struct ble_hs_conn *conn, * representing the group to the response. */ rc = ble_att_svr_read_group_type_entry_write( - txom, ble_l2cap_chan_mtu(chan), - start_group_handle, end_group_handle, + txom, mtu, start_group_handle, end_group_handle, service_uuid16, service_uuid128); start_group_handle = 0; end_group_handle = 0; @@ -2019,8 +2083,7 @@ done: } rc = ble_att_svr_read_group_type_entry_write( - txom, ble_l2cap_chan_mtu(chan), - start_group_handle, end_group_handle, + txom, mtu, start_group_handle, end_group_handle, service_uuid16, service_uuid128); if (rc == BLE_HS_ENOMEM) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; @@ -2037,33 +2100,34 @@ done: rc = ble_att_read_group_type_rsp_write( rsp_buf, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ, &rsp); assert(rc == 0); - - rc = ble_l2cap_tx(conn, chan, txom); - } else { - os_mbuf_free_chain(txom); } + *out_txom = txom; return rc; } - -static int -ble_att_svr_rx_read_group_type_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_read_group_type_req req; + struct os_mbuf *txom; uint8_t uuid128[16]; uint16_t err_handle; uint8_t att_err; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + *rxom = os_mbuf_pullup(*rxom, OS_MBUF_PKTLEN(*rxom)); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_read_group_type_req_parse((*rxom)->om_data, (*rxom)->om_len, @@ -2072,7 +2136,7 @@ ble_att_svr_rx_read_group_type_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_PDU; err_handle = 0; rc = BLE_HS_EBADDATA; - goto err; + goto done; } if (req.bagq_start_handle > req.bagq_end_handle || @@ -2081,7 +2145,7 @@ ble_att_svr_rx_read_group_type_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_HANDLE; err_handle = req.bagq_start_handle; rc = BLE_HS_EBADDATA; - goto err; + goto done; } rc = ble_uuid_extract(*rxom, BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ, @@ -2090,52 +2154,36 @@ ble_att_svr_rx_read_group_type_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INVALID_PDU; err_handle = req.bagq_start_handle; rc = BLE_HS_EBADDATA; - goto err; + goto done; } if (!ble_att_svr_is_valid_group_type(uuid128)) { att_err = BLE_ATT_ERR_UNSUPPORTED_GROUP; err_handle = req.bagq_start_handle; rc = BLE_HS_ENOTSUP; - goto err; + goto done; } - rc = ble_att_svr_tx_read_group_type(conn, chan, &req, uuid128, - &att_err, &err_handle); + rc = ble_att_svr_build_read_group_type_rsp(conn_handle, &req, uuid128, + &txom, &att_err, &err_handle); if (rc != 0) { - goto err; - } - - return 0; - -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_READ_GROUP_TYPE_REQ, - err_handle, att_err); - return rc; -} - -int -ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); - - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_read_group_type_locked(conn, chan, rxom); + goto done; } - ble_hs_conn_unlock(); + rc = 0; +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, + BLE_ATT_OP_READ_GROUP_TYPE_REQ, att_err, + err_handle); return rc; } +/** + * Lock restrictions: None. + */ static int -ble_att_svr_tx_write_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, - uint8_t *att_err) +ble_att_svr_build_write_rsp(struct os_mbuf **out_txom, uint8_t *att_err) { struct os_mbuf *txom; uint8_t *dst; @@ -2145,49 +2193,49 @@ ble_att_svr_tx_write_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } dst = os_mbuf_extend(txom, BLE_ATT_WRITE_RSP_SZ); if (dst == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } *dst = BLE_ATT_OP_WRITE_RSP; - rc = ble_l2cap_tx(conn, chan, txom); - txom = NULL; - if (rc != 0) { - *att_err = BLE_ATT_ERR_UNLIKELY; - goto err; - } - return 0; + rc = 0; -err: - os_mbuf_free_chain(txom); +done: + *out_txom = txom; return rc; } -static int -ble_att_svr_rx_write_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_svr_access_ctxt ctxt; - struct ble_att_svr_entry *entry; struct ble_att_write_req req; + struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + att_err = 0; + err_handle = 0; + *rxom = os_mbuf_pullup(*rxom, BLE_ATT_WRITE_REQ_BASE_SZ); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_write_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); @@ -2195,86 +2243,52 @@ ble_att_svr_rx_write_locked(struct ble_hs_conn *conn, os_mbuf_adj(*rxom, BLE_ATT_WRITE_REQ_BASE_SZ); - entry = NULL; - rc = ble_att_svr_find_by_handle(req.bawq_handle, &entry); - if (rc != 0) { - att_err = BLE_ATT_ERR_INVALID_HANDLE; - err_handle = req.bawq_handle; - rc = BLE_HS_ENOENT; - goto err; - } - - if (entry->ha_cb == NULL) { - att_err = BLE_ATT_ERR_UNLIKELY; - err_handle = req.bawq_handle; - rc = BLE_HS_ENOTSUP; - goto err; - } - ctxt.attr_data = ble_att_svr_flat_buf; ctxt.data_len = OS_MBUF_PKTLEN(*rxom); os_mbuf_copydata(*rxom, 0, ctxt.data_len, ctxt.attr_data); - rc = ble_att_svr_write(conn, entry, &ctxt, &att_err); - if (rc != 0) { - err_handle = req.bawq_handle; - goto err; - } - - rc = ble_att_svr_tx_write_rsp(conn, chan, &att_err); - if (rc != 0) { - err_handle = req.bawq_handle; - goto err; - } - - return 0; - -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_WRITE_REQ, err_handle, - att_err); - return rc; -} - -int -ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); + rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, &ctxt, + &att_err); + if (rc != 0) { + err_handle = req.bawq_handle; + goto done; + } - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_write_locked(conn, chan, rxom); + rc = ble_att_svr_build_write_rsp(&txom, &att_err); + if (rc != 0) { + err_handle = req.bawq_handle; + goto done; } - ble_hs_conn_unlock(); + rc = 0; +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_WRITE_REQ, + att_err, err_handle); return rc; } +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ int ble_att_svr_write_local(uint16_t attr_handle, void *data, uint16_t data_len) { struct ble_att_svr_access_ctxt ctxt; - struct ble_att_svr_entry *entry; int rc; - entry = NULL; - rc = ble_att_svr_find_by_handle(attr_handle, &entry); - if (rc != 0) { - return rc; - } - ctxt.attr_data = data; ctxt.data_len = data_len; ctxt.offset = 0; - rc = ble_att_svr_write(NULL, entry, &ctxt, NULL); + rc = ble_att_svr_write_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, &ctxt, + NULL); return rc; } +/** + * Lock restrictions: None. + */ static void ble_att_svr_prep_free(struct ble_att_prep_entry *entry) { @@ -2282,6 +2296,9 @@ ble_att_svr_prep_free(struct ble_att_prep_entry *entry) os_memblock_put(&ble_att_svr_prep_entry_pool, entry); } +/** + * Lock restrictions: None. + */ static struct ble_att_prep_entry * ble_att_svr_prep_alloc(void) { @@ -2302,6 +2319,9 @@ ble_att_svr_prep_alloc(void) return entry; } +/** + * Lock restrictions: Caller must lock ble_hs_conn mutex. + */ static struct ble_att_prep_entry * ble_att_svr_prep_find_prev(struct ble_att_svr_conn *basc, uint16_t handle, uint16_t offset) @@ -2325,6 +2345,9 @@ ble_att_svr_prep_find_prev(struct ble_att_svr_conn *basc, uint16_t handle, return prev; } +/** + * Lock restrictions: Caller must lock ble_hs_conn mutex. + */ void ble_att_svr_prep_clear(struct ble_att_svr_conn *basc) { @@ -2337,6 +2360,8 @@ ble_att_svr_prep_clear(struct ble_att_svr_conn *basc) } /** + * Lock restrictions: Caller must lock ble_hs_conn mutex. + * * @return 0 on success; ATT error code on failure. */ static int @@ -2377,6 +2402,8 @@ ble_att_svr_prep_validate(struct ble_att_svr_conn *basc, uint16_t *err_handle) } /** + * Lock restrictions: Caller must lock ble_hs_conn mutex. + * * @return 0 on success; ATT error code on failure. */ static int @@ -2421,7 +2448,7 @@ ble_att_svr_prep_write(struct ble_hs_conn *conn, uint16_t *err_handle) ctxt.attr_data = ble_att_svr_flat_buf; ctxt.data_len = buf_off; - rc = ble_att_svr_write(conn, attr, &ctxt, &att_err); + rc = ble_att_svr_write(conn->bhc_handle, attr, &ctxt, &att_err); if (rc != 0) { *err_handle = entry->bape_handle; return att_err; @@ -2436,15 +2463,17 @@ ble_att_svr_prep_write(struct ble_hs_conn *conn, uint16_t *err_handle) return 0; } -static int -ble_att_svr_rx_prep_write_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_prep_write_cmd req; struct ble_att_prep_entry *prep_entry; struct ble_att_prep_entry *prep_prev; struct ble_att_svr_entry *attr_entry; + struct ble_hs_conn *conn; struct os_mbuf *srcom; struct os_mbuf *txom; uint16_t err_handle; @@ -2453,13 +2482,16 @@ ble_att_svr_rx_prep_write_locked(struct ble_hs_conn *conn, /* Initialize some values in case of early error. */ prep_entry = NULL; + txom = NULL; + att_err = 0; + err_handle = 0; *rxom = os_mbuf_pullup(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_prep_write_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); @@ -2472,7 +2504,7 @@ ble_att_svr_rx_prep_write_locked(struct ble_hs_conn *conn, if (rc != 0) { att_err = BLE_ATT_ERR_INVALID_HANDLE; err_handle = req.bapc_handle; - goto err; + goto done; } prep_entry = ble_att_svr_prep_alloc(); @@ -2480,31 +2512,48 @@ ble_att_svr_rx_prep_write_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL; err_handle = req.bapc_handle; rc = BLE_HS_ENOMEM; - goto err; + goto done; } prep_entry->bape_handle = req.bapc_handle; prep_entry->bape_offset = req.bapc_offset; - prep_prev = ble_att_svr_prep_find_prev(&conn->bhc_att_svr, req.bapc_handle, - req.bapc_offset); - if (prep_prev == NULL) { - SLIST_INSERT_HEAD(&conn->bhc_att_svr.basc_prep_list, prep_entry, - bape_next); + ble_hs_conn_lock(); + + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + rc = BLE_HS_ENOTCONN; } else { - SLIST_INSERT_AFTER(prep_prev, prep_entry, bape_next); - } + prep_prev = ble_att_svr_prep_find_prev(&conn->bhc_att_svr, + req.bapc_handle, + req.bapc_offset); + if (prep_prev == NULL) { + SLIST_INSERT_HEAD(&conn->bhc_att_svr.basc_prep_list, prep_entry, + bape_next); + } else { + SLIST_INSERT_AFTER(prep_prev, prep_entry, bape_next); + } - /* Append attribute value from request onto prep mbuf. */ - for (srcom = *rxom; srcom != NULL; srcom = SLIST_NEXT(srcom, om_next)) { - rc = os_mbuf_append(prep_entry->bape_value, srcom->om_data, - srcom->om_len); - if (rc != 0) { - att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL; - err_handle = req.bapc_handle; - goto err; + /* Append attribute value from request onto prep mbuf. */ + for (srcom = *rxom; + srcom != NULL; + srcom = SLIST_NEXT(srcom, om_next)) { + + rc = os_mbuf_append(prep_entry->bape_value, srcom->om_data, + srcom->om_len); + if (rc != 0) { + att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL; + err_handle = req.bapc_handle; + break; + } } } + ble_hs_conn_unlock(); + + if (rc != 0) { + goto done; + } + /* The receive buffer now contains the attribute value. Repurpose this * buffer for the response. Prepend a response header. */ @@ -2513,7 +2562,7 @@ ble_att_svr_rx_prep_write_locked(struct ble_hs_conn *conn, att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = req.bapc_handle; rc = BLE_HS_ENOMEM; - goto err; + goto done; } txom = *rxom; @@ -2521,62 +2570,49 @@ ble_att_svr_rx_prep_write_locked(struct ble_hs_conn *conn, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, &req); assert(rc == 0); - rc = ble_l2cap_tx(conn, chan, txom); - if (rc != 0) { - att_err = BLE_ATT_ERR_UNLIKELY; - err_handle = req.bapc_handle; - goto err; - } - - /* Make sure the receive buffer doesn't get freed since we are using it for - * the response. - */ - *rxom = NULL; + rc = 0; - return 0; +done: + if (rc != 0 && rc != BLE_HS_ENOTCONN) { + ble_hs_conn_lock(); -err: - if (prep_entry != NULL) { - if (prep_prev == NULL) { - SLIST_REMOVE_HEAD(&conn->bhc_att_svr.basc_prep_list, bape_next); + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + rc = BLE_HS_ENOTCONN; } else { - SLIST_NEXT(prep_prev, bape_next) = - SLIST_NEXT(prep_entry, bape_next); - } - - ble_att_svr_prep_free(prep_entry); - } - - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_PREP_WRITE_REQ, - err_handle, att_err); - return rc; -} - -int -ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; + if (prep_entry != NULL) { + if (prep_prev == NULL) { + SLIST_REMOVE_HEAD(&conn->bhc_att_svr.basc_prep_list, + bape_next); + } else { + SLIST_NEXT(prep_prev, bape_next) = + SLIST_NEXT(prep_entry, bape_next); + } - ble_hs_conn_lock(); + ble_att_svr_prep_free(prep_entry); + } + } - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_prep_write_locked(conn, chan, rxom); + ble_hs_conn_unlock(); } - ble_hs_conn_unlock(); + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_PREP_WRITE_REQ, + att_err, err_handle); + /* Make sure the receive buffer doesn't get freed since we are using it for + * the response. + */ + *rxom = NULL; return rc; } /** + * Lock restrictions: None. + * * @return 0 on success; nonzero on failure. */ static int -ble_att_svr_tx_exec_write_rsp(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, uint8_t *att_err) +ble_att_svr_build_exec_write_rsp(struct os_mbuf **out_txom, uint8_t *att_err) { struct os_mbuf *txom; uint8_t *dst; @@ -2586,108 +2622,92 @@ ble_att_svr_tx_exec_write_rsp(struct ble_hs_conn *conn, if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } dst = os_mbuf_extend(txom, BLE_ATT_EXEC_WRITE_RSP_SZ); if (dst == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_exec_write_rsp_write(dst, BLE_ATT_EXEC_WRITE_RSP_SZ); assert(rc == 0); - rc = ble_l2cap_tx(conn, chan, txom); - txom = NULL; - if (rc != 0) { - *att_err = BLE_ATT_ERR_UNLIKELY; - goto err; - } - - return 0; + rc = 0; -err: - os_mbuf_free_chain(txom); +done: + *out_txom = txom; return rc; } -static int -ble_att_svr_rx_exec_write_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_exec_write_req req; + struct ble_hs_conn *conn; + struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + *rxom = os_mbuf_pullup(*rxom, BLE_ATT_EXEC_WRITE_REQ_SZ); if (*rxom == NULL) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; err_handle = 0; rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_exec_write_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); assert(rc == 0); - if (req.baeq_flags & BLE_ATT_EXEC_WRITE_F_CONFIRM) { - /* Perform attribute writes. */ - att_err = ble_att_svr_prep_write(conn, &err_handle); - } else { - att_err = 0; - err_handle = 0; - } - - /* Erase all prep entries. */ - ble_att_svr_prep_clear(&conn->bhc_att_svr); - - if (att_err != 0) { - rc = BLE_HS_EAPP; - goto err; - } - - /* Send response. */ - rc = ble_att_svr_tx_exec_write_rsp(conn, chan, &att_err); + rc = ble_att_svr_build_exec_write_rsp(&txom, &att_err); if (rc != 0) { err_handle = 0; - goto err; + goto done; } - return 0; - -err: - ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_EXEC_WRITE_REQ, - err_handle, att_err); - return rc; -} - -int -ble_att_svr_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); + rc = 0; - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); +done: if (rc == 0) { - rc = ble_att_svr_rx_exec_write_locked(conn, chan, rxom); - } + ble_hs_conn_lock(); + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + rc = BLE_HS_ENOTCONN; + } else { + if (req.baeq_flags & BLE_ATT_EXEC_WRITE_F_CONFIRM) { + /* Perform attribute writes. */ + att_err = ble_att_svr_prep_write(conn, &err_handle); + if (att_err != 0) { + rc = BLE_HS_EAPP; + } + } - ble_hs_conn_unlock(); + /* Erase all prep entries. */ + ble_att_svr_prep_clear(&conn->bhc_att_svr); + } + ble_hs_conn_unlock(); + } + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_EXEC_WRITE_REQ, + att_err, err_handle); return rc; } -static int -ble_att_svr_rx_notify_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_notify_req req; uint16_t attr_len; @@ -2717,7 +2737,7 @@ ble_att_svr_rx_notify_locked(struct ble_hs_conn *conn, os_mbuf_copydata(*rxom, 0, attr_len, attr_data); if (ble_att_svr_notify_cb != NULL) { - rc = ble_att_svr_notify_cb(conn->bhc_handle, req.banq_handle, + rc = ble_att_svr_notify_cb(conn_handle, req.banq_handle, attr_data, attr_len, ble_att_svr_notify_cb_arg); if (rc != 0) { @@ -2728,31 +2748,13 @@ ble_att_svr_rx_notify_locked(struct ble_hs_conn *conn, return 0; } -int -ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); - - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_notify_locked(conn, chan, rxom); - } - - ble_hs_conn_unlock(); - - return rc; -} - /** + * Lock restrictions: None. + * * @return 0 on success; nonzero on failure. */ static int -ble_att_svr_tx_indicate_rsp(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan) +ble_att_svr_build_indicate_rsp(struct os_mbuf **out_txom) { struct os_mbuf *txom; uint8_t *dst; @@ -2761,42 +2763,40 @@ ble_att_svr_tx_indicate_rsp(struct ble_hs_conn *conn, txom = ble_att_get_pkthdr(); if (txom == NULL) { rc = BLE_HS_ENOMEM; - goto err; + goto done; } dst = os_mbuf_extend(txom, BLE_ATT_INDICATE_RSP_SZ); if (dst == NULL) { rc = BLE_HS_ENOMEM; - goto err; + goto done; } rc = ble_att_indicate_rsp_write(dst, BLE_ATT_INDICATE_RSP_SZ); assert(rc == 0); - rc = ble_l2cap_tx(conn, chan, txom); - txom = NULL; - if (rc != 0) { - goto err; - } - - return 0; + rc = 0; -err: - os_mbuf_free_chain(txom); +done: + *out_txom = txom; return rc; } -static int -ble_att_svr_rx_indicate_locked(struct ble_hs_conn *conn, - struct ble_l2cap_chan *chan, - struct os_mbuf **rxom) +/** + * Lock restrictions: Caller must NOT lock ble_hs_conn mutex. + */ +int +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 txrc; int rc; + /* Initialize some values in case of early error. */ + txom = NULL; + if (OS_MBUF_PKTLEN(*rxom) < BLE_ATT_INDICATE_REQ_BASE_SZ) { rc = BLE_HS_EBADDATA; goto done; @@ -2823,7 +2823,7 @@ ble_att_svr_rx_indicate_locked(struct ble_hs_conn *conn, os_mbuf_copydata(*rxom, 0, attr_len, attr_data); if (ble_att_svr_notify_cb != NULL) { - rc = ble_att_svr_notify_cb(conn->bhc_handle, req.baiq_handle, + rc = ble_att_svr_notify_cb(conn_handle, req.baiq_handle, attr_data, attr_len, ble_att_svr_notify_cb_arg); if (rc != 0) { @@ -2832,59 +2832,39 @@ ble_att_svr_rx_indicate_locked(struct ble_hs_conn *conn, } } -done: - txrc = ble_att_svr_tx_indicate_rsp(conn, chan); - if (rc == 0) { - rc = txrc; - } - - return rc; -} - -int -ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom) -{ - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; - int rc; - - ble_hs_conn_lock(); - - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - rc = ble_att_svr_rx_indicate_locked(conn, chan, rxom); + rc = ble_att_svr_build_indicate_rsp(&txom); + if (rc != 0) { + goto done; } - ble_hs_conn_unlock(); + rc = 0; +done: + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_INDICATE_REQ, + 0, 0); return rc; } -static void -ble_att_svr_free_mem(void) -{ -} - +/** + * Lock restrictions: None. + */ int ble_att_svr_init(void) { int rc; - ble_att_svr_free_mem(); - STAILQ_INIT(&ble_att_svr_list); rc = os_mutex_init(&ble_att_svr_list_mutex); if (rc != 0) { - goto err; + return rc; } rc = os_mempool_init(&ble_att_svr_entry_pool, BLE_ATT_SVR_NUM_ENTRIES, sizeof (struct ble_att_svr_entry), ble_att_svr_entry_mem, "ble_att_svr_entry_pool"); if (rc != 0) { - rc = BLE_HS_EOS; - goto err; + return BLE_HS_EOS; } rc = os_mempool_init(&ble_att_svr_prep_entry_pool, @@ -2893,8 +2873,7 @@ ble_att_svr_init(void) ble_att_svr_prep_entry_mem, "ble_att_svr_prep_entry_pool"); if (rc != 0) { - rc = BLE_HS_EOS; - goto err; + return BLE_HS_EOS; } rc = os_mempool_init(&ble_att_svr_prep_mbuf_mempool, @@ -2903,8 +2882,7 @@ ble_att_svr_init(void) ble_att_svr_prep_mbuf_mem, "ble_att_svr_prep_mbuf_pool"); if (rc != 0) { - rc = BLE_HS_EOS; - goto err; + return BLE_HS_EOS; } rc = os_mbuf_pool_init(&ble_att_svr_prep_mbuf_pool, @@ -2912,16 +2890,11 @@ ble_att_svr_init(void) BLE_ATT_SVR_PREP_MBUF_MEMBLOCK_SIZE, BLE_ATT_SVR_NUM_PREP_MBUFS); if (rc != 0) { - rc = BLE_HS_EOS; - goto err; + return BLE_HS_EOS; } ble_att_svr_id = 0; ble_att_svr_notify_cb = NULL; return 0; - -err: - ble_att_svr_free_mem(); - return rc; } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/4980dba7/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 e472f84..d27cd29 100644 --- a/net/nimble/host/src/ble_gattc.c +++ b/net/nimble/host/src/ble_gattc.c @@ -3531,7 +3531,8 @@ ble_gattc_notify(struct ble_hs_conn *conn, uint16_t chr_val_handle) struct ble_att_notify_req req; int rc; - rc = ble_att_svr_read_handle(NULL, chr_val_handle, &ctxt, NULL); + rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, chr_val_handle, + &ctxt, NULL); if (rc != 0) { return rc; } @@ -3596,7 +3597,8 @@ ble_gattc_indicate_kick(struct ble_gattc_proc *proc) if (conn == NULL) { rc = BLE_HS_ENOTCONN; } else { - rc = ble_att_svr_read_handle(NULL, proc->indicate.attr.handle, &ctxt, + rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, + proc->indicate.attr.handle, &ctxt, NULL); if (rc == 0) { proc->indicate.attr.value = ctxt.attr_data;