static int nm_ble_out(struct nmgr_transport *nt, struct os_mbuf *om) { struct ble_gatt_attr attr; uint16_t conn_handle; int rc; assert(OS_MBUF_USRHDR_LEN(om) == 2); memcpy(&conn_handle, OS_MBUF_USRHDR(om), 2); assert(OS_MBUF_PKTLEN(om) <= sizeof nm_buf); rc = os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), nm_buf); assert(rc == 0); attr.handle = nm_attr_val_handle; attr.offset = 0; attr.value_len = OS_MBUF_PKTLEN(om); attr.value = nm_buf; rc = ble_gattc_notify_custom(conn_handle, &attr); console_printf("nm_ble_out(); conn_handle = %d notify-rc=%d\n", conn_handle, rc); return rc; }
static int nmgr_rsp_fragment(struct nmgr_transport *nt, struct nmgr_hdr *rsp_hdr, struct os_mbuf *rsp, struct os_mbuf *req) { uint16_t mtu; uint16_t rsplen; uint16_t len ; int rc; len = 0; mtu = nt->nt_get_mtu(req); do { len = OS_MBUF_PKTLEN(rsp); if (len >= mtu) { rsplen = mtu; } else { rsplen = len; } rc = nmgr_send_rspfrag(nt, rsp, req, rsplen); if (rc) { goto err; } os_mbuf_adj(rsp, rsplen); } while (OS_MBUF_PKTLEN(rsp)); return MGMT_ERR_EOK; err: return rc; }
int ble_hs_test_util_l2cap_rx_payload_flat(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, const void *data, int len) { struct hci_data_hdr hci_hdr; struct os_mbuf *om; int rc; om = ble_hs_misc_pkthdr(); TEST_ASSERT_FATAL(om != NULL); om->om_data += BLE_L2CAP_HDR_SZ; rc = os_mbuf_append(om, data, len); TEST_ASSERT_FATAL(rc == 0); om = ble_l2cap_prepend_hdr(om, chan->blc_cid, OS_MBUF_PKTLEN(om)); TEST_ASSERT_FATAL(om != NULL); hci_hdr.hdh_handle_pb_bc = host_hci_handle_pb_bc_join(conn->bhc_handle, BLE_HCI_PB_FIRST_FLUSH, 0); hci_hdr.hdh_len = OS_MBUF_PKTHDR(om)->omp_len; rc = ble_hs_test_util_l2cap_rx(conn, &hci_hdr, om); return rc; }
static void ble_att_clt_test_misc_prep_good(uint16_t handle, uint16_t offset, uint8_t *attr_data, uint16_t attr_data_len) { struct ble_att_prep_write_cmd req; struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; struct os_mbuf *om; int rc; int i; ble_att_clt_test_misc_init(&conn, &chan); req.bapc_handle = handle; req.bapc_offset = offset; rc = ble_att_clt_tx_prep_write(conn->bhc_handle, &req, attr_data, attr_data_len); TEST_ASSERT(rc == 0); ble_hs_test_util_tx_all(); TEST_ASSERT_FATAL(ble_hs_test_util_prev_tx != NULL); om = os_mbuf_pullup(ble_hs_test_util_prev_tx, OS_MBUF_PKTLEN(ble_hs_test_util_prev_tx)); TEST_ASSERT_FATAL(om != NULL); TEST_ASSERT(om->om_len == BLE_ATT_PREP_WRITE_CMD_BASE_SZ + attr_data_len); ble_att_prep_write_req_parse(om->om_data, om->om_len, &req); TEST_ASSERT(req.bapc_handle == handle); TEST_ASSERT(req.bapc_offset == offset); for (i = 0; i < attr_data_len; i++) { TEST_ASSERT(om->om_data[BLE_ATT_PREP_WRITE_CMD_BASE_SZ + i] == attr_data[i]); } }
static void ble_gatt_find_s_test_misc_verify_tx_read_type(uint16_t start_handle, uint16_t end_handle) { struct ble_att_read_type_req req; struct os_mbuf *om; uint16_t uuid16; int rc; ble_hs_test_util_tx_all(); TEST_ASSERT_FATAL(ble_hs_test_util_prev_tx != NULL); om = os_mbuf_pullup(ble_hs_test_util_prev_tx, OS_MBUF_PKTLEN(ble_hs_test_util_prev_tx)); TEST_ASSERT_FATAL(om != NULL); rc = ble_att_read_type_req_parse(om->om_data, om->om_len, &req); TEST_ASSERT(rc == 0); TEST_ASSERT(req.batq_start_handle == start_handle); TEST_ASSERT(req.batq_end_handle == end_handle); TEST_ASSERT(om->om_len == BLE_ATT_READ_TYPE_REQ_BASE_SZ + 2); uuid16 = le16toh(om->om_data + BLE_ATT_READ_TYPE_REQ_BASE_SZ); TEST_ASSERT(uuid16 == BLE_ATT_UUID_INCLUDE); }
static void ble_att_clt_test_misc_verify_tx_write(uint16_t handle_id, void *value, int value_len, int is_req) { struct ble_att_write_req req; struct os_mbuf *om; int rc; TEST_ASSERT_FATAL(ble_hs_test_util_prev_tx != NULL); om = os_mbuf_pullup(ble_hs_test_util_prev_tx, OS_MBUF_PKTLEN(ble_hs_test_util_prev_tx)); TEST_ASSERT_FATAL(om != NULL); if (is_req) { rc = ble_att_write_req_parse(om->om_data, om->om_len, &req); } else { rc = ble_att_write_cmd_parse(om->om_data, om->om_len, &req); } TEST_ASSERT_FATAL(rc == 0); TEST_ASSERT(req.bawq_handle == handle_id); TEST_ASSERT(om->om_len == BLE_ATT_WRITE_REQ_BASE_SZ + value_len); TEST_ASSERT(memcmp(om->om_data + BLE_ATT_WRITE_REQ_BASE_SZ, value, value_len) == 0); }
int ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) { #if !NIMBLE_OPT(ATT_CLT_FIND_TYPE) return BLE_HS_ENOTSUP; #endif struct ble_att_find_type_value_hinfo hinfo; int rc; /* Reponse consists of a one-byte opcode (already verified) and a variable * length Handles-Information-List field. Strip the opcode from the * response. */ os_mbuf_adj(*rxom, BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ); /* Parse the Handles-Information-List field, passing each entry to GATT. */ rc = 0; while (OS_MBUF_PKTLEN(*rxom) > 0) { rc = ble_att_clt_parse_find_type_value_hinfo(rxom, &hinfo); if (rc != 0) { break; } ble_gattc_rx_find_type_value_hinfo(conn_handle, &hinfo); os_mbuf_adj(*rxom, BLE_ATT_FIND_TYPE_VALUE_HINFO_BASE_SZ); } /* Notify GATT client that the full response has been parsed. */ ble_gattc_rx_find_type_value_complete(conn_handle, rc); return 0; }
static void ble_att_clt_test_misc_exec_good(uint8_t flags) { struct ble_att_exec_write_req req; struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; struct os_mbuf *om; int rc; ble_att_clt_test_misc_init(&conn, &chan); req.baeq_flags = flags; rc = ble_att_clt_tx_exec_write(conn->bhc_handle, &req); TEST_ASSERT(rc == 0); ble_hs_test_util_tx_all(); TEST_ASSERT_FATAL(ble_hs_test_util_prev_tx != NULL); om = os_mbuf_pullup(ble_hs_test_util_prev_tx, OS_MBUF_PKTLEN(ble_hs_test_util_prev_tx)); TEST_ASSERT_FATAL(om != NULL); TEST_ASSERT(om->om_len == BLE_ATT_EXEC_WRITE_REQ_SZ); ble_att_exec_write_req_parse(om->om_data, om->om_len, &req); TEST_ASSERT(req.baeq_flags == flags); }
static int ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { uint16_t uuid16; int rc; uuid16 = ble_uuid_128_to_16(ctxt->chr->uuid128); assert(uuid16 != 0); switch (uuid16) { case BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, ble_svc_gap_name, strlen(ble_svc_gap_name)); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case BLE_SVC_GAP_CHR_UUID16_APPEARANCE: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, &ble_svc_gap_appearance, sizeof ble_svc_gap_appearance); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case BLE_SVC_GAP_CHR_UUID16_PERIPH_PRIV_FLAG: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, &ble_svc_gap_privacy_flag, sizeof ble_svc_gap_privacy_flag); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case BLE_SVC_GAP_CHR_UUID16_RECONNECT_ADDR: assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR); if (OS_MBUF_PKTLEN(ctxt->om) != sizeof ble_svc_gap_reconnect_addr) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } ble_hs_mbuf_to_flat(ctxt->om, ble_svc_gap_reconnect_addr, sizeof ble_svc_gap_reconnect_addr, NULL); return 0; case BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, &ble_svc_gap_pref_conn_params, sizeof ble_svc_gap_pref_conn_params); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; default: assert(0); return BLE_ATT_ERR_UNLIKELY; } }
static int gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len, void *dst, uint16_t *len) { uint16_t om_len; int rc; om_len = OS_MBUF_PKTLEN(om); if (om_len < min_len || om_len > max_len) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } rc = ble_hs_mbuf_to_flat(om, dst, max_len, len); if (rc != 0) { return BLE_ATT_ERR_UNLIKELY; } return 0; }
static int ble_att_clt_tx_req_flags(uint16_t conn_handle, struct os_mbuf *txom, ble_hs_conn_flags_t flags_on_success) { struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; uint16_t total_len; uint16_t mtu; int extra_len; int rc; BLE_HS_DBG_ASSERT_EVAL(txom->om_len >= 1); ble_att_inc_tx_stat(txom->om_data[0]); ble_hs_lock(); rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); if (rc == 0) { /* Reduce the size of the transmission to fit the connection's ATT * MTU. */ total_len = OS_MBUF_PKTLEN(txom); mtu = ble_l2cap_chan_mtu(chan); extra_len = total_len - mtu; if (extra_len > 0) { os_mbuf_adj(txom, -extra_len); } rc = ble_l2cap_tx(conn, chan, txom); txom = NULL; if (rc == 0) { conn->bhc_flags |= flags_on_success; } } ble_hs_unlock(); os_mbuf_free_chain(txom); return rc; }
static void ble_gatt_find_s_test_misc_verify_tx_read(uint16_t handle) { struct ble_att_read_req req; struct os_mbuf *om; int rc; ble_hs_test_util_tx_all(); TEST_ASSERT_FATAL(ble_hs_test_util_prev_tx != NULL); om = os_mbuf_pullup(ble_hs_test_util_prev_tx, OS_MBUF_PKTLEN(ble_hs_test_util_prev_tx)); TEST_ASSERT_FATAL(om != NULL); rc = ble_att_read_req_parse(om->om_data, om->om_len, &req); TEST_ASSERT(rc == 0); TEST_ASSERT(req.barq_handle == handle); TEST_ASSERT(om->om_len == BLE_ATT_READ_REQ_SZ); }
static int ble_att_clt_copy_attr_to_flatbuf(struct os_mbuf *om, void **out_attr_val, uint16_t *out_attr_len) { uint8_t *flat_buf; uint16_t attr_len; /* Make sure the attribute value isn't too big. */ attr_len = OS_MBUF_PKTLEN(om); if (attr_len > BLE_ATT_ATTR_MAX_LEN) { *out_attr_len = 0; *out_attr_val = NULL; return BLE_HS_EBADDATA; } /* Copy the attribute data into the global ATT flat buffer. */ flat_buf = ble_att_get_flat_buf(); os_mbuf_copydata(om, 0, attr_len, flat_buf); *out_attr_val = flat_buf; *out_attr_len = attr_len; return 0; }
int ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) { #if !NIMBLE_OPT(ATT_CLT_READ_GROUP_TYPE) return BLE_HS_ENOTSUP; #endif struct ble_att_read_group_type_adata adata; struct ble_att_read_group_type_rsp rsp; int rc; rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ); if (rc != 0) { goto done; } ble_att_read_group_type_rsp_parse((*rxom)->om_data, (*rxom)->om_len, &rsp); /* Strip the base from the front of the response. */ os_mbuf_adj(*rxom, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ); /* Parse the Attribute Data List field, passing each entry to GATT. */ while (OS_MBUF_PKTLEN(*rxom) > 0) { rc = ble_att_clt_parse_read_group_type_adata(rxom, rsp.bagp_length, &adata); if (rc != 0) { goto done; } ble_gattc_rx_read_group_type_adata(conn_handle, &adata); os_mbuf_adj(*rxom, rsp.bagp_length); } done: /* Notify GATT that the response is done being parsed. */ ble_gattc_rx_read_group_type_complete(conn_handle, rc); return rc; }
int ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om) { #if !NIMBLE_OPT(ATT_CLT_FIND_INFO) return BLE_HS_ENOTSUP; #endif struct ble_att_find_info_idata idata; struct ble_att_find_info_rsp rsp; int rc; rc = ble_hs_misc_pullup_base(om, BLE_ATT_FIND_INFO_RSP_BASE_SZ); if (rc != 0) { goto done; } ble_att_find_info_rsp_parse((*om)->om_data, (*om)->om_len, &rsp); /* Strip the response base from the front of the mbuf. */ os_mbuf_adj((*om), BLE_ATT_FIND_INFO_RSP_BASE_SZ); while (OS_MBUF_PKTLEN(*om) > 0) { rc = ble_att_clt_parse_find_info_entry(om, rsp.bafp_format, &idata); if (rc != 0) { goto done; } /* Hand find-info entry to GATT. */ ble_gattc_rx_find_info_idata(conn_handle, &idata); } rc = 0; done: /* Notify GATT that response processing is done. */ ble_gattc_rx_find_info_complete(conn_handle, rc); return rc; }
static int gatt_svr_chr_access_newtmgr(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { int rc; struct os_mbuf *m_req; switch (ctxt->op) { case BLE_GATT_ACCESS_OP_WRITE_CHR: /* Try to reuse the BLE packet mbuf as the newtmgr request. This * requires a two-byte usrhdr to hold the BLE connection handle so * that the newtmgr response can be sent to the correct peer. If * it is not possible to reuse the mbuf, then allocate a new one * and copy the request contents. */ if (OS_MBUF_USRHDR_LEN(ctxt->om) >= sizeof (conn_handle)) { /* Sufficient usrhdr space already present. */ m_req = ctxt->om; ctxt->om = NULL; } else if (OS_MBUF_LEADINGSPACE(ctxt->om) >= sizeof (conn_handle)) { /* Usrhdr isn't present, but there is enough leading space to * add one. */ m_req = ctxt->om; ctxt->om = NULL; m_req->om_pkthdr_len += sizeof (conn_handle); } else { /* The mbuf can't be reused. Allocate a new one and perform a * copy. Don't set ctxt->om to NULL; let the NimBLE host free * it. */ m_req = os_msys_get_pkthdr(OS_MBUF_PKTLEN(ctxt->om), sizeof (conn_handle)); if (!m_req) { return BLE_ATT_ERR_INSUFFICIENT_RES; } rc = os_mbuf_appendfrom(m_req, ctxt->om, 0, OS_MBUF_PKTLEN(ctxt->om)); if (rc) { return BLE_ATT_ERR_INSUFFICIENT_RES; } } /* Write the connection handle to the newtmgr request usrhdr. This * is necessary so that we later know who to send the newtmgr * response to. */ memcpy(OS_MBUF_USRHDR(m_req), &conn_handle, sizeof(conn_handle)); rc = nmgr_rx_req(&ble_nt, m_req); if (rc != 0) { return BLE_ATT_ERR_UNLIKELY; } return 0; default: assert(0); return BLE_ATT_ERR_UNLIKELY; } }
static int gatt_svr_chr_access_rw_demo( uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { puts("service 'rw demo' callback triggered"); (void) conn_handle; (void) attr_handle; (void) arg; int rc = 0; ble_uuid_t* write_uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_write_uuid.u; ble_uuid_t* readonly_uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_readonly_uuid.u; if (ble_uuid_cmp(ctxt->chr->uuid, write_uuid) == 0) { puts("access to characteristic 'rw demo (write)'"); switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: puts("read from characteristic"); printf("current value of rm_demo_write_data: '%s'\n", rm_demo_write_data); /* send given data to the client */ rc = os_mbuf_append(ctxt->om, &rm_demo_write_data, strlen(rm_demo_write_data)); break; case BLE_GATT_ACCESS_OP_WRITE_CHR: puts("write to characteristic"); printf("old value of rm_demo_write_data: '%s'\n", rm_demo_write_data); uint16_t om_len; om_len = OS_MBUF_PKTLEN(ctxt->om); /* read sent data */ rc = ble_hs_mbuf_to_flat(ctxt->om, &rm_demo_write_data, sizeof rm_demo_write_data, &om_len); /* we need to null-terminate the received string */ rm_demo_write_data[om_len] = '\0'; printf("new value of rm_demo_write_data: '%s'\n", rm_demo_write_data); break; case BLE_GATT_ACCESS_OP_READ_DSC: puts("read from descriptor"); break; case BLE_GATT_ACCESS_OP_WRITE_DSC: puts("write to descriptor"); break; default: puts("unhandled operation!"); rc = 1; break; } puts(""); return rc; } else if (ble_uuid_cmp(ctxt->chr->uuid, readonly_uuid) == 0) { puts("access to characteristic 'rw demo (read-only)'"); if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { char random_digit; /* get random char between '0' and '9' */ random_digit = 48 + (rand() % 10); snprintf(str_answer, STR_ANSWER_BUFFER_SIZE, "new random number: %c", random_digit); puts(str_answer); rc = os_mbuf_append(ctxt->om, &str_answer, strlen(str_answer)); puts(""); return rc; } return 0; } puts("unhandled uuid!"); return 1; }