diff options
Diffstat (limited to 'net')
137 files changed, 15062 insertions, 6696 deletions
diff --git a/net/nimble/controller/include/controller/ble_ll.h b/net/nimble/controller/include/controller/ble_ll.h index 81cba53f..7865cf89 100644 --- a/net/nimble/controller/include/controller/ble_ll.h +++ b/net/nimble/controller/include/controller/ble_ll.h @@ -22,6 +22,7 @@ #include "stats/stats.h" #include "hal/hal_cputime.h" +#include "os/os_eventq.h" #include "nimble/nimble_opt.h" /* Controller revision. */ @@ -85,6 +86,7 @@ STATS_SECT_START(ble_ll_stats) STATS_SECT_ENTRY(hci_events_sent) STATS_SECT_ENTRY(bad_ll_state) STATS_SECT_ENTRY(bad_acl_hdr) + STATS_SECT_ENTRY(no_bufs) STATS_SECT_ENTRY(rx_adv_pdu_crc_ok) STATS_SECT_ENTRY(rx_adv_pdu_crc_err) STATS_SECT_ENTRY(rx_adv_bytes_crc_ok) @@ -311,13 +313,24 @@ int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type); */ void ble_ll_acl_data_in(struct os_mbuf *txpkt); +/** + * Allocate a pdu (chain) for reception. + * + * @param len Length of PDU. This includes the PDU header as well as payload. + * Does not include MIC if encrypted. + * + * @return struct os_mbuf* Pointer to mbuf chain to hold received packet + */ +struct os_mbuf *ble_ll_rxpdu_alloc(uint16_t len); + /*--- PHY interfaces ---*/ +struct ble_mbuf_hdr; + /* Called by the PHY when a packet has started */ -int ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan); +int ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *hdr); /* Called by the PHY when a packet reception ends */ -struct ble_mbuf_hdr; -int ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr); +int ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); /*--- Controller API ---*/ void ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr); @@ -331,6 +344,9 @@ uint8_t ble_ll_state_get(void); /* Send an event to LL task */ void ble_ll_event_send(struct os_event *ev); +/* Hand received pdu's to LL task */ +void ble_ll_rx_pdu_in(struct os_mbuf *rxpdu); + /* Set random address */ int ble_ll_set_random_addr(uint8_t *addr); @@ -382,6 +398,7 @@ int ble_ll_rand_start(void); #define BLE_LL_LOG_ID_CONN_END (30) #define BLE_LL_LOG_ID_ADV_TXBEG (50) #define BLE_LL_LOG_ID_ADV_TXDONE (60) +#define BLE_LL_LOG_ID_SCHED (80) #ifdef BLE_LL_LOG void ble_ll_log(uint8_t id, uint8_t arg8, uint16_t arg16, uint32_t arg32); diff --git a/net/nimble/controller/include/controller/ble_ll_hci.h b/net/nimble/controller/include/controller/ble_ll_hci.h index 47daa765..e3a7e3e5 100644 --- a/net/nimble/controller/include/controller/ble_ll_hci.h +++ b/net/nimble/controller/include/controller/ble_ll_hci.h @@ -24,6 +24,9 @@ #define BLE_LL_SUPP_CMD_LEN (36) extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN]; +/* The largest event the controller will send. */ +#define BLE_LL_MAX_EVT_LEN (70) + /* * This determines the number of outstanding commands allowed from the * host to the controller. diff --git a/net/nimble/controller/include/controller/ble_ll_resolv.h b/net/nimble/controller/include/controller/ble_ll_resolv.h index 251543b2..6c63c79f 100644 --- a/net/nimble/controller/include/controller/ble_ll_resolv.h +++ b/net/nimble/controller/include/controller/ble_ll_resolv.h @@ -23,15 +23,18 @@ /* * An entry in the resolving list. * The identity address is stored in little endian format. + * The local rpa is stored in little endian format. * The IRKs are stored in big endian format. */ struct ble_ll_resolv_entry { - uint8_t rl_reserved; uint8_t rl_addr_type; - uint8_t rl_identity_addr[BLE_DEV_ADDR_LEN]; + uint8_t rl_local_rpa_set; + uint16_t rl_reserved; uint8_t rl_local_irk[16]; uint8_t rl_peer_irk[16]; + uint8_t rl_identity_addr[BLE_DEV_ADDR_LEN]; + uint8_t rl_local_rpa[BLE_DEV_ADDR_LEN]; }; extern struct ble_ll_resolv_entry g_ble_ll_resolv_list[]; diff --git a/net/nimble/controller/include/controller/ble_ll_scan.h b/net/nimble/controller/include/controller/ble_ll_scan.h index 7dafcee2..3b935f43 100644 --- a/net/nimble/controller/include/controller/ble_ll_scan.h +++ b/net/nimble/controller/include/controller/ble_ll_scan.h @@ -96,7 +96,7 @@ void ble_ll_scan_init(void); void ble_ll_scan_reset(void); /* Called when Link Layer starts to receive a PDU and is in scanning state */ -int ble_ll_scan_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu); +int ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint8_t *rxflags); /* Called when Link Layer has finished receiving a PDU while scanning */ int ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok); diff --git a/net/nimble/controller/include/controller/ble_phy.h b/net/nimble/controller/include/controller/ble_phy.h index 1333c192..585c2dc9 100644 --- a/net/nimble/controller/include/controller/ble_phy.h +++ b/net/nimble/controller/include/controller/ble_phy.h @@ -97,6 +97,9 @@ int ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans); /* Place the PHY into receive mode */ int ble_phy_rx(void); +/* Copies the received PHY buffer into the allocated pdu */ +void ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu); + /* Get an RSSI reading */ int ble_phy_rssi_get(void); diff --git a/net/nimble/controller/pkg.yml b/net/nimble/controller/pkg.yml index 07a9d560..8e52aba9 100644 --- a/net/nimble/controller/pkg.yml +++ b/net/nimble/controller/pkg.yml @@ -25,10 +25,14 @@ pkg.keywords: - ble - bluetooth -pkg.req_apis: ble_driver +pkg.req_apis: + - ble_driver + - ble_transport + pkg.deps: - libs/os - sys/stats - net/nimble + pkg.features: - BLE_DEVICE diff --git a/net/nimble/controller/src/ble_ll.c b/net/nimble/controller/src/ble_ll.c index 3a09e3e9..3beb28ea 100644 --- a/net/nimble/controller/src/ble_ll.c +++ b/net/nimble/controller/src/ble_ll.c @@ -26,6 +26,7 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" #include "controller/ble_hw.h" #include "controller/ble_phy.h" #include "controller/ble_ll.h" @@ -150,6 +151,7 @@ STATS_NAME_START(ble_ll_stats) STATS_NAME(ble_ll_stats, hci_events_sent) STATS_NAME(ble_ll_stats, bad_ll_state) STATS_NAME(ble_ll_stats, bad_acl_hdr) + STATS_NAME(ble_ll_stats, no_bufs) STATS_NAME(ble_ll_stats, rx_adv_pdu_crc_ok) STATS_NAME(ble_ll_stats, rx_adv_pdu_crc_err) STATS_NAME(ble_ll_stats, rx_adv_bytes_crc_ok) @@ -182,6 +184,9 @@ STATS_NAME_END(ble_ll_stats) struct os_task g_ble_ll_task; os_stack_t g_ble_ll_stack[BLE_LL_STACK_SIZE]; +struct os_mempool g_ble_ll_hci_ev_pool; +static void *ble_ll_hci_os_event_buf; + /* XXX: temporary logging until we transition to real logging */ #ifdef BLE_LL_LOG struct ble_ll_log @@ -258,6 +263,68 @@ ble_ll_count_rx_adv_pdus(uint8_t pdu_type) } } +/** + * Allocate a pdu (chain) for reception. + * + * @param len + * + * @return struct os_mbuf* + */ +struct os_mbuf * +ble_ll_rxpdu_alloc(uint16_t len) +{ + uint16_t mb_bytes; + struct os_mbuf *m; + struct os_mbuf *n; + struct os_mbuf *p; + struct os_mbuf_pkthdr *pkthdr; + + p = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr)); + if (!p) { + goto rxpdu_alloc_exit; + } + + /* Set packet length */ + pkthdr = OS_MBUF_PKTHDR(p); + pkthdr->omp_len = len; + + /* + * NOTE: first mbuf in chain will have data pre-pended to it so we adjust + * m_data by a word. + */ + p->om_data += 4; + mb_bytes = (p->om_omp->omp_databuf_len - p->om_pkthdr_len - 4); + + if (mb_bytes < len) { + n = p; + len -= mb_bytes; + while (len) { + m = os_msys_get(len, 0); + if (!m) { + os_mbuf_free_chain(p); + p = NULL; + goto rxpdu_alloc_exit; + } + /* Chain new mbuf to existing chain */ + SLIST_NEXT(n, om_next) = m; + n = m; + mb_bytes = m->om_omp->omp_databuf_len; + if (mb_bytes >= len) { + len = 0; + } else { + len -= mb_bytes; + } + } + } + + +rxpdu_alloc_exit: + if (!p) { + STATS_INC(ble_ll_stats, no_bufs); + } + return p; +} + int ble_ll_chk_txrx_octets(uint16_t octets) { @@ -662,25 +729,21 @@ ble_ll_acl_data_in(struct os_mbuf *txpkt) * > 0: Continue to receive frame and go from rx to tx when done */ int -ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan) +ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *rxhdr) { int rc; uint8_t pdu_type; - uint8_t *rxbuf; - struct ble_mbuf_hdr *ble_hdr; - ble_ll_log(BLE_LL_LOG_ID_RX_START, chan, 0, (uint32_t)rxpdu); + ble_ll_log(BLE_LL_LOG_ID_RX_START, chan, 0, rxhdr->beg_cputime); /* Check channel type */ - rxbuf = rxpdu->om_data; if (chan < BLE_PHY_NUM_DATA_CHANS) { /* * Data channel pdu. We should be in CONNECTION state with an * ongoing connection */ if (g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION) { - ble_hdr = BLE_MBUF_HDR_PTR(rxpdu); - rc = ble_ll_conn_rx_isr_start(ble_hdr, ble_phy_access_addr_get()); + rc = ble_ll_conn_rx_isr_start(rxhdr, ble_phy_access_addr_get()); } else { STATS_INC(ble_ll_stats, bad_ll_state); rc = 0; @@ -704,7 +767,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan) } break; case BLE_LL_STATE_SCANNING: - rc = ble_ll_scan_rx_isr_start(pdu_type, rxpdu); + rc = ble_ll_scan_rx_isr_start(pdu_type, &rxhdr->rxinfo.flags); break; case BLE_LL_STATE_CONNECTION: /* Should not occur */ @@ -726,8 +789,8 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan) * * NOTE: Called from interrupt context! * - * @param rxpdu Pointer to received PDU - * ble_hdr Pointer to BLE header of received mbuf + * @param rxbuf Pointer to received PDU data + * rxhdr Pointer to BLE header of received mbuf * * @return int * < 0: Disable the phy after reception. @@ -735,7 +798,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan) * > 0: Do not disable PHY as that has already been done. */ int -ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr) +ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) { int rc; int badpkt; @@ -743,40 +806,23 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr) uint8_t len; uint8_t chan; uint8_t crcok; - uint16_t mblen; - uint8_t *rxbuf; - - /* Set the rx buffer pointer to the start of the received data */ - rxbuf = rxpdu->om_data; + struct os_mbuf *rxpdu; /* Get channel and CRC status from BLE header */ - chan = ble_hdr->rxinfo.channel; - crcok = BLE_MBUF_HDR_CRC_OK(ble_hdr); + chan = rxhdr->rxinfo.channel; + crcok = BLE_MBUF_HDR_CRC_OK(rxhdr); ble_ll_log(BLE_LL_LOG_ID_RX_END, rxbuf[0], - ((uint16_t)ble_hdr->rxinfo.flags << 8) | rxbuf[1], - (BLE_MBUF_HDR_PTR(rxpdu))->beg_cputime); + ((uint16_t)rxhdr->rxinfo.flags << 8) | rxbuf[1], + rxhdr->beg_cputime); /* Check channel type */ if (chan < BLE_PHY_NUM_DATA_CHANS) { - /* Set length in the received PDU */ - mblen = rxbuf[1] + BLE_LL_PDU_HDR_LEN; - OS_MBUF_PKTHDR(rxpdu)->omp_len = mblen; - rxpdu->om_len = mblen; - - /* - * NOTE: this looks a bit odd, and it is, but for now we place the - * received PDU on the Link Layer task before calling the rx end - * function. We do this to guarantee connection event end ordering - * and receive PDU processing. - */ - ble_ll_rx_pdu_in(rxpdu); - /* * Data channel pdu. We should be in CONNECTION state with an * ongoing connection. */ - rc = ble_ll_conn_rx_isr_end(rxpdu); + rc = ble_ll_conn_rx_isr_end(rxbuf, rxhdr); return rc; } @@ -784,14 +830,9 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr) pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK; - /* Setup the mbuf lengths */ - mblen = len + BLE_LL_PDU_HDR_LEN; - OS_MBUF_PKTHDR(rxpdu)->omp_len = mblen; - rxpdu->om_len = mblen; - /* If the CRC checks, make sure lengths check! */ + badpkt = 0; if (crcok) { - badpkt = 0; switch (pdu_type) { case BLE_ADV_PDU_TYPE_SCAN_REQ: case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: @@ -820,22 +861,32 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr) /* If this is a malformed packet, just kill it here */ if (badpkt) { STATS_INC(ble_ll_stats, rx_adv_malformed_pkts); - os_mbuf_free_chain(rxpdu); - rxpdu = NULL; } } - /* Hand packet to the appropriate state machine (if crc ok) */ - switch (BLE_MBUF_HDR_RX_STATE(ble_hdr)) { + rxpdu = NULL; + switch (BLE_MBUF_HDR_RX_STATE(rxhdr)) { case BLE_LL_STATE_ADV: + if (!badpkt) { + rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); + if (rxpdu) { + ble_phy_rxpdu_copy(rxbuf, rxpdu); + } + } rc = ble_ll_adv_rx_isr_end(pdu_type, rxpdu, crcok); break; case BLE_LL_STATE_SCANNING: + if (!badpkt) { + rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); + if (rxpdu) { + ble_phy_rxpdu_copy(rxbuf, rxpdu); + } + } rc = ble_ll_scan_rx_isr_end(rxpdu, crcok); break; case BLE_LL_STATE_INITIATING: - rc = ble_ll_init_rx_isr_end(rxpdu, crcok); + rc = ble_ll_init_rx_isr_end(rxbuf, crcok, rxhdr); break; default: rc = -1; @@ -1129,6 +1180,16 @@ ble_ll_init(uint8_t ll_task_prio, uint8_t num_acl_pkts, uint16_t acl_pkt_size) cputime_timer_init(&g_ble_ll_data.ll_wfr_timer, ble_ll_wfr_timer_exp, NULL); + ble_ll_hci_os_event_buf = malloc( + OS_MEMPOOL_BYTES(16, sizeof (struct os_event))); + assert(ble_ll_hci_os_event_buf != NULL); + + /* Create memory pool of OS events */ + rc = os_mempool_init(&g_ble_ll_hci_ev_pool, 16, + sizeof (struct os_event), ble_ll_hci_os_event_buf, + "g_ble_ll_hci_ev_pool"); + assert(rc == 0); + /* Initialize LL HCI */ ble_ll_hci_init(); @@ -1182,6 +1243,9 @@ ble_ll_init(uint8_t ll_task_prio, uint8_t num_acl_pkts, uint16_t acl_pkt_size) STATS_SIZE_INIT_PARMS(ble_ll_stats, STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_ll_stats), "ble_ll"); + + ble_hci_trans_cfg_ll(ble_ll_hci_cmd_rx, NULL, + ble_ll_hci_acl_rx, NULL); return rc; } diff --git a/net/nimble/controller/src/ble_ll_adv.c b/net/nimble/controller/src/ble_ll_adv.c index 1f43a5d2..0c6df3b1 100644 --- a/net/nimble/controller/src/ble_ll_adv.c +++ b/net/nimble/controller/src/ble_ll_adv.c @@ -121,6 +121,23 @@ struct ble_ll_adv_sm g_ble_ll_adv_sm; #if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1) +/** + * Called to change advertisers ADVA and INITA (for directed advertisements) + * as an advertiser needs to adhere to the resolvable private address generation + * timer. + * + * NOTE: the resolvable private address code uses its own timer to regenerate + * local resolvable private addresses. The advertising code uses its own + * timer to reset the INITA (for directed advertisements). This code also sets + * the appropriate txadd and rxadd bits that will go into the advertisement. + * + * Another thing to note: it is possible that an IRK is all zeroes in the + * resolving list. That is why we need to check if the generated address is + * in fact a RPA as a resolving list entry with all zeroes will use the + * identity address (which may be a private address or public). + * + * @param advsm + */ void ble_ll_adv_chk_rpa_timeout(struct ble_ll_adv_sm *advsm) { diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c index ca94310a..e3c40e26 100644 --- a/net/nimble/controller/src/ble_ll_conn.c +++ b/net/nimble/controller/src/ble_ll_conn.c @@ -25,6 +25,7 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" #include "ble/xcvr.h" #include "controller/ble_ll.h" #include "controller/ble_ll_hci.h" @@ -103,9 +104,6 @@ extern void bletest_completed_pkt(uint16_t handle); * are hosed. Well, anchor point can get really messed up! */ -/* XXX: this does not belong here! Move to transport? */ -extern int ble_hs_rx_data(struct os_mbuf *om); - /* * The amount of time that we will wait to hear the start of a receive * packet after we have transmitted a packet. This time is at least @@ -218,13 +216,13 @@ STATS_NAME_END(ble_ll_conn_stats) * Called to determine if the received PDU is an empty PDU or not. */ static int -ble_ll_conn_is_empty_pdu(struct os_mbuf *rxpdu) +ble_ll_conn_is_empty_pdu(uint8_t *rxbuf) { int rc; uint8_t llid; - llid = rxpdu->om_data[0] & BLE_LL_DATA_HDR_LLID_MASK; - if ((llid == BLE_LL_LLID_DATA_FRAG) && (rxpdu->om_data[1] == 0)) { + llid = rxbuf[0] & BLE_LL_DATA_HDR_LLID_MASK; + if ((llid == BLE_LL_LLID_DATA_FRAG) && (rxbuf[1] == 0)) { rc = 1; } else { rc = 0; @@ -287,7 +285,7 @@ ble_ll_conn_get_ce_end_time(void) * standby and set the current state machine pointer to NULL. */ static void -ble_ll_conn_current_sm_over(void) +ble_ll_conn_current_sm_over(struct ble_ll_conn_sm *connsm) { /* Disable the PHY */ ble_phy_disable(); @@ -300,6 +298,15 @@ ble_ll_conn_current_sm_over(void) /* Set current LL connection to NULL */ g_ble_ll_conn_cur_sm = NULL; + + /* + * NOTE: the connection state machine may be NULL if we are calling + * this when we are ending the connection. In that case, there is no + * need to post to the LL the connection event end event + */ + if (connsm) { + ble_ll_event_send(&connsm->conn_ev_end); + } } /** @@ -462,8 +469,8 @@ ble_ll_conn_calc_access_addr(void) transitions = 0; consecutive = 0; mask = 0x00000001; - prev_bit = aa & mask; while (mask < 0x80000000) { + prev_bit = aa & mask; mask <<= 1; if (mask & aa) { if (prev_bit == 0) { @@ -573,11 +580,8 @@ ble_ll_conn_wfr_timer_exp(void) struct ble_ll_conn_sm *connsm; connsm = g_ble_ll_conn_cur_sm; - ble_ll_conn_current_sm_over(); - if (connsm) { - ble_ll_event_send(&connsm->conn_ev_end); - STATS_INC(ble_ll_conn_stats, wfr_expirations); - } + ble_ll_conn_current_sm_over(connsm); + STATS_INC(ble_ll_conn_stats, wfr_expirations); } /** @@ -594,10 +598,8 @@ ble_ll_conn_wait_txend(void *arg) { struct ble_ll_conn_sm *connsm; - ble_ll_conn_current_sm_over(); - connsm = (struct ble_ll_conn_sm *)arg; - ble_ll_event_send(&connsm->conn_ev_end); + ble_ll_conn_current_sm_over(connsm); } #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) @@ -631,8 +633,7 @@ ble_ll_conn_txend_encrypt(void *arg) connsm = (struct ble_ll_conn_sm *)arg; CONN_F_ENCRYPTED(connsm) = 1; - ble_ll_conn_current_sm_over(); - ble_ll_event_send(&connsm->conn_ev_end); + ble_ll_conn_current_sm_over(connsm); } static void @@ -642,8 +643,7 @@ ble_ll_conn_rxend_unencrypt(void *arg) connsm = (struct ble_ll_conn_sm *)arg; CONN_F_ENCRYPTED(connsm) = 0; - ble_ll_conn_current_sm_over(); - ble_ll_event_send(&connsm->conn_ev_end); + ble_ll_conn_current_sm_over(connsm); } static void @@ -1904,6 +1904,7 @@ ble_ll_conn_event_end(void *arg) * The way this works is that whenever the timer expires it just gets reset * and we send the autheticated payload timeout event. Note that this timer * should run even when encryption is paused. + * XXX: what should be here? Was there code here that got deleted? */ #endif @@ -2195,7 +2196,8 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr) * > 0: Do not disable PHY as that has already been done. */ int -ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) +ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, + struct ble_mbuf_hdr *ble_hdr) { int rc; int resolved; @@ -2208,24 +2210,18 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) uint8_t *adv_addr; uint8_t *peer; uint8_t *init_addr; - uint8_t *rxbuf; uint8_t pyld_len; uint8_t inita_is_rpa; uint32_t endtime; - struct ble_mbuf_hdr *ble_hdr; + struct os_mbuf *rxpdu; struct ble_ll_conn_sm *connsm; /* * We have to restart receive if we cant hand up pdu. We return 0 so that * the phy does not get disabled. */ - if (!rxpdu) { - ble_phy_disable(); - ble_phy_rx(); - return 0; - } - rc = -1; + pyld_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK; if (!crcok) { goto init_rx_isr_exit; } @@ -2234,10 +2230,7 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) connsm = g_ble_ll_conn_create_sm; /* Only interested in ADV IND or ADV DIRECT IND */ - rxbuf = rxpdu->om_data; pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - pyld_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK; - inita_is_rpa = 0; switch (pdu_type) { @@ -2285,7 +2278,6 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) } index = -1; - ble_hdr = BLE_MBUF_HDR_PTR(rxpdu); peer = adv_addr; peer_addr_type = addr_type; @@ -2303,7 +2295,7 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) resolved = 1; } else { if (chk_wl) { - return -1; + goto init_rx_isr_exit; } } } @@ -2312,12 +2304,12 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) /* Check filter policy */ if (chk_wl) { if (!ble_ll_whitelist_match(peer, peer_addr_type, resolved)) { - return -1; + goto init_rx_isr_exit; } } else { /* Must match the connection address */ if (!ble_ll_conn_is_peer_adv(addr_type, adv_addr, index)) { - return -1; + goto init_rx_isr_exit; } } ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH; @@ -2330,7 +2322,7 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) if ((index < 0) || !ble_ll_resolv_rpa(init_addr, g_ble_ll_resolv_list[index].rl_local_irk)) { - return -1; + goto init_rx_isr_exit; } } @@ -2344,6 +2336,8 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) if (!rc) { CONN_F_CONN_REQ_TXD(connsm) = 1; STATS_INC(ble_ll_conn_stats, conn_req_txd); + } else { + ble_ll_sched_rmv_elem(&connsm->conn_sch); } } else { /* Count # of times we could not set schedule */ @@ -2352,9 +2346,24 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) } init_rx_isr_exit: + /* + * We have to restart receive if we cant hand up pdu. We return 0 so that + * the phy does not get disabled. + */ + rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN); + if (rxpdu == NULL) { + ble_phy_disable(); + ble_phy_rx(); + rc = 0; + } else { + ble_phy_rxpdu_copy(rxbuf, rxpdu); + ble_ll_rx_pdu_in(rxpdu); + } + if (rc) { ble_ll_state_set(BLE_LL_STATE_STANDBY); } + return rc; } @@ -2377,7 +2386,7 @@ ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err) was_current = 0; OS_ENTER_CRITICAL(sr); if (g_ble_ll_conn_cur_sm == connsm) { - ble_ll_conn_current_sm_over(); + ble_ll_conn_current_sm_over(NULL); was_current = 1; } OS_EXIT_CRITICAL(sr); @@ -2449,7 +2458,6 @@ ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa) connsm->anchor_point = connsm->last_anchor_point; } } - return 1; } @@ -2569,7 +2577,7 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) acl_hdr = (acl_hdr << 12) | connsm->conn_handle; htole16(rxbuf, acl_hdr); htole16(rxbuf + 2, acl_len); - ble_hs_rx_data(rxpdu); + ble_hci_trans_ll_acl_tx(rxpdu); } /* NOTE: we dont free the mbuf since we handed it off! */ @@ -2601,7 +2609,7 @@ conn_rx_data_pdu_end: * > 0: Do not disable PHY as that has already been done. */ int -ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu) +ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) { int rc; int is_ctrl; @@ -2617,9 +2625,22 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu) uint32_t endtime; struct os_mbuf *txpdu; struct ble_ll_conn_sm *connsm; - struct ble_mbuf_hdr *rxhdr; + struct os_mbuf *rxpdu; struct ble_mbuf_hdr *txhdr; + /* Retrieve the header and payload length */ + hdr_byte = rxbuf[0]; + rx_pyld_len = rxbuf[1]; + + /* + * We need to attempt to allocate a buffer here. The reason we do this + * now is that we should not ack the packet if we have no receive + * buffers available. We want to free up our transmit PDU if it was + * acked, but we should not ack the received frame if we cant hand it up. + * NOTE: we hand up empty pdu's to the LL task! + */ + rxpdu = ble_ll_rxpdu_alloc(rx_pyld_len + BLE_LL_PDU_HDR_LEN); + /* * We should have a current connection state machine. If we dont, we just * hand the packet to the higher layer to count it. @@ -2631,11 +2652,6 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu) goto conn_exit; } - /* Set the handle in the ble mbuf header */ - rxhdr = BLE_MBUF_HDR_PTR(rxpdu); - hdr_byte = rxpdu->om_data[0]; - rx_pyld_len = rxpdu->om_data[1]; - /* * Check the packet CRC. A connection event can continue even if the * received PDU does not pass the CRC check. If we receive two consecutive @@ -2661,15 +2677,13 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu) /* Reset consecutively received bad crcs (since this one was good!) */ connsm->cons_rxd_bad_crc = 0; - /* Check for valid LLID before proceeding. */ + /* + * Check for valid LLID before proceeding. We have seen some weird + * things with the PHY where the CRC is OK but we dont have a valid + * LLID. This should really never happen but if it does we will just + * bail. An error stat will get incremented at the LL. + */ if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == 0) { - /* - * XXX: for now, just exit since we dont trust the length - * and may erroneously adjust anchor. Once we fix the anchor - * point issue we need to decide what to do on bad llid. Note - * that an error stat gets counted at the LL - */ - reply = 0; goto conn_exit; } @@ -2682,10 +2696,10 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu) */ hdr_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK; conn_nesn = connsm->next_exp_seqnum; - if ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn)) { + if (rxpdu && ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn))) { connsm->next_exp_seqnum ^= 1; #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) - if (CONN_F_ENCRYPTED(connsm) && !ble_ll_conn_is_empty_pdu(rxpdu)) { + if (CONN_F_ENCRYPTED(connsm) && !ble_ll_conn_is_empty_pdu(rxbuf)) { ++connsm->enc_data.rx_pkt_cntr; } #endif @@ -2778,13 +2792,13 @@ chk_rx_terminate_ind: is_ctrl = 0; if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) { is_ctrl = 1; - opcode = rxpdu->om_data[2]; + opcode = rxbuf[2]; } /* If we received a terminate IND, we must set some flags */ if (is_ctrl && (opcode == BLE_LL_CTRL_TERMINATE_IND)) { connsm->csmflags.cfbit.terminate_ind_rxd = 1; - connsm->rxd_disconnect_reason = rxpdu->om_data[3]; + connsm->rxd_disconnect_reason = rxbuf[3]; reply = 1; } else if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { reply = CONN_F_LAST_TXD_MD(connsm) || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK); @@ -2810,12 +2824,15 @@ chk_rx_terminate_ind: } conn_exit: + /* Copy the received pdu and hand it up */ + if (rxpdu) { + ble_phy_rxpdu_copy(rxbuf, rxpdu); + ble_ll_rx_pdu_in(rxpdu); + } + /* Send link layer a connection end event if over */ if (rc) { - ble_ll_conn_current_sm_over(); - if (connsm) { - ble_ll_event_send(&connsm->conn_ev_end); - } + ble_ll_conn_current_sm_over(connsm); } return rc; diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c b/net/nimble/controller/src/ble_ll_conn_hci.c index e1bc978f..d7001f89 100644 --- a/net/nimble/controller/src/ble_ll_conn_hci.c +++ b/net/nimble/controller/src/ble_ll_conn_hci.c @@ -25,6 +25,7 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" #include "controller/ble_ll.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_conn.h" @@ -140,7 +141,7 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status) enh_enabled = ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE); if (enabled || enh_enabled) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { /* Put common elements in event */ evbuf[0] = BLE_HCI_EVCODE_LE_META; @@ -202,22 +203,25 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status) } } + /** * Called to create and send the number of completed packets event to the * host. * - * Because of the ridiculous spec, all the connection handles are contiguous and - * then all the completed packets are contiguous. In order to avoid multiple - * passes through the connection list or allocating a large stack variable or - * malloc, I just use the event buffer and place the completed packets after - * the last possible handle. I then copy the completed packets to make it - * contiguous with the handles. - * - * @param connsm + * Because of the ridiculous spec, all the connection handles are contiguous + * and then all the completed packets are contiguous. In order to avoid + * multiple passes through the connection list or allocating a large stack + * variable or malloc, I just use the event buffer and place the completed + * packets after the last possible handle. I then copy the completed packets + * to make it contiguous with the handles. */ void ble_ll_conn_num_comp_pkts_event_send(void) { + /** The maximum number of handles that will fit in an event buffer. */ + static const int max_handles = + (BLE_LL_MAX_EVT_LEN - BLE_HCI_EVENT_HDR_LEN - 1) / 4; + int event_sent; uint8_t *evbuf; uint8_t *handle_ptr; @@ -246,13 +250,13 @@ ble_ll_conn_num_comp_pkts_event_send(void) (connsm->completed_pkts || !STAILQ_EMPTY(&connsm->conn_txq))) { /* If no buffer, get one, If cant get one, leave. */ if (!evbuf) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (!evbuf) { break; } handles = 0; handle_ptr = evbuf + 3; - comp_pkt_ptr = handle_ptr + (sizeof(uint16_t) * 60); + comp_pkt_ptr = handle_ptr + (sizeof(uint16_t) * max_handles); } /* Add handle and complete packets */ @@ -263,11 +267,8 @@ ble_ll_conn_num_comp_pkts_event_send(void) comp_pkt_ptr += sizeof(uint16_t); ++handles; - /* - * The event buffer should fit at least 255 bytes so this means we - * can fit up to 60 handles per event (a little more but who cares). - */ - if (handles == 60) { + /* Send now if the buffer is full. */ + if (handles == max_handles) { evbuf[0] = BLE_HCI_EVCODE_NUM_COMP_PKTS; evbuf[1] = (handles * 2 * sizeof(uint16_t)) + 1; evbuf[2] = handles; @@ -284,9 +285,9 @@ ble_ll_conn_num_comp_pkts_event_send(void) evbuf[0] = BLE_HCI_EVCODE_NUM_COMP_PKTS; evbuf[1] = (handles * 2 * sizeof(uint16_t)) + 1; evbuf[2] = handles; - if (handles < 60) { + if (handles < max_handles) { /* Make the pkt counts contiguous with handles */ - memmove(handle_ptr, evbuf + 3 + (60 * 2), handles * 2); + memmove(handle_ptr, evbuf + 3 + (max_handles * 2), handles * 2); } ble_ll_hci_event_send(evbuf); event_sent = 1; @@ -313,7 +314,7 @@ ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm) uint8_t *evbuf; if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_AUTH_PYLD_TMO)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_AUTH_PYLD_TMO; evbuf[1] = sizeof(uint16_t); @@ -338,7 +339,7 @@ ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason) uint8_t *evbuf; if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DISCONN_CMP)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_DISCONN_CMP; evbuf[1] = BLE_HCI_EVENT_DISCONN_COMPLETE_LEN; diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h b/net/nimble/controller/src/ble_ll_conn_priv.h index 218ecbc4..fc06e5f9 100644 --- a/net/nimble/controller/src/ble_ll_conn_priv.h +++ b/net/nimble/controller/src/ble_ll_conn_priv.h @@ -81,6 +81,9 @@ extern struct ble_ll_conn_free_list g_ble_ll_conn_free_list; /* Pointer to connection state machine we are trying to create */ extern struct ble_ll_conn_sm *g_ble_ll_conn_create_sm; +extern struct os_mempool g_ble_ll_hci_ev_pool; + + /* Generic interface */ struct ble_ll_len_req; struct hci_create_conn; @@ -107,10 +110,11 @@ void ble_ll_conn_event_end(void *arg); void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len); void ble_ll_conn_spvn_timeout(void *arg); int ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa); -int ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu); +int ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr); void ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr); -int ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok); +int ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, + struct ble_mbuf_hdr *ble_hdr); void ble_ll_conn_wfr_timer_exp(void); int ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2); uint32_t ble_ll_conn_get_ce_end_time(void); @@ -150,4 +154,8 @@ void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm); #else #define ble_ll_conn_auth_pyld_timer_start(x) #endif + +int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg); +int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg); + #endif /* H_BLE_LL_CONN_PRIV_ */ diff --git a/net/nimble/controller/src/ble_ll_hci.c b/net/nimble/controller/src/ble_ll_hci.c index 1d73465d..758568b4 100644 --- a/net/nimble/controller/src/ble_ll_hci.c +++ b/net/nimble/controller/src/ble_ll_hci.c @@ -23,7 +23,7 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/hci_transport.h" +#include "nimble/ble_hci_trans.h" #include "controller/ble_hw.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" @@ -64,11 +64,13 @@ ble_ll_hci_event_send(uint8_t *evbuf) { int rc; + assert(BLE_HCI_EVENT_HDR_LEN + evbuf[1] <= BLE_LL_MAX_EVT_LEN); + /* Count number of events sent */ STATS_INC(ble_ll_stats, hci_events_sent); /* Send the event to the host */ - rc = ble_hci_transport_ctlr_event_send(evbuf); + rc = ble_hci_trans_ll_evt_tx(evbuf); return rc; } @@ -86,7 +88,7 @@ ble_ll_hci_send_noop(void) uint8_t *evbuf; uint16_t opcode; - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { /* Create a command complete event with a NO-OP opcode */ opcode = 0; @@ -919,7 +921,7 @@ ble_ll_hci_cmd_proc(struct os_event *ev) assert(cmdbuf != NULL); /* Free the event */ - err = os_memblock_put(&g_hci_os_event_pool, ev); + err = os_memblock_put(&g_ble_ll_hci_ev_pool, ev); assert(err == OS_OK); /* Get the opcode from the command buffer */ @@ -994,12 +996,12 @@ ble_ll_hci_cmd_proc(struct os_event *ev) * BLE_ERR_MEM_CAPACITY on HCI buffer exhaustion. */ int -ble_hci_transport_host_cmd_send(uint8_t *cmd) +ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg) { struct os_event *ev; /* Get an event structure off the queue */ - ev = (struct os_event *)os_memblock_get(&g_hci_os_event_pool); + ev = (struct os_event *)os_memblock_get(&g_ble_ll_hci_ev_pool); if (!ev) { return BLE_ERR_MEM_CAPACITY; } @@ -1015,7 +1017,7 @@ ble_hci_transport_host_cmd_send(uint8_t *cmd) /* Send ACL data from host to contoller */ int -ble_hci_transport_host_acl_data_send(struct os_mbuf *om) +ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg) { ble_ll_acl_data_in(om); return 0; diff --git a/net/nimble/controller/src/ble_ll_hci_ev.c b/net/nimble/controller/src/ble_ll_hci_ev.c index 773e4e6b..2548bdc8 100644 --- a/net/nimble/controller/src/ble_ll_hci_ev.c +++ b/net/nimble/controller/src/ble_ll_hci_ev.c @@ -21,6 +21,7 @@ #include <string.h> #include "nimble/ble.h" #include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" #include "controller/ble_ll.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_ctrl.h" @@ -41,7 +42,7 @@ ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm) uint8_t *evbuf; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DATA_LEN_CHG)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_LE_META; evbuf[1] = BLE_HCI_LE_DATA_LEN_CHG_LEN; @@ -68,7 +69,7 @@ ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm, uint8_t *evbuf; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_LE_META; evbuf[1] = BLE_HCI_LE_REM_CONN_PARM_REQ_LEN; @@ -95,7 +96,7 @@ ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status) uint8_t *evbuf; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_LE_META; evbuf[1] = BLE_HCI_LE_CONN_UPD_LEN; @@ -127,7 +128,7 @@ ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status) } if (ble_ll_hci_is_event_enabled(evcode)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = evcode; evbuf[1] = evlen; @@ -158,7 +159,7 @@ ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm) uint8_t *evbuf; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_LT_KEY_REQ)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_LE_META; evbuf[1] = BLE_HCI_LE_LT_KEY_REQ_LEN; @@ -188,7 +189,7 @@ ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status) uint8_t *evbuf; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_LE_META; evbuf[1] = BLE_HCI_LE_RD_REM_USED_FEAT_LEN; @@ -208,7 +209,7 @@ ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status) uint8_t *evbuf; if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP; evbuf[1] = BLE_HCI_EVENT_RD_RM_VER_LEN; diff --git a/net/nimble/controller/src/ble_ll_rand.c b/net/nimble/controller/src/ble_ll_rand.c index c5201f9f..8d26f8de 100644 --- a/net/nimble/controller/src/ble_ll_rand.c +++ b/net/nimble/controller/src/ble_ll_rand.c @@ -37,7 +37,8 @@ struct ble_ll_rnum_data struct ble_ll_rnum_data g_ble_ll_rnum_data; uint8_t g_ble_ll_rnum_buf[NIMBLE_OPT_LL_RNG_BUFSIZE]; -#define IS_RNUM_BUF_END(x) (x == &g_ble_ll_rnum_buf[NIMBLE_OPT_LL_RNG_BUFSIZE]) +#define IS_RNUM_BUF_END(x) \ + (x == &g_ble_ll_rnum_buf[NIMBLE_OPT_LL_RNG_BUFSIZE - 1]) void ble_ll_rand_sample(uint8_t rnum) diff --git a/net/nimble/controller/src/ble_ll_resolv.c b/net/nimble/controller/src/ble_ll_resolv.c index 4d91685a..903c95fd 100644 --- a/net/nimble/controller/src/ble_ll_resolv.c +++ b/net/nimble/controller/src/ble_ll_resolv.c @@ -31,12 +31,15 @@ #include "ble_ll_conn_priv.h" #if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1) - -/* Flag denoting whether or not address translation is enabled. */ -uint8_t g_ble_ll_addr_res_enabled; -uint8_t g_ble_ll_resolv_list_size; -uint8_t g_ble_ll_resolv_list_cnt; -uint32_t g_ble_ll_resolv_rpa_tmo; +struct ble_ll_resolv_data +{ + uint8_t addr_res_enabled; + uint8_t rl_size; + uint8_t rl_cnt; + uint32_t rpa_tmo; + struct os_callout_func rpa_timer; +}; +struct ble_ll_resolv_data g_ble_ll_resolv_data; struct ble_ll_resolv_entry g_ble_ll_resolv_list[NIMBLE_OPT_LL_RESOLV_LIST_SIZE]; @@ -53,9 +56,9 @@ ble_ll_resolv_list_chg_allowed(void) { int rc; - if (g_ble_ll_addr_res_enabled && (ble_ll_adv_enabled() || - ble_ll_scan_enabled() || - g_ble_ll_conn_create_sm)) { + if (g_ble_ll_resolv_data.addr_res_enabled && + (ble_ll_adv_enabled() || ble_ll_scan_enabled() || + g_ble_ll_conn_create_sm)) { rc = 0; } else { rc = 1; @@ -64,6 +67,32 @@ ble_ll_resolv_list_chg_allowed(void) } /** + * Called when the Resolvable private address timer expires. This timer + * is used to regenerate local RPA's in the resolving list. + * + * @param arg + */ +void +ble_ll_resolv_rpa_timer_cb(void *arg) +{ + int i; + os_sr_t sr; + struct ble_ll_resolv_entry *rl; + + rl = &g_ble_ll_resolv_list[0]; + for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) { + OS_ENTER_CRITICAL(sr); + rl->rl_local_rpa_set = 0; + ble_ll_resolv_gen_priv_addr(rl, 1, rl->rl_local_rpa); + rl->rl_local_rpa_set = 1; + OS_EXIT_CRITICAL(sr); + ++rl; + } + os_callout_reset(&g_ble_ll_resolv_data.rpa_timer.cf_c, + (int32_t)g_ble_ll_resolv_data.rpa_tmo); +} + +/** * Called to determine if the IRK is all zero. * * @param irk @@ -102,7 +131,7 @@ ble_ll_resolv_list_clr(void) } /* Sets total on list to 0. Clears HW resolve list */ - g_ble_ll_resolv_list_cnt = 0; + g_ble_ll_resolv_data.rl_cnt = 0; ble_hw_resolv_list_clear(); return BLE_ERR_SUCCESS; @@ -119,7 +148,7 @@ ble_ll_resolv_list_clr(void) int ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen) { - rspbuf[0] = g_ble_ll_resolv_list_size; + rspbuf[0] = g_ble_ll_resolv_data.rl_size; *rsplen = 1; return BLE_ERR_SUCCESS; } @@ -141,7 +170,7 @@ ble_ll_is_on_resolv_list(uint8_t *addr, uint8_t addr_type) struct ble_ll_resolv_entry *rl; rl = &g_ble_ll_resolv_list[0]; - for (i = 0; i < g_ble_ll_resolv_list_cnt; ++i) { + for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) { if ((rl->rl_addr_type == addr_type) && (!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) { return i + 1; @@ -167,7 +196,7 @@ ble_ll_resolv_list_find(uint8_t *addr, uint8_t addr_type) struct ble_ll_resolv_entry *rl; rl = &g_ble_ll_resolv_list[0]; - for (i = 0; i < g_ble_ll_resolv_list_cnt; ++i) { + for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) { if ((rl->rl_addr_type == addr_type) && (!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) { return rl; @@ -197,7 +226,7 @@ ble_ll_resolv_list_add(uint8_t *cmdbuf) } /* Check if we have any open entries */ - if (g_ble_ll_resolv_list_cnt >= g_ble_ll_resolv_list_size) { + if (g_ble_ll_resolv_data.rl_cnt >= g_ble_ll_resolv_data.rl_size) { return BLE_ERR_MEM_CAPACITY; } @@ -206,14 +235,23 @@ ble_ll_resolv_list_add(uint8_t *cmdbuf) rc = BLE_ERR_SUCCESS; if (!ble_ll_is_on_resolv_list(ident_addr, addr_type)) { - rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_list_cnt]; + rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt]; rl->rl_addr_type = addr_type; + rl->rl_local_rpa_set = 0; memcpy(&rl->rl_identity_addr[0], ident_addr, BLE_DEV_ADDR_LEN); swap_buf(rl->rl_peer_irk, cmdbuf + 7, 16); swap_buf(rl->rl_local_irk, cmdbuf + 23, 16); - ++g_ble_ll_resolv_list_cnt; + /* + * Add peer IRK to HW resolving list. If we can add it, also + * generate a local RPA now to save time later. + */ rc = ble_hw_resolv_list_add(rl->rl_peer_irk); + if (!rc) { + ble_ll_resolv_gen_priv_addr(rl, 1, rl->rl_local_rpa); + rl->rl_local_rpa_set = 1; + } + ++g_ble_ll_resolv_data.rl_cnt; } return rc; @@ -243,11 +281,11 @@ ble_ll_resolv_list_rmv(uint8_t *cmdbuf) /* Remove from IRK records */ position = ble_ll_is_on_resolv_list(ident_addr, addr_type); - if (position && (position < g_ble_ll_resolv_list_cnt)) { + if (position && (position < g_ble_ll_resolv_data.rl_cnt)) { memmove(&g_ble_ll_resolv_list[position - 1], &g_ble_ll_resolv_list[position], - g_ble_ll_resolv_list_cnt - position); - --g_ble_ll_resolv_list_cnt; + g_ble_ll_resolv_data.rl_cnt - position); + --g_ble_ll_resolv_data.rl_cnt; /* Remove from HW list */ ble_hw_resolv_list_rmv(position - 1); @@ -267,13 +305,29 @@ int ble_ll_resolv_enable_cmd(uint8_t *cmdbuf) { int rc; + int32_t tmo; + uint8_t enabled; if (ble_ll_adv_enabled() || ble_ll_scan_enabled() || g_ble_ll_conn_create_sm) { rc = BLE_ERR_CMD_DISALLOWED; } else { - g_ble_ll_addr_res_enabled = cmdbuf[0]; - rc = BLE_ERR_SUCCESS; + enabled = cmdbuf[0]; + if (enabled <= 1) { + /* If we change state, we need to disable/enable the RPA timer */ + if ((enabled ^ g_ble_ll_resolv_data.addr_res_enabled) != 0) { + if (enabled) { + tmo = (int32_t)g_ble_ll_resolv_data.rpa_tmo; + os_callout_reset(&g_ble_ll_resolv_data.rpa_timer.cf_c, tmo); + } else { + os_callout_stop(&g_ble_ll_resolv_data.rpa_timer.cf_c); + } + g_ble_ll_resolv_data.addr_res_enabled = enabled; + } + rc = BLE_ERR_SUCCESS; + } else { + rc = BLE_ERR_INV_HCI_CMD_PARMS; + } } return rc; @@ -306,7 +360,11 @@ ble_ll_resolv_set_rpa_tmo(uint8_t *cmdbuf) tmo_secs = le16toh(cmdbuf); if ((tmo_secs > 0) && (tmo_secs <= 0xA1B8)) { - g_ble_ll_resolv_rpa_tmo = tmo_secs * OS_TICKS_PER_SEC; + g_ble_ll_resolv_data.rpa_tmo = tmo_secs * OS_TICKS_PER_SEC; + if (g_ble_ll_resolv_data.addr_res_enabled) { + os_callout_reset(&g_ble_ll_resolv_data.rpa_timer.cf_c, + (int32_t)g_ble_ll_resolv_data.rpa_tmo); + } } else { rc = BLE_ERR_INV_HCI_CMD_PARMS; } @@ -323,12 +381,11 @@ ble_ll_resolv_set_rpa_tmo(uint8_t *cmdbuf) uint32_t ble_ll_resolv_get_rpa_tmo(void) { - return g_ble_ll_resolv_rpa_tmo; + return g_ble_ll_resolv_data.rpa_tmo; } /** - * Called the generate a resolvable private address - * + * Called to generate a resolvable private address * * @param rl * @param local @@ -340,11 +397,20 @@ ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local, { uint8_t *irk; uint8_t *prand; + uint32_t *irk32; + uint32_t *key32; + uint32_t *pt32; struct ble_encryption_block ecb; assert(rl != NULL); assert(addr != NULL); + /* If the local rpa has already been generated, just copy it */ + if (local && rl->rl_local_rpa_set) { + memcpy(addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); + return; + } + /* Get prand */ prand = addr + 3; ble_ll_rand_prand_get(prand); @@ -356,13 +422,27 @@ ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local, irk = rl->rl_peer_irk; } - memcpy(ecb.key, irk, BLE_ENC_BLOCK_SIZE); - memset(ecb.plain_text, 0, BLE_ENC_BLOCK_SIZE); - swap_buf(&ecb.plain_text[13], prand, 3); + irk32 = (uint32_t *)irk; + key32 = (uint32_t *)&ecb.key[0]; + key32[0] = irk32[0]; + key32[1] = irk32[1]; + key32[2] = irk32[2]; + key32[3] = irk32[3]; + pt32 = (uint32_t *)&ecb.plain_text[0]; + pt32[0] = 0; + pt32[1] = 0; + pt32[2] = 0; + ecb.plain_text[12] = 0; + ecb.plain_text[13] = prand[2]; + ecb.plain_text[14] = prand[1]; + ecb.plain_text[15] = prand[0]; /* Calculate hash */ ble_hw_encrypt_block(&ecb); - swap_buf(addr, ecb.cipher_text + 13, 3); + + addr[0] = ecb.cipher_text[15]; + addr[1] = ecb.cipher_text[14]; + addr[2] = ecb.cipher_text[13]; } /** @@ -410,11 +490,29 @@ int ble_ll_resolv_rpa(uint8_t *rpa, uint8_t *irk) { int rc; + uint32_t *irk32; + uint32_t *key32; + uint32_t *pt32; struct ble_encryption_block ecb; - memcpy(ecb.key, irk, BLE_ENC_BLOCK_SIZE); - memset(ecb.plain_text, 0, BLE_ENC_BLOCK_SIZE); - swap_buf(&ecb.plain_text[13], rpa + 3, 3); + irk32 = (uint32_t *)irk; + key32 = (uint32_t *)&ecb.key[0]; + + key32[0] = irk32[0]; + key32[1] = irk32[1]; + key32[2] = irk32[2]; + key32[3] = irk32[3]; + + pt32 = (uint32_t *)&ecb.plain_text[0]; + pt32[0] = 0; + pt32[1] = 0; + pt32[2] = 0; + pt32[3] = 0; + + ecb.plain_text[15] = rpa[3]; + ecb.plain_text[14] = rpa[4]; + ecb.plain_text[13] = rpa[5]; + ble_hw_encrypt_block(&ecb); if ((ecb.cipher_text[15] == rpa[0]) && (ecb.cipher_text[14] == rpa[1]) && (ecb.cipher_text[13] == rpa[2])) { @@ -434,7 +532,7 @@ ble_ll_resolv_rpa(uint8_t *rpa, uint8_t *irk) uint8_t ble_ll_resolv_enabled(void) { - return g_ble_ll_addr_res_enabled; + return g_ble_ll_resolv_data.addr_res_enabled; } /** @@ -443,7 +541,8 @@ ble_ll_resolv_enabled(void) void ble_ll_resolv_list_reset(void) { - g_ble_ll_addr_res_enabled = 0; + g_ble_ll_resolv_data.addr_res_enabled = 0; + os_callout_stop(&g_ble_ll_resolv_data.rpa_timer.cf_c); ble_ll_resolv_list_clr(); ble_ll_resolv_init(); } @@ -454,14 +553,18 @@ ble_ll_resolv_init(void) uint8_t hw_size; /* Default is 15 minutes */ - g_ble_ll_resolv_rpa_tmo = 15 * 60 * OS_TICKS_PER_SEC; + g_ble_ll_resolv_data.rpa_tmo = 15 * 60 * OS_TICKS_PER_SEC; hw_size = ble_hw_resolv_list_size(); if (hw_size > NIMBLE_OPT_LL_RESOLV_LIST_SIZE) { hw_size = NIMBLE_OPT_LL_RESOLV_LIST_SIZE; } - g_ble_ll_resolv_list_size = hw_size; + g_ble_ll_resolv_data.rl_size = hw_size; + os_callout_func_init(&g_ble_ll_resolv_data.rpa_timer, + &g_ble_ll_data.ll_evq, + ble_ll_resolv_rpa_timer_cb, + NULL); } #endif /* if BLE_LL_CFG_FEAT_LL_PRIVACY == 1 */ diff --git a/net/nimble/controller/src/ble_ll_scan.c b/net/nimble/controller/src/ble_ll_scan.c index e7346baf..29193dc8 100644 --- a/net/nimble/controller/src/ble_ll_scan.c +++ b/net/nimble/controller/src/ble_ll_scan.c @@ -25,6 +25,7 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" #include "controller/ble_phy.h" #include "controller/ble_hw.h" #include "controller/ble_ll.h" @@ -424,7 +425,7 @@ ble_ll_hci_send_adv_report(uint8_t pdu_type, uint8_t txadd, uint8_t *rxbuf, } if (ble_ll_hci_is_le_event_enabled(subev)) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); if (evbuf) { evbuf[0] = BLE_HCI_EVCODE_LE_META; evbuf[1] = event_len; @@ -447,7 +448,7 @@ ble_ll_hci_send_adv_report(uint8_t pdu_type, uint8_t txadd, uint8_t *rxbuf, * are 2 greater than the unresolved ones in the spec, so * we just add 2 here. */ - addr_type += 2; + addr_type = g_ble_ll_resolv_list[index].rl_addr_type + 2; } else{ adv_addr = rxbuf; } @@ -837,11 +838,10 @@ ble_ll_scan_event_proc(void *arg) * 1: we may send a response to this frame. */ int -ble_ll_scan_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu) +ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint8_t *rxflags) { int rc; struct ble_ll_scan_sm *scansm; - struct ble_mbuf_hdr *ble_hdr; rc = 0; scansm = &g_ble_ll_scan_sm; @@ -863,8 +863,7 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu) */ if (scansm->scan_rsp_pending) { if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_RSP) { - ble_hdr = BLE_MBUF_HDR_PTR(rxpdu); - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_CHK; + *rxflags |= BLE_MBUF_HDR_F_SCAN_RSP_CHK; } else { ble_ll_scan_req_backoff(scansm, 0); } @@ -990,7 +989,7 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) /* If whitelist enabled, check to see if device is in the white list */ if (chk_wl && !ble_ll_whitelist_match(peer, peer_addr_type, resolved)) { - return -1; + goto scan_rx_isr_exit; } ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH; @@ -998,7 +997,7 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) if (chk_send_req) { /* Dont send scan request if we have sent one to this advertiser */ if (ble_ll_scan_have_rxd_scan_rsp(peer, peer_addr_type)) { - return -1; + goto scan_rx_isr_exit; } /* Better not be a scan response pending */ diff --git a/net/nimble/controller/src/ble_ll_sched.c b/net/nimble/controller/src/ble_ll_sched.c index 5b792176..90cb510e 100644 --- a/net/nimble/controller/src/ble_ll_sched.c +++ b/net/nimble/controller/src/ble_ll_sched.c @@ -32,6 +32,10 @@ /* XXX: this is temporary. Not sure what I want to do here */ struct cpu_timer g_ble_ll_sched_timer; +#if (BLE_LL_SCHED_DEBUG == 1) +int32_t g_ble_ll_sched_max_late; +#endif + /* XXX: TODO: * 1) Add some accounting to the schedule code to see how late we are * (min/max?) @@ -645,6 +649,7 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch) } else { STATS_INC(ble_ll_stats, sched_state_conn_errs); ble_ll_conn_event_halt(); + return -1; } } @@ -663,12 +668,19 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch) void ble_ll_sched_run(void *arg) { + int32_t dt; struct ble_ll_sched_item *sch; /* Look through schedule queue */ while ((sch = TAILQ_FIRST(&g_ble_ll_sched_q)) != NULL) { /* Make sure we have passed the start time of the first event */ - if ((int32_t)(cputime_get32() - sch->start_time) >= 0) { + dt = (int32_t)(cputime_get32() - sch->start_time); + if (dt >= 0) { +#if (BLE_LL_SCHED_DEBUG == 1) + if (dt > g_ble_ll_sched_max_late) { + g_ble_ll_sched_max_late = dt; + } +#endif /* Remove schedule item and execute the callback */ TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); sch->enqueued = 0; diff --git a/net/nimble/drivers/native/src/ble_phy.c b/net/nimble/drivers/native/src/ble_phy.c index e2c9f259..ff195fc6 100644 --- a/net/nimble/drivers/native/src/ble_phy.c +++ b/net/nimble/drivers/native/src/ble_phy.c @@ -18,24 +18,32 @@ */ #include <stdint.h> +#include <string.h> #include <assert.h> #include "os/os.h" -#include "nimble/ble.h" /* XXX: needed for ble mbuf header.*/ +#include "ble/xcvr.h" +#include "nimble/ble.h" +#include "nimble/nimble_opt.h" #include "controller/ble_phy.h" #include "controller/ble_ll.h" /* BLE PHY data structure */ struct ble_phy_obj { + uint8_t phy_stats_initialized; int8_t phy_txpwr_dbm; uint8_t phy_chan; uint8_t phy_state; uint8_t phy_transition; uint8_t phy_rx_started; + uint8_t phy_encrypted; uint8_t phy_privacy; + uint8_t phy_tx_pyld_len; + uint32_t phy_aar_scratch; uint32_t phy_access_address; - struct os_mbuf *rxpdu; + struct ble_mbuf_hdr rxhdr; void *txend_arg; + uint8_t *rxdptr; ble_phy_tx_end_func txend_cb; }; struct ble_phy_obj g_ble_phy_data; @@ -75,6 +83,42 @@ static struct xcvr_data g_xcvr_data; #define BLE_XCVR_TX_PWR_MAX_DBM (30) #define BLE_XCVR_TX_PWR_MIN_DBM (-20) +/* Statistics */ +STATS_SECT_START(ble_phy_stats) + STATS_SECT_ENTRY(phy_isrs) + STATS_SECT_ENTRY(tx_good) + STATS_SECT_ENTRY(tx_fail) + STATS_SECT_ENTRY(tx_late) + STATS_SECT_ENTRY(tx_bytes) + STATS_SECT_ENTRY(rx_starts) + STATS_SECT_ENTRY(rx_aborts) + STATS_SECT_ENTRY(rx_valid) + STATS_SECT_ENTRY(rx_crc_err) + STATS_SECT_ENTRY(rx_late) + STATS_SECT_ENTRY(no_bufs) + STATS_SECT_ENTRY(radio_state_errs) + STATS_SECT_ENTRY(rx_hw_err) + STATS_SECT_ENTRY(tx_hw_err) +STATS_SECT_END +STATS_SECT_DECL(ble_phy_stats) ble_phy_stats; + +STATS_NAME_START(ble_phy_stats) + STATS_NAME(ble_phy_stats, phy_isrs) + STATS_NAME(ble_phy_stats, tx_good) + STATS_NAME(ble_phy_stats, tx_fail) + STATS_NAME(ble_phy_stats, tx_late) + STATS_NAME(ble_phy_stats, tx_bytes) + STATS_NAME(ble_phy_stats, rx_starts) + STATS_NAME(ble_phy_stats, rx_aborts) + STATS_NAME(ble_phy_stats, rx_valid) + STATS_NAME(ble_phy_stats, rx_crc_err) + STATS_NAME(ble_phy_stats, rx_late) + STATS_NAME(ble_phy_stats, no_bufs) + STATS_NAME(ble_phy_stats, radio_state_errs) + STATS_NAME(ble_phy_stats, rx_hw_err) + STATS_NAME(ble_phy_stats, tx_hw_err) +STATS_NAME_END(ble_phy_stats) + /* XXX: TODO: * 1) Test the following to make sure it works: suppose an event is already @@ -95,28 +139,81 @@ ble_xcvr_clear_irq(uint32_t mask) } /** - * ble phy rxpdu get + * Copies the data from the phy receive buffer into a mbuf chain. * - * Gets a mbuf for PDU reception. + * @param dptr Pointer to receive buffer + * @param rxpdu Pointer to already allocated mbuf chain + * + * NOTE: the packet header already has the total mbuf length in it. The + * lengths of the individual mbufs are not set prior to calling. * - * @return struct os_mbuf* Pointer to retrieved mbuf or NULL if none available */ -static struct os_mbuf * -ble_phy_rxpdu_get(void) +void +ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) { + uint16_t rem_bytes; + uint16_t mb_bytes; + uint16_t copylen; + uint32_t *dst; + uint32_t *src; struct os_mbuf *m; + struct ble_mbuf_hdr *ble_hdr; + struct os_mbuf_pkthdr *pkthdr; + + /* Better be aligned */ + assert(((uint32_t)dptr & 3) == 0); + + pkthdr = OS_MBUF_PKTHDR(rxpdu); + rem_bytes = pkthdr->omp_len; + + /* Fill in the mbuf pkthdr first. */ + dst = (uint32_t *)(rxpdu->om_data); + src = (uint32_t *)dptr; + + mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4); + copylen = min(mb_bytes, rem_bytes); + copylen &= 0xFFFC; + rem_bytes -= copylen; + mb_bytes -= copylen; + rxpdu->om_len = copylen; + while (copylen > 0) { + *dst = *src; + ++dst; + ++src; + copylen -= 4; + } - m = g_ble_phy_data.rxpdu; - if (m == NULL) { - m = os_msys_get_pkthdr(BLE_MBUF_PAYLOAD_SIZE, sizeof(struct ble_mbuf_hdr)); - if (!m) { - ++g_ble_phy_stats.no_bufs; - } else { - g_ble_phy_data.rxpdu = m; + /* Copy remaining bytes */ + m = rxpdu; + while (rem_bytes > 0) { + /* If there are enough bytes in the mbuf, copy them and leave */ + if (rem_bytes <= mb_bytes) { + memcpy(m->om_data + m->om_len, src, rem_bytes); + m->om_len += rem_bytes; + break; + } + + m = SLIST_NEXT(m, om_next); + assert(m != NULL); + + mb_bytes = m->om_omp->omp_databuf_len; + copylen = min(mb_bytes, rem_bytes); + copylen &= 0xFFFC; + rem_bytes -= copylen; + mb_bytes -= copylen; + m->om_len = copylen; + dst = (uint32_t *)m->om_data; + while (copylen > 0) { + *dst = *src; + ++dst; + ++src; + copylen -= 4; } } - return m; + /* Copy ble header */ + ble_hdr = BLE_MBUF_HDR_PTR(rxpdu); + memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr)); } void @@ -126,7 +223,6 @@ ble_phy_isr(void) uint8_t crcok; uint8_t transition; uint32_t irq_en; - struct os_mbuf *rxpdu; struct ble_mbuf_hdr *ble_hdr; /* Check for disabled event. This only happens for transmits now */ @@ -139,14 +235,9 @@ ble_phy_isr(void) transition = g_ble_phy_data.phy_transition; if (transition == BLE_PHY_TRANSITION_TX_RX) { - /* Packet pointer needs to be reset. */ - if (g_ble_phy_data.rxpdu != NULL) { - g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; - } else { - /* Disable the phy */ - /* XXX: count no bufs? */ - ble_phy_disable(); - } + /* Disable the phy */ + /* XXX: count no bufs? */ + ble_phy_disable(); } else { /* Better not be going from rx to tx! */ assert(transition == BLE_PHY_TRANSITION_NONE); @@ -158,11 +249,9 @@ ble_phy_isr(void) ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_RX_START); - /* Better have a PDU! */ - assert(g_ble_phy_data.rxpdu != NULL); - /* Call Link Layer receive start function */ - rc = ble_ll_rx_start(g_ble_phy_data.rxpdu, g_ble_phy_data.phy_chan); + rc = ble_ll_rx_start(g_ble_phy_data.rxdptr, g_ble_phy_data.phy_chan, + &g_ble_phy_data.rxhdr); if (rc >= 0) { /* XXX: set rx end enable isr */ } else { @@ -182,7 +271,7 @@ ble_phy_isr(void) ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_RX_END); /* Construct BLE header before handing up */ - ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu); + ble_hdr = &g_ble_phy_data.rxhdr; ble_hdr->rxinfo.flags = 0; ble_hdr->rxinfo.rssi = -77; /* XXX: dummy rssi */ ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; @@ -197,9 +286,7 @@ ble_phy_isr(void) } /* Call Link Layer receive payload function */ - rxpdu = g_ble_phy_data.rxpdu; - g_ble_phy_data.rxpdu = NULL; - rc = ble_ll_rx_end(rxpdu, ble_hdr); + rc = ble_ll_rx_end(g_ble_phy_data.rxdptr, ble_hdr); if (rc < 0) { /* Disable the PHY. */ ble_phy_disable(); @@ -239,11 +326,6 @@ ble_phy_rx(void) return BLE_PHY_ERR_RADIO_STATE; } - /* If no pdu, get one */ - if (ble_phy_rxpdu_get() == NULL) { - return BLE_PHY_ERR_NO_BUFS; - } - g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; return 0; @@ -348,11 +430,6 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) } - /* Enable shortcuts for transmit start/end. */ - if (end_trans == BLE_PHY_TRANSITION_TX_RX) { - ble_phy_rxpdu_get(); - } - /* Set the PHY transition */ g_ble_phy_data.phy_transition = end_trans; diff --git a/net/nimble/drivers/nrf51/src/ble_phy.c b/net/nimble/drivers/nrf51/src/ble_phy.c index 0c050119..a24a434e 100644 --- a/net/nimble/drivers/nrf51/src/ble_phy.c +++ b/net/nimble/drivers/nrf51/src/ble_phy.c @@ -28,17 +28,12 @@ #include "controller/ble_ll.h" #include "mcu/nrf51_bitfields.h" -/* - * XXX: need to make the copy from mbuf into the PHY data structures 32-bit - * copies or we are screwed. - */ - /* XXX: 4) Make sure RF is higher priority interrupt than schedule */ /* * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal * and 16ms for a 30ppm crystal! We need to limit PDU size based on - * crystal accuracy + * crystal accuracy. Look at this in the spec. */ /* XXX: private header file? */ @@ -82,9 +77,10 @@ struct ble_phy_obj uint8_t phy_encrypted; uint8_t phy_privacy; uint8_t phy_tx_pyld_len; + uint8_t *rxdptr; uint32_t phy_aar_scratch; uint32_t phy_access_address; - struct os_mbuf *rxpdu; + struct ble_mbuf_hdr rxhdr; void *txend_arg; ble_phy_tx_end_func txend_cb; }; @@ -92,7 +88,8 @@ struct ble_phy_obj g_ble_phy_data; /* XXX: if 27 byte packets desired we can make this smaller */ /* Global transmit/receive buffer */ -static uint32_t g_ble_phy_txrx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; +static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; +static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) /* Make sure word-aligned for faster copies */ @@ -111,7 +108,6 @@ STATS_SECT_START(ble_phy_stats) STATS_SECT_ENTRY(rx_valid) STATS_SECT_ENTRY(rx_crc_err) STATS_SECT_ENTRY(rx_late) - STATS_SECT_ENTRY(no_bufs) STATS_SECT_ENTRY(radio_state_errs) STATS_SECT_ENTRY(rx_hw_err) STATS_SECT_ENTRY(tx_hw_err) @@ -129,7 +125,6 @@ STATS_NAME_START(ble_phy_stats) STATS_NAME(ble_phy_stats, rx_valid) STATS_NAME(ble_phy_stats, rx_crc_err) STATS_NAME(ble_phy_stats, rx_late) - STATS_NAME(ble_phy_stats, no_bufs) STATS_NAME(ble_phy_stats, radio_state_errs) STATS_NAME(ble_phy_stats, rx_hw_err) STATS_NAME(ble_phy_stats, tx_hw_err) @@ -183,33 +178,81 @@ struct nrf_ccm_data g_nrf_ccm_data; #endif /** - * ble phy rxpdu get + * Copies the data from the phy receive buffer into a mbuf chain. * - * Gets a mbuf for PDU reception. + * @param dptr Pointer to receive buffer + * @param rxpdu Pointer to already allocated mbuf chain + * + * NOTE: the packet header already has the total mbuf length in it. The + * lengths of the individual mbufs are not set prior to calling. * - * @return struct os_mbuf* Pointer to retrieved mbuf or NULL if none available */ -static struct os_mbuf * -ble_phy_rxpdu_get(void) +void +ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) { + uint16_t rem_bytes; + uint16_t mb_bytes; + uint16_t copylen; + uint32_t *dst; + uint32_t *src; struct os_mbuf *m; + struct ble_mbuf_hdr *ble_hdr; + struct os_mbuf_pkthdr *pkthdr; + + /* Better be aligned */ + assert(((uint32_t)dptr & 3) == 0); + + pkthdr = OS_MBUF_PKTHDR(rxpdu); + rem_bytes = pkthdr->omp_len; + + /* Fill in the mbuf pkthdr first. */ + dst = (uint32_t *)(rxpdu->om_data); + src = (uint32_t *)dptr; + + mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4); + copylen = min(mb_bytes, rem_bytes); + copylen &= 0xFFFC; + rem_bytes -= copylen; + mb_bytes -= copylen; + rxpdu->om_len = copylen; + while (copylen > 0) { + *dst = *src; + ++dst; + ++src; + copylen -= 4; + } - m = g_ble_phy_data.rxpdu; - if (m == NULL) { - m = os_msys_get_pkthdr(BLE_MBUF_PAYLOAD_SIZE, sizeof(struct ble_mbuf_hdr)); - if (!m) { - STATS_INC(ble_phy_stats, no_bufs); - } else { - /* - * NOTE: we add two bytes to the data pointer as we will prepend - * two bytes if we hand this received pdu up to host. - */ - m->om_data += 2; - g_ble_phy_data.rxpdu = m; + /* Copy remaining bytes */ + m = rxpdu; + while (rem_bytes > 0) { + /* If there are enough bytes in the mbuf, copy them and leave */ + if (rem_bytes <= mb_bytes) { + memcpy(m->om_data + m->om_len, src, rem_bytes); + m->om_len += rem_bytes; + break; + } + + m = SLIST_NEXT(m, om_next); + assert(m != NULL); + + mb_bytes = m->om_omp->omp_databuf_len; + copylen = min(mb_bytes, rem_bytes); + copylen &= 0xFFFC; + rem_bytes -= copylen; + mb_bytes -= copylen; + m->om_len = copylen; + dst = (uint32_t *)m->om_data; + while (copylen > 0) { + *dst = *src; + ++dst; + ++src; + copylen -= 4; } } - return m; + /* Copy ble header */ + ble_hdr = BLE_MBUF_HDR_PTR(rxpdu); + memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr)); } /** @@ -241,11 +284,16 @@ nrf_wait_disabled(void) static void ble_phy_rx_xcvr_setup(void) { + uint8_t *dptr; + + dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; + #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) if (g_ble_phy_data.phy_encrypted) { + dptr += 3; NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->OUTPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data; + NRF_CCM->OUTPTR = (uint32_t)dptr; NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; NRF_CCM->MODE = CCM_MODE_MODE_Decryption; NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; @@ -254,20 +302,22 @@ ble_phy_rx_xcvr_setup(void) NRF_CCM->EVENTS_ENDCRYPT = 0; NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk; } else { - NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data; + NRF_RADIO->PACKETPTR = (uint32_t)dptr; } #else - NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data; + NRF_RADIO->PACKETPTR = (uint32_t)dptr; #endif #if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1) if (g_ble_phy_data.phy_privacy) { + dptr += 3; + NRF_RADIO->PACKETPTR = (uint32_t)dptr; NRF_RADIO->PCNF0 = (6 << RADIO_PCNF0_LFLEN_Pos) | (2 << RADIO_PCNF0_S1LEN_Pos) | (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled; NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR->ADDRPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data; + NRF_AAR->ADDRPTR = (uint32_t)dptr; NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; NRF_AAR->EVENTS_END = 0; NRF_AAR->EVENTS_RESOLVED = 0; @@ -289,6 +339,7 @@ ble_phy_rx_xcvr_setup(void) /* Reset the rx started flag. Used for the wait for response */ g_ble_phy_data.phy_rx_started = 0; g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; + g_ble_phy_data.rxdptr = dptr; /* I want to know when 1st byte received (after address) */ NRF_RADIO->BCC = 8; /* in bits */ @@ -313,16 +364,28 @@ ble_phy_rx_xcvr_setup(void) static void ble_phy_tx_end_isr(void) { + uint8_t was_encrypted; uint8_t transition; uint8_t txlen; uint32_t wfr_time; + uint32_t txstart; + + /* + * Read captured tx start time. This is not the actual transmit start + * time but it is the time at which the address event occurred + * (after transmission of access address) + */ + txstart = NRF_TIMER0->CC[1]; + + /* If this transmission was encrypted we need to remember it */ + was_encrypted = g_ble_phy_data.phy_encrypted; /* Better be in TX state! */ assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); /* Log the event */ - ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_txrx_buf[0] >> 8) & 0xFF, - g_ble_phy_data.phy_encrypted, NRF_TIMER0->CC[1]); + ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_tx_buf[0] >> 8) & 0xFF, + was_encrypted, txstart); /* Clear events and clear interrupt on disabled event */ NRF_RADIO->EVENTS_DISABLED = 0; @@ -335,7 +398,7 @@ ble_phy_tx_end_isr(void) * XXX: not sure what to do. We had a HW error during transmission. * For now I just count a stat but continue on like all is good. */ - if (g_ble_phy_data.phy_encrypted) { + if (was_encrypted) { if (NRF_CCM->EVENTS_ERROR) { STATS_INC(ble_phy_stats, tx_hw_err); NRF_CCM->EVENTS_ERROR = 0; @@ -343,26 +406,25 @@ ble_phy_tx_end_isr(void) } #endif + /* Call transmit end callback */ + if (g_ble_phy_data.txend_cb) { + g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); + } + transition = g_ble_phy_data.phy_transition; if (transition == BLE_PHY_TRANSITION_TX_RX) { /* Packet pointer needs to be reset. */ - if (g_ble_phy_data.rxpdu != NULL) { - ble_phy_rx_xcvr_setup(); - } else { - /* Disable the phy */ - STATS_INC(ble_phy_stats, no_bufs); - ble_phy_disable(); - } + ble_phy_rx_xcvr_setup(); /* * Enable the wait for response timer. Note that cc #1 on * timer 0 contains the transmit start time */ txlen = g_ble_phy_data.phy_tx_pyld_len; - if (txlen && g_ble_phy_data.phy_encrypted) { + if (txlen && was_encrypted) { txlen += BLE_LL_DATA_MIC_LEN; } - wfr_time = NRF_TIMER0->CC[1] - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET); + wfr_time = txstart - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET); wfr_time += BLE_TX_DUR_USECS_M(txlen); wfr_time += cputime_usecs_to_ticks(BLE_LL_WFR_USECS); ble_ll_wfr_enable(wfr_time); @@ -371,22 +433,14 @@ ble_phy_tx_end_isr(void) NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; assert(transition == BLE_PHY_TRANSITION_NONE); } - - /* Call transmit end callback */ - if (g_ble_phy_data.txend_cb) { - g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); - } } static void ble_phy_rx_end_isr(void) { int rc; -#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) uint8_t *dptr; -#endif uint8_t crcok; - struct os_mbuf *rxpdu; struct ble_mbuf_hdr *ble_hdr; /* Clear events and clear interrupt */ @@ -397,12 +451,12 @@ ble_phy_rx_end_isr(void) NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; /* Set RSSI and CRC status flag in header */ - ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu); + ble_hdr = &g_ble_phy_data.rxhdr; assert(NRF_RADIO->EVENTS_RSSIEND != 0); ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE; -#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) - dptr = g_ble_phy_data.rxpdu->om_data; -#endif + + dptr = g_ble_phy_data.rxdptr; + /* Count PHY crc errors and valid packets */ crcok = (uint8_t)NRF_RADIO->CRCSTATUS; if (!crcok) { @@ -441,10 +495,6 @@ ble_phy_rx_end_isr(void) #endif } - /* Call Link Layer receive payload function */ - rxpdu = g_ble_phy_data.rxpdu; - g_ble_phy_data.rxpdu = NULL; - #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) || (BLE_LL_CFG_FEAT_LL_PRIVACY == 1) if (g_ble_phy_data.phy_encrypted || g_ble_phy_data.phy_privacy) { /* @@ -454,10 +504,10 @@ ble_phy_rx_end_isr(void) */ dptr[2] = dptr[1]; dptr[1] = dptr[0]; - rxpdu->om_data += 1; + ++dptr; } #endif - rc = ble_ll_rx_end(rxpdu, ble_hdr); + rc = ble_ll_rx_end(dptr, ble_hdr); if (rc < 0) { ble_phy_disable(); } @@ -474,8 +524,6 @@ ble_phy_rx_start_isr(void) NRF_RADIO->EVENTS_ADDRESS = 0; NRF_RADIO->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk; - assert(g_ble_phy_data.rxpdu != NULL); - /* Wait to get 1st byte of frame */ while (1) { state = NRF_RADIO->STATE; @@ -495,7 +543,7 @@ ble_phy_rx_start_isr(void) } /* Initialize flags, channel and state in ble header at rx start */ - ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu); + ble_hdr = &g_ble_phy_data.rxhdr; ble_hdr->rxinfo.flags = ble_ll_state_get(); ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; ble_hdr->rxinfo.handle = 0; @@ -503,7 +551,8 @@ ble_phy_rx_start_isr(void) BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET); /* Call Link Layer receive start function */ - rc = ble_ll_rx_start(g_ble_phy_data.rxpdu, g_ble_phy_data.phy_chan); + rc = ble_ll_rx_start(g_ble_phy_data.rxdptr, g_ble_phy_data.phy_chan, + &g_ble_phy_data.rxhdr); if (rc >= 0) { /* Set rx started flag and enable rx end ISR */ g_ble_phy_data.phy_rx_started = 1; @@ -672,11 +721,6 @@ ble_phy_rx(void) return BLE_PHY_ERR_RADIO_STATE; } - /* If no pdu, get one */ - if (ble_phy_rxpdu_get() == NULL) { - return BLE_PHY_ERR_NO_BUFS; - } - /* Make sure all interrupts are disabled */ NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; @@ -855,7 +899,7 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) NRF_CCM->SHORTS = 1; NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->OUTPTR = (uint32_t)&g_ble_phy_txrx_buf[0]; + NRF_CCM->OUTPTR = (uint32_t)&g_ble_phy_tx_buf[0]; NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->MODE = CCM_MODE_MODE_Encryption; @@ -872,7 +916,7 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; #endif /* RAM representation has S0 and LENGTH fields (2 bytes) */ - dptr = (uint8_t *)&g_ble_phy_txrx_buf[0]; + dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; dptr[0] = ble_hdr->txinfo.hdr_byte; dptr[1] = payload_len; dptr += 2; @@ -887,13 +931,13 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) #endif /* RAM representation has S0 and LENGTH fields (2 bytes) */ - dptr = (uint8_t *)&g_ble_phy_txrx_buf[0]; + dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; dptr[0] = ble_hdr->txinfo.hdr_byte; dptr[1] = payload_len; dptr += 2; #endif - NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0]; + NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_tx_buf[0]; /* Clear the ready, end and disabled events */ NRF_RADIO->EVENTS_READY = 0; @@ -903,13 +947,10 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) /* Enable shortcuts for transmit start/end. */ shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; if (end_trans == BLE_PHY_TRANSITION_TX_RX) { - /* If we are going into receive after this, try to get a buffer. */ - if (ble_phy_rxpdu_get()) { - shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk; - } + shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk; } - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; NRF_RADIO->SHORTS = shortcuts; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; /* Set transmitted payload length */ g_ble_phy_data.phy_tx_pyld_len = payload_len; diff --git a/net/nimble/drivers/nrf52/src/ble_phy.c b/net/nimble/drivers/nrf52/src/ble_phy.c index 541ece95..2e346699 100644 --- a/net/nimble/drivers/nrf52/src/ble_phy.c +++ b/net/nimble/drivers/nrf52/src/ble_phy.c @@ -29,17 +29,12 @@ #include "controller/ble_ll.h" #include "mcu/nrf52_bitfields.h" -/* - * XXX: need to make the copy from mbuf into the PHY data structures 32-bit - * copies or we are screwed. - */ - /* XXX: 4) Make sure RF is higher priority interrupt than schedule */ /* * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal * and 16ms for a 30ppm crystal! We need to limit PDU size based on - * crystal accuracy + * crystal accuracy. Look at this in the spec. */ /* XXX: private header file? */ @@ -79,7 +74,7 @@ struct ble_phy_obj uint8_t phy_tx_pyld_len; uint32_t phy_aar_scratch; uint32_t phy_access_address; - struct os_mbuf *rxpdu; + struct ble_mbuf_hdr rxhdr; void *txend_arg; ble_phy_tx_end_func txend_cb; }; @@ -87,7 +82,8 @@ struct ble_phy_obj g_ble_phy_data; /* XXX: if 27 byte packets desired we can make this smaller */ /* Global transmit/receive buffer */ -static uint32_t g_ble_phy_txrx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; +static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; +static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) /* Make sure word-aligned for faster copies */ @@ -106,7 +102,6 @@ STATS_SECT_START(ble_phy_stats) STATS_SECT_ENTRY(rx_valid) STATS_SECT_ENTRY(rx_crc_err) STATS_SECT_ENTRY(rx_late) - STATS_SECT_ENTRY(no_bufs) STATS_SECT_ENTRY(radio_state_errs) STATS_SECT_ENTRY(rx_hw_err) STATS_SECT_ENTRY(tx_hw_err) @@ -124,7 +119,6 @@ STATS_NAME_START(ble_phy_stats) STATS_NAME(ble_phy_stats, rx_valid) STATS_NAME(ble_phy_stats, rx_crc_err) STATS_NAME(ble_phy_stats, rx_late) - STATS_NAME(ble_phy_stats, no_bufs) STATS_NAME(ble_phy_stats, radio_state_errs) STATS_NAME(ble_phy_stats, rx_hw_err) STATS_NAME(ble_phy_stats, tx_hw_err) @@ -185,33 +179,81 @@ struct nrf_ccm_data g_nrf_ccm_data; #endif /** - * ble phy rxpdu get + * Copies the data from the phy receive buffer into a mbuf chain. * - * Gets a mbuf for PDU reception. + * @param dptr Pointer to receive buffer + * @param rxpdu Pointer to already allocated mbuf chain + * + * NOTE: the packet header already has the total mbuf length in it. The + * lengths of the individual mbufs are not set prior to calling. * - * @return struct os_mbuf* Pointer to retrieved mbuf or NULL if none available */ -static struct os_mbuf * -ble_phy_rxpdu_get(void) +void +ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) { + uint16_t rem_bytes; + uint16_t mb_bytes; + uint16_t copylen; + uint32_t *dst; + uint32_t *src; struct os_mbuf *m; + struct ble_mbuf_hdr *ble_hdr; + struct os_mbuf_pkthdr *pkthdr; + + /* Better be aligned */ + assert(((uint32_t)dptr & 3) == 0); + + pkthdr = OS_MBUF_PKTHDR(rxpdu); + rem_bytes = pkthdr->omp_len; + + /* Fill in the mbuf pkthdr first. */ + dst = (uint32_t *)(rxpdu->om_data); + src = (uint32_t *)dptr; + + mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4); + copylen = min(mb_bytes, rem_bytes); + copylen &= 0xFFFC; + rem_bytes -= copylen; + mb_bytes -= copylen; + rxpdu->om_len = copylen; + while (copylen > 0) { + *dst = *src; + ++dst; + ++src; + copylen -= 4; + } - m = g_ble_phy_data.rxpdu; - if (m == NULL) { - m = os_msys_get_pkthdr(BLE_MBUF_PAYLOAD_SIZE, sizeof(struct ble_mbuf_hdr)); - if (!m) { - STATS_INC(ble_phy_stats, no_bufs); - } else { - /* - * NOTE: we add two bytes to the data pointer as we will prepend - * two bytes if we hand this received pdu up to host. - */ - m->om_data += 2; - g_ble_phy_data.rxpdu = m; + /* Copy remaining bytes */ + m = rxpdu; + while (rem_bytes > 0) { + /* If there are enough bytes in the mbuf, copy them and leave */ + if (rem_bytes <= mb_bytes) { + memcpy(m->om_data + m->om_len, src, rem_bytes); + m->om_len += rem_bytes; + break; + } + + m = SLIST_NEXT(m, om_next); + assert(m != NULL); + + mb_bytes = m->om_omp->omp_databuf_len; + copylen = min(mb_bytes, rem_bytes); + copylen &= 0xFFFC; + rem_bytes -= copylen; + mb_bytes -= copylen; + m->om_len = copylen; + dst = (uint32_t *)m->om_data; + while (copylen > 0) { + *dst = *src; + ++dst; + ++src; + copylen -= 4; } } - return m; + /* Copy ble header */ + ble_hdr = BLE_MBUF_HDR_PTR(rxpdu); + memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr)); } /** @@ -243,11 +285,16 @@ nrf_wait_disabled(void) static void ble_phy_rx_xcvr_setup(void) { + uint8_t *dptr; + + dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; + dptr += 3; + #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) if (g_ble_phy_data.phy_encrypted) { NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->OUTPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data; + NRF_CCM->OUTPTR = (uint32_t)dptr; NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption; NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; @@ -256,17 +303,17 @@ ble_phy_rx_xcvr_setup(void) NRF_CCM->EVENTS_ENDCRYPT = 0; NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk; } else { - NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data; + NRF_RADIO->PACKETPTR = (uint32_t)dptr; } #else - NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data; + NRF_RADIO->PACKETPTR = (uint32_t)dptr; #endif #if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1) if (g_ble_phy_data.phy_privacy) { NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled; NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR->ADDRPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data; + NRF_AAR->ADDRPTR = (uint32_t)dptr; NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; NRF_AAR->EVENTS_END = 0; NRF_AAR->EVENTS_RESOLVED = 0; @@ -308,16 +355,28 @@ ble_phy_rx_xcvr_setup(void) static void ble_phy_tx_end_isr(void) { + uint8_t was_encrypted; uint8_t transition; uint8_t txlen; uint32_t wfr_time; + uint32_t txstart; + + /* + * Read captured tx start time. This is not the actual transmit start + * time but it is the time at which the address event occurred + * (after transmission of access address) + */ + txstart = NRF_TIMER0->CC[1]; + + /* If this transmission was encrypted we need to remember it */ + was_encrypted = g_ble_phy_data.phy_encrypted; /* Better be in TX state! */ assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); /* Log the event */ - ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_txrx_buf[0] >> 8) & 0xFF, - g_ble_phy_data.phy_encrypted, NRF_TIMER0->CC[1]); + ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_tx_buf[0] >> 8) & 0xFF, + was_encrypted, txstart); /* Clear events and clear interrupt on disabled event */ NRF_RADIO->EVENTS_DISABLED = 0; @@ -330,7 +389,7 @@ ble_phy_tx_end_isr(void) * XXX: not sure what to do. We had a HW error during transmission. * For now I just count a stat but continue on like all is good. */ - if (g_ble_phy_data.phy_encrypted) { + if (was_encrypted) { if (NRF_CCM->EVENTS_ERROR) { STATS_INC(ble_phy_stats, tx_hw_err); NRF_CCM->EVENTS_ERROR = 0; @@ -338,26 +397,25 @@ ble_phy_tx_end_isr(void) } #endif + /* Call transmit end callback */ + if (g_ble_phy_data.txend_cb) { + g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); + } + transition = g_ble_phy_data.phy_transition; if (transition == BLE_PHY_TRANSITION_TX_RX) { /* Packet pointer needs to be reset. */ - if (g_ble_phy_data.rxpdu != NULL) { - ble_phy_rx_xcvr_setup(); - } else { - /* Disable the phy */ - STATS_INC(ble_phy_stats, no_bufs); - ble_phy_disable(); - } + ble_phy_rx_xcvr_setup(); /* * Enable the wait for response timer. Note that cc #1 on * timer 0 contains the transmit start time */ txlen = g_ble_phy_data.phy_tx_pyld_len; - if (txlen && g_ble_phy_data.phy_encrypted) { + if (txlen && was_encrypted) { txlen += BLE_LL_DATA_MIC_LEN; } - wfr_time = NRF_TIMER0->CC[1] - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET); + wfr_time = txstart - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET); wfr_time += BLE_TX_DUR_USECS_M(txlen); wfr_time += cputime_usecs_to_ticks(BLE_LL_WFR_USECS); ble_ll_wfr_enable(wfr_time); @@ -366,11 +424,6 @@ ble_phy_tx_end_isr(void) NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; assert(transition == BLE_PHY_TRANSITION_NONE); } - - /* Call transmit end callback */ - if (g_ble_phy_data.txend_cb) { - g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); - } } static void @@ -379,7 +432,6 @@ ble_phy_rx_end_isr(void) int rc; uint8_t *dptr; uint8_t crcok; - struct os_mbuf *rxpdu; struct ble_mbuf_hdr *ble_hdr; /* Clear events and clear interrupt */ @@ -390,11 +442,12 @@ ble_phy_rx_end_isr(void) NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; /* Set RSSI and CRC status flag in header */ - ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu); + ble_hdr = &g_ble_phy_data.rxhdr; assert(NRF_RADIO->EVENTS_RSSIEND != 0); ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE; - dptr = g_ble_phy_data.rxpdu->om_data; + dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; + dptr += 3; /* Count PHY crc errors and valid packets */ crcok = (uint8_t)NRF_RADIO->CRCSTATUS; @@ -434,10 +487,6 @@ ble_phy_rx_end_isr(void) #endif } - /* Call Link Layer receive payload function */ - rxpdu = g_ble_phy_data.rxpdu; - g_ble_phy_data.rxpdu = NULL; - /* * XXX: This is a horrible ugly hack to deal with the RAM S1 byte * that is not sent over the air but is present here. Simply move the @@ -445,9 +494,7 @@ ble_phy_rx_end_isr(void) */ dptr[2] = dptr[1]; dptr[1] = dptr[0]; - rxpdu->om_data += 1; - - rc = ble_ll_rx_end(rxpdu, ble_hdr); + rc = ble_ll_rx_end(dptr + 1, ble_hdr); if (rc < 0) { ble_phy_disable(); } @@ -464,8 +511,6 @@ ble_phy_rx_start_isr(void) NRF_RADIO->EVENTS_ADDRESS = 0; NRF_RADIO->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk; - assert(g_ble_phy_data.rxpdu != NULL); - /* Wait to get 1st byte of frame */ while (1) { state = NRF_RADIO->STATE; @@ -485,7 +530,7 @@ ble_phy_rx_start_isr(void) } /* Initialize flags, channel and state in ble header at rx start */ - ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu); + ble_hdr = &g_ble_phy_data.rxhdr; ble_hdr->rxinfo.flags = ble_ll_state_get(); ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; ble_hdr->rxinfo.handle = 0; @@ -493,7 +538,9 @@ ble_phy_rx_start_isr(void) BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET); /* Call Link Layer receive start function */ - rc = ble_ll_rx_start(g_ble_phy_data.rxpdu, g_ble_phy_data.phy_chan); + rc = ble_ll_rx_start((uint8_t *)&g_ble_phy_rx_buf[0] + 3, + g_ble_phy_data.phy_chan, + &g_ble_phy_data.rxhdr); if (rc >= 0) { /* Set rx started flag and enable rx end ISR */ g_ble_phy_data.phy_rx_started = 1; @@ -589,6 +636,7 @@ ble_phy_init(void) RADIO_PCNF0_S1INCL_Msk | (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos) | (RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos); + /* XXX: should maxlen be 251 for encryption? */ NRF_RADIO->PCNF1 = NRF_MAXLEN | (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | @@ -664,11 +712,6 @@ ble_phy_rx(void) return BLE_PHY_ERR_RADIO_STATE; } - /* If no pdu, get one */ - if (ble_phy_rxpdu_get() == NULL) { - return BLE_PHY_ERR_NO_BUFS; - } - /* Make sure all interrupts are disabled */ NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; @@ -809,6 +852,7 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) { int rc; uint8_t *dptr; + uint8_t *pktptr; uint8_t payload_len; uint32_t state; uint32_t shortcuts; @@ -829,9 +873,11 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) if (g_ble_phy_data.phy_encrypted) { dptr = (uint8_t *)&g_ble_phy_enc_buf[0]; + ++dptr; + pktptr = (uint8_t *)&g_ble_phy_tx_buf[0]; NRF_CCM->SHORTS = 1; - NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->OUTPTR = (uint32_t)&g_ble_phy_txrx_buf[0]; + NRF_CCM->INPTR = (uint32_t)dptr; + NRF_CCM->OUTPTR = (uint32_t)pktptr; NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->MODE = CCM_MODE_LENGTH_Msk; @@ -843,13 +889,17 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk; NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; #endif - dptr = (uint8_t *)&g_ble_phy_txrx_buf[0]; + dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; + ++dptr; + pktptr = dptr; } #else #if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1) NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk; #endif - dptr = (uint8_t *)&g_ble_phy_txrx_buf[0]; + dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; + ++dptr; + pktptr = dptr; #endif /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */ @@ -857,7 +907,7 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) dptr[1] = payload_len; dptr[2] = 0; dptr += 3; - NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0]; + NRF_RADIO->PACKETPTR = (uint32_t)pktptr; /* Clear the ready, end and disabled events */ NRF_RADIO->EVENTS_READY = 0; @@ -867,13 +917,10 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) /* Enable shortcuts for transmit start/end. */ shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; if (end_trans == BLE_PHY_TRANSITION_TX_RX) { - /* If we are going into receive after this, try to get a buffer. */ - if (ble_phy_rxpdu_get()) { - shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk; - } + shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk; } - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; NRF_RADIO->SHORTS = shortcuts; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; /* Set transmitted payload length */ g_ble_phy_data.phy_tx_pyld_len = payload_len; diff --git a/net/nimble/host/include/host/ble_att.h b/net/nimble/host/include/host/ble_att.h index 53b4e19f..24b44961 100644 --- a/net/nimble/host/include/host/ble_att.h +++ b/net/nimble/host/include/host/ble_att.h @@ -21,6 +21,7 @@ #define H_BLE_ATT_ #include "os/queue.h" +struct os_mbuf; #define BLE_ATT_UUID_PRIMARY_SERVICE 0x2800 #define BLE_ATT_UUID_SECONDARY_SERVICE 0x2801 @@ -31,14 +32,17 @@ #define BLE_ATT_ERR_READ_NOT_PERMITTED 0x02 #define BLE_ATT_ERR_WRITE_NOT_PERMITTED 0x03 #define BLE_ATT_ERR_INVALID_PDU 0x04 -#define BLE_ATT_ERR_INSUFFICIENT_AUTHENT 0x05 +#define BLE_ATT_ERR_INSUFFICIENT_AUTHEN 0x05 #define BLE_ATT_ERR_REQ_NOT_SUPPORTED 0x06 #define BLE_ATT_ERR_INVALID_OFFSET 0x07 +#define BLE_ATT_ERR_INSUFFICIENT_AUTHOR 0x08 #define BLE_ATT_ERR_PREPARE_QUEUE_FULL 0x09 #define BLE_ATT_ERR_ATTR_NOT_FOUND 0x0a #define BLE_ATT_ERR_ATTR_NOT_LONG 0x0b +#define BLE_ATT_ERR_INSUFFICIENT_KEY_SZ 0x0c #define BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN 0x0d #define BLE_ATT_ERR_UNLIKELY 0x0e +#define BLE_ATT_ERR_INSUFFICIENT_ENC 0x0f #define BLE_ATT_ERR_UNSUPPORTED_GROUP 0x10 #define BLE_ATT_ERR_INSUFFICIENT_RES 0x11 @@ -86,44 +90,15 @@ #define BLE_ATT_ACCESS_OP_READ 1 #define BLE_ATT_ACCESS_OP_WRITE 2 -struct ble_att_svr_access_ctxt { - void *attr_data; - uint16_t data_len; - uint16_t offset; /* Only used for read-blob requests. */ -}; +#define BLE_ATT_MTU_DFLT 23 /* Also the minimum. */ +#define BLE_ATT_MTU_MAX 240 +#define BLE_ATT_MTU_PREFERRED_DFLT 240 -/** - * Handles a host attribute request. - * - * @param entry The host attribute being requested. - * @param op The operation being performed on the attribute. - * @param arg The request data associated with that host - * attribute. - * - * @return 0 on success; - * One of the BLE_ATT_ERR_[...] codes on - * failure. - */ -typedef int ble_att_svr_access_fn(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, - void *arg); - -int ble_att_svr_register(uint8_t *uuid, uint8_t flags, uint16_t *handle_id, - ble_att_svr_access_fn *cb, void *cb_arg); -int ble_att_svr_register_uuid16(uint16_t uuid16, uint8_t flags, - uint16_t *handle_id, ble_att_svr_access_fn *cb, - void *cb_arg); - -typedef int ble_att_svr_notify_fn(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *attr_val, uint16_t attr_len, - void *arg); - -int ble_att_svr_read_local(uint16_t attr_handle, void **out_data, - uint16_t *out_attr_len); -int ble_att_svr_write_local(uint16_t attr_handle, void *data, - uint16_t data_len); +int ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om); +int ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf *om); +uint16_t ble_att_mtu(uint16_t conn_handle); +uint16_t ble_att_preferred_mtu(void); int ble_att_set_preferred_mtu(uint16_t mtu); #endif diff --git a/net/nimble/host/include/host/ble_gap.h b/net/nimble/host/include/host/ble_gap.h index 23b8f462..960ad7b2 100644 --- a/net/nimble/host/include/host/ble_gap.h +++ b/net/nimble/host/include/host/ble_gap.h @@ -24,7 +24,6 @@ #include "host/ble_hs.h" struct hci_le_conn_complete; struct hci_conn_update; -struct hci_adv_params; /** 30 ms. */ #define BLE_GAP_ADV_FAST_INTERVAL1_MIN (30 * 1000 / BLE_HCI_ADV_ITVL) @@ -44,6 +43,12 @@ struct hci_adv_params; /** 60 ms; active scanning. */ #define BLE_GAP_SCAN_FAST_INTERVAL_MAX (60 * 1000 / BLE_HCI_ADV_ITVL) +/** 11.25 ms; limited discovery interval. */ +#define BLE_GAP_LIM_DISC_SCAN_INT (11.25 * 1000 / BLE_HCI_SCAN_ITVL) + +/** 11.25 ms; limited discovery window (not from the spec). */ +#define BLE_GAP_LIM_DISC_SCAN_WINDOW (11.25 * 1000 / BLE_HCI_SCAN_ITVL) + /** 30 ms; active scanning. */ #define BLE_GAP_SCAN_FAST_WINDOW (30 * 1000 / BLE_HCI_SCAN_ITVL) @@ -57,7 +62,10 @@ struct hci_adv_params; #define BLE_GAP_SCAN_SLOW_WINDOW1 (11.25 * 1000 / BLE_HCI_SCAN_ITVL) /** 10.24 seconds. */ -#define BLE_GAP_GEN_DISC_SCAN_MIN (10.24 * 1000) +#define BLE_GAP_DISC_DUR_DFLT (10.24 * 1000) + +/** 30 seconds (not from the spec). */ +#define BLE_GAP_CONN_DUR_DFLT (30 * 1000) /** 1 second. */ #define BLE_GAP_CONN_PAUSE_CENTRAL (1 * 1000) @@ -71,21 +79,18 @@ struct hci_adv_params; /* 50 ms. */ #define BLE_GAP_INITIAL_CONN_ITVL_MAX (50 * 1000 / BLE_HCI_CONN_ITVL) +#define BLE_GAP_ADV_DFLT_CHANNEL_MAP 0x07 /* All three channels. */ + #define BLE_GAP_INITIAL_CONN_LATENCY 0 #define BLE_GAP_INITIAL_SUPERVISION_TIMEOUT 0x0100 #define BLE_GAP_INITIAL_CONN_MIN_CE_LEN 0x0010 #define BLE_GAP_INITIAL_CONN_MAX_CE_LEN 0x0300 -#define BLE_GAP_SVC_UUID16 0x1800 -#define BLE_GAP_CHR_UUID16_DEVICE_NAME 0x2a00 -#define BLE_GAP_CHR_UUID16_APPEARANCE 0x2a01 -#define BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG 0x2a02 -#define BLE_GAP_CHR_UUID16_RECONNECT_ADDR 0x2a03 -#define BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS 0x2a04 - -#define BLE_GAP_APPEARANCE_GEN_COMPUTER 128 - #define BLE_GAP_ADDR_TYPE_WL 0xff +#define BLE_GAP_ADDR_TYPE_NONE 0xfe + +#define BLE_GAP_ROLE_MASTER 0 +#define BLE_GAP_ROLE_SLAVE 1 #define BLE_GAP_EVENT_CONNECT 0 #define BLE_GAP_EVENT_DISCONNECT 1 @@ -94,12 +99,29 @@ struct hci_adv_params; #define BLE_GAP_EVENT_CONN_UPDATE_REQ 4 #define BLE_GAP_EVENT_L2CAP_UPDATE_REQ 5 #define BLE_GAP_EVENT_TERM_FAILURE 6 -#define BLE_GAP_EVENT_DISC_SUCCESS 7 +#define BLE_GAP_EVENT_DISC 7 #define BLE_GAP_EVENT_DISC_COMPLETE 8 #define BLE_GAP_EVENT_ADV_COMPLETE 9 #define BLE_GAP_EVENT_ENC_CHANGE 10 #define BLE_GAP_EVENT_PASSKEY_ACTION 11 -#define BLE_GAP_EVENT_NOTIFY 12 +#define BLE_GAP_EVENT_NOTIFY_RX 12 +#define BLE_GAP_EVENT_NOTIFY_TX 13 +#define BLE_GAP_EVENT_SUBSCRIBE 14 +#define BLE_GAP_EVENT_MTU 15 + +/*** Reason codes for the subscribe GAP event. */ + +/** Peer's CCCD subscription state changed due to a descriptor write. */ +#define BLE_GAP_SUBSCRIBE_REASON_WRITE 1 + +/** Peer's CCCD subscription state cleared due to connection termination. */ +#define BLE_GAP_SUBSCRIBE_REASON_TERM 2 + +/** + * Peer's CCCD subscription state changed due to restore from persistence + * (bonding restored). + */ +#define BLE_GAP_SUBSCRIBE_REASON_RESTORE 3 struct ble_gap_sec_state { unsigned encrypted:1; @@ -107,13 +129,33 @@ struct ble_gap_sec_state { unsigned bonded:1; }; +/** + * @param discoverable_mode One of the following constants: + * o BLE_GAP_DISC_MODE_NON + * (non-discoverable; 3.C.9.2.2). + * o BLE_GAP_DISC_MODE_LTD + * (limited-discoverable; 3.C.9.2.3). + * o BLE_GAP_DISC_MODE_GEN + * (general-discoverable; 3.C.9.2.4). + * @param connectable_mode One of the following constants: + * o BLE_GAP_CONN_MODE_NON + * (non-connectable; 3.C.9.3.2). + * o BLE_GAP_CONN_MODE_DIR + * (directed-connectable; 3.C.9.3.3). + * o BLE_GAP_CONN_MODE_UND + * (undirected-connectable; 3.C.9.3.4). + */ struct ble_gap_adv_params { - uint8_t adv_type; - uint8_t adv_channel_map; - uint8_t own_addr_type; - uint8_t adv_filter_policy; - uint16_t adv_itvl_min; - uint16_t adv_itvl_max; + /*** Mandatory fields. */ + uint8_t conn_mode; + uint8_t disc_mode; + + /*** Optional fields; assign 0 to make the stack calculate them. */ + uint16_t itvl_min; + uint16_t itvl_max; + uint8_t channel_map; + uint8_t filter_policy; + uint8_t high_duty_cycle:1; }; struct ble_gap_conn_desc { @@ -130,12 +172,13 @@ struct ble_gap_conn_desc { uint8_t peer_id_addr_type; uint8_t our_id_addr_type; uint8_t our_ota_addr_type; + uint8_t role; + uint8_t master_clock_accuracy; }; -struct ble_gap_crt_params { - uint16_t scan_window; +struct ble_gap_conn_params { uint16_t scan_itvl; - uint8_t our_addr_type; + uint16_t scan_window; uint16_t itvl_min; uint16_t itvl_max; uint16_t latency; @@ -144,6 +187,15 @@ struct ble_gap_crt_params { uint16_t max_ce_len; }; +struct ble_gap_disc_params { + uint16_t itvl; + uint16_t window; + uint8_t filter_policy; + uint8_t limited:1; + uint8_t passive:1; + uint8_t filter_duplicates:1; +}; + struct ble_gap_upd_params { uint16_t itvl_min; uint16_t itvl_max; @@ -153,85 +205,315 @@ struct ble_gap_upd_params { uint16_t max_ce_len; }; -struct ble_gap_notify_params { - uint16_t attr_handle; - void *attr_data; - uint16_t attr_len; - - unsigned indication:1; -}; - -struct ble_gap_enhanced_conn { - uint8_t peer_rpa[6]; - uint8_t local_rpa[6]; -}; - -struct ble_gap_passkey_action { +struct ble_gap_passkey_params { uint8_t action; uint32_t numcmp; }; -struct ble_gap_conn_ctxt { - struct ble_gap_conn_desc *desc; +struct ble_gap_disc_desc { + /*** Common fields. */ + uint8_t event_type; + uint8_t addr_type; + uint8_t length_data; + int8_t rssi; + uint8_t addr[6]; + + /*** LE advertising report fields; both null if no data present. */ + uint8_t *data; + struct ble_hs_adv_fields *fields; + + /*** + * LE direct advertising report fields; direct_addr_type is + * BLE_GAP_ADDR_TYPE_NONE if direct address fields are not present. + */ + uint8_t direct_addr_type; + uint8_t direct_addr[6]; +}; +/** + * Represents a GAP-related event. When such an event occurs, the host + * notifies the application by passing an instance of this structure to an + * application-specified callback. + */ +struct ble_gap_event { + /** + * Indicates the type of GAP event that occurred. This is one of the + * BLE_GAP_EVENT codes. + */ + uint8_t type; + + /** + * A discriminated union containing additional details concerning the GAP + * event. The 'type' field indicates which member of the union is valid. + */ union { + /** + * Represents a connection attempt. Valid for the following event + * types: + * o BLE_GAP_EVENT_CONNECT + */ struct { + /** + * The status of the connection attempt; + * o 0: the connection was successfully established. + * o BLE host error code: the connection attempt failed for + * the specified reason. + */ int status; - struct ble_gap_enhanced_conn *enhanced_conn; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; } connect; + /** + * Represents a terminated connection. Valid for the following event + * types: + * o BLE_GAP_EVENT_DISCONNECT + */ struct { + /** + * A BLE host return code indicating the reason for the + * disconnect. + */ int reason; + + /** Information about the connection prior to termination. */ + struct ble_gap_conn_desc conn; } disconnect; + /** + * Represents an advertising report received during a discovery + * procedure. Valid for the following event types: + * o BLE_GAP_EVENT_DISC + */ + struct ble_gap_disc_desc disc; + + /** + * Represents an attempt to update a connection's parameters. If the + * attempt was successful, the connection's descriptor reflects the + * updated parameters. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_CONN_UPDATE + */ struct { + /** + * The result of the connection update attempt; + * o 0: the connection was successfully updated. + * o BLE host error code: the connection update attempt failed + * for the specified reason. + */ int status; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; } conn_update; + /** + * Represents a peer's request to update the connection parameters. + * This event is generated when a peer performs any of the following + * procedures: + * o L2CAP Connection Parameter Update Procedure + * o Link-Layer Connection Parameters Request Procedure + * + * To reject the request, return a non-zero HCI error code. The value + * returned is the reject reason given to the controller. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_L2CAP_UPDATE_REQ + * o BLE_GAP_EVENT_CONN_UPDATE_REQ + */ struct { + /** + * Indicates the connection parameters that the peer would like to + * use. + */ + const struct ble_gap_upd_params *peer_params; + + /** + * Indicates the connection parameters that the local device would + * like to use. The application callback should fill this in. By + * default, this struct contains the requested parameters (i.e., + * it is a copy of 'peer_params'). + */ struct ble_gap_upd_params *self_params; - struct ble_gap_upd_params *peer_params; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; } conn_update_req; + /** + * Represents a failed attempt to terminate an established connection. + * Valid for the following event types: + * o BLE_GAP_EVENT_TERM_FAILURE + */ struct { + /** + * A BLE host return code indicating the reason for the failure. + */ int status; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; } term_failure; + /** + * Represents an attempt to change the encrypted state of a + * connection. If the attempt was successful, the connection + * descriptor reflects the updated encrypted state. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_ENC_CHANGE + */ struct { + /** + * Indicates the result of the encryption state change attempt; + * o 0: the encrypted state was successfully updated; + * o BLE host error code: the encryption state change attempt + * failed for the specified reason. + */ int status; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; } enc_change; - struct ble_gap_passkey_action passkey_action; + /** + * Represents a passkey query needed to complete a pairing procedure. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_PASSKEY_ACTION + */ + struct { + /** Contains details about the passkey query. */ + struct ble_gap_passkey_params params; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; + } passkey; + + /** + * Represents a received ATT notification or indication. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_NOTIFY_RX + */ + struct { + /** + * The contents of the notification or indication. If the + * application wishes to retain this mbuf for later use, it must + * set this pointer to NULL to prevent the stack from freeing it. + */ + struct os_mbuf *om; + + /** The handle of the relevant ATT attribute. */ + uint16_t attr_handle; + /** The handle of the relevant connection. */ + uint16_t conn_handle; + + /** + * Whether the received command is a notification or an + * indication; + * o 0: Notification; + * o 1: Indication. + */ + uint8_t indication:1; + } notify_rx; + + /** + * Represents a transmitted ATT notification or indication, or a + * completed indication transaction. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_NOTIFY_TX + */ struct { + /** + * The status of the notification or indication transaction; + * o 0: Command successfully sent; + * o BLE_HS_EDONE: Confirmation (indication ack) received; + * o BLE_HS_ETIMEOUT: Confirmation (indication ack) never + * received; + * o Other return code: Error. + */ + int status; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; + + /** The handle of the relevant characterstic value. */ uint16_t attr_handle; - void *attr_data; - uint16_t attr_len; - unsigned indication:1; - } notify; + /** + * Whether the transmitted command is a notification or an + * indication; + * o 0: Notification; + * o 1: Indication. + */ + uint8_t indication:1; + } notify_tx; + + /** + * Represents a state change in a peer's subscription status. In this + * comment, the term "update" is used to refer to either a notification + * or an indication. This event is triggered by any of the following + * occurrences: + * o Peer enables or disables updates via a CCCD write. + * o Connection is about to be terminated and the peer is + * subscribed to updates. + * o Peer is now subscribed to updates after its state was restored + * from persistence. This happens when bonding is restored. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_SUBSCRIBE + */ + struct { + /** The handle of the relevant connection. */ + uint16_t conn_handle; - struct ble_gap_ltk_params *ltk_params; - }; -}; + /** The value handle of the relevant characteristic. */ + uint16_t attr_handle; -typedef int ble_gap_event_fn(int event, struct ble_gap_conn_ctxt *ctxt, - void *arg); + /** One of the BLE_GAP_SUBSCRIBE_REASON codes. */ + uint8_t reason; -struct ble_gap_disc_desc { - uint8_t event_type; - uint8_t addr_type; - uint8_t length_data; - int8_t rssi; - uint8_t addr[6]; - uint8_t *data; - struct ble_hs_adv_fields *fields; -}; + /** Whether the peer was previously subscribed to notifications. */ + uint8_t prev_notify:1; + + /** Whether the peer is currently subscribed to notifications. */ + uint8_t cur_notify:1; -typedef void ble_gap_disc_fn(int event, int status, - struct ble_gap_disc_desc *desc, void *arg); + /** Whether the peer was previously subscribed to indications. */ + uint8_t prev_indicate:1; -typedef void ble_gap_wl_fn(int status, void *arg); + /** Whether the peer is currently subscribed to indications. */ + uint8_t cur_indicate:1; + } subscribe; + + /** + * Represents a change in an L2CAP channel's MTU. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_MTU + */ + struct { + /** The handle of the relevant connection. */ + uint16_t conn_handle; + + /** + * Indicates the channel whose MTU has been updated; either + * BLE_L2CAP_CID_ATT or the ID of a connection-oriented channel. + */ + uint16_t channel_id; + + /* The channel's new MTU. */ + uint16_t value; + } mtu; + }; +}; + +typedef int ble_gap_event_fn(struct ble_gap_event *event, void *arg); #define BLE_GAP_CONN_MODE_NON 0 #define BLE_GAP_CONN_MODE_DIR 1 @@ -246,35 +528,37 @@ struct ble_gap_white_entry { uint8_t addr[6]; }; -int ble_gap_find_conn(uint16_t handle, struct ble_gap_conn_desc *out_desc); +int ble_gap_conn_find(uint16_t handle, struct ble_gap_conn_desc *out_desc); -int ble_gap_adv_start(uint8_t discoverable_mode, uint8_t connectable_mode, - uint8_t *peer_addr, uint8_t peer_addr_type, +int ble_gap_adv_start(uint8_t own_addr_type, uint8_t peer_addr_type, + const uint8_t *peer_addr, int32_t duration_ms, const struct ble_gap_adv_params *adv_params, ble_gap_event_fn *cb, void *cb_arg); - int ble_gap_adv_stop(void); -int ble_gap_adv_set_fields(struct ble_hs_adv_fields *adv_fields); -int ble_gap_adv_rsp_set_fields(struct ble_hs_adv_fields *rsp_fields); -int ble_gap_disc(uint32_t duration_ms, uint8_t discovery_mode, - uint8_t scan_type, uint8_t filter_policy, - uint8_t addr_mode, - ble_gap_disc_fn *cb, void *cb_arg); +int ble_gap_adv_active(void); +int ble_gap_adv_set_fields(const struct ble_hs_adv_fields *adv_fields); +int ble_gap_adv_rsp_set_fields(const struct ble_hs_adv_fields *rsp_fields); +int ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, + const struct ble_gap_disc_params *disc_params, + ble_gap_event_fn *cb, void *cb_arg); int ble_gap_disc_cancel(void); -int ble_gap_conn_initiate(int addr_type, uint8_t *addr, - struct ble_gap_crt_params *params, - ble_gap_event_fn *cb, void *cb_arg); -int ble_gap_terminate(uint16_t handle); -int ble_gap_cancel(void); -int ble_gap_wl_set(struct ble_gap_white_entry *white_list, +int ble_gap_disc_active(void); +int ble_gap_connect(uint8_t own_addr_type, + uint8_t peer_addr_type, const uint8_t *peer_addr, + int32_t duration_ms, + const struct ble_gap_conn_params *params, + ble_gap_event_fn *cb, void *cb_arg); +int ble_gap_conn_cancel(void); +int ble_gap_conn_active(void); +int ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason); +int ble_gap_wl_set(const struct ble_gap_white_entry *white_list, uint8_t white_list_count); int ble_gap_update_params(uint16_t conn_handle, - struct ble_gap_upd_params *params); + const struct ble_gap_upd_params *params); int ble_gap_security_initiate(uint16_t conn_handle); int ble_gap_pair_initiate(uint16_t conn_handle); -int ble_gap_encryption_initiate(uint16_t conn_handle, uint8_t *ltk, +int ble_gap_encryption_initiate(uint16_t conn_handle, const uint8_t *ltk, uint16_t ediv, uint64_t rand_val, int auth); -int ble_gap_provide_ltk(uint16_t conn_handle, uint8_t *ltk); -void ble_gap_init_identity_addr(uint8_t *addr); +int ble_gap_conn_rssi(uint16_t conn_handle, int8_t *out_rssi); #endif diff --git a/net/nimble/host/include/host/ble_gatt.h b/net/nimble/host/include/host/ble_gatt.h index 194ebf31..fbc32a2f 100644 --- a/net/nimble/host/include/host/ble_gatt.h +++ b/net/nimble/host/include/host/ble_gatt.h @@ -24,9 +24,48 @@ #include "host/ble_att.h" struct ble_hs_conn; struct ble_att_error_rsp; +struct ble_hs_cfg; + +#define BLE_GATT_REGISTER_OP_SVC 1 +#define BLE_GATT_REGISTER_OP_CHR 2 +#define BLE_GATT_REGISTER_OP_DSC 3 #define BLE_GATT_SVC_UUID16 0x1801 -#define BLE_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05 +#define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902 + +#define BLE_GATT_CHR_PROP_BROADCAST 0x01 +#define BLE_GATT_CHR_PROP_READ 0x02 +#define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04 +#define BLE_GATT_CHR_PROP_WRITE 0x08 +#define BLE_GATT_CHR_PROP_NOTIFY 0x10 +#define BLE_GATT_CHR_PROP_INDICATE 0x20 +#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40 +#define BLE_GATT_CHR_PROP_EXTENDED 0x80 + +#define BLE_GATT_ACCESS_OP_READ_CHR 0 +#define BLE_GATT_ACCESS_OP_WRITE_CHR 1 +#define BLE_GATT_ACCESS_OP_READ_DSC 2 +#define BLE_GATT_ACCESS_OP_WRITE_DSC 3 + +#define BLE_GATT_CHR_F_BROADCAST 0x0001 +#define BLE_GATT_CHR_F_READ 0x0002 +#define BLE_GATT_CHR_F_WRITE_NO_RSP 0x0004 +#define BLE_GATT_CHR_F_WRITE 0x0008 +#define BLE_GATT_CHR_F_NOTIFY 0x0010 +#define BLE_GATT_CHR_F_INDICATE 0x0020 +#define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x0040 +#define BLE_GATT_CHR_F_RELIABLE_WRITE 0x0080 +#define BLE_GATT_CHR_F_AUX_WRITE 0x0100 +#define BLE_GATT_CHR_F_READ_ENC 0x0200 +#define BLE_GATT_CHR_F_READ_AUTHEN 0x0400 +#define BLE_GATT_CHR_F_READ_AUTHOR 0x0800 +#define BLE_GATT_CHR_F_WRITE_ENC 0x1000 +#define BLE_GATT_CHR_F_WRITE_AUTHEN 0x2000 +#define BLE_GATT_CHR_F_WRITE_AUTHOR 0x4000 + +#define BLE_GATT_SVC_TYPE_END 0 +#define BLE_GATT_SVC_TYPE_PRIMARY 1 +#define BLE_GATT_SVC_TYPE_SECONDARY 2 /*** @client. */ struct ble_gatt_error { @@ -43,8 +82,7 @@ struct ble_gatt_svc { struct ble_gatt_attr { uint16_t handle; uint16_t offset; - uint16_t value_len; - void *value; + struct os_mbuf *om; }; struct ble_gatt_chr { @@ -59,32 +97,49 @@ struct ble_gatt_dsc { uint8_t uuid128[16]; }; -typedef int ble_gatt_mtu_fn(uint16_t conn_handle, struct ble_gatt_error *error, +typedef int ble_gatt_mtu_fn(uint16_t conn_handle, + const struct ble_gatt_error *error, uint16_t mtu, void *arg); typedef int ble_gatt_disc_svc_fn(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_svc *service, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, void *arg); + +/** + * The host will free the attribute mbuf automatically after the callback is + * executed. The application can take ownership of the mbuf and prevent it + * from being freed by assigning NULL to attr->om. + */ typedef int ble_gatt_attr_fn(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg); + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg); + +/** + * The host will free the attribute mbufs automatically after the callback is + * executed. The application can take ownership of the mbufs and prevent them + * from being freed by assigning NULL to each attribute's om field. + */ typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle, - struct ble_gatt_error *error, + const struct ble_gatt_error *error, struct ble_gatt_attr *attrs, uint8_t num_attrs, void *arg); -typedef int ble_gatt_chr_fn(uint16_t conn_handle, struct ble_gatt_error *error, - struct ble_gatt_chr *chr, void *arg); +typedef int ble_gatt_chr_fn(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg); -typedef int ble_gatt_dsc_fn(uint16_t conn_handle, struct ble_gatt_error *error, - uint16_t chr_def_handle, struct ble_gatt_dsc *dsc, +typedef int ble_gatt_dsc_fn(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_def_handle, + const struct ble_gatt_dsc *dsc, void *arg); int ble_gattc_exchange_mtu(uint16_t conn_handle, ble_gatt_mtu_fn *cb, void *cb_arg); int ble_gattc_disc_all_svcs(uint16_t conn_handle, ble_gatt_disc_svc_fn *cb, void *cb_arg); -int ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, void *service_uuid128, +int ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const void *svc_uuid128, ble_gatt_disc_svc_fn *cb, void *cb_arg); int ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, @@ -93,7 +148,7 @@ int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, ble_gatt_chr_fn *cb, void *cb_arg); int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, void *uuid128, + uint16_t end_handle, const void *uuid128, ble_gatt_chr_fn *cb, void *cb_arg); int ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t chr_val_handle, uint16_t chr_end_handle, @@ -101,150 +156,295 @@ int ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t chr_val_handle, int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle, ble_gatt_attr_fn *cb, void *cb_arg); int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, void *uuid128, + uint16_t end_handle, const void *uuid128, ble_gatt_attr_fn *cb, void *cb_arg); int ble_gattc_read_long(uint16_t conn_handle, uint16_t handle, ble_gatt_attr_fn *cb, void *cb_arg); -int ble_gattc_read_mult(uint16_t conn_handle, uint16_t *handles, +int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, uint8_t num_handles, ble_gatt_attr_fn *cb, void *cb_arg); int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, - void *value, uint16_t value_len); -int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, void *value, - uint16_t value_len, ble_gatt_attr_fn *cb, void *cb_arg); + struct os_mbuf *om); +int ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle, + const void *data, uint16_t data_len); +int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, + struct os_mbuf *om, + ble_gatt_attr_fn *cb, void *cb_arg); +int ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg); int ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle, - void *value, uint16_t value_len, ble_gatt_attr_fn *cb, - void *cb_arg); -int ble_gattc_write_reliable(uint16_t conn_handle, struct ble_gatt_attr *attrs, + struct os_mbuf *om, + ble_gatt_attr_fn *cb, void *cb_arg); +int ble_gattc_write_reliable(uint16_t conn_handle, + struct ble_gatt_attr *attrs, int num_attrs, ble_gatt_reliable_attr_fn *cb, void *cb_arg); -int ble_gattc_read_dsc(uint16_t conn_handle, uint16_t attr_handle, - ble_gatt_attr_fn *cb, void *cb_arg); -int ble_gattc_read_long_dsc(uint16_t conn_handle, uint16_t attr_handle, - ble_gatt_attr_fn *cb, void *cb_arg); -int ble_gattc_write_dsc(uint16_t conn_handle, uint16_t attr_handle, - void *value, uint16_t value_len, - ble_gatt_attr_fn *cb, void *cb_arg); -int ble_gattc_write_long_dsc(uint16_t conn_handle, uint16_t attr_handle, - void *value, uint16_t value_len, - ble_gatt_attr_fn *cb, void *cb_arg); -int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle); int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle, - void *attr_data, uint16_t attr_data_len); + struct os_mbuf *om); +int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle); +int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle); int ble_gattc_init(void); /*** @server. */ -#define BLE_GATT_CHR_PROP_BROADCAST 0x01 -#define BLE_GATT_CHR_PROP_READ 0x02 -#define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04 -#define BLE_GATT_CHR_PROP_WRITE 0x08 -#define BLE_GATT_CHR_PROP_NOTIFY 0x10 -#define BLE_GATT_CHR_PROP_INDICATE 0x20 -#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40 -#define BLE_GATT_CHR_PROP_EXTENDED 0x80 - -#define BLE_GATT_ACCESS_OP_READ_CHR 0 -#define BLE_GATT_ACCESS_OP_WRITE_CHR 1 -#define BLE_GATT_ACCESS_OP_READ_DSC 2 -#define BLE_GATT_ACCESS_OP_WRITE_DSC 3 - -union ble_gatt_access_ctxt; +struct ble_gatt_access_ctxt; typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle, - uint8_t op, union ble_gatt_access_ctxt *ctxt, - void *arg); + struct ble_gatt_access_ctxt *ctxt, void *arg); typedef uint16_t ble_gatt_chr_flags; -#define BLE_GATT_CHR_F_BROADCAST 0x0001 -#define BLE_GATT_CHR_F_READ 0x0002 -#define BLE_GATT_CHR_F_WRITE_NO_RSP 0x0004 -#define BLE_GATT_CHR_F_WRITE 0x0008 -#define BLE_GATT_CHR_F_NOTIFY 0x0010 -#define BLE_GATT_CHR_F_INDICATE 0x0020 -#define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x0040 -#define BLE_GATT_CHR_F_RELIABLE_WRITE 0x0080 -#define BLE_GATT_CHR_F_AUX_WRITE 0x0100 -#define BLE_GATT_CHR_F_READ_ENC 0x0200 -#define BLE_GATT_CHR_F_READ_AUTHEN 0x0400 -#define BLE_GATT_CHR_F_READ_AUTHOR 0x0800 -#define BLE_GATT_CHR_F_WRITE_ENC 0x1000 -#define BLE_GATT_CHR_F_WRITE_AUTHEN 0x2000 -#define BLE_GATT_CHR_F_WRITE_AUTHOR 0x4000 - struct ble_gatt_chr_def { - uint8_t *uuid128; /* NULL if no more characteristics. */ + /** + * Pointer to first element in a uint8_t[16]; use the BLE_UUID16 macro for + * 16-bit UUIDs; NULL if there are no more characteristics in the service. + */ + const uint8_t *uuid128; + + /** + * Callback that gets executed when this characteristic is read or + * written. + */ ble_gatt_access_fn *access_cb; + + /** Optional argument for callback. */ void *arg; + + /** + * Array of this characteristic's descriptors. NULL if no descriptors. + * Do not include CCCD; it gets added automatically if this + * characteristic's notify or indicate flag is set. + */ struct ble_gatt_dsc_def *descriptors; + + /** Specifies the set of permitted operations for this characteristic. */ ble_gatt_chr_flags flags; -}; -#define BLE_GATT_SVC_TYPE_END 0 -#define BLE_GATT_SVC_TYPE_PRIMARY 1 -#define BLE_GATT_SVC_TYPE_SECONDARY 2 + /** + * At registration time, this is filled in with the characteristic's value + * attribute handle. + */ + uint16_t * const val_handle; +}; struct ble_gatt_svc_def { + /** + * One of the following: + * o BLE_GATT_SVC_TYPE_PRIMARY - primary service + * o BLE_GATT_SVC_TYPE_SECONDARY - secondary service + * o 0 - No more services in this array. + */ uint8_t type; - uint8_t *uuid128; - const struct ble_gatt_svc_def **includes; /* Terminated with null. */ - struct ble_gatt_chr_def *characteristics; -}; - -union ble_gatt_access_ctxt { - struct { - const struct ble_gatt_chr_def *chr; - void *data; - int len; - } chr_access; - struct { - const struct ble_gatt_dsc_def *dsc; - void *data; - int len; - } dsc_access; + /** + * Pointer to first element in a uint8_t[16]; use the BLE_UUID16 macro for + * 16-bit UUIDs. + */ + const uint8_t *uuid128; + + /** + * Array of pointers to other service definitions. These services are + * reported as "included services" during service discovery. Terminate the + * array with NULL. + */ + const struct ble_gatt_svc_def **includes; + + /** + * Array of characteristic definitions corresponding to characteristics + * belonging to this service. + */ + const struct ble_gatt_chr_def *characteristics; }; struct ble_gatt_dsc_def { + /** + * The first element in a uint8_t[16]; use the BLE_UUID16 macro for 16-bit + * UUIDs; NULL if there are no more descriptors in the characteristic. + */ uint8_t *uuid128; + + /** Specifies the set of permitted operations for this descriptor. */ uint8_t att_flags; + + /** Callback that gets executed when the descriptor is read or written. */ ble_gatt_access_fn *access_cb; + + /** Optional argument for callback. */ void *arg; }; -#define BLE_GATT_REGISTER_OP_SVC 1 -#define BLE_GATT_REGISTER_OP_CHR 2 -#define BLE_GATT_REGISTER_OP_DSC 3 +/** + * Context for an access to a GATT characteristic or descriptor. When a client + * reads or writes a locally registered characteristic or descriptor, an + * instance of this struct gets passed to the application callback. + */ +struct ble_gatt_access_ctxt { + /** + * Indicates the gatt operation being performed. This is equal to one of + * the following values: + * o BLE_GATT_ACCESS_OP_READ_CHR + * o BLE_GATT_ACCESS_OP_WRITE_CHR + * o BLE_GATT_ACCESS_OP_READ_DSC + * o BLE_GATT_ACCESS_OP_WRITE_DSC + */ + uint8_t op; + + /** + * A container for the GATT access data. + * o For reads: The application populates this with the value of the + * characteristic or descriptor being read. + * o For writes: This is already populated with the value being written + * by the peer. If the application wishes to retain this mbuf for + * later use, the access callback must set this pointer to NULL to + * prevent the stack from freeing it. + */ + struct os_mbuf *om; + + /** + * The GATT operation being performed dictates which field in this union is + * valid. If a characteristic is being accessed, the chr field is valid. + * Otherwise a descriptor is being accessed, in which case the dsc field + * is valid. + */ + union { + /** + * The characteristic definition corresponding to the characteristic + * being accessed. This is what the app registered at startup. + */ + const struct ble_gatt_chr_def *chr; + + /** + * The descriptor definition corresponding to the descriptor being + * accessed. This is what the app registered at startup. + */ + const struct ble_gatt_dsc_def *dsc; + }; +}; + +/** + * Context passed to the registration callback; represents the GATT service, + * characteristic, or descriptor being registered. + */ +struct ble_gatt_register_ctxt { + /** + * Indicates the gatt registration operation just performed. This is + * equal to one of the following values: + * o BLE_GATT_REGISTER_OP_SVC + * o BLE_GATT_REGISTER_OP_CHR + * o BLE_GATT_REGISTER_OP_DSC + */ + uint8_t op; + + /** + * The value of the op field determines which field in this union is valid. + */ + union { + /** Service; valid if op == BLE_GATT_REGISTER_OP_SVC. */ + struct { + /** The ATT handle of the service definition attribute. */ + uint16_t handle; + + /** + * The service definition representing the service being + * registered. + */ + const struct ble_gatt_svc_def *svc_def; + } svc; + + /** Characteristic; valid if op == BLE_GATT_REGISTER_OP_CHR. */ + struct { + /** The ATT handle of the characteristic definition attribute. */ + uint16_t def_handle; + + /** The ATT handle of the characteristic value attribute. */ + uint16_t val_handle; + + /** + * The characteristic definition representing the characteristic + * being registered. + */ + const struct ble_gatt_chr_def *chr_def; + + /** + * The service definition corresponding to the characteristic's + * parent service. + */ + const struct ble_gatt_svc_def *svc_def; + } chr; + + /** Descriptor; valid if op == BLE_GATT_REGISTER_OP_DSC. */ + struct { + /** The ATT handle of the descriptor definition attribute. */ + uint16_t handle; + + /** + * The descriptor definition corresponding to the descriptor being + * registered. + */ + const struct ble_gatt_dsc_def *dsc_def; + + /** + * The characteristic definition corresponding to the descriptor's + * parent characteristic. + */ + const struct ble_gatt_chr_def *chr_def; + + /** + * The service definition corresponding to the descriptor's + * grandparent service + */ + const struct ble_gatt_svc_def *svc_def; + } dsc; + }; +}; + +/** + * Contains counts of resources required by the GATT server. The contents of + * this struct are generally used to populate a configuration struct before + * the host is initialized. + */ +struct ble_gatt_resources { + /** Number of services. */ + uint16_t svcs; + + /** Number of included services. */ + uint16_t incs; -union ble_gatt_register_ctxt; -typedef void ble_gatt_register_fn(uint8_t op, - union ble_gatt_register_ctxt *ctxt, + /** Number of characteristics. */ + uint16_t chrs; + + /** Number of descriptors. */ + uint16_t dscs; + + /** + * Number of client characteristic configuration descriptors. Each of + * these also contributes to the total descriptor count. + */ + uint16_t cccds; + + /** Total number of ATT attributes. */ + uint16_t attrs; +}; + +typedef void ble_gatt_register_fn(struct ble_gatt_register_ctxt *ctxt, void *arg); int ble_gatts_register_svcs(const struct ble_gatt_svc_def *svcs, ble_gatt_register_fn *register_cb, void *cb_arg); -void ble_gatts_chr_updated(uint16_t chr_def_handle); +int ble_gatts_add_svcs(const struct ble_gatt_svc_def *svcs); +int ble_gatts_count_resources(const struct ble_gatt_svc_def *svcs, + struct ble_gatt_resources *res); +int ble_gatts_count_cfg(const struct ble_gatt_svc_def *defs, + struct ble_hs_cfg *cfg); -union ble_gatt_register_ctxt { - struct { - uint16_t handle; - const struct ble_gatt_svc_def *svc; - } svc_reg; - - struct { - uint16_t def_handle; - uint16_t val_handle; - const struct ble_gatt_chr_def *chr; - } chr_reg; +void ble_gatts_chr_updated(uint16_t chr_def_handle); - struct { - uint16_t dsc_handle; - const struct ble_gatt_dsc_def *dsc; - uint16_t chr_def_handle; - const struct ble_gatt_chr_def *chr; - } dsc_reg; -}; +int ble_gatts_find_svc(const void *uuid128, uint16_t *out_handle); +int ble_gatts_find_chr(const void *svc_uuid128, const void *chr_uuid128, + uint16_t *out_def_handle, uint16_t *out_val_handle); +int ble_gatts_find_dsc(const void *svc_uuid128, const void *chr_uuid128, + const void *dsc_uuid128, uint16_t *out_dsc_handle); #endif diff --git a/net/nimble/host/include/host/ble_hs.h b/net/nimble/host/include/host/ble_hs.h index e493723f..8d850097 100644 --- a/net/nimble/host/include/host/ble_hs.h +++ b/net/nimble/host/include/host/ble_hs.h @@ -21,17 +21,24 @@ #define H_BLE_HS_ #include <inttypes.h> +#include "nimble/hci_common.h" #include "host/ble_att.h" #include "host/ble_gap.h" #include "host/ble_gatt.h" #include "host/ble_hs.h" +#include "host/ble_hs_adv.h" +#include "host/ble_hs_id.h" +#include "host/ble_hs_log.h" #include "host/ble_hs_test.h" -#include "host/ble_uuid.h" +#include "host/ble_hs_mbuf.h" +#include "host/ble_sm.h" #include "host/ble_store.h" -#include "host/host_hci.h" +#include "host/ble_uuid.h" struct os_eventq; struct os_event; +#define BLE_HS_FOREVER INT32_MAX + #define BLE_HS_CONN_HANDLE_NONE 0xffff #define BLE_HS_EAGAIN 1 @@ -45,17 +52,17 @@ struct os_event; #define BLE_HS_EAPP 9 #define BLE_HS_EBADDATA 10 #define BLE_HS_EOS 11 -#define BLE_HS_ECONGESTED 12 -#define BLE_HS_ECONTROLLER 13 -#define BLE_HS_ETIMEOUT 14 -#define BLE_HS_EDONE 15 -#define BLE_HS_EBUSY 16 -#define BLE_HS_EREJECT 17 -#define BLE_HS_EUNKNOWN 18 -#define BLE_HS_EROLE 19 -#define BLE_HS_ETIMEOUT_HCI 20 -#define BLE_HS_ENOMEM_HCI 21 -#define BLE_HS_ENOMEM_EVT 22 +#define BLE_HS_ECONTROLLER 12 +#define BLE_HS_ETIMEOUT 13 +#define BLE_HS_EDONE 14 +#define BLE_HS_EBUSY 15 +#define BLE_HS_EREJECT 16 +#define BLE_HS_EUNKNOWN 17 +#define BLE_HS_EROLE 18 +#define BLE_HS_ETIMEOUT_HCI 19 +#define BLE_HS_ENOMEM_EVT 20 +#define BLE_HS_ENOADDR 21 +#define BLE_HS_ENOTSYNCED 22 #define BLE_HS_ERR_ATT_BASE 0x100 /* 256 */ #define BLE_HS_ATT_ERR(x) ((x) ? BLE_HS_ERR_ATT_BASE + (x) : 0) @@ -69,39 +76,31 @@ struct os_event; #define BLE_HS_ERR_SM_US_BASE 0x400 /* 1024 */ #define BLE_HS_SM_US_ERR(x) ((x) ? BLE_HS_ERR_SM_US_BASE + (x) : 0) -#define BLE_HS_ERR_SM_THEM_BASE 0x500 /* 1280 */ -#define BLE_HS_SM_THEM_ERR(x) ((x) ? BLE_HS_ERR_SM_THEM_BASE + (x) : 0) +#define BLE_HS_ERR_SM_PEER_BASE 0x500 /* 1280 */ +#define BLE_HS_SM_PEER_ERR(x) ((x) ? BLE_HS_ERR_SM_PEER_BASE + (x) : 0) -/* defines the input output (io) capabilities for the host device */ +/* Note: A hardware error of 0 is not success. */ +#define BLE_HS_ERR_HW_BASE 0x600 /* 1536 */ +#define BLE_HS_HW_ERR(x) (BLE_HS_ERR_HW_BASE + (x)) + +/* Defines the IO capabilities for the local device. */ #define BLE_HS_IO_DISPLAY_ONLY 0x00 #define BLE_HS_IO_DISPLAY_YESNO 0x01 #define BLE_HS_IO_KEYBOARD_ONLY 0x02 #define BLE_HS_IO_NO_INPUT_OUTPUT 0x03 #define BLE_HS_IO_KEYBOARD_DISPLAY 0x04 -#define BLE_HS_PRIVACY_MODE_NONE 0 -#define BLE_HS_PRIVACY_MODE_RANDOM_STATIC 1 -#define BLE_HS_PRIVACY_MODE_RESOLV_RAND 2 +typedef void ble_hs_reset_fn(int reason); +typedef void ble_hs_sync_fn(void); struct ble_hs_cfg { - /*** HCI settings. */ /** - * An HCI buffer is a "flat" 260-byte buffer. HCI buffers are used by the - * controller to send unsolicited events to the host. - * - * HCI buffers can get tied up when the controller sends lots of - * asynchronous / unsolicited events (i.e., non-acks). When the controller - * needs to send one of these events, it allocates an HCI buffer, fills it - * with the event payload, and puts it on a host queue. If the controller - * sends a quick burst of these events, the buffer pool may be exhausted, - * preventing the host from sending an HCI command to the controller. - * * Every time the controller sends a non-ack HCI event to the host, it also * allocates an OS event (it is unfortunate that these are both called * "events"). The OS event is put on the host-parent-task's event queue; * it is what wakes up the host-parent-task and indicates that an HCI event - * needs to be processsed. The pool of OS events is allocated with the - * same number of elements as the HCI buffer pool. + * needs to be processsed. This setting should be equal to the total + * number of HCI event buffers that the transport is configured to use. */ uint8_t max_hci_bufs; @@ -132,6 +131,18 @@ struct ble_hs_cfg { */ uint16_t max_client_configs; + /** + * An optional callback that gets executed upon registration of each GATT + * resource (service, characteristic, or descriptor). + */ + ble_gatt_register_fn *gatts_register_cb; + + /** + * An optional argument that gets passed to the GATT registration + * callback. + */ + void *gatts_register_arg; + /*** GATT client settings. */ /** * The maximum number of concurrent GATT client procedures. When you @@ -197,6 +208,19 @@ struct ble_hs_cfg { uint8_t sm_our_key_dist; uint8_t sm_their_key_dist; + /*** HCI settings */ + /** + * This callback is executed when the host resets itself and the controller + * due to fatal error. + */ + ble_hs_reset_fn *reset_cb; + + /** + * This callback is executed when the host and controller become synced. + * This happens at startup and after a reset. + */ + ble_hs_sync_fn *sync_cb; + /*** Store settings. */ /** * These function callbacks handle persistence of sercurity material @@ -206,7 +230,7 @@ struct ble_hs_cfg { ble_store_write_fn *store_write_cb; ble_store_delete_fn *store_delete_cb; - /*** privacy settings */ + /*** Privacy settings. */ /** * The frequency at which new resovlable private addresses are generated. * Units are seconds. @@ -216,9 +240,8 @@ struct ble_hs_cfg { extern const struct ble_hs_cfg ble_hs_cfg_dflt; +int ble_hs_synced(void); int ble_hs_start(void); -void ble_hs_event_enqueue(struct os_event *ev); -int ble_ibeacon_set_adv_data(void *uuid128, uint16_t major, uint16_t minor); int ble_hs_init(struct os_eventq *app_evq, struct ble_hs_cfg *cfg); #endif diff --git a/net/nimble/host/include/host/ble_hs_adv.h b/net/nimble/host/include/host/ble_hs_adv.h index 0377d1d9..8ae2b00b 100644 --- a/net/nimble/host/include/host/ble_hs_adv.h +++ b/net/nimble/host/include/host/ble_hs_adv.h @@ -22,18 +22,21 @@ #include <inttypes.h> +/** Max field payload size (account for 2-byte header). */ +#define BLE_HS_ADV_MAX_FIELD_SZ (BLE_HCI_MAX_ADV_DATA_LEN - 2) + struct ble_hs_adv_fields { /*** 0x01 - Flags. */ uint8_t flags; unsigned flags_is_present:1; /*** 0x02,0x03 - 16-bit service class UUIDs. */ - void *uuids16; + uint16_t *uuids16; uint8_t num_uuids16; unsigned uuids16_is_complete:1; /*** 0x04,0x05 - 32-bit service class UUIDs. */ - void *uuids32; + uint32_t *uuids32; uint8_t num_uuids32; unsigned uuids32_is_complete:1; @@ -48,7 +51,7 @@ struct ble_hs_adv_fields { unsigned name_is_complete:1; /*** 0x0a - Tx power level. */ - uint8_t tx_pwr_lvl; + int8_t tx_pwr_lvl; unsigned tx_pwr_lvl_is_present:1; /*** 0x0d - Class of device. */ @@ -141,6 +144,12 @@ struct ble_hs_adv_fields { #define BLE_HS_ADV_TX_PWR_LVL_LEN 1 +/** + * Set the tx_pwr_lvl field to this if you want the stack to fill in the tx + * power level field. + */ +#define BLE_HS_ADV_TX_PWR_LVL_AUTO (-128) + #define BLE_HS_ADV_DEVICE_CLASS_LEN 3 #define BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN 4 @@ -165,10 +174,4 @@ struct ble_hs_adv_fields { #define BLE_HS_ADV_SVC_DATA_UUID128_MIN_LEN 16 -int ble_hs_adv_set_flat(uint8_t type, int data_len, void *data, - uint8_t *dst, uint8_t *dst_len, uint8_t max_len); -int ble_hs_adv_set_fields(struct ble_hs_adv_fields *adv_fields, - uint8_t *dst, uint8_t *dst_len, uint8_t max_len); -int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields, uint8_t *src, - uint8_t src_len); #endif diff --git a/net/nimble/host/src/ble_hci_util_priv.h b/net/nimble/host/include/host/ble_hs_id.h index f4455147..749524b8 100644 --- a/net/nimble/host/src/ble_hci_util_priv.h +++ b/net/nimble/host/include/host/ble_hs_id.h @@ -17,14 +17,14 @@ * under the License. */ -#ifndef H_BLE_HCI_UTIL_ -#define H_BLE_HCI_UTIL_ +#ifndef H_BLE_HS_ID_ +#define H_BLE_HS_ID_ -int ble_hci_util_read_adv_tx_pwr(int8_t *out_pwr); -int ble_hci_util_rand(void *dst, int len); -int ble_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi); -int ble_hs_util_set_random_addr(uint8_t *addr); -int ble_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, - uint16_t tx_time); +#include <inttypes.h> + +int ble_hs_id_gen_rnd(int nrpa, uint8_t *out_addr); +int ble_hs_id_set_rnd(const uint8_t *rnd_addr); +int ble_hs_id_copy_addr(uint8_t id_addr_type, uint8_t *out_id_addr, + int *out_is_nrpa); #endif diff --git a/net/nimble/host/include/host/ble_hs_log.h b/net/nimble/host/include/host/ble_hs_log.h new file mode 100644 index 00000000..fd10ddba --- /dev/null +++ b/net/nimble/host/include/host/ble_hs_log.h @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_HS_LOG_ +#define H_BLE_HS_LOG_ + +#include "log/log.h" +struct os_mbuf; + +extern struct log ble_hs_log; + +#define BLE_HS_LOG(lvl, ...) \ + LOG_ ## lvl(&ble_hs_log, LOG_MODULE_NIMBLE_HOST, __VA_ARGS__) + +#define BLE_HS_LOG_ADDR(lvl, addr) \ + BLE_HS_LOG(lvl, "%02x:%02x:%02x:%02x:%02x:%02x", \ + (addr)[5], (addr)[4], (addr)[3], \ + (addr)[2], (addr)[1], (addr)[0]) + +void ble_hs_log_mbuf(const struct os_mbuf *om); +void ble_hs_log_flat_buf(const void *data, int len); + +#endif diff --git a/net/nimble/host/include/host/ble_hs_mbuf.h b/net/nimble/host/include/host/ble_hs_mbuf.h new file mode 100644 index 00000000..d3606f2e --- /dev/null +++ b/net/nimble/host/include/host/ble_hs_mbuf.h @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_HS_MBUF_ +#define H_BLE_HS_MBUF_ + +#include <inttypes.h> +struct os_mbuf; + +struct os_mbuf *ble_hs_mbuf_att_pkt(void); +struct os_mbuf *ble_hs_mbuf_from_flat(const void *buf, uint16_t len); +int ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len, + uint16_t *out_copy_len); + +#endif diff --git a/net/nimble/host/include/host/ble_hs_test.h b/net/nimble/host/include/host/ble_hs_test.h index 787ec41e..3247b59d 100644 --- a/net/nimble/host/include/host/ble_hs_test.h +++ b/net/nimble/host/include/host/ble_hs_test.h @@ -23,9 +23,6 @@ #include <inttypes.h> struct os_mbuf; -void ble_hs_test_pkt_txed(struct os_mbuf *om); -void ble_hs_test_hci_txed(uint8_t *cmdbuf); - int ble_att_clt_test_all(void); int ble_att_svr_test_all(void); int ble_gap_test_all(void); @@ -37,16 +34,16 @@ int ble_gatt_find_s_test_all(void); int ble_gatt_read_test_all(void); int ble_gatt_write_test_all(void); int ble_gatts_notify_test_all(void); +int ble_gatts_read_test_suite(void); int ble_gatts_reg_test_all(void); -int ble_host_hci_test_all(void); +int ble_hs_hci_test_all(void); int ble_hs_adv_test_all(void); int ble_hs_conn_test_all(void); int ble_l2cap_test_all(void); int ble_os_test_all(void); -int ble_sm_test_all(void); -int ble_uuid_test_all(void); - int ble_sm_lgcy_test_suite(void); int ble_sm_sc_test_suite(void); +int ble_sm_test_all(void); +int ble_uuid_test_all(void); #endif diff --git a/net/nimble/host/src/host_dbg_priv.h b/net/nimble/host/include/host/ble_ibeacon.h index 8d548cab..112f52b3 100644 --- a/net/nimble/host/src/host_dbg_priv.h +++ b/net/nimble/host/include/host/ble_ibeacon.h @@ -6,7 +6,7 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, @@ -17,9 +17,9 @@ * under the License. */ -#ifndef H_HOST_DBG_ -#define H_HOST_DBG_ +#ifndef H_BLE_IBEACON_ +#define H_BLE_IBEACON_ -void host_hci_dbg_event_disp(uint8_t *evbuf); +int ble_ibeacon_set_adv_data(void *uuid128, uint16_t major, uint16_t minor); -#endif /* H_HOST_DBG_ */ +#endif diff --git a/net/nimble/host/include/host/ble_store.h b/net/nimble/host/include/host/ble_store.h index 9a7efab3..a5331594 100644 --- a/net/nimble/host/include/host/ble_store.h +++ b/net/nimble/host/include/host/ble_store.h @@ -28,6 +28,12 @@ #define BLE_STORE_ADDR_TYPE_NONE 0xff +/** + * Used as a key for lookups of security material. This struct corresponds to + * the following store object types: + * o BLE_STORE_OBJ_TYPE_OUR_SEC + * o BLE_STORE_OBJ_TYPE_PEER_SEC + */ struct ble_store_key_sec { /** * Key by peer identity address; @@ -52,6 +58,12 @@ struct ble_store_key_sec { uint8_t idx; }; +/** + * Represents stored security material. This struct corresponds to the + * following store object types: + * o BLE_STORE_OBJ_TYPE_OUR_SEC + * o BLE_STORE_OBJ_TYPE_PEER_SEC + */ struct ble_store_value_sec { uint8_t peer_addr[6]; uint8_t peer_addr_type; @@ -71,6 +83,11 @@ struct ble_store_value_sec { unsigned sc:1; }; +/** + * Used as a key for lookups of stored client characteristic configuration + * descriptors (CCCDs). This struct corresponds to the BLE_STORE_OBJ_TYPE_CCCD + * store object type. + */ struct ble_store_key_cccd { /** * Key by peer identity address; @@ -89,6 +106,10 @@ struct ble_store_key_cccd { uint8_t idx; }; +/** + * Represents a stored client characteristic configuration descriptor (CCCD). + * This struct corresponds to the BLE_STORE_OBJ_TYPE_CCCD store object type. + */ struct ble_store_value_cccd { uint8_t peer_addr[6]; uint8_t peer_addr_type; @@ -97,21 +118,72 @@ struct ble_store_value_cccd { unsigned value_changed:1; }; +/** + * Used as a key for store lookups. This union must be accompanied by an + * object type code to indicate which field is valid. + */ union ble_store_key { struct ble_store_key_sec sec; struct ble_store_key_cccd cccd; }; +/** + * Represents stored data. This union must be accompanied by an object type + * code to indicate which field is valid. + */ union ble_store_value { struct ble_store_value_sec sec; struct ble_store_value_cccd cccd; }; +/** + * Searches the store for an object matching the specified criteria. If a + * match is found, it is read from the store and the dst parameter is populated + * with the retrieved object. + * + * @param obj_type The type of object to search for; one of the + * BLE_STORE_OBJ_TYPE_[...] codes. + * @param key Specifies properties of the object to search + * for. An object is retrieved if it matches + * these criteria. + * @param dst On success, this is populated with the + * retrieved object. + * + * @return 0 if an object was successfully retreived; + * BLE_HS_ENOENT if no matching object was found; + * Other nonzero on error. + */ typedef int ble_store_read_fn(int obj_type, union ble_store_key *key, union ble_store_value *dst); +/** + * Writes the specified object to the store. If an object with the same + * identity is already in the store, it is replaced. If the store lacks + * sufficient capacity to write the object, this function may remove previously + * stored values to make room. + * + * @param obj_type The type of object being written; one of the + * BLE_STORE_OBJ_TYPE_[...] codes. + * @param val The object to persist. + * + * @return 0 if the object was successfully written; + * Other nonzero on error. + */ typedef int ble_store_write_fn(int obj_type, union ble_store_value *val); +/** + * Searches the store for the first object matching the specified criteria. If + * a match is found, it is deleted from the store. + * + * @param obj_type The type of object to delete; one of the + * BLE_STORE_OBJ_TYPE_[...] codes. + * @param key Specifies properties of the object to search + * for. An object is deleted if it matches + * these criteria. + * @return 0 if an object was successfully retreived; + * BLE_HS_ENOENT if no matching object was found; + * Other nonzero on error. + */ typedef int ble_store_delete_fn(int obj_type, union ble_store_key *key); int ble_store_read(int obj_type, union ble_store_key *key, diff --git a/net/nimble/host/include/host/ble_uuid.h b/net/nimble/host/include/host/ble_uuid.h index a092dd66..89d9df07 100644 --- a/net/nimble/host/include/host/ble_uuid.h +++ b/net/nimble/host/include/host/ble_uuid.h @@ -23,10 +23,8 @@ #include <inttypes.h> struct os_mbuf; -uint16_t ble_uuid_128_to_16(void *uuid128); +uint16_t ble_uuid_128_to_16(const void *uuid128); int ble_uuid_16_to_128(uint16_t uuid16, void *dst); -int ble_uuid_append(struct os_mbuf *om, void *uuid128); -int ble_uuid_extract(struct os_mbuf *om, int off, void *uuid128); #define BLE_UUID16_ARR(uuid16) { \ 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, \ diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h deleted file mode 100644 index c33cb390..00000000 --- a/net/nimble/host/include/host/host_hci.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_HOST_HCI_ -#define H_HOST_HCI_ - -#include "nimble/hci_common.h" -struct ble_hs_conn; -struct os_mbuf; - -#define HCI_CMD_BUF_SIZE 260 - -extern uint8_t host_hci_cmd_buf[HCI_CMD_BUF_SIZE]; - -int host_hci_os_event_proc(struct os_event *ev); -int host_hci_event_rx(uint8_t *data); -uint16_t host_hci_opcode_join(uint8_t ogf, uint16_t ocf); -void host_hci_write_hdr(uint8_t ogf, uint8_t ocf, uint8_t len, void *buf); -int host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata); -int host_hci_cmd_send_buf(void *cmddata); -void host_hci_cmd_build_set_event_mask(uint64_t event_mask, - uint8_t *dst, int dst_len); -void host_hci_cmd_build_set_event_mask2(uint64_t event_mask, uint8_t *dst, - int dst_len); -void host_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason, - uint8_t *dst, int dst_len); -int host_hci_cmd_disconnect(uint16_t handle, uint8_t reason); -void host_hci_cmd_build_read_rssi(uint16_t handle, uint8_t *dst, int dst_len); -int host_hci_cmd_read_rssi(uint16_t handle); -int host_hci_cmd_build_le_set_scan_rsp_data(uint8_t *data, uint8_t len, - uint8_t *dst, int dst_len); -int host_hci_cmd_build_le_set_adv_data(uint8_t *data, uint8_t len, - uint8_t *dst, int dst_len); -int host_hci_cmd_build_le_set_adv_params(struct hci_adv_params *adv, - uint8_t *dst, int dst_len); -void host_hci_cmd_build_le_set_event_mask(uint64_t event_mask, - uint8_t *dst, int dst_len); -void host_hci_cmd_build_le_read_buffer_size(uint8_t *dst, int dst_len); -int host_hci_cmd_le_read_buffer_size(void); -void host_hci_cmd_build_le_read_loc_supp_feat(uint8_t *dst, uint8_t dst_len); -void host_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst, - int dst_len); -int host_hci_cmd_le_set_adv_enable(uint8_t enable); -int host_hci_cmd_build_le_set_scan_params(uint8_t scan_type, - uint16_t scan_itvl, - uint16_t scan_window, - uint8_t own_addr_type, - uint8_t filter_policy, - uint8_t *cmd, int cmd_len); -void host_hci_cmd_build_le_set_scan_enable(uint8_t enable, - uint8_t filter_dups, - uint8_t *dst, uint8_t dst_len); -int host_hci_cmd_le_set_scan_enable(uint8_t enable, uint8_t filter_dups); -int host_hci_cmd_build_le_create_connection(struct hci_create_conn *hcc, - uint8_t *cmd, int cmd_len); -int host_hci_cmd_le_create_connection(struct hci_create_conn *hcc); -void host_hci_cmd_build_le_clear_whitelist(uint8_t *dst, int dst_len); -int host_hci_cmd_build_le_add_to_whitelist(uint8_t *addr, uint8_t addr_type, - uint8_t *dst, int dst_len); -void host_hci_cmd_build_reset(uint8_t *dst, int dst_len); -int host_hci_cmd_reset(void); -void host_hci_cmd_build_read_adv_pwr(uint8_t *dst, int dst_len); -int host_hci_cmd_read_adv_pwr(void); -void host_hci_cmd_build_le_create_conn_cancel(uint8_t *dst, int dst_len); -int host_hci_cmd_le_create_conn_cancel(void); -int host_hci_cmd_build_le_conn_update(struct hci_conn_update *hcu, - uint8_t *dst, int dst_len); -int host_hci_cmd_le_conn_update(struct hci_conn_update *hcu); -void host_hci_cmd_build_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr, - uint8_t *dst, int dst_len); -void host_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle, - uint8_t *dst, int dst_len); -void host_hci_cmd_build_le_conn_param_reply(struct hci_conn_param_reply *hcr, - uint8_t *dst, int dst_len); -int host_hci_cmd_le_conn_param_reply(struct hci_conn_param_reply *hcr); -void host_hci_cmd_build_le_conn_param_neg_reply( - struct hci_conn_param_neg_reply *hcn, uint8_t *dst, int dst_len); -int host_hci_cmd_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn); -void host_hci_cmd_build_le_rand(uint8_t *dst, int dst_len); -void host_hci_cmd_build_le_start_encrypt(struct hci_start_encrypt *cmd, - uint8_t *dst, int dst_len); -int host_hci_set_buf_size(uint16_t pktlen, uint8_t max_pkts); - -uint16_t host_hci_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc); - -int host_hci_data_rx(struct os_mbuf *om); -int host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf *om); - -int host_hci_cmd_build_set_data_len(uint16_t connection_handle, - uint16_t tx_octets, uint16_t tx_time, - uint8_t *dst, int dst_len); -int host_hci_cmd_build_add_to_resolv_list( - struct hci_add_dev_to_resolving_list *padd, - uint8_t *dst, int dst_len); -int host_hci_cmd_build_remove_from_resolv_list(uint8_t addr_type, - uint8_t *addr, uint8_t *dst, - int dst_len); -int host_hci_cmd_build_read_resolv_list_size(uint8_t *dst, int dst_len); -int -host_hci_cmd_build_clear_resolv_list(uint8_t *dst, int dst_len); -int host_hci_cmd_build_read_peer_resolv_addr(uint8_t peer_identity_addr_type, - uint8_t *peer_identity_addr, - uint8_t *dst, int dst_len); -int host_hci_cmd_build_read_lcl_resolv_addr(uint8_t local_identity_addr_type, - uint8_t *local_identity_addr, - uint8_t *dst, int dst_len); -int host_hci_cmd_build_set_addr_res_en(uint8_t enable, - uint8_t *dst, int dst_len); -int host_hci_cmd_build_set_resolv_priv_addr_timeout(uint16_t timeout, - uint8_t *dst, - int dst_len); - -void host_hci_timer_set(void); - -int host_hci_cmd_build_set_random_addr(uint8_t *addr, uint8_t *dst, int dst_len); - -#endif /* H_HOST_HCI_ */ diff --git a/net/nimble/host/pkg.yml b/net/nimble/host/pkg.yml index f597f344..a45ba1e5 100644 --- a/net/nimble/host/pkg.yml +++ b/net/nimble/host/pkg.yml @@ -36,17 +36,23 @@ pkg.deps: # Tinycrypt is only required when secure connections (NIMBPLE_OPT_SM_SC) # is enabled. It always gets built as a dependency, but not is not # included by the linker unless SC is enabled. XXX: We should not build - # this library if it is not requiresd. + # this library if it is not required. - libs/tinycrypt pkg.req_apis: + - ble_transport - console +pkg.features: + - BLE_HOST + # Satisfy capability dependencies for the self-contained test executable. -pkg.deps.SELFTEST: libs/console/stub +pkg.deps.SELFTEST: + - libs/console/stub + - net/nimble/transport/ram + pkg.cflags.SELFTEST: - - -DPHONY_TRANSPORT=1 - - -DPHONY_HCI_ACKS=1 - - -DNIMBLE_OPT_SM=1 - - -DNIMBLE_OPT_SM_SC=1 + - "-DPHONY_HCI_ACKS=1" + - "-DNIMBLE_OPT_SM=1" + - "-DNIMBLE_OPT_SM_SC=1" pkg.cflags.TEST: -DBLE_HS_DEBUG diff --git a/net/nimble/host/services/gap/include/services/gap/ble_svc_gap.h b/net/nimble/host/services/gap/include/services/gap/ble_svc_gap.h new file mode 100644 index 00000000..95d4226c --- /dev/null +++ b/net/nimble/host/services/gap/include/services/gap/ble_svc_gap.h @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_SVC_GAP_ +#define H_BLE_SVC_GAP_ + +struct ble_hs_cfg; + +#define BLE_SVC_GAP_UUID16 0x1800 +#define BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME 0x2a00 +#define BLE_SVC_GAP_CHR_UUID16_APPEARANCE 0x2a01 +#define BLE_SVC_GAP_CHR_UUID16_PERIPH_PRIV_FLAG 0x2a02 +#define BLE_SVC_GAP_CHR_UUID16_RECONNECT_ADDR 0x2a03 +#define BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS 0x2a04 + +#define BLE_SVC_GAP_APPEARANCE_GEN_COMPUTER 128 + +const char *ble_svc_gap_device_name(void); +int ble_svc_gap_device_name_set(const char *name); + +int ble_svc_gap_init(struct ble_hs_cfg *cfg); + +#endif diff --git a/net/nimble/host/services/gap/pkg.yml b/net/nimble/host/services/gap/pkg.yml new file mode 100644 index 00000000..b84e8161 --- /dev/null +++ b/net/nimble/host/services/gap/pkg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: net/nimble/host/services/gap +pkg.description: Implements the GAP Service. +pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - nimble + - gap + +pkg.deps: + - net/nimble/host diff --git a/net/nimble/host/services/gap/src/ble_svc_gap.c b/net/nimble/host/services/gap/src/ble_svc_gap.c new file mode 100644 index 00000000..1a2e8a48 --- /dev/null +++ b/net/nimble/host/services/gap/src/ble_svc_gap.c @@ -0,0 +1,167 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <assert.h> +#include <string.h> +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" + +/* XXX: This should be configurable. */ +#define BLE_SVC_GAP_NAME_MAX_LEN 31 + +static char ble_svc_gap_name[BLE_SVC_GAP_NAME_MAX_LEN + 1] = "nimble"; +static uint16_t ble_svc_gap_appearance; +static uint8_t ble_svc_gap_privacy_flag; +static uint8_t ble_svc_gap_reconnect_addr[6]; +static uint8_t ble_svc_gap_pref_conn_params[8]; + +static int +ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_gap_defs[] = { + { + /*** Service: GAP. */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid128 = BLE_UUID16(BLE_SVC_GAP_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + /*** Characteristic: Device Name. */ + .uuid128 = BLE_UUID16(BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME), + .access_cb = ble_svc_gap_access, + .flags = BLE_GATT_CHR_F_READ, + }, { + /*** Characteristic: Appearance. */ + .uuid128 = BLE_UUID16(BLE_SVC_GAP_CHR_UUID16_APPEARANCE), + .access_cb = ble_svc_gap_access, + .flags = BLE_GATT_CHR_F_READ, + }, { + /*** Characteristic: Peripheral Privacy Flag. */ + .uuid128 = BLE_UUID16(BLE_SVC_GAP_CHR_UUID16_PERIPH_PRIV_FLAG), + .access_cb = ble_svc_gap_access, + .flags = BLE_GATT_CHR_F_READ, + }, { + /*** Characteristic: Reconnection Address. */ + .uuid128 = BLE_UUID16(BLE_SVC_GAP_CHR_UUID16_RECONNECT_ADDR), + .access_cb = ble_svc_gap_access, + .flags = BLE_GATT_CHR_F_WRITE, + }, { + /*** Characteristic: Peripheral Preferred Connection Parameters. */ + .uuid128 = + BLE_UUID16(BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS), + .access_cb = ble_svc_gap_access, + .flags = BLE_GATT_CHR_F_READ, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, + + { + 0, /* No more services. */ + }, +}; + +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; + } +} + +const char * +ble_svc_gap_device_name(void) +{ + return ble_svc_gap_name; +} + +int +ble_svc_gap_device_name_set(const char *name) +{ + int len; + + len = strlen(name); + if (len > BLE_SVC_GAP_NAME_MAX_LEN) { + return BLE_HS_EINVAL; + } + + memcpy(ble_svc_gap_name, name, len); + ble_svc_gap_name[len] = '\0'; + + return 0; +} + +int +ble_svc_gap_init(struct ble_hs_cfg *cfg) +{ + int rc; + + rc = ble_gatts_count_cfg(ble_svc_gap_defs, cfg); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(ble_svc_gap_defs); + if (rc != 0) { + return rc; + } + + return 0; +} diff --git a/net/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h b/net/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h new file mode 100644 index 00000000..320a3ff1 --- /dev/null +++ b/net/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_SVC_GATT_ +#define H_BLE_SVC_GATT_ + +struct ble_hs_cfg; + +#define BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05 + +int ble_svc_gatt_init(struct ble_hs_cfg *cfg); + +#endif diff --git a/net/nimble/host/services/gatt/pkg.yml b/net/nimble/host/services/gatt/pkg.yml new file mode 100644 index 00000000..b8fdabe1 --- /dev/null +++ b/net/nimble/host/services/gatt/pkg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: net/nimble/host/services/gatt +pkg.description: Implements the GATT service. +pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - nimble + - gatt + +pkg.deps: + - net/nimble/host diff --git a/net/nimble/host/services/gatt/src/ble_svc_gatt.c b/net/nimble/host/services/gatt/src/ble_svc_gatt.c new file mode 100644 index 00000000..74d3ac97 --- /dev/null +++ b/net/nimble/host/services/gatt/src/ble_svc_gatt.c @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <assert.h> + +#include "host/ble_hs.h" +#include "services/gatt/ble_svc_gatt.h" + +static int +ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = { + { + /*** Service: GATT */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid128 = BLE_UUID16(BLE_GATT_SVC_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid128 = BLE_UUID16(BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16), + .access_cb = ble_svc_gatt_access, + .flags = BLE_GATT_CHR_F_INDICATE, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, + + { + 0, /* No more services. */ + }, +}; + +static int +ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + uint8_t *u8; + + /* The only operation allowed for this characteristic is indicate. This + * access callback gets called by the stack when it needs to read the + * characteristic value to populate the outgoing indication command. + * Therefore, this callback should only get called during an attempt to + * read the characteristic. + */ + assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + assert(ctxt->chr == &ble_svc_gatt_defs[0].characteristics[0]); + + /* XXX: For now, always respond with 0 (unchanged). */ + u8 = os_mbuf_extend(ctxt->om, 1); + if (u8 == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + *u8 = 0; + + return 0; +} + +int +ble_svc_gatt_init(struct ble_hs_cfg *cfg) +{ + int rc; + + rc = ble_gatts_count_cfg(ble_svc_gatt_defs, cfg); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(ble_svc_gatt_defs); + if (rc != 0) { + return rc; + } + + return 0; +} diff --git a/net/nimble/host/services/lls/include/services/lls/ble_svc_lls.h b/net/nimble/host/services/lls/include/services/lls/ble_svc_lls.h new file mode 100644 index 00000000..8dee7796 --- /dev/null +++ b/net/nimble/host/services/lls/include/services/lls/ble_svc_lls.h @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_SVC_LLS_ +#define H_BLE_SVC_LLS_ + +struct ble_hs_cfg; + +#define BLE_SVC_LLS_UUID16 0x1803 +#define BLE_SVC_LLS_CHR_UUID16_ALERT_LEVEL 0x2a06 + +/* Alert level definitions */ +#define BLE_SVC_LLS_ALERT_LEVEL_NO_ALERT 0 +#define BLE_SVC_LLS_ALERT_LEVEL_MILD_ALERT 1 +#define BLE_SVC_LLS_ALERT_LEVEL_HIGH_ALERT 2 + +typedef int ble_svc_lls_event_fn(uint8_t alert_level); + +uint8_t ble_svc_lls_alert_level_get(void); +int ble_svc_lls_alert_level_set(uint8_t alert_level); +void ble_svc_lls_on_gap_disconnect(int reason); + +int ble_svc_lls_init(struct ble_hs_cfg *cfg, + uint8_t initial_alert_level, + ble_svc_lls_event_fn *cb); + +#endif + diff --git a/net/nimble/host/services/lls/pkg.yml b/net/nimble/host/services/lls/pkg.yml new file mode 100644 index 00000000..d45c49bb --- /dev/null +++ b/net/nimble/host/services/lls/pkg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: net/nimble/host/services/lls +pkg.description: Link Loss Service Implementation. +pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - lls + - nimble + +pkg.deps: + - net/nimble/host diff --git a/net/nimble/host/services/lls/src/ble_svc_lls.c b/net/nimble/host/services/lls/src/ble_svc_lls.c new file mode 100644 index 00000000..3371fda8 --- /dev/null +++ b/net/nimble/host/services/lls/src/ble_svc_lls.c @@ -0,0 +1,201 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <assert.h> +#include <string.h> +#include "host/ble_hs.h" +#include "services/lls/ble_svc_lls.h" + +/* Callback function */ +static ble_svc_lls_event_fn *cb_fn; +/* Alert level */ +static uint8_t ble_svc_lls_alert_level; + +/* Write characteristic function */ +static int +ble_svc_lls_chr_write(struct os_mbuf *om, uint16_t min_len, + uint16_t max_len, void *dst, + uint16_t *len); + +/* Access function */ +static int +ble_svc_lls_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_lls_defs[] = { + { + /*** Service: Link Loss Service (LLS). */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid128 = BLE_UUID16(BLE_SVC_LLS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + /*** Characteristic: Alert Level. */ + .uuid128 = BLE_UUID16(BLE_SVC_LLS_CHR_UUID16_ALERT_LEVEL), + .access_cb = ble_svc_lls_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, + + { + 0, /* No more services. */ + }, +}; + +/** + * Writes the received value from a characteristic write to + * the given destination. + */ +static int +ble_svc_lls_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; +} + +/** + * Simple read/write access callback for the alert level + * characteristic. + */ +static int +ble_svc_lls_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + assert(ctxt->chr == &ble_svc_lls_defs[0].characteristics[0]); + int rc; + switch (ctxt->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + rc = os_mbuf_append(ctxt->om, &ble_svc_lls_alert_level, + sizeof ble_svc_lls_alert_level); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + rc = ble_svc_lls_chr_write(ctxt->om, + sizeof ble_svc_lls_alert_level, + sizeof ble_svc_lls_alert_level, + &ble_svc_lls_alert_level, NULL); + return rc; + + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } + + return 0; +} + +/** + * This function is the crux of the link loss service. The application + * developer must call this function inside the gap event callback + * function when a BLE_GAP_EVENT_DISCONNECT event is received and + * pass the disconnect reason into this function. + * + * Here, we then check if the disconnect reason is due to a timout, and if + * so, we call the ble_svc_lls_event_fn callback with the current + * alert level. The actual alert implementation is left up to the + * developer. + * + * @param reason The reason attatched to the GAP disconnect + * event. + */ +void +ble_svc_lls_on_gap_disconnect(int reason) +{ + if (reason == BLE_HS_HCI_ERR(BLE_ERR_CONN_SPVN_TMO)) { + cb_fn(ble_svc_lls_alert_level); + } +} + +/** + * Gets the current alert level. + * + * @return The current alert level + */ +uint8_t +ble_svc_lls_alert_level_get(void) +{ + return ble_svc_lls_alert_level; +} + +/** + * Sets the current alert level. + * + * @return 0 on success, BLE_HS_EINVAL if the given alert level is not valid. + */ +int +ble_svc_lls_alert_level_set(uint8_t alert_level) +{ + if (alert_level > BLE_SVC_LLS_ALERT_LEVEL_HIGH_ALERT) { + return BLE_HS_EINVAL; + } + + memcpy(&ble_svc_lls_alert_level, &alert_level, + sizeof alert_level); + + return 0; +} + +/** + * Initialize the LLS. The developer must specify the event function + * callback for the LLS to function properly. + * + * @param initial_alert_level The initial alert value to set + * @param cb The callback function to call when + * connection has been lost due to + * link loss + */ +int +ble_svc_lls_init(struct ble_hs_cfg *cfg, uint8_t initial_alert_level, + ble_svc_lls_event_fn *cb) +{ + int rc; + + if (!cb) { + return BLE_HS_EINVAL; + } + + ble_svc_lls_alert_level = initial_alert_level; + cb_fn = cb; + + rc = ble_gatts_count_cfg(ble_svc_lls_defs, cfg); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(ble_svc_lls_defs); + if (rc != 0) { + return rc; + } + + return 0; +} diff --git a/net/nimble/host/src/ble_att.c b/net/nimble/host/src/ble_att.c index 68e1c7b2..a6d39b82 100644 --- a/net/nimble/host/src/ble_att.c +++ b/net/nimble/host/src/ble_att.c @@ -22,9 +22,7 @@ #include "bsp/bsp.h" #include "ble_hs_priv.h" -static bssnz_t uint8_t ble_att_flat_buf[BLE_ATT_ATTR_MAX_LEN]; - -static uint16_t ble_att_preferred_mtu; +static uint16_t ble_att_preferred_mtu_val; /** Dispatch table for incoming ATT requests. Sorted by op code. */ typedef int ble_att_rx_fn(uint16_t conn_handle, struct os_mbuf **om); @@ -145,15 +143,12 @@ ble_att_rx_dispatch_entry_find(uint8_t op) return NULL; } -int +void ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn, struct ble_l2cap_chan **out_chan) { - int rc; - - rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_ATT, - out_conn, out_chan); - return rc; + ble_hs_misc_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, + out_conn, out_chan); } void @@ -390,17 +385,29 @@ ble_att_inc_rx_stat(uint8_t att_op) } } -/** - * Retrieves a pointer to the global ATT flat buffer. This buffer is only used - * by the host parent task, so users can assume exclusive access. - */ -uint8_t * -ble_att_get_flat_buf(void) +void +ble_att_truncate_to_mtu(const struct ble_l2cap_chan *att_chan, + struct os_mbuf *txom) { - BLE_HS_DBG_ASSERT(ble_hs_is_parent_task()); - return ble_att_flat_buf; + int32_t extra_len; + uint16_t mtu; + + mtu = ble_l2cap_chan_mtu(att_chan); + extra_len = OS_MBUF_PKTLEN(txom) - mtu; + if (extra_len > 0) { + os_mbuf_adj(txom, -extra_len); + } } +/** + * Retrieves the ATT MTU of the specified connection. If an MTU exchange for + * this connection has occurred, the MTU is the lower of the two peers' + * preferred values. Otherwise, the MTU is the default value of 23. + * + * @param conn_handle The handle of the connection to query. + * + * @return The specified connection's ATT MTU. + */ uint16_t ble_att_mtu(uint16_t conn_handle) { @@ -422,6 +429,16 @@ ble_att_mtu(uint16_t conn_handle) return mtu; } +void +ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu) +{ + if (peer_mtu < BLE_ATT_MTU_DFLT) { + peer_mtu = BLE_ATT_MTU_DFLT; + } + + chan->blc_peer_mtu = peer_mtu; +} + static int ble_att_rx(uint16_t conn_handle, struct os_mbuf **om) { @@ -449,19 +466,40 @@ ble_att_rx(uint16_t conn_handle, struct os_mbuf **om) return 0; } -void -ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu) +/** + * Retrieves the preferred ATT MTU. + * + * @return The preferred ATT MTU. + */ +uint16_t +ble_att_preferred_mtu(void) { - if (peer_mtu < BLE_ATT_MTU_DFLT) { - peer_mtu = BLE_ATT_MTU_DFLT; - } - - chan->blc_peer_mtu = peer_mtu; + return ble_att_preferred_mtu_val; } +/** + * Sets the preferred ATT MTU; the device will indicate this value in all + * subseqeunt ATT MTU exchanges. The ATT MTU of a connection is equal to the + * lower of the two peers' preferred MTU values. The ATT MTU is what dictates + * the maximum size of any message sent during a GATT procedure. + * + * The specified MTU must be within the following range: [23, BLE_ATT_MTU_MAX]. + * 23 is a minimum imposed by the Bluetooth specification; BLE_ATT_MTU_MAX is a + * NimBLE compile-time setting. + * + * @param mtu The preferred ATT MTU. + * + * @return 0 on success; + * BLE_HS_EINVAL if the specifeid value is not + * within the allowed range. + */ int ble_att_set_preferred_mtu(uint16_t mtu) { + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + int i; + if (mtu < BLE_ATT_MTU_DFLT) { return BLE_HS_EINVAL; } @@ -469,9 +507,24 @@ ble_att_set_preferred_mtu(uint16_t mtu) return BLE_HS_EINVAL; } - ble_att_preferred_mtu = mtu; + ble_att_preferred_mtu_val = mtu; + + /* Set my_mtu for established connections that haven't exchanged. */ + ble_hs_lock(); - /* XXX: Set my_mtu for established connections that haven't exchanged. */ + i = 0; + while ((conn = ble_hs_conn_find_by_idx(i)) != NULL) { + chan = ble_hs_conn_chan_find(conn, BLE_L2CAP_CID_ATT); + BLE_HS_DBG_ASSERT(chan != NULL); + + if (!(chan->blc_flags & BLE_L2CAP_CHAN_F_TXED_MTU)) { + chan->blc_my_mtu = mtu; + } + + i++; + } + + ble_hs_unlock(); return 0; } @@ -487,7 +540,7 @@ ble_att_create_chan(void) } chan->blc_cid = BLE_L2CAP_CID_ATT; - chan->blc_my_mtu = ble_att_preferred_mtu; + chan->blc_my_mtu = ble_att_preferred_mtu_val; chan->blc_default_mtu = BLE_ATT_MTU_DFLT; chan->blc_rx_fn = ble_att_rx; @@ -499,7 +552,7 @@ ble_att_init(void) { int rc; - ble_att_preferred_mtu = BLE_ATT_MTU_PREFERRED_DFLT; + ble_att_preferred_mtu_val = BLE_ATT_MTU_PREFERRED_DFLT; rc = stats_init_and_reg( STATS_HDR(ble_att_stats), STATS_SIZE_INIT_PARMS(ble_att_stats, diff --git a/net/nimble/host/src/ble_att_clt.c b/net/nimble/host/src/ble_att_clt.c index dba3527b..2e7352ba 100644 --- a/net/nimble/host/src/ble_att_clt.c +++ b/net/nimble/host/src/ble_att_clt.c @@ -29,84 +29,40 @@ static int ble_att_clt_init_req(uint16_t initial_sz, struct os_mbuf **out_txom) { + struct os_mbuf *om; void *buf; int rc; - *out_txom = ble_hs_misc_pkthdr(); - if (*out_txom == NULL) { + *out_txom = NULL; + + om = ble_hs_mbuf_l2cap_pkt(); + if (om == NULL) { rc = BLE_HS_ENOMEM; goto err; } - buf = os_mbuf_extend(*out_txom, initial_sz); + buf = os_mbuf_extend(om, initial_sz); if (buf == NULL) { rc = BLE_HS_ENOMEM; goto err; } /* The caller expects the initial buffer to be at the start of the mbuf. */ - BLE_HS_DBG_ASSERT(buf == (*out_txom)->om_data); + BLE_HS_DBG_ASSERT(buf == om->om_data); + *out_txom = om; return 0; err: - os_mbuf_free_chain(*out_txom); - *out_txom = NULL; + os_mbuf_free_chain(om); return rc; } static int -ble_att_clt_append_blob(uint16_t conn_handle, struct os_mbuf *txom, - void *blob, int blob_len) -{ - int rc; - - if (blob_len < 0) { - return BLE_HS_EINVAL; - } - if (blob_len == 0) { - return 0; - } - - rc = os_mbuf_append(txom, blob, blob_len); - if (rc != 0) { - return rc; - } - - return 0; -} - -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; -} - -static int ble_att_clt_tx_req(uint16_t conn_handle, struct os_mbuf *txom) { 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); @@ -114,25 +70,16 @@ ble_att_clt_tx_req(uint16_t conn_handle, struct os_mbuf *txom) 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; - } + ble_att_conn_chan_find(conn_handle, &conn, &chan); + ble_att_truncate_to_mtu(chan, txom); + rc = ble_l2cap_tx(conn, chan, txom); ble_hs_unlock(); - os_mbuf_free_chain(txom); + if (rc != 0) { + os_mbuf_free_chain(txom); + } + return rc; } @@ -141,17 +88,17 @@ ble_att_clt_tx_req(uint16_t conn_handle, struct os_mbuf *txom) *****************************************************************************/ int -ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **om) +ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_error_rsp rsp; int rc; - rc = ble_hs_misc_pullup_base(om, BLE_ATT_ERROR_RSP_SZ); + rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_ERROR_RSP_SZ); if (rc != 0) { return rc; } - ble_att_error_rsp_parse((*om)->om_data, (*om)->om_len, &rsp); + ble_att_error_rsp_parse((*rxom)->om_data, (*rxom)->om_len, &rsp); BLE_ATT_LOG_CMD(0, "error rsp", conn_handle, ble_att_error_rsp_log, &rsp); ble_gattc_rx_err(conn_handle, &rsp); @@ -163,62 +110,51 @@ ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **om) * $mtu exchange * *****************************************************************************/ -static int -ble_att_clt_build_mtu_req(struct ble_att_mtu_cmd *req, - struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_MTU_CMD_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_mtu_req_write(txom->om_data, txom->om_len, req); - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int -ble_att_clt_tx_mtu(uint16_t conn_handle, struct ble_att_mtu_cmd *req) +ble_att_clt_tx_mtu(uint16_t conn_handle, const struct ble_att_mtu_cmd *req) { struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "mtu req", conn_handle, ble_att_mtu_cmd_log, req); - if (req->bamc_mtu < BLE_ATT_MTU_DFLT) { return BLE_HS_EINVAL; } - rc = ble_att_clt_build_mtu_req(req, &txom); + ble_hs_lock(); + + ble_att_conn_chan_find(conn_handle, &conn, &chan); + if (chan == NULL) { + rc = BLE_HS_ENOTCONN; + } else if (chan->blc_flags & BLE_L2CAP_CHAN_F_TXED_MTU) { + rc = BLE_HS_EALREADY; + } else { + rc = 0; + } + ble_hs_unlock(); + if (rc != 0) { return rc; } + rc = ble_att_clt_init_req(BLE_ATT_MTU_CMD_SZ, &txom); + if (rc != 0) { + return rc; + } + ble_att_mtu_req_write(txom->om_data, txom->om_len, req); + rc = ble_att_clt_tx_req(conn_handle, txom); if (rc != 0) { return rc; } + BLE_ATT_LOG_CMD(1, "mtu req", conn_handle, ble_att_mtu_cmd_log, req); + ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc == 0) { - chan->blc_flags |= BLE_L2CAP_CHAN_F_TXED_MTU; - } + ble_att_conn_chan_find(conn_handle, &conn, &chan); + chan->blc_flags |= BLE_L2CAP_CHAN_F_TXED_MTU; ble_hs_unlock(); @@ -226,7 +162,7 @@ ble_att_clt_tx_mtu(uint16_t conn_handle, struct ble_att_mtu_cmd *req) } int -ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **om) +ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_mtu_cmd cmd; struct ble_l2cap_chan *chan; @@ -235,20 +171,20 @@ ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **om) mtu = 0; - rc = ble_hs_misc_pullup_base(om, BLE_ATT_MTU_CMD_SZ); + rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_MTU_CMD_SZ); if (rc == 0) { - ble_att_mtu_cmd_parse((*om)->om_data, (*om)->om_len, &cmd); + ble_att_mtu_rsp_parse((*rxom)->om_data, (*rxom)->om_len, &cmd); BLE_ATT_LOG_CMD(0, "mtu rsp", conn_handle, ble_att_mtu_cmd_log, &cmd); ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, NULL, &chan); - if (rc == 0) { - ble_att_set_peer_mtu(chan, cmd.bamc_mtu); - mtu = ble_l2cap_chan_mtu(chan); - } + ble_att_conn_chan_find(conn_handle, NULL, &chan); + ble_att_set_peer_mtu(chan, cmd.bamc_mtu); + mtu = ble_l2cap_chan_mtu(chan); ble_hs_unlock(); + + ble_gap_mtu_event(conn_handle, BLE_L2CAP_CID_ATT, mtu); } ble_gattc_rx_mtu(conn_handle, rc, mtu); @@ -259,27 +195,9 @@ ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **om) * $find information * *****************************************************************************/ -static int -ble_att_clt_build_find_info_req(struct ble_att_find_info_req *req, - struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - rc = ble_att_clt_init_req(BLE_ATT_FIND_INFO_REQ_SZ, &txom); - if (rc != 0) { - return rc; - } - - ble_att_find_info_req_write(txom->om_data, txom->om_len, req); - *out_txom = txom; - - return 0; -} - int ble_att_clt_tx_find_info(uint16_t conn_handle, - struct ble_att_find_info_req *req) + const struct ble_att_find_info_req *req) { #if !NIMBLE_OPT(ATT_CLT_FIND_INFO) return BLE_HS_ENOTSUP; @@ -288,25 +206,26 @@ ble_att_clt_tx_find_info(uint16_t conn_handle, struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "find info req", conn_handle, - ble_att_find_info_req_log, req); - if (req->bafq_start_handle == 0 || req->bafq_start_handle > req->bafq_end_handle) { return BLE_HS_EINVAL; } - rc = ble_att_clt_build_find_info_req(req, &txom); + rc = ble_att_clt_init_req(BLE_ATT_FIND_INFO_REQ_SZ, &txom); if (rc != 0) { return rc; } + ble_att_find_info_req_write(txom->om_data, txom->om_len, req); rc = ble_att_clt_tx_req(conn_handle, txom); if (rc != 0) { return rc; } + BLE_ATT_LOG_CMD(1, "find info req", conn_handle, + ble_att_find_info_req_log, req); + return 0; } @@ -331,7 +250,7 @@ ble_att_clt_parse_find_info_entry(struct os_mbuf **rxom, uint8_t rsp_format, return BLE_HS_EBADDATA; } - rc = ble_hs_misc_pullup_base(rxom, entry_len); + rc = ble_hs_mbuf_pullup_base(rxom, entry_len); if (rc != 0) { return rc; } @@ -374,7 +293,7 @@ ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om) struct ble_att_find_info_rsp rsp; int rc; - rc = ble_hs_misc_pullup_base(om, BLE_ATT_FIND_INFO_RSP_BASE_SZ); + rc = ble_hs_mbuf_pullup_base(om, BLE_ATT_FIND_INFO_RSP_BASE_SZ); if (rc != 0) { goto done; } @@ -408,63 +327,53 @@ done: * $find by type value * *****************************************************************************/ -static int -ble_att_clt_build_find_type_value_req(struct ble_att_find_type_value_req *req, - void *attribute_value, int value_len, - struct os_mbuf **out_txom) -{ - int rc; - - rc = ble_att_clt_init_req(BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, out_txom); - if (rc != 0) { - return rc; - } - - ble_att_find_type_value_req_write((*out_txom)->om_data, - (*out_txom)->om_len, - req); - rc = os_mbuf_append(*out_txom, attribute_value, value_len); - if (rc != 0) { - os_mbuf_free_chain(*out_txom); - return BLE_HS_ENOMEM; - } - - return 0; -} - int ble_att_clt_tx_find_type_value(uint16_t conn_handle, - struct ble_att_find_type_value_req *req, - void *attribute_value, int value_len) + const struct ble_att_find_type_value_req *req, + const void *attribute_value, int value_len) { #if !NIMBLE_OPT(ATT_CLT_FIND_TYPE) return BLE_HS_ENOTSUP; #endif - BLE_ATT_LOG_CMD(1, "find type value req", conn_handle, - ble_att_find_type_value_req_log, req); - struct os_mbuf *txom; int rc; + txom = NULL; + if (req->bavq_start_handle == 0 || req->bavq_start_handle > req->bavq_end_handle) { - return BLE_HS_EINVAL; + rc = BLE_HS_EINVAL; + goto err; } - rc = ble_att_clt_build_find_type_value_req(req, attribute_value, value_len, - &txom); + rc = ble_att_clt_init_req(BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, &txom); if (rc != 0) { - return rc; + goto err; + } + + ble_att_find_type_value_req_write(txom->om_data, txom->om_len, req); + rc = os_mbuf_append(txom, attribute_value, value_len); + if (rc != 0) { + rc = BLE_HS_ENOMEM; + goto err; } rc = ble_att_clt_tx_req(conn_handle, txom); + txom = NULL; if (rc != 0) { - return rc; + goto err; } + BLE_ATT_LOG_CMD(1, "find type value req", conn_handle, + ble_att_find_type_value_req_log, req); + return 0; + +err: + os_mbuf_free_chain(txom); + return rc; } static int @@ -524,42 +433,10 @@ ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) * $read by type * *****************************************************************************/ -static int -ble_att_clt_build_read_type_req(struct ble_att_read_type_req *req, - void *uuid128, struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_READ_TYPE_REQ_BASE_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_read_type_req_write(txom->om_data, txom->om_len, req); - - rc = ble_uuid_append(txom, uuid128); - if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; - } - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int ble_att_clt_tx_read_type(uint16_t conn_handle, - struct ble_att_read_type_req *req, - void *uuid128) + const struct ble_att_read_type_req *req, + const void *uuid128) { #if !NIMBLE_OPT(ATT_CLT_READ_TYPE) return BLE_HS_ENOTSUP; @@ -568,25 +445,40 @@ ble_att_clt_tx_read_type(uint16_t conn_handle, struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "read type req", conn_handle, - ble_att_read_type_req_log, req); + txom = NULL; if (req->batq_start_handle == 0 || req->batq_start_handle > req->batq_end_handle) { - return BLE_HS_EINVAL; + rc = BLE_HS_EINVAL; + goto err; } - rc = ble_att_clt_build_read_type_req(req, uuid128, &txom); + rc = ble_att_clt_init_req(BLE_ATT_READ_TYPE_REQ_BASE_SZ, &txom); if (rc != 0) { - return rc; + goto err; + } + + ble_att_read_type_req_write(txom->om_data, txom->om_len, req); + rc = ble_uuid_append(txom, uuid128); + if (rc != 0) { + rc = BLE_HS_ENOMEM; + goto err; } rc = ble_att_clt_tx_req(conn_handle, txom); + txom = NULL; if (rc != 0) { - return rc; + goto err; } + BLE_ATT_LOG_CMD(1, "read type req", conn_handle, + ble_att_read_type_req_log, req); + + return 0; + +err: + os_mbuf_free_chain(txom); return 0; } @@ -596,7 +488,7 @@ ble_att_clt_parse_read_type_adata(struct os_mbuf **om, int data_len, { int rc; - rc = ble_hs_misc_pullup_base(om, data_len); + rc = ble_hs_mbuf_pullup_base(om, data_len); if (rc != 0) { return rc; } @@ -619,7 +511,7 @@ ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) struct ble_att_read_type_rsp rsp; int rc; - rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_READ_TYPE_RSP_BASE_SZ); + rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_READ_TYPE_RSP_BASE_SZ); if (rc != 0) { goto done; } @@ -653,34 +545,8 @@ done: * $read * *****************************************************************************/ -static int -ble_att_clt_build_read_req(struct ble_att_read_req *req, - struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_READ_REQ_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_read_req_write(txom->om_data, txom->om_len, req); - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int -ble_att_clt_tx_read(uint16_t conn_handle, struct ble_att_read_req *req) +ble_att_clt_tx_read(uint16_t conn_handle, const struct ble_att_read_req *req) { #if !NIMBLE_OPT(ATT_CLT_READ) return BLE_HS_ENOTSUP; @@ -689,23 +555,23 @@ ble_att_clt_tx_read(uint16_t conn_handle, struct ble_att_read_req *req) struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "read req", conn_handle, - ble_att_read_req_log, req); - if (req->barq_handle == 0) { return BLE_HS_EINVAL; } - rc = ble_att_clt_build_read_req(req, &txom); + rc = ble_att_clt_init_req(BLE_ATT_READ_REQ_SZ, &txom); if (rc != 0) { return rc; } + ble_att_read_req_write(txom->om_data, txom->om_len, req); rc = ble_att_clt_tx_req(conn_handle, txom); if (rc != 0) { return rc; } + BLE_ATT_LOG_CMD(1, "read req", conn_handle, ble_att_read_req_log, req); + return 0; } @@ -716,10 +582,6 @@ ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) return BLE_HS_ENOTSUP; #endif - uint16_t value_len; - void *value; - int rc; - BLE_ATT_LOG_EMPTY_CMD(0, "read rsp", conn_handle); /* Reponse consists of a one-byte opcode (already verified) and a variable @@ -727,47 +589,18 @@ ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) */ os_mbuf_adj(*rxom, BLE_ATT_READ_RSP_BASE_SZ); - /* Copy the attribute data into the global ATT flat buffer. */ - rc = ble_att_clt_copy_attr_to_flatbuf(*rxom, &value, &value_len); - /* Pass the Attribute Value field to GATT. */ - ble_gattc_rx_read_rsp(conn_handle, rc, value, value_len); - return rc; + ble_gattc_rx_read_rsp(conn_handle, 0, rxom); + return 0; } /***************************************************************************** * $read blob * *****************************************************************************/ -static int -ble_att_clt_build_read_blob_req(struct ble_att_read_blob_req *req, - struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_READ_BLOB_REQ_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_read_blob_req_write(txom->om_data, txom->om_len, req); - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int ble_att_clt_tx_read_blob(uint16_t conn_handle, - struct ble_att_read_blob_req *req) + const struct ble_att_read_blob_req *req) { #if !NIMBLE_OPT(ATT_CLT_READ_BLOB) return BLE_HS_ENOTSUP; @@ -776,23 +609,24 @@ ble_att_clt_tx_read_blob(uint16_t conn_handle, struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "read blob req", conn_handle, - ble_att_read_blob_req_log, req); - if (req->babq_handle == 0) { return BLE_HS_EINVAL; } - rc = ble_att_clt_build_read_blob_req(req, &txom); + rc = ble_att_clt_init_req(BLE_ATT_READ_BLOB_REQ_SZ, &txom); if (rc != 0) { return rc; } + ble_att_read_blob_req_write(txom->om_data, txom->om_len, req); rc = ble_att_clt_tx_req(conn_handle, txom); if (rc != 0) { return rc; } + BLE_ATT_LOG_CMD(1, "read blob req", conn_handle, + ble_att_read_blob_req_log, req); + return 0; } @@ -803,10 +637,6 @@ ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) return BLE_HS_ENOTSUP; #endif - uint16_t value_len; - void *value; - int rc; - BLE_ATT_LOG_EMPTY_CMD(0, "read blob rsp", conn_handle); /* Reponse consists of a one-byte opcode (already verified) and a variable @@ -814,12 +644,9 @@ ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) */ os_mbuf_adj(*rxom, BLE_ATT_READ_BLOB_RSP_BASE_SZ); - /* Copy the attribute data into the global ATT flat buffer. */ - rc = ble_att_clt_copy_attr_to_flatbuf(*rxom, &value, &value_len); - /* Pass the Attribute Value field to GATT. */ - ble_gattc_rx_read_blob_rsp(conn_handle, rc, value, value_len); - return rc; + ble_gattc_rx_read_blob_rsp(conn_handle, 0, rxom); + return 0; } /***************************************************************************** @@ -827,7 +654,8 @@ ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ static int -ble_att_clt_build_read_mult_req(uint16_t *att_handles, int num_att_handles, +ble_att_clt_build_read_mult_req(const uint16_t *att_handles, + int num_att_handles, struct os_mbuf **out_txom) { struct os_mbuf *txom; @@ -835,39 +663,34 @@ ble_att_clt_build_read_mult_req(uint16_t *att_handles, int num_att_handles, int rc; int i; - txom = NULL; + *out_txom = NULL; rc = ble_att_clt_init_req(BLE_ATT_READ_MULT_REQ_BASE_SZ, &txom); if (rc != 0) { - goto done; + goto err; } - ble_att_read_mult_req_write(txom->om_data, txom->om_len); for (i = 0; i < num_att_handles; i++) { buf = os_mbuf_extend(txom, 2); if (buf == NULL) { rc = BLE_HS_ENOMEM; - goto done; + goto err; } htole16(buf, att_handles[i]); } - rc = 0; - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - *out_txom = txom; + return 0; + +err: + os_mbuf_free_chain(txom); return rc; } int -ble_att_clt_tx_read_mult(uint16_t conn_handle, uint16_t *att_handles, +ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *att_handles, int num_att_handles) { #if !NIMBLE_OPT(ATT_CLT_READ_MULT) @@ -903,10 +726,6 @@ ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) return BLE_HS_ENOTSUP; #endif - uint16_t value_len; - void *value; - int rc; - BLE_ATT_LOG_EMPTY_CMD(0, "read mult rsp", conn_handle); /* Reponse consists of a one-byte opcode (already verified) and a variable @@ -914,53 +733,19 @@ ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) */ os_mbuf_adj(*rxom, BLE_ATT_READ_MULT_RSP_BASE_SZ); - /* Copy the attribute data into the global ATT flat buffer. */ - rc = ble_att_clt_copy_attr_to_flatbuf(*rxom, &value, &value_len); - /* Pass the Attribute Value field to GATT. */ - ble_gattc_rx_read_mult_rsp(conn_handle, rc, value, value_len); - return rc; + ble_gattc_rx_read_mult_rsp(conn_handle, 0, rxom); + return 0; } /***************************************************************************** * $read by group type * *****************************************************************************/ -static int -ble_att_clt_build_read_group_type_req(struct ble_att_read_group_type_req *req, - void *uuid128, struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_read_group_type_req_write(txom->om_data, txom->om_len, req); - - rc = ble_uuid_append(txom, uuid128); - if (rc != 0) { - goto done; - } - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int ble_att_clt_tx_read_group_type(uint16_t conn_handle, - struct ble_att_read_group_type_req *req, - void *uuid128) + const struct ble_att_read_group_type_req *req, + const void *uuid128) { #if !NIMBLE_OPT(ATT_CLT_READ_GROUP_TYPE) return BLE_HS_ENOTSUP; @@ -971,26 +756,38 @@ ble_att_clt_tx_read_group_type(uint16_t conn_handle, txom = NULL; - BLE_ATT_LOG_CMD(1, "read group type req", conn_handle, - ble_att_read_group_type_req_log, req); - if (req->bagq_start_handle == 0 || req->bagq_start_handle > req->bagq_end_handle) { - return BLE_HS_EINVAL; + rc = BLE_HS_EINVAL; + goto err; } - rc = ble_att_clt_build_read_group_type_req(req, uuid128, &txom); + rc = ble_att_clt_init_req(BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ, &txom); if (rc != 0) { - return rc; + goto err; + } + ble_att_read_group_type_req_write(txom->om_data, txom->om_len, req); + + rc = ble_uuid_append(txom, uuid128); + if (rc != 0) { + goto err; } rc = ble_att_clt_tx_req(conn_handle, txom); + txom = NULL; if (rc != 0) { - return rc; + goto err; } + BLE_ATT_LOG_CMD(1, "read group type req", conn_handle, + ble_att_read_group_type_req_log, req); + return 0; + +err: + os_mbuf_free_chain(txom); + return rc; } static int @@ -1004,7 +801,7 @@ ble_att_clt_parse_read_group_type_adata( return BLE_HS_EMSGSIZE; } - rc = ble_hs_misc_pullup_base(om, data_len); + rc = ble_hs_mbuf_pullup_base(om, data_len); if (rc != 0) { return rc; } @@ -1028,7 +825,7 @@ ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) 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); + rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ); if (rc != 0) { goto done; } @@ -1063,55 +860,21 @@ done: *****************************************************************************/ static int -ble_att_clt_build_write_req_or_cmd(uint16_t conn_handle, - struct ble_att_write_req *req, - void *value, uint16_t value_len, int is_req, - struct os_mbuf **out_txom) +ble_att_clt_tx_write_req_or_cmd(uint16_t conn_handle, + const struct ble_att_write_req *req, + struct os_mbuf *txom, int is_req) { - struct os_mbuf *txom; int rc; - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_WRITE_REQ_BASE_SZ, &txom); - if (rc != 0) { - goto done; + txom = os_mbuf_prepend_pullup(txom, BLE_ATT_WRITE_REQ_BASE_SZ); + if (txom == NULL) { + return BLE_HS_ENOMEM; } if (is_req) { - ble_att_write_req_write(txom->om_data, txom->om_len, req); + ble_att_write_req_write(txom->om_data, BLE_ATT_WRITE_REQ_BASE_SZ, req); } else { - ble_att_write_cmd_write(txom->om_data, txom->om_len, req); - } - - rc = ble_att_clt_append_blob(conn_handle, txom, value, value_len); - if (rc != 0) { - goto done; - } - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - -static int -ble_att_clt_tx_write_req_or_cmd(uint16_t conn_handle, - struct ble_att_write_req *req, - void *value, uint16_t value_len, - int is_req) -{ - struct os_mbuf *txom; - int rc; - - rc = ble_att_clt_build_write_req_or_cmd(conn_handle, req, value, value_len, - is_req, &txom); - if (rc != 0) { - return rc; + ble_att_write_cmd_write(txom->om_data, BLE_ATT_WRITE_REQ_BASE_SZ, req); } rc = ble_att_clt_tx_req(conn_handle, txom); @@ -1123,8 +886,9 @@ ble_att_clt_tx_write_req_or_cmd(uint16_t conn_handle, } int -ble_att_clt_tx_write_req(uint16_t conn_handle, struct ble_att_write_req *req, - void *value, uint16_t value_len) +ble_att_clt_tx_write_req(uint16_t conn_handle, + const struct ble_att_write_req *req, + struct os_mbuf *txom) { #if !NIMBLE_OPT(ATT_CLT_WRITE) return BLE_HS_ENOTSUP; @@ -1132,17 +896,20 @@ ble_att_clt_tx_write_req(uint16_t conn_handle, struct ble_att_write_req *req, int rc; + rc = ble_att_clt_tx_write_req_or_cmd(conn_handle, req, txom, 1); + if (rc != 0) { + return rc; + } + BLE_ATT_LOG_CMD(1, "write req", conn_handle, ble_att_write_cmd_log, req); - rc = ble_att_clt_tx_write_req_or_cmd(conn_handle, req, value, value_len, - 1); - return rc; + return 0; } int ble_att_clt_tx_write_cmd(uint16_t conn_handle, - struct ble_att_write_req *req, - void *value, uint16_t value_len) + const struct ble_att_write_req *req, + struct os_mbuf *txom) { #if !NIMBLE_OPT(ATT_CLT_WRITE_NO_RSP) return BLE_HS_ENOTSUP; @@ -1150,11 +917,14 @@ ble_att_clt_tx_write_cmd(uint16_t conn_handle, int rc; + rc = ble_att_clt_tx_write_req_or_cmd(conn_handle, req, txom, 0); + if (rc != 0) { + return rc; + } + BLE_ATT_LOG_CMD(1, "write cmd", conn_handle, ble_att_write_cmd_log, req); - rc = ble_att_clt_tx_write_req_or_cmd(conn_handle, req, value, value_len, - 0); - return rc; + return 0; } int @@ -1175,80 +945,57 @@ ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) * $prepare write request * *****************************************************************************/ -static int -ble_att_clt_build_prep_write_req(uint16_t conn_handle, - struct ble_att_prep_write_cmd *req, - void *value, uint16_t value_len, - struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_PREP_WRITE_CMD_BASE_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_prep_write_req_write(txom->om_data, txom->om_len, req); - - rc = ble_att_clt_append_blob(conn_handle, txom, value, value_len); - if (rc != 0) { - goto done; - } - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int ble_att_clt_tx_prep_write(uint16_t conn_handle, - struct ble_att_prep_write_cmd *req, - void *value, uint16_t value_len) + const struct ble_att_prep_write_cmd *req, + struct os_mbuf *txom) { #if !NIMBLE_OPT(ATT_CLT_PREP_WRITE) return BLE_HS_ENOTSUP; #endif - struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "prep write req", conn_handle, - ble_att_prep_write_cmd_log, req); - if (req->bapc_handle == 0) { - return BLE_HS_EINVAL; + rc = BLE_HS_EINVAL; + goto err; } - if (req->bapc_offset + value_len > BLE_ATT_ATTR_MAX_LEN) { - return BLE_HS_EINVAL; + if (req->bapc_offset + OS_MBUF_PKTLEN(txom) > BLE_ATT_ATTR_MAX_LEN) { + rc = BLE_HS_EINVAL; + goto err; } - if (value_len > + if (OS_MBUF_PKTLEN(txom) > ble_att_mtu(conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ) { - return BLE_HS_EINVAL; + rc = BLE_HS_EINVAL; + goto err; } - rc = ble_att_clt_build_prep_write_req(conn_handle, req, value, value_len, - &txom); - if (rc != 0) { - return rc; + txom = os_mbuf_prepend_pullup(txom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + if (txom == NULL) { + rc = BLE_HS_ENOMEM; + goto err; } + ble_att_prep_write_req_write(txom->om_data, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, + req); + rc = ble_att_clt_tx_req(conn_handle, txom); + txom = NULL; if (rc != 0) { - return rc; + goto err; } + BLE_ATT_LOG_CMD(1, "prep write req", conn_handle, + ble_att_prep_write_cmd_log, req); + return 0; + +err: + os_mbuf_free_chain(txom); + return rc; } int @@ -1259,16 +1006,12 @@ ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) #endif struct ble_att_prep_write_cmd rsp; - uint16_t value_len; - void *value; int rc; /* Initialize some values in case of early error. */ memset(&rsp, 0, sizeof rsp); - value = NULL; - value_len = 0; - rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); if (rc != 0) { goto done; } @@ -1280,12 +1023,9 @@ ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) /* Strip the base from the front of the response. */ os_mbuf_adj(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); - /* Copy the attribute data into the global ATT flat buffer. */ - rc = ble_att_clt_copy_attr_to_flatbuf(*rxom, &value, &value_len); - done: /* Notify GATT client that the full response has been parsed. */ - ble_gattc_rx_prep_write_rsp(conn_handle, rc, &rsp, value, value_len); + ble_gattc_rx_prep_write_rsp(conn_handle, rc, &rsp, rxom); return rc; } @@ -1293,35 +1033,9 @@ done: * $execute write request * *****************************************************************************/ -static int -ble_att_clt_build_exec_write_req(struct ble_att_exec_write_req *req, - struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_EXEC_WRITE_REQ_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_exec_write_req_write(txom->om_data, txom->om_len, req); - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int ble_att_clt_tx_exec_write(uint16_t conn_handle, - struct ble_att_exec_write_req *req) + const struct ble_att_exec_write_req *req) { #if !NIMBLE_OPT(ATT_CLT_EXEC_WRITE) return BLE_HS_ENOTSUP; @@ -1330,23 +1044,24 @@ ble_att_clt_tx_exec_write(uint16_t conn_handle, struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "exec write req", conn_handle, - ble_att_exec_write_req_log, req); - if ((req->baeq_flags & BLE_ATT_EXEC_WRITE_F_RESERVED) != 0) { return BLE_HS_EINVAL; } - rc = ble_att_clt_build_exec_write_req(req, &txom); + rc = ble_att_clt_init_req(BLE_ATT_EXEC_WRITE_REQ_SZ, &txom); if (rc != 0) { return rc; } + ble_att_exec_write_req_write(txom->om_data, txom->om_len, req); rc = ble_att_clt_tx_req(conn_handle, txom); if (rc != 0) { return rc; } + BLE_ATT_LOG_CMD(1, "exec write req", conn_handle, + ble_att_exec_write_req_log, req); + return 0; } @@ -1361,7 +1076,7 @@ ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom) BLE_ATT_LOG_EMPTY_CMD(0, "exec write rsp", conn_handle); - rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_EXEC_WRITE_RSP_SZ); + rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_EXEC_WRITE_RSP_SZ); if (rc == 0) { ble_att_exec_write_rsp_parse((*rxom)->om_data, (*rxom)->om_len); } @@ -1374,138 +1089,87 @@ ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom) * $handle value notification * *****************************************************************************/ -static int -ble_att_clt_build_notify_req(uint16_t conn_handle, - struct ble_att_notify_req *req, - void *value, uint16_t value_len, - struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_NOTIFY_REQ_BASE_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_notify_req_write(txom->om_data, txom->om_len, req); - - rc = ble_att_clt_append_blob(conn_handle, txom, value, value_len); - if (rc != 0) { - goto done; - } - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int -ble_att_clt_tx_notify(uint16_t conn_handle, struct ble_att_notify_req *req, - void *value, uint16_t value_len) +ble_att_clt_tx_notify(uint16_t conn_handle, + const struct ble_att_notify_req *req, + struct os_mbuf *txom) { #if !NIMBLE_OPT(ATT_CLT_NOTIFY) return BLE_HS_ENOTSUP; #endif - struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "notify req", conn_handle, ble_att_notify_req_log, req); - if (req->banq_handle == 0) { - return BLE_HS_EINVAL; + rc = BLE_HS_EINVAL; + goto err; } - rc = ble_att_clt_build_notify_req(conn_handle, req, value, value_len, - &txom); - if (rc != 0) { - return rc; + txom = os_mbuf_prepend_pullup(txom, BLE_ATT_NOTIFY_REQ_BASE_SZ); + if (txom == NULL) { + rc = BLE_HS_ENOMEM; + goto err; } + ble_att_notify_req_write(txom->om_data, BLE_ATT_NOTIFY_REQ_BASE_SZ, req); rc = ble_att_clt_tx_req(conn_handle, txom); + txom = NULL; if (rc != 0) { - return rc; + goto err; } + BLE_ATT_LOG_CMD(1, "notify req", conn_handle, ble_att_notify_req_log, req); + return 0; + +err: + os_mbuf_free_chain(txom); + return rc; } /***************************************************************************** * $handle value indication * *****************************************************************************/ -static int -ble_att_clt_build_indicate_req(uint16_t conn_handle, - struct ble_att_indicate_req *req, - void *value, uint16_t value_len, - struct os_mbuf **out_txom) -{ - struct os_mbuf *txom; - int rc; - - txom = NULL; - - rc = ble_att_clt_init_req(BLE_ATT_INDICATE_REQ_BASE_SZ, &txom); - if (rc != 0) { - goto done; - } - - ble_att_indicate_req_write(txom->om_data, txom->om_len, req); - - rc = ble_att_clt_append_blob(conn_handle, txom, value, value_len); - if (rc != 0) { - goto done; - } - -done: - if (rc != 0) { - os_mbuf_free_chain(txom); - txom = NULL; - } - - *out_txom = txom; - return rc; -} - int ble_att_clt_tx_indicate(uint16_t conn_handle, - struct ble_att_indicate_req *req, - void *value, uint16_t value_len) + const struct ble_att_indicate_req *req, + struct os_mbuf *txom) { #if !NIMBLE_OPT(ATT_CLT_INDICATE) return BLE_HS_ENOTSUP; #endif - struct os_mbuf *txom; int rc; - BLE_ATT_LOG_CMD(1, "indicate req", conn_handle, ble_att_indicate_req_log, - req); - if (req->baiq_handle == 0) { - return BLE_HS_EINVAL; + rc = BLE_HS_EINVAL; + goto err; } - rc = ble_att_clt_build_indicate_req(conn_handle, req, value, value_len, - &txom); - if (rc != 0) { - return rc; + txom = os_mbuf_prepend_pullup(txom, BLE_ATT_INDICATE_REQ_BASE_SZ); + if (txom == NULL) { + rc = BLE_HS_ENOMEM; + goto err; } + ble_att_indicate_req_write(txom->om_data, BLE_ATT_INDICATE_REQ_BASE_SZ, + req); + rc = ble_att_clt_tx_req(conn_handle, txom); + txom = NULL; if (rc != 0) { - return rc; + goto err; } + BLE_ATT_LOG_CMD(1, "indicate req", conn_handle, ble_att_indicate_req_log, + req); + return 0; + +err: + os_mbuf_free_chain(txom); + return rc; } int diff --git a/net/nimble/host/src/ble_att_cmd.c b/net/nimble/host/src/ble_att_cmd.c index 5df08466..05c68749 100644 --- a/net/nimble/host/src/ble_att_cmd.c +++ b/net/nimble/host/src/ble_att_cmd.c @@ -26,10 +26,11 @@ #include "host/ble_uuid.h" #include "ble_hs_priv.h" -static void * -ble_att_init_parse(uint8_t op, void *payload, int min_len, int actual_len) +static const void * +ble_att_init_parse(uint8_t op, const void *payload, + int min_len, int actual_len) { - uint8_t *u8ptr; + const uint8_t *u8ptr; BLE_HS_DBG_ASSERT(actual_len >= min_len); @@ -40,20 +41,6 @@ ble_att_init_parse(uint8_t op, void *payload, int min_len, int actual_len) } static void * -ble_att_init_parse_2op(uint8_t op1, uint8_t op2, void *payload, - int min_len, int actual_len) -{ - uint8_t *u8ptr; - - BLE_HS_DBG_ASSERT(actual_len >= min_len); - - u8ptr = payload; - BLE_HS_DBG_ASSERT(u8ptr[0] == op1 || u8ptr[0] == op2); - - return u8ptr + 1; -} - -static void * ble_att_init_write(uint8_t op, void *payload, int min_len, int actual_len) { uint8_t *u8ptr; @@ -68,7 +55,7 @@ ble_att_init_write(uint8_t op, void *payload, int min_len, int actual_len) static void ble_att_error_rsp_swap(struct ble_att_error_rsp *dst, - struct ble_att_error_rsp *src) + const struct ble_att_error_rsp *src) { dst->baep_req_op = src->baep_req_op; dst->baep_handle = TOFROMLE16(src->baep_handle); @@ -76,9 +63,10 @@ ble_att_error_rsp_swap(struct ble_att_error_rsp *dst, } void -ble_att_error_rsp_parse(void *payload, int len, struct ble_att_error_rsp *dst) +ble_att_error_rsp_parse(const void *payload, int len, + struct ble_att_error_rsp *dst) { - struct ble_att_error_rsp *src; + const struct ble_att_error_rsp *src; src = ble_att_init_parse(BLE_ATT_OP_ERROR_RSP, payload, BLE_ATT_ERROR_RSP_SZ, len); @@ -86,7 +74,8 @@ ble_att_error_rsp_parse(void *payload, int len, struct ble_att_error_rsp *dst) } void -ble_att_error_rsp_write(void *payload, int len, struct ble_att_error_rsp *src) +ble_att_error_rsp_write(void *payload, int len, + const struct ble_att_error_rsp *src) { struct ble_att_error_rsp *dst; @@ -96,30 +85,44 @@ ble_att_error_rsp_write(void *payload, int len, struct ble_att_error_rsp *src) } void -ble_att_error_rsp_log(struct ble_att_error_rsp *cmd) +ble_att_error_rsp_log(const struct ble_att_error_rsp *cmd) { BLE_HS_LOG(DEBUG, "req_op=%d handle=0x%04x error_code=%d", cmd->baep_req_op, cmd->baep_handle, cmd->baep_error_code); } static void -ble_att_mtu_cmd_swap(struct ble_att_mtu_cmd *dst, struct ble_att_mtu_cmd *src) +ble_att_mtu_cmd_swap(struct ble_att_mtu_cmd *dst, + const struct ble_att_mtu_cmd *src) { dst->bamc_mtu = TOFROMLE16(src->bamc_mtu); } void -ble_att_mtu_cmd_parse(void *payload, int len, struct ble_att_mtu_cmd *dst) +ble_att_mtu_req_parse(const void *payload, int len, + struct ble_att_mtu_cmd *dst) +{ + const struct ble_att_mtu_cmd *src; + + src = ble_att_init_parse(BLE_ATT_OP_MTU_REQ, payload, BLE_ATT_MTU_CMD_SZ, + len); + ble_att_mtu_cmd_swap(dst, src); +} + +void +ble_att_mtu_rsp_parse(const void *payload, int len, + struct ble_att_mtu_cmd *dst) { - struct ble_att_mtu_cmd *src; + const struct ble_att_mtu_cmd *src; - src = ble_att_init_parse_2op(BLE_ATT_OP_MTU_REQ, BLE_ATT_OP_MTU_RSP, - payload, BLE_ATT_MTU_CMD_SZ, len); + src = ble_att_init_parse(BLE_ATT_OP_MTU_RSP, payload, BLE_ATT_MTU_CMD_SZ, + len); ble_att_mtu_cmd_swap(dst, src); } void -ble_att_mtu_req_write(void *payload, int len, struct ble_att_mtu_cmd *src) +ble_att_mtu_req_write(void *payload, int len, + const struct ble_att_mtu_cmd *src) { struct ble_att_mtu_cmd *dst; @@ -129,7 +132,8 @@ ble_att_mtu_req_write(void *payload, int len, struct ble_att_mtu_cmd *src) } void -ble_att_mtu_rsp_write(void *payload, int len, struct ble_att_mtu_cmd *src) +ble_att_mtu_rsp_write(void *payload, int len, + const struct ble_att_mtu_cmd *src) { struct ble_att_mtu_cmd *dst; @@ -139,24 +143,24 @@ ble_att_mtu_rsp_write(void *payload, int len, struct ble_att_mtu_cmd *src) } void -ble_att_mtu_cmd_log(struct ble_att_mtu_cmd *cmd) +ble_att_mtu_cmd_log(const struct ble_att_mtu_cmd *cmd) { BLE_HS_LOG(DEBUG, "mtu=%d", cmd->bamc_mtu); } static void ble_att_find_info_req_swap(struct ble_att_find_info_req *dst, - struct ble_att_find_info_req *src) + const struct ble_att_find_info_req *src) { dst->bafq_start_handle = TOFROMLE16(src->bafq_start_handle); dst->bafq_end_handle = TOFROMLE16(src->bafq_end_handle); } void -ble_att_find_info_req_parse(void *payload, int len, +ble_att_find_info_req_parse(const void *payload, int len, struct ble_att_find_info_req *dst) { - struct ble_att_find_info_req *src; + const struct ble_att_find_info_req *src; src = ble_att_init_parse(BLE_ATT_OP_FIND_INFO_REQ, payload, BLE_ATT_FIND_INFO_REQ_SZ, len); @@ -165,7 +169,7 @@ ble_att_find_info_req_parse(void *payload, int len, void ble_att_find_info_req_write(void *payload, int len, - struct ble_att_find_info_req *src) + const struct ble_att_find_info_req *src) { struct ble_att_find_info_req *dst; @@ -175,7 +179,7 @@ ble_att_find_info_req_write(void *payload, int len, } void -ble_att_find_info_req_log(struct ble_att_find_info_req *cmd) +ble_att_find_info_req_log(const struct ble_att_find_info_req *cmd) { BLE_HS_LOG(DEBUG, "start_handle=0x%04x end_handle=0x%04x", cmd->bafq_start_handle, cmd->bafq_end_handle); @@ -183,16 +187,16 @@ ble_att_find_info_req_log(struct ble_att_find_info_req *cmd) static void ble_att_find_info_rsp_swap(struct ble_att_find_info_rsp *dst, - struct ble_att_find_info_rsp *src) + const struct ble_att_find_info_rsp *src) { dst->bafp_format = src->bafp_format; } void -ble_att_find_info_rsp_parse(void *payload, int len, +ble_att_find_info_rsp_parse(const void *payload, int len, struct ble_att_find_info_rsp *dst) { - struct ble_att_find_info_rsp *src; + const struct ble_att_find_info_rsp *src; src = ble_att_init_parse(BLE_ATT_OP_FIND_INFO_RSP, payload, BLE_ATT_FIND_INFO_RSP_BASE_SZ, len); @@ -201,7 +205,7 @@ ble_att_find_info_rsp_parse(void *payload, int len, void ble_att_find_info_rsp_write(void *payload, int len, - struct ble_att_find_info_rsp *src) + const struct ble_att_find_info_rsp *src) { struct ble_att_find_info_rsp *dst; @@ -211,14 +215,14 @@ ble_att_find_info_rsp_write(void *payload, int len, } void -ble_att_find_info_rsp_log(struct ble_att_find_info_rsp *cmd) +ble_att_find_info_rsp_log(const struct ble_att_find_info_rsp *cmd) { BLE_HS_LOG(DEBUG, "format=%d", cmd->bafp_format); } static void ble_att_find_type_value_req_swap(struct ble_att_find_type_value_req *dst, - struct ble_att_find_type_value_req *src) + const struct ble_att_find_type_value_req *src) { dst->bavq_start_handle = TOFROMLE16(src->bavq_start_handle); dst->bavq_end_handle = TOFROMLE16(src->bavq_end_handle); @@ -226,10 +230,10 @@ ble_att_find_type_value_req_swap(struct ble_att_find_type_value_req *dst, } void -ble_att_find_type_value_req_parse(void *payload, int len, +ble_att_find_type_value_req_parse(const void *payload, int len, struct ble_att_find_type_value_req *dst) { - struct ble_att_find_type_value_req *src; + const struct ble_att_find_type_value_req *src; src = ble_att_init_parse(BLE_ATT_OP_FIND_TYPE_VALUE_REQ, payload, BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, len); @@ -237,8 +241,8 @@ ble_att_find_type_value_req_parse(void *payload, int len, } void -ble_att_find_type_value_req_write(void *payload, int len, - struct ble_att_find_type_value_req *src) +ble_att_find_type_value_req_write( + void *payload, int len, const struct ble_att_find_type_value_req *src) { struct ble_att_find_type_value_req *dst; @@ -248,7 +252,7 @@ ble_att_find_type_value_req_write(void *payload, int len, } void -ble_att_find_type_value_req_log(struct ble_att_find_type_value_req *cmd) +ble_att_find_type_value_req_log(const struct ble_att_find_type_value_req *cmd) { BLE_HS_LOG(DEBUG, "start_handle=0x%04x end_handle=0x%04x attr_type=%d", cmd->bavq_start_handle, cmd->bavq_end_handle, @@ -257,17 +261,17 @@ ble_att_find_type_value_req_log(struct ble_att_find_type_value_req *cmd) static void ble_att_read_type_req_swap(struct ble_att_read_type_req *dst, - struct ble_att_read_type_req *src) + const struct ble_att_read_type_req *src) { dst->batq_start_handle = TOFROMLE16(src->batq_start_handle); dst->batq_end_handle = TOFROMLE16(src->batq_end_handle); } void -ble_att_read_type_req_parse(void *payload, int len, +ble_att_read_type_req_parse(const void *payload, int len, struct ble_att_read_type_req *dst) { - struct ble_att_read_type_req *src; + const struct ble_att_read_type_req *src; src = ble_att_init_parse(BLE_ATT_OP_READ_TYPE_REQ, payload, BLE_ATT_READ_TYPE_REQ_BASE_SZ, len); @@ -276,7 +280,7 @@ ble_att_read_type_req_parse(void *payload, int len, void ble_att_read_type_req_write(void *payload, int len, - struct ble_att_read_type_req *src) + const struct ble_att_read_type_req *src) { struct ble_att_read_type_req *dst; @@ -286,7 +290,7 @@ ble_att_read_type_req_write(void *payload, int len, } void -ble_att_read_type_req_log(struct ble_att_read_type_req *cmd) +ble_att_read_type_req_log(const struct ble_att_read_type_req *cmd) { BLE_HS_LOG(DEBUG, "start_handle=0x%04x end_handle=0x%04x", cmd->batq_start_handle, cmd->batq_end_handle); @@ -294,16 +298,16 @@ ble_att_read_type_req_log(struct ble_att_read_type_req *cmd) static void ble_att_read_type_rsp_swap(struct ble_att_read_type_rsp *dst, - struct ble_att_read_type_rsp *src) + const struct ble_att_read_type_rsp *src) { dst->batp_length = src->batp_length; } void -ble_att_read_type_rsp_parse(void *payload, int len, +ble_att_read_type_rsp_parse(const void *payload, int len, struct ble_att_read_type_rsp *dst) { - struct ble_att_read_type_rsp *src; + const struct ble_att_read_type_rsp *src; src = ble_att_init_parse(BLE_ATT_OP_READ_TYPE_RSP, payload, BLE_ATT_READ_TYPE_RSP_BASE_SZ, len); @@ -312,7 +316,7 @@ ble_att_read_type_rsp_parse(void *payload, int len, void ble_att_read_type_rsp_write(void *payload, int len, - struct ble_att_read_type_rsp *src) + const struct ble_att_read_type_rsp *src) { struct ble_att_read_type_rsp *dst; @@ -322,22 +326,23 @@ ble_att_read_type_rsp_write(void *payload, int len, } void -ble_att_read_type_rsp_log(struct ble_att_read_type_rsp *cmd) +ble_att_read_type_rsp_log(const struct ble_att_read_type_rsp *cmd) { BLE_HS_LOG(DEBUG, "length=%d", cmd->batp_length); } static void ble_att_read_req_swap(struct ble_att_read_req *dst, - struct ble_att_read_req *src) + const struct ble_att_read_req *src) { dst->barq_handle = TOFROMLE16(src->barq_handle); } void -ble_att_read_req_parse(void *payload, int len, struct ble_att_read_req *dst) +ble_att_read_req_parse(const void *payload, int len, + struct ble_att_read_req *dst) { - struct ble_att_read_req *src; + const struct ble_att_read_req *src; src = ble_att_init_parse(BLE_ATT_OP_READ_REQ, payload, BLE_ATT_READ_REQ_SZ, len); @@ -345,7 +350,8 @@ ble_att_read_req_parse(void *payload, int len, struct ble_att_read_req *dst) } void -ble_att_read_req_write(void *payload, int len, struct ble_att_read_req *src) +ble_att_read_req_write(void *payload, int len, + const struct ble_att_read_req *src) { struct ble_att_read_req *dst; @@ -355,24 +361,24 @@ ble_att_read_req_write(void *payload, int len, struct ble_att_read_req *src) } void -ble_att_read_req_log(struct ble_att_read_req *cmd) +ble_att_read_req_log(const struct ble_att_read_req *cmd) { BLE_HS_LOG(DEBUG, "handle=0x%04x", cmd->barq_handle); } static void ble_att_read_blob_req_swap(struct ble_att_read_blob_req *dst, - struct ble_att_read_blob_req *src) + const struct ble_att_read_blob_req *src) { dst->babq_handle = TOFROMLE16(src->babq_handle); dst->babq_offset = TOFROMLE16(src->babq_offset); } void -ble_att_read_blob_req_parse(void *payload, int len, +ble_att_read_blob_req_parse(const void *payload, int len, struct ble_att_read_blob_req *dst) { - struct ble_att_read_blob_req *src; + const struct ble_att_read_blob_req *src; src = ble_att_init_parse(BLE_ATT_OP_READ_BLOB_REQ, payload, BLE_ATT_READ_BLOB_REQ_SZ, len); @@ -381,7 +387,7 @@ ble_att_read_blob_req_parse(void *payload, int len, void ble_att_read_blob_req_write(void *payload, int len, - struct ble_att_read_blob_req *src) + const struct ble_att_read_blob_req *src) { struct ble_att_read_blob_req *dst; @@ -391,14 +397,14 @@ ble_att_read_blob_req_write(void *payload, int len, } void -ble_att_read_blob_req_log(struct ble_att_read_blob_req *cmd) +ble_att_read_blob_req_log(const struct ble_att_read_blob_req *cmd) { BLE_HS_LOG(DEBUG, "handle=0x%04x offset=%d", cmd->babq_handle, cmd->babq_offset); } void -ble_att_read_mult_req_parse(void *payload, int len) +ble_att_read_mult_req_parse(const void *payload, int len) { ble_att_init_parse(BLE_ATT_OP_READ_MULT_REQ, payload, BLE_ATT_READ_MULT_REQ_BASE_SZ, len); @@ -412,7 +418,7 @@ ble_att_read_mult_req_write(void *payload, int len) } void -ble_att_read_mult_rsp_parse(void *payload, int len) +ble_att_read_mult_rsp_parse(const void *payload, int len) { ble_att_init_parse(BLE_ATT_OP_READ_MULT_RSP, payload, BLE_ATT_READ_MULT_RSP_BASE_SZ, len); @@ -427,17 +433,17 @@ ble_att_read_mult_rsp_write(void *payload, int len) static void ble_att_read_group_type_req_swap(struct ble_att_read_group_type_req *dst, - struct ble_att_read_group_type_req *src) + const struct ble_att_read_group_type_req *src) { dst->bagq_start_handle = TOFROMLE16(src->bagq_start_handle); dst->bagq_end_handle = TOFROMLE16(src->bagq_end_handle); } void -ble_att_read_group_type_req_parse(void *payload, int len, +ble_att_read_group_type_req_parse(const void *payload, int len, struct ble_att_read_group_type_req *dst) { - struct ble_att_read_group_type_req *src; + const struct ble_att_read_group_type_req *src; src = ble_att_init_parse(BLE_ATT_OP_READ_GROUP_TYPE_REQ, payload, BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ, len); @@ -445,8 +451,8 @@ ble_att_read_group_type_req_parse(void *payload, int len, } void -ble_att_read_group_type_req_write(void *payload, int len, - struct ble_att_read_group_type_req *src) +ble_att_read_group_type_req_write( + void *payload, int len, const struct ble_att_read_group_type_req *src) { struct ble_att_read_group_type_req *dst; @@ -456,7 +462,7 @@ ble_att_read_group_type_req_write(void *payload, int len, } void -ble_att_read_group_type_req_log(struct ble_att_read_group_type_req *cmd) +ble_att_read_group_type_req_log(const struct ble_att_read_group_type_req *cmd) { BLE_HS_LOG(DEBUG, "start_handle=0x%04x end_handle=0x%04x", cmd->bagq_start_handle, cmd->bagq_end_handle); @@ -464,16 +470,16 @@ ble_att_read_group_type_req_log(struct ble_att_read_group_type_req *cmd) static void ble_att_read_group_type_rsp_swap(struct ble_att_read_group_type_rsp *dst, - struct ble_att_read_group_type_rsp *src) + const struct ble_att_read_group_type_rsp *src) { dst->bagp_length = src->bagp_length; } void -ble_att_read_group_type_rsp_parse(void *payload, int len, +ble_att_read_group_type_rsp_parse(const void *payload, int len, struct ble_att_read_group_type_rsp *dst) { - struct ble_att_read_group_type_rsp *src; + const struct ble_att_read_group_type_rsp *src; src = ble_att_init_parse(BLE_ATT_OP_READ_GROUP_TYPE_RSP, payload, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ, len); @@ -481,8 +487,8 @@ ble_att_read_group_type_rsp_parse(void *payload, int len, } void -ble_att_read_group_type_rsp_write(void *payload, int len, - struct ble_att_read_group_type_rsp *src) +ble_att_read_group_type_rsp_write( + void *payload, int len, const struct ble_att_read_group_type_rsp *src) { struct ble_att_read_group_type_rsp *dst; @@ -492,22 +498,23 @@ ble_att_read_group_type_rsp_write(void *payload, int len, } void -ble_att_read_group_type_rsp_log(struct ble_att_read_group_type_rsp *cmd) +ble_att_read_group_type_rsp_log(const struct ble_att_read_group_type_rsp *cmd) { BLE_HS_LOG(DEBUG, "length=%d", cmd->bagp_length); } static void ble_att_write_req_swap(struct ble_att_write_req *dst, - struct ble_att_write_req *src) + const struct ble_att_write_req *src) { dst->bawq_handle = TOFROMLE16(src->bawq_handle); } void -ble_att_write_req_parse(void *payload, int len, struct ble_att_write_req *dst) +ble_att_write_req_parse(const void *payload, int len, + struct ble_att_write_req *dst) { - struct ble_att_write_req *src; + const struct ble_att_write_req *src; src = ble_att_init_parse(BLE_ATT_OP_WRITE_REQ, payload, BLE_ATT_WRITE_REQ_BASE_SZ, len); @@ -515,9 +522,10 @@ ble_att_write_req_parse(void *payload, int len, struct ble_att_write_req *dst) } void -ble_att_write_cmd_parse(void *payload, int len, struct ble_att_write_req *dst) +ble_att_write_cmd_parse(const void *payload, int len, + struct ble_att_write_req *dst) { - struct ble_att_write_req *src; + const struct ble_att_write_req *src; src = ble_att_init_parse(BLE_ATT_OP_WRITE_CMD, payload, BLE_ATT_WRITE_REQ_BASE_SZ, len); @@ -525,7 +533,8 @@ ble_att_write_cmd_parse(void *payload, int len, struct ble_att_write_req *dst) } void -ble_att_write_req_write(void *payload, int len, struct ble_att_write_req *src) +ble_att_write_req_write(void *payload, int len, + const struct ble_att_write_req *src) { struct ble_att_write_req *dst; @@ -535,7 +544,8 @@ ble_att_write_req_write(void *payload, int len, struct ble_att_write_req *src) } void -ble_att_write_cmd_write(void *payload, int len, struct ble_att_write_req *src) +ble_att_write_cmd_write(void *payload, int len, + const struct ble_att_write_req *src) { struct ble_att_write_req *dst; @@ -545,24 +555,24 @@ ble_att_write_cmd_write(void *payload, int len, struct ble_att_write_req *src) } void -ble_att_write_cmd_log(struct ble_att_write_req *cmd) +ble_att_write_cmd_log(const struct ble_att_write_req *cmd) { BLE_HS_LOG(DEBUG, "handle=0x%04x", cmd->bawq_handle); } static void ble_att_prep_write_cmd_swap(struct ble_att_prep_write_cmd *dst, - struct ble_att_prep_write_cmd *src) + const struct ble_att_prep_write_cmd *src) { dst->bapc_handle = TOFROMLE16(src->bapc_handle); dst->bapc_offset = TOFROMLE16(src->bapc_offset); } void -ble_att_prep_write_req_parse(void *payload, int len, +ble_att_prep_write_req_parse(const void *payload, int len, struct ble_att_prep_write_cmd *dst) { - struct ble_att_prep_write_cmd *src; + const struct ble_att_prep_write_cmd *src; src = ble_att_init_parse(BLE_ATT_OP_PREP_WRITE_REQ, payload, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, len); @@ -571,7 +581,7 @@ ble_att_prep_write_req_parse(void *payload, int len, void ble_att_prep_write_req_write(void *payload, int len, - struct ble_att_prep_write_cmd *src) + const struct ble_att_prep_write_cmd *src) { struct ble_att_prep_write_cmd *dst; @@ -581,10 +591,10 @@ ble_att_prep_write_req_write(void *payload, int len, } void -ble_att_prep_write_rsp_parse(void *payload, int len, +ble_att_prep_write_rsp_parse(const void *payload, int len, struct ble_att_prep_write_cmd *dst) { - struct ble_att_prep_write_cmd *src; + const struct ble_att_prep_write_cmd *src; src = ble_att_init_parse(BLE_ATT_OP_PREP_WRITE_RSP, payload, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, len); @@ -593,7 +603,7 @@ ble_att_prep_write_rsp_parse(void *payload, int len, void ble_att_prep_write_rsp_write(void *payload, int len, - struct ble_att_prep_write_cmd *src) + const struct ble_att_prep_write_cmd *src) { struct ble_att_prep_write_cmd *dst; @@ -603,7 +613,7 @@ ble_att_prep_write_rsp_write(void *payload, int len, } void -ble_att_prep_write_cmd_log(struct ble_att_prep_write_cmd *cmd) +ble_att_prep_write_cmd_log(const struct ble_att_prep_write_cmd *cmd) { BLE_HS_LOG(DEBUG, "handle=0x%04x offset=%d", cmd->bapc_handle, cmd->bapc_offset); @@ -611,16 +621,16 @@ ble_att_prep_write_cmd_log(struct ble_att_prep_write_cmd *cmd) static void ble_att_exec_write_req_swap(struct ble_att_exec_write_req *dst, - struct ble_att_exec_write_req *src) + const struct ble_att_exec_write_req *src) { dst->baeq_flags = src->baeq_flags; } void -ble_att_exec_write_req_parse(void *payload, int len, +ble_att_exec_write_req_parse(const void *payload, int len, struct ble_att_exec_write_req *dst) { - struct ble_att_exec_write_req *src; + const struct ble_att_exec_write_req *src; src = ble_att_init_parse(BLE_ATT_OP_EXEC_WRITE_REQ, payload, BLE_ATT_EXEC_WRITE_REQ_SZ, len); @@ -629,7 +639,7 @@ ble_att_exec_write_req_parse(void *payload, int len, void ble_att_exec_write_req_write(void *payload, int len, - struct ble_att_exec_write_req *src) + const struct ble_att_exec_write_req *src) { struct ble_att_exec_write_req *dst; @@ -639,13 +649,13 @@ ble_att_exec_write_req_write(void *payload, int len, } void -ble_att_exec_write_req_log(struct ble_att_exec_write_req *cmd) +ble_att_exec_write_req_log(const struct ble_att_exec_write_req *cmd) { BLE_HS_LOG(DEBUG, "flags=0x%02x", cmd->baeq_flags); } void -ble_att_exec_write_rsp_parse(void *payload, int len) +ble_att_exec_write_rsp_parse(const void *payload, int len) { ble_att_init_parse(BLE_ATT_OP_EXEC_WRITE_RSP, payload, BLE_ATT_EXEC_WRITE_RSP_SZ, len); @@ -660,16 +670,16 @@ ble_att_exec_write_rsp_write(void *payload, int len) static void ble_att_notify_req_swap(struct ble_att_notify_req *dst, - struct ble_att_notify_req *src) + const struct ble_att_notify_req *src) { dst->banq_handle = TOFROMLE16(src->banq_handle); } void -ble_att_notify_req_parse(void *payload, int len, +ble_att_notify_req_parse(const void *payload, int len, struct ble_att_notify_req *dst) { - struct ble_att_notify_req *src; + const struct ble_att_notify_req *src; src = ble_att_init_parse(BLE_ATT_OP_NOTIFY_REQ, payload, BLE_ATT_NOTIFY_REQ_BASE_SZ, len); @@ -678,7 +688,7 @@ ble_att_notify_req_parse(void *payload, int len, void ble_att_notify_req_write(void *payload, int len, - struct ble_att_notify_req *src) + const struct ble_att_notify_req *src) { struct ble_att_notify_req *dst; @@ -688,23 +698,23 @@ ble_att_notify_req_write(void *payload, int len, } void -ble_att_notify_req_log(struct ble_att_notify_req *cmd) +ble_att_notify_req_log(const struct ble_att_notify_req *cmd) { BLE_HS_LOG(DEBUG, "handle=0x%04x", cmd->banq_handle); } static void ble_att_indicate_req_swap(struct ble_att_indicate_req *dst, - struct ble_att_indicate_req *src) + const struct ble_att_indicate_req *src) { dst->baiq_handle = TOFROMLE16(src->baiq_handle); } void -ble_att_indicate_req_parse(void *payload, int len, +ble_att_indicate_req_parse(const void *payload, int len, struct ble_att_indicate_req *dst) { - struct ble_att_indicate_req *src; + const struct ble_att_indicate_req *src; src = ble_att_init_parse(BLE_ATT_OP_INDICATE_REQ, payload, BLE_ATT_INDICATE_REQ_BASE_SZ, len); @@ -713,7 +723,7 @@ ble_att_indicate_req_parse(void *payload, int len, void ble_att_indicate_req_write(void *payload, int len, - struct ble_att_indicate_req *src) + const struct ble_att_indicate_req *src) { struct ble_att_indicate_req *dst; @@ -723,13 +733,13 @@ ble_att_indicate_req_write(void *payload, int len, } void -ble_att_indicate_req_log(struct ble_att_indicate_req *cmd) +ble_att_indicate_req_log(const struct ble_att_indicate_req *cmd) { BLE_HS_LOG(DEBUG, "handle=0x%04x", cmd->baiq_handle); } void -ble_att_indicate_rsp_parse(void *payload, int len) +ble_att_indicate_rsp_parse(const void *payload, int len) { ble_att_init_parse(BLE_ATT_OP_INDICATE_RSP, payload, BLE_ATT_INDICATE_RSP_SZ, len); diff --git a/net/nimble/host/src/ble_att_cmd_priv.h b/net/nimble/host/src/ble_att_cmd_priv.h index 38af5f2e..bfeb28f1 100644 --- a/net/nimble/host/src/ble_att_cmd_priv.h +++ b/net/nimble/host/src/ble_att_cmd_priv.h @@ -304,103 +304,108 @@ struct ble_att_indicate_req { */ #define BLE_ATT_INDICATE_RSP_SZ 1 -void ble_att_error_rsp_parse(void *payload, int len, - struct ble_att_error_rsp *rsp); +void ble_att_error_rsp_parse(const void *payload, int len, + struct ble_att_error_rsp *rsp); void ble_att_error_rsp_write(void *payload, int len, - struct ble_att_error_rsp *rsp); -void ble_att_error_rsp_log(struct ble_att_error_rsp *cmd); -void ble_att_mtu_cmd_parse(void *payload, int len, - struct ble_att_mtu_cmd *cmd); + const struct ble_att_error_rsp *rsp); +void ble_att_error_rsp_log(const struct ble_att_error_rsp *cmd); +void ble_att_mtu_req_parse(const void *payload, int len, + struct ble_att_mtu_cmd *cmd); void ble_att_mtu_req_write(void *payload, int len, - struct ble_att_mtu_cmd *cmd); -void ble_att_mtu_rsp_write(void *payload, int len, + const struct ble_att_mtu_cmd *cmd); +void ble_att_mtu_rsp_parse(const void *payload, int len, struct ble_att_mtu_cmd *cmd); -void ble_att_mtu_cmd_log(struct ble_att_mtu_cmd *cmd); -void ble_att_find_info_req_parse(void *payload, int len, +void ble_att_mtu_rsp_write(void *payload, int len, + const struct ble_att_mtu_cmd *cmd); +void ble_att_mtu_cmd_log(const struct ble_att_mtu_cmd *cmd); +void ble_att_find_info_req_parse(const void *payload, int len, struct ble_att_find_info_req *req); void ble_att_find_info_req_write(void *payload, int len, - struct ble_att_find_info_req *req); -void ble_att_find_info_req_log(struct ble_att_find_info_req *cmd); -void ble_att_find_info_rsp_parse(void *payload, int len, + const struct ble_att_find_info_req *req); +void ble_att_find_info_req_log(const struct ble_att_find_info_req *cmd); +void ble_att_find_info_rsp_parse(const void *payload, int len, struct ble_att_find_info_rsp *rsp); void ble_att_find_info_rsp_write(void *payload, int len, - struct ble_att_find_info_rsp *rsp); -void ble_att_find_info_rsp_log(struct ble_att_find_info_rsp *cmd); -void ble_att_find_type_value_req_parse(void *payload, int len, - struct ble_att_find_type_value_req *req); -void ble_att_find_type_value_req_write(void *payload, int len, - struct ble_att_find_type_value_req *req); -void ble_att_find_type_value_req_log(struct ble_att_find_type_value_req *cmd); -void ble_att_read_type_req_parse(void *payload, int len, + const struct ble_att_find_info_rsp *rsp); +void ble_att_find_info_rsp_log(const struct ble_att_find_info_rsp *cmd); +void ble_att_find_type_value_req_parse( + const void *payload, int len, struct ble_att_find_type_value_req *req); +void ble_att_find_type_value_req_write( + void *payload, int len, const struct ble_att_find_type_value_req *req); +void ble_att_find_type_value_req_log( + const struct ble_att_find_type_value_req *cmd); +void ble_att_read_type_req_parse(const void *payload, int len, struct ble_att_read_type_req *req); void ble_att_read_type_req_write(void *payload, int len, - struct ble_att_read_type_req *req); -void ble_att_read_type_req_log(struct ble_att_read_type_req *cmd); -void ble_att_read_type_rsp_parse(void *payload, int len, + const struct ble_att_read_type_req *req); +void ble_att_read_type_req_log(const struct ble_att_read_type_req *cmd); +void ble_att_read_type_rsp_parse(const void *payload, int len, struct ble_att_read_type_rsp *rsp); void ble_att_read_type_rsp_write(void *payload, int len, - struct ble_att_read_type_rsp *rsp); -void ble_att_read_type_rsp_log(struct ble_att_read_type_rsp *cmd); -void ble_att_read_req_parse(void *payload, int len, + const struct ble_att_read_type_rsp *rsp); +void ble_att_read_type_rsp_log(const struct ble_att_read_type_rsp *cmd); +void ble_att_read_req_parse(const void *payload, int len, struct ble_att_read_req *req); void ble_att_read_req_write(void *payload, int len, - struct ble_att_read_req *req); -void ble_att_read_req_log(struct ble_att_read_req *cmd); -void ble_att_read_blob_req_parse(void *payload, int len, + const struct ble_att_read_req *req); +void ble_att_read_req_log(const struct ble_att_read_req *cmd); +void ble_att_read_blob_req_parse(const void *payload, int len, struct ble_att_read_blob_req *req); void ble_att_read_blob_req_write(void *payload, int len, - struct ble_att_read_blob_req *req); -void ble_att_read_blob_req_log(struct ble_att_read_blob_req *cmd); -void ble_att_read_mult_req_parse(void *payload, int len); + const struct ble_att_read_blob_req *req); +void ble_att_read_blob_req_log(const struct ble_att_read_blob_req *cmd); +void ble_att_read_mult_req_parse(const void *payload, int len); void ble_att_read_mult_req_write(void *payload, int len); -void ble_att_read_mult_rsp_parse(void *payload, int len); +void ble_att_read_mult_rsp_parse(const void *payload, int len); void ble_att_read_mult_rsp_write(void *payload, int len); void ble_att_read_group_type_req_parse( - void *payload, int len, struct ble_att_read_group_type_req *req); + const void *payload, int len, struct ble_att_read_group_type_req *req); void ble_att_read_group_type_req_write( - void *payload, int len, struct ble_att_read_group_type_req *req); -void ble_att_read_group_type_req_log(struct ble_att_read_group_type_req *cmd); + void *payload, int len, const struct ble_att_read_group_type_req *req); +void ble_att_read_group_type_req_log( + const struct ble_att_read_group_type_req *cmd); void ble_att_read_group_type_rsp_parse( - void *payload, int len, struct ble_att_read_group_type_rsp *rsp); + const void *payload, int len, struct ble_att_read_group_type_rsp *rsp); void ble_att_read_group_type_rsp_write( - void *payload, int len, struct ble_att_read_group_type_rsp *rsp); -void ble_att_read_group_type_rsp_log(struct ble_att_read_group_type_rsp *cmd); -void ble_att_write_req_parse(void *payload, int len, + void *payload, int len, const struct ble_att_read_group_type_rsp *rsp); +void ble_att_read_group_type_rsp_log( + const struct ble_att_read_group_type_rsp *cmd); +void ble_att_write_req_parse(const void *payload, int len, struct ble_att_write_req *req); void ble_att_write_req_write(void *payload, int len, - struct ble_att_write_req *req); -void ble_att_write_cmd_parse(void *payload, int len, + const struct ble_att_write_req *req); +void ble_att_write_cmd_parse(const void *payload, int len, struct ble_att_write_req *req); void ble_att_write_cmd_write(void *payload, int len, - struct ble_att_write_req *req); -void ble_att_write_cmd_log(struct ble_att_write_req *cmd); -void ble_att_prep_write_req_parse(void *payload, int len, + const struct ble_att_write_req *req); +void ble_att_write_cmd_log(const struct ble_att_write_req *cmd); +void ble_att_prep_write_req_parse(const void *payload, int len, struct ble_att_prep_write_cmd *cmd); void ble_att_prep_write_req_write(void *payload, int len, - struct ble_att_prep_write_cmd *cmd); -void ble_att_prep_write_cmd_log(struct ble_att_prep_write_cmd *cmd); -void ble_att_prep_write_rsp_parse(void *payload, int len, + const struct ble_att_prep_write_cmd *cmd); +void ble_att_prep_write_cmd_log(const struct ble_att_prep_write_cmd *cmd); +void ble_att_prep_write_rsp_parse(const void *payload, int len, struct ble_att_prep_write_cmd *cmd); void ble_att_prep_write_rsp_write(void *payload, int len, - struct ble_att_prep_write_cmd *cmd); -void ble_att_exec_write_req_parse(void *payload, int len, + const struct ble_att_prep_write_cmd *cmd); +void ble_att_exec_write_req_parse(const void *payload, int len, struct ble_att_exec_write_req *req); -void ble_att_exec_write_req_log(struct ble_att_exec_write_req *cmd); +void ble_att_exec_write_req_log(const struct ble_att_exec_write_req *cmd); void ble_att_exec_write_req_write(void *payload, int len, - struct ble_att_exec_write_req *req); -void ble_att_exec_write_rsp_parse(void *payload, int len); + const struct ble_att_exec_write_req *req); +void ble_att_exec_write_rsp_parse(const void *payload, int len); void ble_att_exec_write_rsp_write(void *payload, int len); -void ble_att_notify_req_parse(void *payload, int len, +void ble_att_notify_req_parse(const void *payload, int len, struct ble_att_notify_req *req); void ble_att_notify_req_write(void *payload, int len, - struct ble_att_notify_req *req); -void ble_att_notify_req_log(struct ble_att_notify_req *cmd); -void ble_att_indicate_req_parse(void *payload, int len, + const struct ble_att_notify_req *req); +void ble_att_notify_req_log(const struct ble_att_notify_req *cmd); +void ble_att_indicate_req_parse(const void *payload, int len, struct ble_att_indicate_req *req); void ble_att_indicate_req_write(void *payload, int len, - struct ble_att_indicate_req *req); -void ble_att_indicate_rsp_parse(void *payload, int len); + const struct ble_att_indicate_req *req); +void ble_att_indicate_rsp_parse(const void *payload, int len); void ble_att_indicate_rsp_write(void *payload, int len); -void ble_att_indicate_req_log(struct ble_att_indicate_req *cmd); +void ble_att_indicate_req_log(const struct ble_att_indicate_req *cmd); #endif diff --git a/net/nimble/host/src/ble_att_priv.h b/net/nimble/host/src/ble_att_priv.h index f908b9c1..ee9a9e98 100644 --- a/net/nimble/host/src/ble_att_priv.h +++ b/net/nimble/host/src/ble_att_priv.h @@ -100,10 +100,6 @@ STATS_SECT_START(ble_att_stats) STATS_SECT_END extern STATS_SECT_DECL(ble_att_stats) ble_att_stats; -#define BLE_ATT_MTU_DFLT 23 /* Also the minimum. */ -#define BLE_ATT_MTU_MAX 240 -#define BLE_ATT_MTU_PREFERRED_DFLT 240 - struct ble_att_prep_entry { SLIST_ENTRY(ble_att_prep_entry) bape_next; uint16_t bape_handle; @@ -123,6 +119,29 @@ struct ble_att_svr_conn { uint32_t basc_prep_write_rx_time; }; +/** + * Handles a host attribute request. + * + * @param entry The host attribute being requested. + * @param op The operation being performed on the attribute. + * @param arg The request data associated with that host + * attribute. + * + * @return 0 on success; + * One of the BLE_ATT_ERR_[...] codes on + * failure. + */ +typedef int ble_att_svr_access_fn(uint16_t conn_handle, uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg); + +int ble_att_svr_register(const uint8_t *uuid, uint8_t flags, + uint16_t *handle_id, + ble_att_svr_access_fn *cb, void *cb_arg); +int ble_att_svr_register_uuid16(uint16_t uuid16, uint8_t flags, + uint16_t *handle_id, ble_att_svr_access_fn *cb, + void *cb_arg); + struct ble_att_svr_entry { STAILQ_ENTRY(ble_att_svr_entry) ha_next; @@ -139,11 +158,11 @@ SLIST_HEAD(ble_att_clt_entry_list, ble_att_clt_entry); /*** @gen */ 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); +void ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn, + struct ble_l2cap_chan **out_chan); void ble_att_inc_tx_stat(uint8_t att_op); -uint8_t *ble_att_get_flat_buf(void); -uint16_t ble_att_mtu(uint16_t conn_handle); +void ble_att_truncate_to_mtu(const struct ble_l2cap_chan *att_chan, + struct os_mbuf *txom); void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu); int ble_att_init(void); @@ -156,9 +175,12 @@ int ble_att_init(void); /*** @svr */ struct ble_att_svr_entry * -ble_att_svr_find_by_uuid(struct ble_att_svr_entry *start_at, uint8_t *uuid); +ble_att_svr_find_by_uuid(struct ble_att_svr_entry *start_at, + const uint8_t *uuid, + uint16_t end_handle); uint16_t ble_att_svr_prev_handle(void); -int ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om); +int ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom); +struct ble_att_svr_entry *ble_att_svr_find_by_handle(uint16_t handle_id); int ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom); @@ -185,7 +207,7 @@ int ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom); void ble_att_svr_prep_clear(struct ble_att_prep_entry_list *prep_list); int ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle, - struct ble_att_svr_access_ctxt *ctxt, + uint16_t offset, struct os_mbuf *om, uint8_t *out_att_err); int ble_att_svr_init(void); @@ -209,6 +231,7 @@ struct ble_att_read_type_adata { uint16_t att_handle; int value_len; uint8_t *value; + }; /** An attribute-data entry in a read by group type response. */ @@ -220,53 +243,55 @@ struct ble_att_read_group_type_adata { }; int ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_mtu(uint16_t conn_handle, struct ble_att_mtu_cmd *req); +int ble_att_clt_tx_mtu(uint16_t conn_handle, + const struct ble_att_mtu_cmd *req); int ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_read(uint16_t conn_handle, struct ble_att_read_req *req); +int ble_att_clt_tx_read(uint16_t conn_handle, + const struct ble_att_read_req *req); int ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_read_blob(uint16_t conn_handle, - struct ble_att_read_blob_req *req); + const struct ble_att_read_blob_req *req); int ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_read_mult(uint16_t conn_handle, - uint16_t *handles, int num_handles); + const uint16_t *handles, int num_handles); int ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_read_type(uint16_t conn_handle, - struct ble_att_read_type_req *req, - void *uuid128); + const struct ble_att_read_type_req *req, + const void *uuid128); int ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_read_group_type(uint16_t conn_handle, - struct ble_att_read_group_type_req *req, - void *uuid128); +int ble_att_clt_tx_read_group_type( + uint16_t conn_handle, const struct ble_att_read_group_type_req *req, + const void *uuid128); int ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_find_info(uint16_t conn_handle, - struct ble_att_find_info_req *req); -int ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om); -int ble_att_clt_tx_find_type_value(uint16_t conn_handle, - struct ble_att_find_type_value_req *req, - void *attribute_value, int value_len); + const struct ble_att_find_info_req *req); +int ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom); +int ble_att_clt_tx_find_type_value( + uint16_t conn_handle, const struct ble_att_find_type_value_req *req, + const void *attribute_value, int value_len); int ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_write_req(uint16_t conn_handle, - struct ble_att_write_req *req, - void *value, uint16_t value_len); + const struct ble_att_write_req *req, + struct os_mbuf *txom); int ble_att_clt_tx_write_cmd(uint16_t conn_handle, - struct ble_att_write_req *req, - void *value, uint16_t value_len); + const struct ble_att_write_req *req, + struct os_mbuf *txom); int ble_att_clt_tx_prep_write(uint16_t conn_handle, - struct ble_att_prep_write_cmd *req, - void *value, uint16_t value_len); + const struct ble_att_prep_write_cmd *req, + struct os_mbuf *txom); int ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_exec_write(uint16_t conn_handle, - struct ble_att_exec_write_req *req); + const struct ble_att_exec_write_req *req); int ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_notify(uint16_t conn_handle, - struct ble_att_notify_req *req, - void *value, uint16_t value_len); + const struct ble_att_notify_req *req, + struct os_mbuf *txom); int ble_att_clt_tx_indicate(uint16_t conn_handle, - struct ble_att_indicate_req *req, - void *value, uint16_t value_len); + const struct ble_att_indicate_req *req, + struct os_mbuf *txom); int ble_att_clt_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom); #endif diff --git a/net/nimble/host/src/ble_att_svr.c b/net/nimble/host/src/ble_att_svr.c index 1017fc8e..5d64c25b 100644 --- a/net/nimble/host/src/ble_att_svr.c +++ b/net/nimble/host/src/ble_att_svr.c @@ -25,7 +25,9 @@ #include "host/ble_uuid.h" #include "ble_hs_priv.h" -static STAILQ_HEAD(, ble_att_svr_entry) ble_att_svr_list; +STAILQ_HEAD(ble_att_svr_entry_list, ble_att_svr_entry); +static struct ble_att_svr_entry_list ble_att_svr_list; + static uint16_t ble_att_svr_id; static void *ble_att_svr_entry_mem; @@ -72,7 +74,7 @@ ble_att_svr_next_id(void) * @return 0 on success, non-zero error code on failure. */ int -ble_att_svr_register(uint8_t *uuid, uint8_t flags, uint16_t *handle_id, +ble_att_svr_register(const uint8_t *uuid, uint8_t flags, uint16_t *handle_id, ble_att_svr_access_fn *cb, void *cb_arg) { struct ble_att_svr_entry *entry; @@ -159,7 +161,7 @@ ble_att_svr_find_by_handle(uint16_t handle_id) * Find a host attribute by UUID. * * @param uuid The ble_uuid_t to search for - * @param ha_ptr On input: Indicates the starting point of the + * @param prev On input: Indicates the starting point of the * walk; null means start at the beginning of * the list, non-null means start at the * following entry. @@ -170,7 +172,8 @@ ble_att_svr_find_by_handle(uint16_t handle_id) * @return 0 on success; BLE_HS_ENOENT on not found. */ struct ble_att_svr_entry * -ble_att_svr_find_by_uuid(struct ble_att_svr_entry *prev, uint8_t *uuid) +ble_att_svr_find_by_uuid(struct ble_att_svr_entry *prev, const uint8_t *uuid, + uint16_t end_handle) { struct ble_att_svr_entry *entry; @@ -180,7 +183,10 @@ ble_att_svr_find_by_uuid(struct ble_att_svr_entry *prev, uint8_t *uuid) entry = STAILQ_NEXT(prev, ha_next); } - for (; entry != NULL; entry = STAILQ_NEXT(entry, ha_next)) { + for (; + entry != NULL && entry->ha_handle_id <= end_handle; + entry = STAILQ_NEXT(entry, ha_next)) { + if (memcmp(entry->ha_uuid, uuid, sizeof entry->ha_uuid) == 0) { return entry; } @@ -196,7 +202,7 @@ ble_att_svr_pullup_req_base(struct os_mbuf **om, int base_len, uint8_t att_err; int rc; - rc = ble_hs_misc_pullup_base(om, base_len); + rc = ble_hs_mbuf_pullup_base(om, base_len); if (rc == BLE_HS_ENOMEM) { att_err = BLE_ATT_ERR_INSUFFICIENT_RES; } else { @@ -210,42 +216,45 @@ ble_att_svr_pullup_req_base(struct os_mbuf **om, int base_len, return rc; } -static int +static void ble_att_svr_get_sec_state(uint16_t conn_handle, struct ble_gap_sec_state *out_sec_state) { struct ble_hs_conn *conn; ble_hs_lock(); - conn = ble_hs_conn_find(conn_handle); - if (conn != NULL) { - *out_sec_state = conn->bhc_sec_state; - } - ble_hs_unlock(); - if (conn == NULL) { - return BLE_HS_ENOTCONN; - } else { - return 0; - } + conn = ble_hs_conn_find_assert(conn_handle); + *out_sec_state = conn->bhc_sec_state; + + ble_hs_unlock(); } static int -ble_att_svr_check_security(uint16_t conn_handle, int is_read, - struct ble_att_svr_entry *entry, - uint8_t *out_att_err) +ble_att_svr_check_perms(uint16_t conn_handle, int is_read, + struct ble_att_svr_entry *entry, + uint8_t *out_att_err) { struct ble_gap_sec_state sec_state; int author; int authen; int enc; - int rc; if (is_read) { + if (!(entry->ha_flags & BLE_ATT_F_READ)) { + *out_att_err = BLE_ATT_ERR_READ_NOT_PERMITTED; + return BLE_HS_ENOTSUP; + } + enc = entry->ha_flags & BLE_ATT_F_READ_ENC; authen = entry->ha_flags & BLE_ATT_F_READ_AUTHEN; author = entry->ha_flags & BLE_ATT_F_READ_AUTHOR; } else { + if (!(entry->ha_flags & BLE_ATT_F_WRITE)) { + *out_att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED; + return BLE_HS_ENOTSUP; + } + enc = entry->ha_flags & BLE_ATT_F_WRITE_ENC; authen = entry->ha_flags & BLE_ATT_F_WRITE_AUTHEN; author = entry->ha_flags & BLE_ATT_F_WRITE_AUTHOR; @@ -256,21 +265,17 @@ ble_att_svr_check_security(uint16_t conn_handle, int is_read, return 0; } - rc = ble_att_svr_get_sec_state(conn_handle, &sec_state); - if (rc != 0) { - return rc; - } - + ble_att_svr_get_sec_state(conn_handle, &sec_state); if (enc && !sec_state.encrypted) { /* XXX: Check security database; if required key present, respond with * insufficient encryption error code. */ - *out_att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHENT; + *out_att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHEN; return BLE_HS_ATT_ERR(*out_att_err); } if (authen && !sec_state.authenticated) { - *out_att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHENT; + *out_att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHEN; return BLE_HS_ATT_ERR(*out_att_err); } @@ -284,7 +289,8 @@ ble_att_svr_check_security(uint16_t conn_handle, int is_read, static int ble_att_svr_read(uint16_t conn_handle, struct ble_att_svr_entry *entry, - struct ble_att_svr_access_ctxt *ctxt, + uint16_t offset, + struct os_mbuf *om, uint8_t *out_att_err) { uint8_t att_err; @@ -293,13 +299,7 @@ ble_att_svr_read(uint16_t conn_handle, att_err = 0; /* Silence gcc warning. */ if (conn_handle != BLE_HS_CONN_HANDLE_NONE) { - if (!(entry->ha_flags & BLE_ATT_F_READ)) { - att_err = BLE_ATT_ERR_READ_NOT_PERMITTED; - rc = BLE_HS_ENOTSUP; - goto err; - } - - rc = ble_att_svr_check_security(conn_handle, 1, entry, &att_err); + rc = ble_att_svr_check_perms(conn_handle, 1, entry, &att_err); if (rc != 0) { goto err; } @@ -307,8 +307,7 @@ ble_att_svr_read(uint16_t conn_handle, BLE_HS_DBG_ASSERT(entry->ha_cb != NULL); rc = entry->ha_cb(conn_handle, entry->ha_handle_id, - entry->ha_uuid, BLE_ATT_ACCESS_OP_READ, ctxt, - entry->ha_cb_arg); + BLE_ATT_ACCESS_OP_READ, offset, &om, entry->ha_cb_arg); if (rc != 0) { att_err = rc; rc = BLE_HS_EAPP; @@ -324,9 +323,51 @@ err: return rc; } +static int +ble_att_svr_read_flat(uint16_t conn_handle, + struct ble_att_svr_entry *entry, + uint16_t offset, + uint16_t max_len, + void *dst, + uint16_t *out_len, + uint8_t *out_att_err) +{ + struct os_mbuf *om; + uint16_t len; + int rc; + + om = ble_hs_mbuf_l2cap_pkt(); + if (om == NULL) { + rc = BLE_HS_ENOMEM; + goto done; + } + + rc = ble_att_svr_read(conn_handle, entry, offset, om, out_att_err); + if (rc != 0) { + goto done; + } + + len = OS_MBUF_PKTLEN(om); + if (len > max_len) { + rc = BLE_HS_EMSGSIZE; + *out_att_err = BLE_ATT_ERR_UNLIKELY; + goto done; + } + + rc = os_mbuf_copydata(om, 0, len, dst); + BLE_HS_DBG_ASSERT(rc == 0); + + *out_len = len; + rc = 0; + +done: + os_mbuf_free_chain(om); + return rc; +} + int ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle, - struct ble_att_svr_access_ctxt *ctxt, + uint16_t offset, struct os_mbuf *om, uint8_t *out_att_err) { struct ble_att_svr_entry *entry; @@ -340,7 +381,7 @@ ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle, return BLE_HS_ENOENT; } - rc = ble_att_svr_read(conn_handle, entry, ctxt, out_att_err); + rc = ble_att_svr_read(conn_handle, entry, offset, om, out_att_err); if (rc != 0) { return rc; } @@ -348,30 +389,51 @@ ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle, return 0; } +/** + * Reads a locally registered attribute. If the specified attribute handle + * coresponds to a GATT characteristic value or descriptor, the read is + * performed by calling the registered GATT access callback. + * + * @param attr_handle The 16-bit handle of the attribute to read. + * @param out_om On success, this is made to point to a + * newly-allocated mbuf containing the + * attribute data read. + * + * @return 0 on success; + * NimBLE host ATT return code if the attribute + * access callback reports failure; + * NimBLE host core return code on unexpected + * error. + */ int -ble_att_svr_read_local(uint16_t attr_handle, void **out_data, - uint16_t *out_attr_len) +ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om) { - struct ble_att_svr_access_ctxt ctxt; + struct os_mbuf *om; int rc; - ctxt.offset = 0; + om = ble_hs_mbuf_bare_pkt(); + if (om == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } - rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, &ctxt, + rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, 0, om, NULL); if (rc != 0) { - return rc; + goto err; } - *out_attr_len = ctxt.data_len; - *out_data = ctxt.attr_data; - + *out_om = om; return 0; + +err: + os_mbuf_free_chain(om); + return rc; } static int ble_att_svr_write(uint16_t conn_handle, struct ble_att_svr_entry *entry, - struct ble_att_svr_access_ctxt *ctxt, uint8_t *out_att_err) + uint16_t offset, struct os_mbuf **om, uint8_t *out_att_err) { uint8_t att_err; int rc; @@ -379,31 +441,22 @@ ble_att_svr_write(uint16_t conn_handle, struct ble_att_svr_entry *entry, BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); if (conn_handle != BLE_HS_CONN_HANDLE_NONE) { - if (!(entry->ha_flags & BLE_ATT_F_WRITE)) { - att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED; - rc = BLE_HS_ENOTSUP; - goto err; - } - - rc = ble_att_svr_check_security(conn_handle, 0, entry, &att_err); + rc = ble_att_svr_check_perms(conn_handle, 0, entry, &att_err); if (rc != 0) { - goto err; + goto done; } } BLE_HS_DBG_ASSERT(entry->ha_cb != NULL); rc = entry->ha_cb(conn_handle, entry->ha_handle_id, - entry->ha_uuid, BLE_ATT_ACCESS_OP_WRITE, ctxt, - entry->ha_cb_arg); + BLE_ATT_ACCESS_OP_WRITE, offset, om, entry->ha_cb_arg); if (rc != 0) { att_err = rc; rc = BLE_HS_EAPP; - goto err; + goto done; } - return 0; - -err: +done: if (out_att_err != NULL) { *out_att_err = att_err; } @@ -412,7 +465,7 @@ err: static int ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle, - struct ble_att_svr_access_ctxt *ctxt, + uint16_t offset, struct os_mbuf **om, uint8_t *out_att_err) { struct ble_att_svr_entry *entry; @@ -420,11 +473,13 @@ ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle, entry = ble_att_svr_find_by_handle(attr_handle); if (entry == NULL) { - *out_att_err = BLE_ATT_ERR_INVALID_HANDLE; + if (out_att_err != NULL) { + *out_att_err = BLE_ATT_ERR_INVALID_HANDLE; + } return BLE_HS_ENOENT; } - rc = ble_att_svr_write(conn_handle, entry, ctxt, out_att_err); + rc = ble_att_svr_write(conn_handle, entry, offset, om, out_att_err); if (rc != 0) { return rc; } @@ -434,20 +489,15 @@ ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle, static int ble_att_svr_tx_error_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, - uint8_t req_op, uint16_t handle, uint8_t error_code) + struct os_mbuf *txom, uint8_t req_op, + uint16_t handle, uint8_t error_code) { struct ble_att_error_rsp rsp; - struct os_mbuf *txom; void *dst; int rc; BLE_HS_DBG_ASSERT(error_code != 0); - - txom = ble_hs_misc_pkthdr(); - if (txom == NULL) { - rc = BLE_HS_ENOMEM; - goto err; - } + BLE_HS_DBG_ASSERT(OS_MBUF_PKTLEN(txom) == 0); dst = os_mbuf_extend(txom, BLE_ATT_ERROR_RSP_SZ); if (dst == NULL) { @@ -460,8 +510,6 @@ ble_att_svr_tx_error_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, rsp.baep_error_code = error_code; ble_att_error_rsp_write(dst, BLE_ATT_ERROR_RSP_SZ, &rsp); - BLE_ATT_LOG_CMD(1, "error rsp", conn->bhc_handle, - ble_att_error_rsp_log, &rsp); rc = ble_l2cap_tx(conn, chan, txom); txom = NULL; @@ -469,6 +517,9 @@ ble_att_svr_tx_error_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, goto err; } + BLE_ATT_LOG_CMD(1, "error rsp", conn->bhc_handle, + ble_att_error_rsp_log, &rsp); + return 0; err: @@ -479,10 +530,10 @@ err: /** * Transmits a response or error message over the specified connection. * - * The specified rc value controls what gets sent as follows: + * The specified rc and err_status values control 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. + * o Else if err_status != 0: tx an error response. + * o Else: tx nothing. * * In addition, if transmission of an affirmative response fails, an error is * sent instead. @@ -500,17 +551,14 @@ err: * field. */ static int -ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom, +ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *om, uint8_t att_op, uint8_t err_status, uint16_t err_handle) { struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; int do_tx; - if (rc == BLE_HS_ENOTCONN) { - /* No connection; tx is not possible. */ - do_tx = 0; - } else if (rc != 0 && err_status == 0) { + if (rc != 0 && err_status == 0) { /* Processing failed, but err_status of 0 means don't send error. */ do_tx = 0; } else { @@ -521,30 +569,41 @@ ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom, ble_hs_lock(); ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (chan == NULL) { - rc = BLE_HS_ENOTCONN; - } else { - if (rc == 0) { - BLE_HS_DBG_ASSERT(txom != NULL); - ble_att_inc_tx_stat(txom->om_data[0]); - rc = ble_l2cap_tx(conn, chan, txom); - txom = NULL; - if (rc != 0) { - err_status = BLE_ATT_ERR_UNLIKELY; - } - } + BLE_HS_DBG_ASSERT(chan != NULL); + if (rc == 0) { + BLE_HS_DBG_ASSERT(om != NULL); + + ble_att_inc_tx_stat(om->om_data[0]); + ble_att_truncate_to_mtu(chan, om); + rc = ble_l2cap_tx(conn, chan, om); + om = NULL; if (rc != 0) { - STATS_INC(ble_att_stats, error_rsp_tx); - ble_att_svr_tx_error_rsp(conn, chan, att_op, + err_status = BLE_ATT_ERR_UNLIKELY; + } + } + + if (rc != 0) { + STATS_INC(ble_att_stats, error_rsp_tx); + + /* Reuse om for error response. */ + if (om == NULL) { + om = ble_hs_mbuf_l2cap_pkt(); + } else { + os_mbuf_adj(om, OS_MBUF_PKTLEN(om)); + } + if (om != NULL) { + ble_att_svr_tx_error_rsp(conn, chan, om, att_op, err_handle, err_status); + om = NULL; } } ble_hs_unlock(); } - os_mbuf_free_chain(txom); + /* Free mbuf if it was not consumed (i.e., if the send failed). */ + os_mbuf_free_chain(om); return rc; } @@ -564,17 +623,11 @@ ble_att_svr_build_mtu_rsp(uint16_t conn_handle, struct os_mbuf **out_txom, txom = NULL; ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, NULL, &chan); - if (rc == 0) { - mtu = chan->blc_my_mtu; - } + ble_att_conn_chan_find(conn_handle, NULL, &chan); + mtu = chan->blc_my_mtu; ble_hs_unlock(); - if (rc != 0) { - goto done; - } - - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; @@ -601,23 +654,24 @@ done: } int -ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om) +ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) { struct ble_att_mtu_cmd cmd; struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; struct os_mbuf *txom; + uint16_t mtu; uint8_t att_err; int rc; txom = NULL; - rc = ble_att_svr_pullup_req_base(om, BLE_ATT_MTU_CMD_SZ, &att_err); + rc = ble_att_svr_pullup_req_base(rxom, BLE_ATT_MTU_CMD_SZ, &att_err); if (rc != 0) { goto done; } - ble_att_mtu_cmd_parse((*om)->om_data, (*om)->om_len, &cmd); + ble_att_mtu_req_parse((*rxom)->om_data, (*rxom)->om_len, &cmd); BLE_ATT_LOG_CMD(0, "mtu req", conn_handle, ble_att_mtu_cmd_log, &cmd); rc = ble_att_svr_build_mtu_rsp(conn_handle, &txom, &att_err); @@ -632,12 +686,15 @@ done: att_err, 0); if (rc == 0) { ble_hs_lock(); + ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (chan != NULL) { - ble_att_set_peer_mtu(chan, cmd.bamc_mtu); - chan->blc_flags |= BLE_L2CAP_CHAN_F_TXED_MTU; - } + ble_att_set_peer_mtu(chan, cmd.bamc_mtu); + chan->blc_flags |= BLE_L2CAP_CHAN_F_TXED_MTU; + mtu = ble_l2cap_chan_mtu(chan); + ble_hs_unlock(); + + ble_gap_mtu_event(conn_handle, BLE_L2CAP_CID_ATT, mtu); } return rc; } @@ -754,12 +811,8 @@ ble_att_svr_build_find_info_rsp(uint16_t conn_handle, txom = NULL; mtu = ble_att_mtu(conn_handle); - if (mtu == 0) { - rc = BLE_HS_ENOTCONN; - goto done; - } - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; @@ -777,8 +830,6 @@ ble_att_svr_build_find_info_rsp(uint16_t conn_handle, } ble_att_find_info_rsp_write(buf, BLE_ATT_FIND_INFO_RSP_BASE_SZ, &rsp); - BLE_ATT_LOG_CMD(1, "find info rsp", conn_handle, ble_att_find_info_rsp_log, - &rsp); /* Write the variable length Information Data field, populating the format * field as appropriate. @@ -790,6 +841,9 @@ ble_att_svr_build_find_info_rsp(uint16_t conn_handle, goto done; } + BLE_ATT_LOG_CMD(1, "find info rsp", conn_handle, ble_att_find_info_rsp_log, + &rsp); + rc = 0; done: @@ -986,8 +1040,9 @@ ble_att_svr_fill_type_value(uint16_t conn_handle, struct os_mbuf *rxom, struct os_mbuf *txom, uint16_t mtu, uint8_t *out_att_err) { - struct ble_att_svr_access_ctxt ctxt; struct ble_att_svr_entry *ha; + uint8_t buf[16]; + uint16_t attr_len; uint16_t uuid16; uint16_t first; uint16_t prev; @@ -1016,13 +1071,13 @@ ble_att_svr_fill_type_value(uint16_t conn_handle, */ uuid16 = ble_uuid_128_to_16(ha->ha_uuid); if (uuid16 == req->bavq_attr_type) { - ctxt.offset = 0; - rc = ble_att_svr_read(conn_handle, ha, &ctxt, out_att_err); + rc = ble_att_svr_read_flat(conn_handle, ha, 0, sizeof buf, buf, + &attr_len, out_att_err); if (rc != 0) { goto done; } - rc = os_mbuf_memcmp(rxom, BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, - ctxt.attr_data, ctxt.data_len); + rc = os_mbuf_cmpf(rxom, BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, + buf, attr_len); if (rc == 0) { match = 1; } @@ -1075,7 +1130,7 @@ ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle, uint8_t *buf; int rc; - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; @@ -1093,10 +1148,6 @@ ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle, /* Write the variable length Information Data field. */ mtu = ble_att_mtu(conn_handle); - if (mtu == 0) { - rc = BLE_HS_ENOTCONN; - goto done; - } rc = ble_att_svr_fill_type_value(conn_handle, req, rxom, txom, mtu, out_att_err); @@ -1179,15 +1230,15 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, 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 attr_len; uint16_t mtu; + uint8_t buf[19]; uint8_t *dptr; int entry_written; int txomlen; int prev_attr_len; - int attr_len; int rc; *att_err = 0; /* Silence unnecessary warning. */ @@ -1197,11 +1248,8 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, prev_attr_len = 0; mtu = ble_att_mtu(conn_handle); - if (mtu == 0) { - return BLE_HS_ENOTCONN; - } - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; *err_handle = 0; @@ -1223,28 +1271,22 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, /* Find all matching attributes, writing a record for each. */ entry = NULL; while (1) { - entry = ble_att_svr_find_by_uuid(entry, uuid128); + entry = ble_att_svr_find_by_uuid(entry, uuid128, req->batq_end_handle); if (entry == NULL) { rc = BLE_HS_ENOENT; break; } - if (entry->ha_handle_id > req->batq_end_handle) { - break; - } - if (entry->ha_handle_id >= req->batq_start_handle) { - ctxt.offset = 0; - rc = ble_att_svr_read(conn_handle, entry, &ctxt, att_err); + rc = ble_att_svr_read_flat(conn_handle, entry, 0, sizeof buf, buf, + &attr_len, att_err); if (rc != 0) { *err_handle = entry->ha_handle_id; goto done; } - if (ctxt.data_len > mtu - 4) { + if (attr_len > mtu - 4) { attr_len = mtu - 4; - } else { - attr_len = ctxt.data_len; } if (prev_attr_len == 0) { @@ -1267,7 +1309,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, } htole16(dptr + 0, entry->ha_handle_id); - memcpy(dptr + 2, ctxt.attr_data, attr_len); + memcpy(dptr + 2, buf, attr_len); entry_written = 1; } } @@ -1335,6 +1377,7 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) BLE_ATT_LOG_CMD(0, "read type req", conn_handle, ble_att_read_type_req_log, &req); + if (req.batq_start_handle > req.batq_end_handle || req.batq_start_handle == 0) { @@ -1381,64 +1424,6 @@ done: return rc; } -/** - * @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 os_mbuf *txom; - uint16_t data_len; - uint16_t mtu; - uint8_t op; - int rc; - - txom = NULL; - - mtu = ble_att_mtu(conn_handle); - if (mtu == 0) { - rc = BLE_HS_ENOTCONN; - goto done; - } - - txom = ble_hs_misc_pkthdr(); - if (txom == NULL) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; - rc = BLE_HS_ENOMEM; - goto done; - } - - op = BLE_ATT_OP_READ_RSP; - rc = os_mbuf_append(txom, &op, 1); - if (rc != 0) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; - rc = BLE_HS_ENOMEM; - goto done; - } - - /* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */ - if (attr_len > mtu - 1) { - data_len = mtu - 1; - } else { - data_len = attr_len; - } - - rc = os_mbuf_append(txom, attr_data, data_len); - if (rc != 0) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; - rc = BLE_HS_ENOMEM; - goto done; - } - - BLE_ATT_LOG_EMPTY_CMD(1, "read rsp", conn_handle); - rc = 0; - -done: - *out_txom = txom; - return rc; -} - int ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) { @@ -1446,11 +1431,11 @@ ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) return BLE_HS_ENOTSUP; #endif - struct ble_att_svr_access_ctxt ctxt; struct ble_att_read_req req; struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; + uint8_t *dptr; int rc; /* Initialize some values in case of early error. */ @@ -1467,74 +1452,31 @@ ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) ble_att_read_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); BLE_ATT_LOG_CMD(0, "read req", conn_handle, ble_att_read_req_log, &req); - ctxt.offset = 0; - rc = ble_att_svr_read_handle(conn_handle, req.barq_handle, &ctxt, - &att_err); - if (rc != 0) { - err_handle = req.barq_handle; - goto done; - } - - rc = ble_att_svr_build_read_rsp(conn_handle, ctxt.attr_data, ctxt.data_len, - &txom, &att_err); - if (rc != 0) { - err_handle = req.barq_handle; - goto done; - } - - rc = 0; - -done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_REQ, - att_err, err_handle); - return rc; -} - -/** - * @return 0 on success; nonzero on failure. - */ -static int -ble_att_svr_build_read_blob_rsp(void *attr_data, int attr_len, uint16_t mtu, - struct os_mbuf **out_txom, uint8_t *att_err) -{ - struct os_mbuf *txom; - uint16_t data_len; - uint8_t op; - int rc; - - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; goto done; } - op = BLE_ATT_OP_READ_BLOB_RSP; - rc = os_mbuf_append(txom, &op, 1); - if (rc != 0) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + dptr = os_mbuf_extend(txom, 1); + if (dptr == NULL) { + att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; goto done; } + *dptr = BLE_ATT_OP_READ_RSP; - /* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */ - if (attr_len > mtu - 1) { - data_len = mtu - 1; - } else { - data_len = attr_len; - } - - rc = os_mbuf_append(txom, attr_data, data_len); + rc = ble_att_svr_read_handle(conn_handle, req.barq_handle, 0, txom, + &att_err); if (rc != 0) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; - rc = BLE_HS_ENOMEM; + err_handle = req.barq_handle; goto done; } - rc = 0; - done: - *out_txom = txom; + rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_REQ, + att_err, err_handle); return rc; } @@ -1545,11 +1487,10 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) return BLE_HS_ENOTSUP; #endif - struct ble_att_svr_access_ctxt ctxt; struct ble_att_read_blob_req req; struct os_mbuf *txom; uint16_t err_handle; - uint16_t mtu; + uint8_t *dptr; uint8_t att_err; int rc; @@ -1558,12 +1499,6 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) att_err = 0; err_handle = 0; - mtu = ble_att_mtu(conn_handle); - if (mtu == 0) { - rc = BLE_HS_ENOTCONN; - goto done; - } - rc = ble_att_svr_pullup_req_base(rxom, BLE_ATT_READ_BLOB_REQ_SZ, &att_err); if (rc != 0) { err_handle = 0; @@ -1574,27 +1509,28 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) BLE_ATT_LOG_CMD(0, "read blob req", conn_handle, ble_att_read_blob_req_log, &req); - ctxt.offset = req.babq_offset; - rc = ble_att_svr_read_handle(conn_handle, req.babq_handle, &ctxt, - &att_err); - if (rc != 0) { - err_handle = req.babq_handle; + txom = ble_hs_mbuf_l2cap_pkt(); + if (txom == NULL) { + att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + rc = BLE_HS_ENOMEM; goto done; } - if (ctxt.offset + ctxt.data_len <= mtu - 3) { - att_err = BLE_ATT_ERR_ATTR_NOT_LONG; - err_handle = req.babq_handle; - rc = BLE_HS_ENOTSUP; + dptr = os_mbuf_extend(txom, 1); + if (dptr == NULL) { + att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + rc = BLE_HS_ENOMEM; goto done; } + *dptr = BLE_ATT_OP_READ_BLOB_RSP; - rc = ble_att_svr_build_read_blob_rsp(ctxt.attr_data, ctxt.data_len, mtu, - &txom, &att_err); + rc = ble_att_svr_read_handle(conn_handle, req.babq_handle, req.babq_offset, + txom, &att_err); if (rc != 0) { err_handle = req.babq_handle; goto done; } + BLE_ATT_LOG_EMPTY_CMD(1, "read blob rsp", conn_handle); rc = 0; @@ -1612,24 +1548,15 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, uint8_t *att_err, uint16_t *err_handle) { - struct ble_att_svr_access_ctxt ctxt; struct os_mbuf *txom; - uint16_t chunk_sz; - uint16_t tx_space; uint16_t handle; uint16_t mtu; uint8_t *dptr; int rc; - txom = NULL; - mtu = ble_att_mtu(conn_handle); - if (mtu == 0) { - rc = BLE_HS_ENOTCONN; - goto done; - } - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; *err_handle = 0; @@ -1646,13 +1573,11 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, } ble_att_read_mult_rsp_write(dptr, BLE_ATT_READ_MULT_RSP_BASE_SZ); - tx_space = mtu - OS_MBUF_PKTLEN(txom); - /* Iterate through requested handles, reading the corresponding attribute * for each. Stop when there are no more handles to process, or the * response is full. */ - while (OS_MBUF_PKTLEN(*rxom) >= 2 && tx_space > 0) { + while (OS_MBUF_PKTLEN(*rxom) >= 2 && OS_MBUF_PKTLEN(txom) < mtu) { /* Ensure the full 16-bit handle is contiguous at the start of the * mbuf. */ @@ -1668,28 +1593,11 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, handle = le16toh((*rxom)->om_data); os_mbuf_adj(*rxom, 2); - ctxt.offset = 0; - rc = ble_att_svr_read_handle(conn_handle, handle, &ctxt, att_err); + rc = ble_att_svr_read_handle(conn_handle, handle, 0, txom, att_err); if (rc != 0) { *err_handle = handle; goto done; } - - if (ctxt.data_len > tx_space) { - chunk_sz = tx_space; - } else { - chunk_sz = ctxt.data_len; - } - - rc = os_mbuf_append(txom, ctxt.attr_data, chunk_sz); - if (rc != 0) { - *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; - *err_handle = handle; - rc = BLE_HS_ENOMEM; - goto done; - } - - tx_space -= chunk_sz; } BLE_ATT_LOG_EMPTY_CMD(1, "read mult rsp", conn_handle); @@ -1760,23 +1668,22 @@ static int ble_att_svr_service_uuid(struct ble_att_svr_entry *entry, uint16_t *uuid16, uint8_t *uuid128) { - struct ble_att_svr_access_ctxt ctxt; + uint16_t attr_len; int rc; - ctxt.offset = 0; - rc = ble_att_svr_read(BLE_HS_CONN_HANDLE_NONE, entry, &ctxt, NULL); + rc = ble_att_svr_read_flat(BLE_HS_CONN_HANDLE_NONE, entry, 0, 16, uuid128, + &attr_len, NULL); if (rc != 0) { return rc; } - switch (ctxt.data_len) { + switch (attr_len) { case 16: *uuid16 = 0; - memcpy(uuid128, ctxt.attr_data, 16); return 0; case 2: - *uuid16 = le16toh(ctxt.attr_data); + *uuid16 = le16toh(uuid128); if (*uuid16 == 0) { return BLE_HS_EINVAL; } @@ -1852,15 +1759,9 @@ ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle, *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_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; @@ -2091,7 +1992,7 @@ ble_att_svr_build_write_rsp(struct os_mbuf **out_txom, uint8_t *att_err) uint8_t *dst; int rc; - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; @@ -2121,7 +2022,6 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) return BLE_HS_ENOTSUP; #endif - struct ble_att_svr_access_ctxt ctxt; struct ble_att_write_req req; struct os_mbuf *txom; uint16_t err_handle; @@ -2147,10 +2047,7 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) /* Strip the request base from the front of the mbuf. */ os_mbuf_adj(*rxom, BLE_ATT_WRITE_REQ_BASE_SZ); - ctxt.attr_data = ble_att_get_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_handle(conn_handle, req.bawq_handle, &ctxt, + rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, 0, rxom, &att_err); if (rc != 0) { err_handle = req.bawq_handle; @@ -2179,7 +2076,6 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom) return BLE_HS_ENOTSUP; #endif - struct ble_att_svr_access_ctxt ctxt; struct ble_att_write_req req; uint8_t att_err; int rc; @@ -2197,10 +2093,7 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom) /* Strip the request base from the front of the mbuf. */ os_mbuf_adj(*rxom, BLE_ATT_WRITE_REQ_BASE_SZ); - ctxt.attr_data = ble_att_get_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_handle(conn_handle, req.bawq_handle, &ctxt, + rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, 0, rxom, &att_err); if (rc != 0) { return rc; @@ -2209,18 +2102,31 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom) return 0; } +/** + * Writes a locally registered attribute. This function consumes the supplied + * mbuf regardless of the outcome. If the specified attribute handle + * coresponds to a GATT characteristic value or descriptor, the write is + * performed by calling the registered GATT access callback. + * + * @param attr_handle The 16-bit handle of the attribute to write. + * @param om The value to write to the attribute. + * + * @return 0 on success; + * NimBLE host ATT return code if the attribute + * access callback reports failure; + * NimBLE host core return code on unexpected + * error. + */ int -ble_att_svr_write_local(uint16_t attr_handle, void *data, uint16_t data_len) +ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf *om) { - struct ble_att_svr_access_ctxt ctxt; int rc; - ctxt.attr_data = data; - ctxt.data_len = data_len; - ctxt.offset = 0; + rc = ble_att_svr_write_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, 0, + &om, NULL); - rc = ble_att_svr_write_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, &ctxt, - NULL); + /* Free the mbuf if it wasn't relinquished to the application. */ + os_mbuf_free_chain(om); return rc; } @@ -2228,8 +2134,10 @@ ble_att_svr_write_local(uint16_t attr_handle, void *data, uint16_t data_len) static void ble_att_svr_prep_free(struct ble_att_prep_entry *entry) { - os_mbuf_free_chain(entry->bape_value); - os_memblock_put(&ble_att_svr_prep_entry_pool, entry); + if (entry != NULL) { + os_mbuf_free_chain(entry->bape_value); + os_memblock_put(&ble_att_svr_prep_entry_pool, entry); + } } static struct ble_att_prep_entry * @@ -2243,7 +2151,7 @@ ble_att_svr_prep_alloc(void) } memset(entry, 0, sizeof *entry); - entry->bape_value = ble_hs_misc_pkthdr(); + entry->bape_value = ble_hs_mbuf_l2cap_pkt(); if (entry->bape_value == NULL) { ble_att_svr_prep_free(entry); return NULL; @@ -2327,6 +2235,42 @@ ble_att_svr_prep_validate(struct ble_att_prep_entry_list *prep_list, return 0; } +static void +ble_att_svr_prep_extract(struct ble_att_prep_entry_list *prep_list, + uint16_t *out_attr_handle, + struct os_mbuf **out_om) +{ + struct ble_att_prep_entry *entry; + struct ble_att_prep_entry *first; + struct os_mbuf *om; + uint16_t attr_handle; + + BLE_HS_DBG_ASSERT(!SLIST_EMPTY(prep_list)); + + first = SLIST_FIRST(prep_list); + attr_handle = first->bape_handle; + om = NULL; + + while ((entry = SLIST_FIRST(prep_list)) != NULL) { + if (entry->bape_handle != attr_handle) { + break; + } + + if (om == NULL) { + om = entry->bape_value; + } else { + os_mbuf_concat(om, entry->bape_value); + } + entry->bape_value = NULL; + + SLIST_REMOVE_HEAD(prep_list, bape_next); + ble_att_svr_prep_free(entry); + } + + *out_attr_handle = attr_handle; + *out_om = om; +} + /** * @return 0 on success; ATT error code on failure. */ @@ -2335,13 +2279,10 @@ ble_att_svr_prep_write(uint16_t conn_handle, struct ble_att_prep_entry_list *prep_list, uint16_t *err_handle) { - struct ble_att_svr_access_ctxt ctxt; - struct ble_att_prep_entry *entry; - struct ble_att_prep_entry *next; struct ble_att_svr_entry *attr; - uint8_t *flat_buf; + struct os_mbuf *om; + uint16_t attr_handle; uint8_t att_err; - int buf_off; int rc; *err_handle = 0; /* Silence unnecessary warning. */ @@ -2352,40 +2293,68 @@ ble_att_svr_prep_write(uint16_t conn_handle, return rc; } - flat_buf = ble_att_get_flat_buf(); - /* Contents are valid; perform the writes. */ - buf_off = 0; - entry = SLIST_FIRST(prep_list); - while (entry != NULL) { - next = SLIST_NEXT(entry, bape_next); - - rc = os_mbuf_copydata(entry->bape_value, 0, - OS_MBUF_PKTLEN(entry->bape_value), - flat_buf + buf_off); - BLE_HS_DBG_ASSERT_EVAL(rc == 0); - buf_off += OS_MBUF_PKTLEN(entry->bape_value); - - /* If this is the last entry for this attribute, perform the write. */ - if (next == NULL || entry->bape_handle != next->bape_handle) { - attr = ble_att_svr_find_by_handle(entry->bape_handle); - if (attr == NULL) { - *err_handle = entry->bape_handle; - return BLE_ATT_ERR_INVALID_HANDLE; - } + while (!SLIST_EMPTY(prep_list)) { + ble_att_svr_prep_extract(prep_list, &attr_handle, &om); - ctxt.attr_data = flat_buf; - ctxt.data_len = buf_off; - rc = ble_att_svr_write(conn_handle, attr, &ctxt, &att_err); - if (rc != 0) { - *err_handle = entry->bape_handle; - return att_err; - } + /* Attribute existence was verified during prepare-write request + * processing. + */ + attr = ble_att_svr_find_by_handle(attr_handle); + BLE_HS_DBG_ASSERT(attr != NULL); - buf_off = 0; + rc = ble_att_svr_write(conn_handle, attr, 0, &om, &att_err); + os_mbuf_free_chain(om); + if (rc != 0) { + *err_handle = attr_handle; + return att_err; } + } + + return 0; +} - entry = next; +static int +ble_att_svr_insert_prep_entry(uint16_t conn_handle, + const struct ble_att_prep_write_cmd *req, + const struct os_mbuf *rxom, + uint8_t *out_att_err) +{ + struct ble_att_prep_entry *prep_entry; + struct ble_att_prep_entry *prep_prev; + struct ble_hs_conn *conn; + int rc; + + conn = ble_hs_conn_find_assert(conn_handle); + + prep_entry = ble_att_svr_prep_alloc(); + if (prep_entry == NULL) { + *out_att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL; + return BLE_HS_ENOMEM; + } + prep_entry->bape_handle = req->bapc_handle; + prep_entry->bape_offset = req->bapc_offset; + + /* Append attribute value from request onto prep mbuf. */ + rc = os_mbuf_appendfrom( + prep_entry->bape_value, + rxom, + BLE_ATT_PREP_WRITE_CMD_BASE_SZ, + OS_MBUF_PKTLEN(rxom) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + if (rc != 0) { + ble_att_svr_prep_free(prep_entry); + *out_att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL; + return rc; + } + + 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); } return 0; @@ -2399,18 +2368,13 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) #endif 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; uint8_t att_err; int rc; /* Initialize some values in case of early error. */ - prep_entry = NULL; txom = NULL; att_err = 0; err_handle = 0; @@ -2425,115 +2389,55 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) ble_att_prep_write_req_parse((*rxom)->om_data, (*rxom)->om_len, &req); BLE_ATT_LOG_CMD(0, "prep write req", conn_handle, ble_att_prep_write_cmd_log, &req); - - /* Strip the request base from the front of the mbuf. */ - os_mbuf_adj(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + err_handle = req.bapc_handle; attr_entry = ble_att_svr_find_by_handle(req.bapc_handle); + + /* A prepare write request gets rejected for the following reasons: + * 1. Insufficient authorization. + * 2. Insufficient authentication. + * 3. Insufficient encryption key size (XXX: Not checked). + * 4. Insufficient encryption (XXX: Not checked). + * 5. Invalid handle. + * 6. Write not permitted. + */ + + /* <5> */ if (attr_entry == NULL) { rc = BLE_HS_ENOENT; att_err = BLE_ATT_ERR_INVALID_HANDLE; - err_handle = req.bapc_handle; goto done; } - prep_entry = ble_att_svr_prep_alloc(); - if (prep_entry == NULL) { - att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL; - err_handle = req.bapc_handle; - rc = BLE_HS_ENOMEM; + /* <1>, <2>, <4>, <6> */ + rc = ble_att_svr_check_perms(conn_handle, 0, attr_entry, &att_err); + if (rc != 0) { goto done; } - prep_entry->bape_handle = req.bapc_handle; - prep_entry->bape_offset = req.bapc_offset; ble_hs_lock(); - - conn = ble_hs_conn_find(conn_handle); - if (conn == NULL) { - rc = BLE_HS_ENOTCONN; - } else { - 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; - break; - } - } - } - + rc = ble_att_svr_insert_prep_entry(conn_handle, &req, *rxom, &att_err); ble_hs_unlock(); if (rc != 0) { goto done; } - /* The receive buffer now contains the attribute value. Repurpose this - * buffer for the response. Prepend a response header. + /* Reuse rxom for response. Response is identical to request except for + * op code. */ - *rxom = os_mbuf_prepend(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); - if (*rxom == NULL) { - att_err = BLE_ATT_ERR_INSUFFICIENT_RES; - err_handle = req.bapc_handle; - rc = BLE_HS_ENOMEM; - goto done; - } txom = *rxom; + *rxom = NULL; + txom->om_data[0] = BLE_ATT_OP_PREP_WRITE_RSP; - ble_att_prep_write_rsp_write(txom->om_data, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, - &req); BLE_ATT_LOG_CMD(1, "prep write rsp", conn_handle, ble_att_prep_write_cmd_log, &req); rc = 0; done: - if (rc != 0 && rc != BLE_HS_ENOTCONN) { - ble_hs_lock(); - - conn = ble_hs_conn_find(conn_handle); - if (conn == NULL) { - rc = BLE_HS_ENOTCONN; - } else { - 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_att_svr_prep_free(prep_entry); - } - } - - ble_hs_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; } @@ -2547,7 +2451,7 @@ ble_att_svr_build_exec_write_rsp(struct os_mbuf **out_txom, uint8_t *att_err) uint8_t *dst; int rc; - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; rc = BLE_HS_ENOMEM; @@ -2610,33 +2514,28 @@ ble_att_svr_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom) done: if (rc == 0) { ble_hs_lock(); - conn = ble_hs_conn_find(conn_handle); - if (conn == NULL) { - rc = BLE_HS_ENOTCONN; - } else { - /* Extract the list of prepared writes from the connection so - * that they can be processed after the mutex is unlocked. They - * aren't processed now because attribute writes involve executing - * an application callback. - */ - prep_list = conn->bhc_att_svr.basc_prep_list; - SLIST_INIT(&conn->bhc_att_svr.basc_prep_list); - } + conn = ble_hs_conn_find_assert(conn_handle); + + /* Extract the list of prepared writes from the connection so + * that they can be processed after the mutex is unlocked. They + * aren't processed now because attribute writes involve executing + * an application callback. + */ + prep_list = conn->bhc_att_svr.basc_prep_list; + SLIST_INIT(&conn->bhc_att_svr.basc_prep_list); ble_hs_unlock(); - if (conn != NULL) { - if (req.baeq_flags & BLE_ATT_EXEC_WRITE_F_CONFIRM) { - /* Perform attribute writes. */ - att_err = ble_att_svr_prep_write(conn_handle, &prep_list, - &err_handle); - if (att_err != 0) { - rc = BLE_HS_EAPP; - } + if (req.baeq_flags & BLE_ATT_EXEC_WRITE_F_CONFIRM) { + /* Perform attribute writes. */ + att_err = ble_att_svr_prep_write(conn_handle, &prep_list, + &err_handle); + if (att_err != 0) { + rc = BLE_HS_EAPP; } - - /* Free the prep entries. */ - ble_att_svr_prep_clear(&prep_list); } + + /* Free the prep entries. */ + ble_att_svr_prep_clear(&prep_list); } rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_EXEC_WRITE_REQ, @@ -2652,8 +2551,6 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom) #endif struct ble_att_notify_req req; - uint16_t attr_len; - void *attr_data; int rc; if (OS_MBUF_PKTLEN(*rxom) < BLE_ATT_NOTIFY_REQ_BASE_SZ) { @@ -2676,11 +2573,8 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom) /* Strip the request base from the front of the mbuf. */ os_mbuf_adj(*rxom, BLE_ATT_NOTIFY_REQ_BASE_SZ); - attr_data = ble_att_get_flat_buf(); - attr_len = OS_MBUF_PKTLEN(*rxom); - os_mbuf_copydata(*rxom, 0, attr_len, attr_data); - - ble_gap_notify_event(conn_handle, req.banq_handle, attr_data, attr_len, 0); + ble_gap_notify_rx_event(conn_handle, req.banq_handle, *rxom, 0); + *rxom = NULL; return 0; } @@ -2695,7 +2589,7 @@ ble_att_svr_build_indicate_rsp(struct os_mbuf **out_txom) uint8_t *dst; int rc; - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { rc = BLE_HS_ENOMEM; goto done; @@ -2725,8 +2619,6 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom) struct ble_att_indicate_req req; struct os_mbuf *txom; - uint16_t attr_len; - void *attr_data; int rc; /* Initialize some values in case of early error. */ @@ -2754,11 +2646,8 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom) /* Strip the request base from the front of the mbuf. */ os_mbuf_adj(*rxom, BLE_ATT_INDICATE_REQ_BASE_SZ); - attr_data = ble_att_get_flat_buf(); - attr_len = OS_MBUF_PKTLEN(*rxom); - os_mbuf_copydata(*rxom, 0, attr_len, attr_data); - - ble_gap_notify_event(conn_handle, req.baiq_handle, attr_data, attr_len, 1); + ble_gap_notify_rx_event(conn_handle, req.baiq_handle, *rxom, 1); + *rxom = NULL; rc = ble_att_svr_build_indicate_rsp(&txom); if (rc != 0) { diff --git a/net/nimble/host/src/ble_eddystone.c b/net/nimble/host/src/ble_eddystone.c index dbd8a716..2ca496f6 100644 --- a/net/nimble/host/src/ble_eddystone.c +++ b/net/nimble/host/src/ble_eddystone.c @@ -19,6 +19,7 @@ #include <string.h> #include "host/ble_eddystone.h" +#include "host/ble_hs_adv.h" #include "ble_hs_priv.h" #define BLE_EDDYSTONE_MAX_SVC_DATA_LEN 23 @@ -112,7 +113,11 @@ ble_eddystone_set_adv_data_gen(struct ble_hs_adv_fields *adv_fields, * this struct before calling this function. * @param uid The 16-byte UID to advertise. * - * @return 0 on success; BLE_HS_E... on failure. + * @return 0 on success; + * BLE_HS_EBUSY if advertising is in progress; + * BLE_HS_EMSGSIZE if the specified data is too + * large to fit in an advertisement; + * Other nonzero on failure. */ int ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields, void *uid) @@ -151,7 +156,11 @@ ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields, void *uid) * BLE_EDDYSTONE_URL_SUFFIX_NONE if the suffix * is embedded in the body argument. * - * @return 0 on success; BLE_HS_E... on failure. + * @return 0 on success; + * BLE_HS_EBUSY if advertising is in progress; + * BLE_HS_EMSGSIZE if the specified data is too + * large to fit in an advertisement; + * Other nonzero on failure. */ int ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields, @@ -177,7 +186,7 @@ ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields, svc_data = ble_eddystone_set_svc_data_base(BLE_EDDYSTONE_FRAME_TYPE_URL); - rc = ble_hci_util_read_adv_tx_pwr(&tx_pwr); + rc = ble_hs_hci_util_read_adv_tx_pwr(&tx_pwr); if (rc != 0) { return rc; } diff --git a/net/nimble/host/src/ble_gap.c b/net/nimble/host/src/ble_gap.c index 309b7cf1..f53a7385 100644 --- a/net/nimble/host/src/ble_gap.c +++ b/net/nimble/host/src/ble_gap.c @@ -23,7 +23,7 @@ #include "bsp/bsp.h" #include "os/os.h" #include "nimble/nimble_opt.h" -#include "host/host_hci.h" +#include "host/ble_hs_adv.h" #include "ble_hs_priv.h" /** @@ -65,18 +65,20 @@ #define BLE_GAP_OP_S_ADV 1 /** + * If an attempt to cancel an active procedure fails, the attempt is retried + * at this rate (ms). + */ +#define BLE_GAP_CANCEL_RETRY_RATE 100 /* ms */ + +/** * The maximum amount of user data that can be put into the advertising data. - * The stack may automatically insert some fields on its own, limiting the - * maximum amount of user data. The following fields are automatically - * inserted: - * o Flags (3 bytes) - * o Tx-power-level (3 bytes) - Only if the application specified a - * tx_pwr_llvl_present value of 1 in a call to ble_gap_set_adv_data(). + * The stack will automatically insert the flags field on its own if requested + * by the application, limiting the maximum amount of user data. */ -#define BLE_GAP_ADV_DATA_LIMIT_PWR (BLE_HCI_MAX_ADV_DATA_LEN - 6) -#define BLE_GAP_ADV_DATA_LIMIT_NO_PWR (BLE_HCI_MAX_ADV_DATA_LEN - 3) +#define BLE_GAP_ADV_DATA_LIMIT_FLAGS (BLE_HCI_MAX_ADV_DATA_LEN - 3) +#define BLE_GAP_ADV_DATA_LIMIT_NO_FLAGS BLE_HCI_MAX_ADV_DATA_LEN -static const struct ble_gap_crt_params ble_gap_params_dflt = { +static const struct ble_gap_conn_params ble_gap_conn_params_dflt = { .scan_itvl = 0x0010, .scan_window = 0x0010, .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN, @@ -87,41 +89,33 @@ static const struct ble_gap_crt_params ble_gap_params_dflt = { .max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN, }; -static const struct ble_gap_adv_params ble_gap_adv_params_dflt = { - .adv_itvl_min = 0, - .adv_itvl_max = 0, - .adv_type = BLE_HCI_ADV_TYPE_ADV_IND, - .own_addr_type = BLE_HCI_ADV_OWN_ADDR_PUBLIC, - .adv_channel_map = BLE_HCI_ADV_CHANMASK_DEF, - .adv_filter_policy = BLE_HCI_ADV_FILT_DEF, -}; - /** * The state of the in-progress master connection. If no master connection is * currently in progress, then the op field is set to BLE_GAP_OP_NULL. */ -static bssnz_t struct { +struct ble_gap_master_state { uint8_t op; - unsigned exp_set:1; + uint8_t exp_set:1; os_time_t exp_os_ticks; + ble_gap_event_fn *cb; + void *cb_arg; + union { - struct { - ble_gap_event_fn *cb; - void *cb_arg; - unsigned using_wl:1; - unsigned our_addr_type:2; + struct { + uint8_t using_wl:1; + uint8_t our_addr_type:2; + uint8_t cancel:1; } conn; struct { - uint8_t disc_mode; - ble_gap_disc_fn *cb; - void *cb_arg; + uint8_t limited:1; } disc; }; -} ble_gap_master; +}; +static bssnz_t struct ble_gap_master_state ble_gap_master; /** * The state of the in-progress slave connection. If no slave connection is @@ -130,6 +124,9 @@ static bssnz_t struct { static bssnz_t struct { uint8_t op; + unsigned exp_set:1; + os_time_t exp_os_ticks; + uint8_t conn_mode; uint8_t disc_mode; unsigned our_addr_type:2; @@ -140,15 +137,16 @@ static bssnz_t struct { uint8_t rsp_data[BLE_HCI_MAX_ADV_DATA_LEN]; uint8_t adv_data_len; uint8_t rsp_data_len; - int8_t tx_pwr_lvl; - unsigned adv_pwr_lvl:1; + unsigned adv_auto_flags:1; } ble_gap_slave; -static int ble_gap_disc_tx_disable(void); +static int ble_gap_adv_enable_tx(int enable); +static int ble_gap_conn_cancel_tx(void); +static int ble_gap_disc_enable_tx(int enable, int filter_duplicates); struct ble_gap_snapshot { - struct ble_gap_conn_desc desc; + struct ble_gap_conn_desc *desc; ble_gap_event_fn *cb; void *cb_arg; }; @@ -184,6 +182,8 @@ STATS_NAME_START(ble_gap_stats) STATS_NAME(ble_gap_stats, rx_conn_complete) STATS_NAME(ble_gap_stats, discover_cancel) STATS_NAME(ble_gap_stats, discover_cancel_fail) + STATS_NAME(ble_gap_stats, security_initiate) + STATS_NAME(ble_gap_stats, security_initiate_fail) STATS_NAME_END(ble_gap_stats) /***************************************************************************** @@ -191,34 +191,49 @@ STATS_NAME_END(ble_gap_stats) *****************************************************************************/ static void -ble_gap_log_conn(uint8_t addr_type, uint8_t *addr, - struct ble_gap_crt_params *params) +ble_gap_log_duration(int32_t duration_ms) +{ + if (duration_ms == BLE_HS_FOREVER) { + BLE_HS_LOG(INFO, "duration=forever"); + } else { + BLE_HS_LOG(INFO, "duration=%dms", duration_ms); + } +} + +static void +ble_gap_log_conn(uint8_t own_addr_type, + uint8_t peer_addr_type, const uint8_t *peer_addr, + const struct ble_gap_conn_params *params) { - BLE_HS_LOG(INFO, "addr_type=%d addr=", addr_type); - if (addr == NULL) { + BLE_HS_LOG(INFO, "peer_addr_type=%d peer_addr=", peer_addr_type); + if (peer_addr == NULL) { BLE_HS_LOG(INFO, "N/A"); } else { - BLE_HS_LOG_ADDR(INFO, addr); + BLE_HS_LOG_ADDR(INFO, peer_addr); } BLE_HS_LOG(INFO, " scan_itvl=%d scan_window=%d itvl_min=%d itvl_max=%d " "latency=%d supervision_timeout=%d min_ce_len=%d " - "max_ce_len=%d our_addr_type=%d", + "max_ce_len=%d own_addr_type=%d", params->scan_itvl, params->scan_window, params->itvl_min, params->itvl_max, params->latency, params->supervision_timeout, - params->min_ce_len, params->max_ce_len, params->our_addr_type); + params->min_ce_len, params->max_ce_len, own_addr_type); } static void -ble_gap_log_disc(uint8_t scan_type, uint8_t filter_policy, uint8_t addr_mode) +ble_gap_log_disc(uint8_t own_addr_type, int32_t duration_ms, + const struct ble_gap_disc_params *disc_params) { - BLE_HS_LOG(INFO, "disc_mode=%d filter_policy=%d scan_type=%d addr_node %d", - ble_gap_master.disc.disc_mode, - filter_policy, scan_type, addr_mode); + BLE_HS_LOG(INFO, "own_addr_type=%d filter_policy=%d passive=%d limited=%d " + "filter_duplicates=%d ", + own_addr_type, disc_params->filter_policy, disc_params->passive, + disc_params->limited, disc_params->filter_duplicates); + ble_gap_log_duration(duration_ms); } static void -ble_gap_log_update(uint16_t conn_handle, struct ble_gap_upd_params *params) +ble_gap_log_update(uint16_t conn_handle, + const struct ble_gap_upd_params *params) { BLE_HS_LOG(INFO, "connection parameter update; " "conn_handle=%d itvl_min=%d itvl_max=%d latency=%d " @@ -229,10 +244,10 @@ ble_gap_log_update(uint16_t conn_handle, struct ble_gap_upd_params *params) } static void -ble_gap_log_wl(struct ble_gap_white_entry *white_list, +ble_gap_log_wl(const struct ble_gap_white_entry *white_list, uint8_t white_list_count) { - struct ble_gap_white_entry *entry; + const struct ble_gap_white_entry *entry; int i; BLE_HS_LOG(INFO, "count=%d ", white_list_count); @@ -247,25 +262,25 @@ ble_gap_log_wl(struct ble_gap_white_entry *white_list, } static void -ble_gap_log_adv(const struct ble_gap_adv_params *adv_params, - uint8_t *peer_addr, uint8_t peer_addr_type) +ble_gap_log_adv(uint8_t own_addr_type, uint8_t peer_addr_type, + const uint8_t *peer_addr, + const struct ble_gap_adv_params *adv_params) { - BLE_HS_LOG(INFO, "disc_mode=%d addr_type=%d addr=", + BLE_HS_LOG(INFO, "disc_mode=%d peer_addr_type=%d peer_addr=", ble_gap_slave.disc_mode, peer_addr_type); if(peer_addr) { BLE_HS_LOG_ADDR(INFO, peer_addr); } else { BLE_HS_LOG(INFO, "none"); } - BLE_HS_LOG(INFO, " adv_type=%d adv_channel_map=%d own_addr_type=%d " + BLE_HS_LOG(INFO, " adv_channel_map=%d own_addr_type=%d " "adv_filter_policy=%d adv_itvl_min=%d adv_itvl_max=%d " "adv_data_len=%d", - adv_params->adv_type, - adv_params->adv_channel_map, - adv_params->own_addr_type, - adv_params->adv_filter_policy, - adv_params->adv_itvl_min, - adv_params->adv_itvl_max, + adv_params->channel_map, + own_addr_type, + adv_params->filter_policy, + adv_params->itvl_min, + adv_params->itvl_max, ble_gap_slave.adv_data_len); } @@ -294,14 +309,21 @@ ble_gap_fill_conn_desc(struct ble_hs_conn *conn, desc->conn_itvl = conn->bhc_itvl; desc->conn_latency = conn->bhc_latency; desc->supervision_timeout = conn->bhc_supervision_timeout; + desc->master_clock_accuracy = conn->bhc_master_clock_accuracy; desc->sec_state = conn->bhc_sec_state; + + if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { + desc->role = BLE_GAP_ROLE_MASTER; + } else { + desc->role = BLE_GAP_ROLE_SLAVE; + } } static void ble_gap_conn_to_snapshot(struct ble_hs_conn *conn, struct ble_gap_snapshot *snap) { - ble_gap_fill_conn_desc(conn, &snap->desc); + ble_gap_fill_conn_desc(conn, snap->desc); snap->cb = conn->bhc_cb; snap->cb_arg = conn->bhc_cb_arg; } @@ -341,7 +363,7 @@ ble_gap_find_snapshot(uint16_t handle, struct ble_gap_snapshot *snap) * connection was found. */ int -ble_gap_find_conn(uint16_t handle, struct ble_gap_conn_desc *out_desc) +ble_gap_conn_find(uint16_t handle, struct ble_gap_conn_desc *out_desc) { struct ble_hs_conn *conn; @@ -361,12 +383,40 @@ ble_gap_find_conn(uint16_t handle, struct ble_gap_conn_desc *out_desc) } } +static int +ble_gap_extract_conn_cb(uint16_t conn_handle, + ble_gap_event_fn **out_cb, void **out_cb_arg) +{ + const struct ble_hs_conn *conn; + + BLE_HS_DBG_ASSERT(conn_handle != 0); + + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + if (conn != NULL) { + *out_cb = conn->bhc_cb; + *out_cb_arg = conn->bhc_cb_arg; + } else { + *out_cb = NULL; + *out_cb_arg = NULL; + } + + ble_hs_unlock(); + + if (conn == NULL) { + return BLE_HS_ENOTCONN; + } else { + return 0; + } +} + /***************************************************************************** * $misc * *****************************************************************************/ static int -ble_gap_call_event_cb(int event, struct ble_gap_conn_ctxt *ctxt, +ble_gap_call_event_cb(struct ble_gap_event *event, ble_gap_event_fn *cb, void *cb_arg) { int rc; @@ -374,12 +424,12 @@ ble_gap_call_event_cb(int event, struct ble_gap_conn_ctxt *ctxt, BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); if (cb != NULL) { - rc = cb(event, ctxt, cb_arg); + rc = cb(event, cb_arg); } else { - if (event == BLE_GAP_EVENT_CONN_UPDATE_REQ) { + if (event->type == BLE_GAP_EVENT_CONN_UPDATE_REQ) { /* Just copy peer parameters back into the reply. */ - *ctxt->conn_update_req.self_params = - *ctxt->conn_update_req.peer_params; + *event->conn_update_req.self_params = + *event->conn_update_req.peer_params; } rc = 0; } @@ -387,34 +437,25 @@ ble_gap_call_event_cb(int event, struct ble_gap_conn_ctxt *ctxt, return rc; } -static void -ble_gap_slave_extract_cb(ble_gap_event_fn **out_cb, void **out_cb_arg) -{ - ble_hs_lock(); - - *out_cb = ble_gap_slave.cb; - *out_cb_arg = ble_gap_slave.cb_arg; - ble_gap_slave.op = BLE_GAP_OP_NULL; - ble_hs_unlock(); -} - -static void -ble_gap_adv_finished(int event) +static int +ble_gap_call_conn_event_cb(struct ble_gap_event *event, uint16_t conn_handle) { - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_conn_desc desc; ble_gap_event_fn *cb; void *cb_arg; + int rc; - ble_gap_slave_extract_cb(&cb, &cb_arg); - if (cb != NULL) { - memset(&ctxt, 0, sizeof ctxt); - desc.conn_handle = BLE_HS_CONN_HANDLE_NONE; - ctxt.desc = &desc; + rc = ble_gap_extract_conn_cb(conn_handle, &cb, &cb_arg); + if (rc != 0) { + return rc; + } - cb(event, &ctxt, cb_arg); + rc = ble_gap_call_event_cb(event, cb, cb_arg); + if (rc != 0) { + return rc; } + + return 0; } static void @@ -422,63 +463,73 @@ ble_gap_master_reset_state(void) { ble_gap_master.op = BLE_GAP_OP_NULL; ble_gap_master.exp_set = 0; + ble_gap_master.conn.cancel = 0; +} + +static void +ble_gap_slave_reset_state(void) +{ + ble_gap_slave.op = BLE_GAP_OP_NULL; + ble_gap_slave.exp_set = 0; } static void -ble_gap_master_extract_cb(ble_gap_event_fn **out_cb, void **out_cb_arg) +ble_gap_master_extract_state(struct ble_gap_master_state *out_state, + int reset_state) { ble_hs_lock(); - *out_cb = ble_gap_master.conn.cb; - *out_cb_arg = ble_gap_master.conn.cb_arg; - ble_gap_master_reset_state(); + *out_state = ble_gap_master; + + if (reset_state) { + ble_gap_master_reset_state(); + } ble_hs_unlock(); } -static int -ble_gap_master_connect_failure(int status) +static void +ble_gap_slave_extract_cb(ble_gap_event_fn **out_cb, void **out_cb_arg) { - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_conn_desc desc; + ble_hs_lock(); + + *out_cb = ble_gap_slave.cb; + *out_cb_arg = ble_gap_slave.cb_arg; + ble_gap_slave_reset_state(); + + ble_hs_unlock(); +} + +static void +ble_gap_adv_finished(void) +{ + struct ble_gap_event event; ble_gap_event_fn *cb; void *cb_arg; - int rc; - - memset(&desc, 0, sizeof ctxt); - ble_gap_master_extract_cb(&cb, &cb_arg); + ble_gap_slave_extract_cb(&cb, &cb_arg); if (cb != NULL) { - memset(&ctxt, 0, sizeof ctxt); - desc.conn_handle = BLE_HS_CONN_HANDLE_NONE; - ctxt.desc = &desc; - ctxt.connect.status = status; + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_ADV_COMPLETE; - rc = cb(BLE_GAP_EVENT_CONNECT, &ctxt, cb_arg); - } else { - rc = 0; + cb(&event, cb_arg); } - - return rc; } static int -ble_gap_master_connect_cancel(void) +ble_gap_master_connect_failure(int status) { - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_conn_desc desc; - ble_gap_event_fn *cb; - void *cb_arg; + struct ble_gap_master_state state; + struct ble_gap_event event; int rc; - memset(&desc, 0, sizeof ctxt); - desc.conn_handle = BLE_HS_CONN_HANDLE_NONE; + ble_gap_master_extract_state(&state, 1); + if (state.cb != NULL) { + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_CONNECT; + event.connect.status = status; - ble_gap_master_extract_cb(&cb, &cb_arg); - if (cb != NULL) { - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &desc; - rc = cb(BLE_GAP_EVENT_CONN_CANCEL, &ctxt, cb_arg); + rc = state.cb(&event, state.cb_arg); } else { rc = 0; } @@ -487,58 +538,128 @@ ble_gap_master_connect_cancel(void) } static void -ble_gap_call_master_disc_cb(int event, int status, struct ble_hs_adv *adv, - struct ble_hs_adv_fields *fields, int reset_state) +ble_gap_master_connect_cancelled(void) { - struct ble_gap_disc_desc desc; - ble_gap_disc_fn *cb; - void *cb_arg; + struct ble_gap_master_state state; + struct ble_gap_event event; - ble_hs_lock(); + ble_gap_master_extract_state(&state, 1); + if (state.cb != NULL) { + /* The GAP event type depends on whether 1) the application manually + * cancelled the connect procedure or 2) the connect procedure timed + * out. + */ + memset(&event, 0, sizeof event); + if (state.conn.cancel) { + event.type = BLE_GAP_EVENT_CONN_CANCEL; + } else { + event.type = BLE_GAP_EVENT_CONNECT; + event.connect.status = BLE_HS_ETIMEOUT; + event.connect.conn_handle = BLE_HS_CONN_HANDLE_NONE; - if (adv != NULL) { - desc.event_type = adv->event_type; - desc.addr_type = adv->addr_type; - desc.length_data = adv->length_data; - desc.rssi = adv->rssi; - memcpy(desc.addr, adv->addr, sizeof adv->addr); - desc.data = adv->data; - desc.fields = fields; - } else { - memset(&desc, 0, sizeof desc); + } + state.cb(&event, state.cb_arg); } +} - cb = ble_gap_master.disc.cb; - cb_arg = ble_gap_master.disc.cb_arg; +static void +ble_gap_disc_report(struct ble_gap_disc_desc *desc) +{ + struct ble_gap_master_state state; + struct ble_gap_event event; - if (reset_state) { - ble_gap_master_reset_state(); + ble_gap_master_extract_state(&state, 0); + + if (state.cb != NULL) { + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_DISC; + event.disc = *desc; + + state.cb(&event, state.cb_arg); } +} - ble_hs_unlock(); +static void +ble_gap_disc_complete(void) +{ + struct ble_gap_master_state state; + struct ble_gap_event event; - if (cb != NULL) { - cb(event, status, &desc, cb_arg); + ble_gap_master_extract_state(&state, 1); + + if (state.cb != NULL) { + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_DISC_COMPLETE; + + ble_gap_call_event_cb(&event, state.cb, state.cb_arg); } } static void ble_gap_update_notify(uint16_t conn_handle, int status) { - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; - int rc; + struct ble_gap_event event; - rc = ble_gap_find_snapshot(conn_handle, &snap); - if (rc != 0) { - return; + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_CONN_UPDATE; + event.conn_update.conn_handle = conn_handle; + event.conn_update.status = status; + + ble_gap_call_conn_event_cb(&event, conn_handle); +} + +static uint32_t +ble_gap_master_ticks_until_exp(void) +{ + int32_t ticks; + + if (ble_gap_master.op == BLE_GAP_OP_NULL || !ble_gap_master.exp_set) { + /* Timer not set; infinity ticks until next event. */ + return BLE_HS_FOREVER; } - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - ctxt.conn_update.status = status; - ble_gap_call_event_cb(BLE_GAP_EVENT_CONN_UPDATE, &ctxt, - snap.cb, snap.cb_arg); + ticks = ble_gap_master.exp_os_ticks - os_time_get(); + if (ticks > 0) { + /* Timer not expired yet. */ + return ticks; + } + + /* Timer just expired. */ + return 0; +} + +static uint32_t +ble_gap_slave_ticks_until_exp(void) +{ + int32_t ticks; + + if (ble_gap_slave.op == BLE_GAP_OP_NULL || !ble_gap_slave.exp_set) { + /* Timer not set; infinity ticks until next event. */ + return BLE_HS_FOREVER; + } + + ticks = ble_gap_slave.exp_os_ticks - os_time_get(); + if (ticks > 0) { + /* Timer not expired yet. */ + return ticks; + } + + /* Timer just expired. */ + return 0; +} + +static void +ble_gap_heartbeat_sched(void) +{ + int32_t mst_ticks; + int32_t slv_ticks; + int32_t ticks; + + mst_ticks = ble_gap_master_ticks_until_exp(); + slv_ticks = ble_gap_slave_ticks_until_exp(); + ticks = min(mst_ticks, slv_ticks); + + ble_hs_heartbeat_sched(ticks); } static void @@ -546,29 +667,34 @@ ble_gap_master_set_timer(uint32_t ticks_from_now) { ble_gap_master.exp_os_ticks = os_time_get() + ticks_from_now; ble_gap_master.exp_set = 1; + + ble_gap_heartbeat_sched(); +} + +static void +ble_gap_slave_set_timer(uint32_t ticks_from_now) +{ + ble_gap_slave.exp_os_ticks = os_time_get() + ticks_from_now; + ble_gap_slave.exp_set = 1; + + ble_gap_heartbeat_sched(); } /** * Called when an error is encountered while the master-connection-fsm is - * active. Resets the state machine, clears the HCI ack callback, and notifies - * the host task that the next hci_batch item can be processed. + * active. */ static void ble_gap_master_failed(int status) { switch (ble_gap_master.op) { - case BLE_GAP_OP_M_DISC: - STATS_INC(ble_gap_stats, discover_fail); - ble_gap_call_master_disc_cb(BLE_GAP_EVENT_DISC_COMPLETE, status, - NULL, NULL, 1); - break; - case BLE_GAP_OP_M_CONN: STATS_INC(ble_gap_stats, initiate_fail); ble_gap_master_connect_failure(status); break; default: + BLE_HS_DBG_ASSERT(0); break; } } @@ -581,25 +707,35 @@ ble_gap_update_failed(uint16_t conn_handle, int status) ble_gap_update_notify(conn_handle, status); } -static void -ble_gap_conn_broken(struct ble_gap_snapshot *snap, int reason) +void +ble_gap_conn_broken(uint16_t conn_handle, int reason) { - struct ble_gap_conn_ctxt ctxt; + struct ble_gap_snapshot snap; + struct ble_gap_event event; + int rc; - /* XXX: Consider removing the connection from the list and handing it to - * each fo the "connection_broken" functions below. - */ + memset(&event, 0, sizeof event); + snap.desc = &event.disconnect.conn; + + rc = ble_gap_find_snapshot(conn_handle, &snap); + if (rc != 0) { + /* No longer connected. */ + return; + } - ble_sm_connection_broken(snap->desc.conn_handle); - ble_gattc_connection_broken(snap->desc.conn_handle); + /* Indicate the connection termination to each module. The order matters + * here: gatts must come before gattc to ensure the application does not + * get informed of spurious notify-tx events. + */ + ble_sm_connection_broken(conn_handle); + ble_gatts_connection_broken(conn_handle); + ble_gattc_connection_broken(conn_handle); - ble_hs_atomic_conn_delete(snap->desc.conn_handle); + ble_hs_atomic_conn_delete(conn_handle); - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap->desc; - ctxt.disconnect.reason = reason; - ble_gap_call_event_cb(BLE_GAP_EVENT_DISCONNECT, &ctxt, - snap->cb, snap->cb_arg); + event.type = BLE_GAP_EVENT_DISCONNECT; + event.disconnect.reason = reason; + ble_gap_call_event_cb(&event, snap.cb, snap.cb_arg); STATS_INC(ble_gap_stats, disconnect); } @@ -611,28 +747,19 @@ ble_gap_rx_disconn_complete(struct hci_disconn_complete *evt) return; #endif - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; - int status; - int rc; + struct ble_gap_event event; STATS_INC(ble_gap_stats, rx_disconnect); - rc = ble_gap_find_snapshot(evt->connection_handle, &snap); - if (rc != 0) { - /* No longer connected. */ - return; - } - if (evt->status == 0) { - status = BLE_HS_HCI_ERR(evt->reason); - ble_gap_conn_broken(&snap, status); + ble_gap_conn_broken(evt->connection_handle, + BLE_HS_HCI_ERR(evt->reason)); } else { - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - ctxt.term_failure.status = BLE_HS_HCI_ERR(evt->status); - ble_gap_call_event_cb(BLE_GAP_EVENT_TERM_FAILURE, &ctxt, - snap.cb, snap.cb_arg); + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_TERM_FAILURE; + event.term_failure.conn_handle = evt->connection_handle; + event.term_failure.status = BLE_HS_HCI_ERR(evt->status); + ble_gap_call_conn_event_cb(&event, evt->connection_handle); } } @@ -643,12 +770,13 @@ ble_gap_rx_update_complete(struct hci_le_conn_upd_complete *evt) return; #endif - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; + struct ble_gap_event event; struct ble_hs_conn *conn; STATS_INC(ble_gap_stats, rx_update_complete); + memset(&event, 0, sizeof event); + ble_hs_lock(); conn = ble_hs_conn_find(evt->connection_handle); @@ -658,25 +786,20 @@ ble_gap_rx_update_complete(struct hci_le_conn_upd_complete *evt) conn->bhc_latency = evt->conn_latency; conn->bhc_supervision_timeout = evt->supervision_timeout; } - - ble_gap_conn_to_snapshot(conn, &snap); } conn->bhc_flags &= ~BLE_HS_CONN_F_UPDATE; ble_hs_unlock(); - if (conn != NULL) { - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - ctxt.conn_update.status = BLE_HS_HCI_ERR(evt->status); - ble_gap_call_event_cb(BLE_GAP_EVENT_CONN_UPDATE, &ctxt, - snap.cb, snap.cb_arg); - } + event.type = BLE_GAP_EVENT_CONN_UPDATE; + event.conn_update.conn_handle = evt->connection_handle; + event.conn_update.status = BLE_HS_HCI_ERR(evt->status); + ble_gap_call_conn_event_cb(&event, evt->connection_handle); } /** - * Tells you if the BLE host is in the process of creating a master connection. + * Tells you if there is an active central GAP procedure (connect or discover). */ int ble_gap_master_in_progress(void) @@ -685,21 +808,6 @@ ble_gap_master_in_progress(void) } /** - * Tells you if the BLE host is in the process of creating a slave connection. - */ -int -ble_gap_slave_in_progress(void) -{ - return ble_gap_slave.op != BLE_GAP_OP_NULL; -} - -static int -ble_gap_currently_advertising(void) -{ - return ble_gap_slave.op == BLE_GAP_OP_S_ADV; -} - -/** * Attempts to complete the master connection process in response to a * "connection complete" event from the controller. If the master connection * FSM is in a state that can accept this event, and the peer device address is @@ -764,7 +872,7 @@ ble_gap_accept_slave_conn(uint8_t addr_type, uint8_t *addr) { int rc; - if (!ble_gap_currently_advertising()) { + if (!ble_gap_adv_active()) { rc = BLE_HS_ENOENT; } else { switch (ble_gap_slave.conn_mode) { @@ -795,7 +903,7 @@ ble_gap_accept_slave_conn(uint8_t addr_type, uint8_t *addr) } void -ble_gap_rx_adv_report(struct ble_hs_adv *adv) +ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc) { #if !NIMBLE_OPT(ROLE_OBSERVER) return; @@ -810,20 +918,23 @@ ble_gap_rx_adv_report(struct ble_hs_adv *adv) return; } - rc = ble_hs_adv_parse_fields(&fields, adv->data, adv->length_data); + rc = ble_hs_adv_parse_fields(&fields, desc->data, desc->length_data); if (rc != 0) { /* XXX: Increment stat. */ return; } - if (ble_gap_master.disc.disc_mode == BLE_GAP_DISC_MODE_LTD && + /* If a limited discovery procedure is active, discard non-limited + * advertisements. + */ + if (ble_gap_master.disc.limited && !(fields.flags & BLE_HS_ADV_F_DISC_LTD)) { return; } - ble_gap_call_master_disc_cb(BLE_GAP_EVENT_DISC_SUCCESS, 0, adv, - &fields, 0); + desc->fields = &fields; + ble_gap_disc_report(desc); } /** @@ -836,25 +947,21 @@ ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt) return BLE_HS_ENOTSUP; #endif - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; + struct ble_gap_event event; struct ble_hs_conn *conn; - struct ble_gap_enhanced_conn enhanced_conn; int rc; STATS_INC(ble_gap_stats, rx_conn_complete); - /* Determine if this event refers to a completed connection or a connection - * in progress. - */ - rc = ble_gap_find_snapshot(evt->connection_handle, &snap); - /* Apply the event to the existing connection if it exists. */ - if (rc == 0) { + if (evt->status != BLE_ERR_UNK_CONN_ID && + ble_hs_atomic_conn_flags(evt->connection_handle, NULL) == 0) { + /* XXX: Does this ever happen? */ if (evt->status != 0) { - ble_gap_conn_broken(&snap, BLE_HS_HCI_ERR(evt->status)); + ble_gap_conn_broken(evt->connection_handle, + BLE_HS_HCI_ERR(evt->status)); } return 0; } @@ -865,8 +972,8 @@ ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt) /* Determine the role from the status code. */ switch (evt->status) { case BLE_ERR_DIR_ADV_TMO: - if (ble_gap_slave_in_progress()) { - ble_gap_adv_finished(BLE_GAP_EVENT_ADV_COMPLETE); + if (ble_gap_adv_active()) { + ble_gap_adv_finished(); } break; @@ -874,7 +981,7 @@ ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt) if (ble_gap_master_in_progress()) { if (evt->status == BLE_ERR_UNK_CONN_ID) { /* Connect procedure successfully cancelled. */ - ble_gap_master_connect_cancel(); + ble_gap_master_connect_cancelled(); } else { ble_gap_master_failed(BLE_HS_HCI_ERR(evt->status)); } @@ -910,40 +1017,43 @@ ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt) BLE_HS_DBG_ASSERT(conn != NULL); conn->bhc_handle = evt->connection_handle; - memcpy(conn->bhc_addr, evt->peer_addr, sizeof conn->bhc_addr); - conn->bhc_addr_type = evt->peer_addr_type; - memcpy(conn->our_rpa_addr, evt->local_rpa, sizeof(conn->our_rpa_addr)); - memcpy(conn->peer_rpa_addr, evt->peer_rpa, sizeof(conn->peer_rpa_addr)); + memcpy(conn->bhc_peer_addr, evt->peer_addr, sizeof conn->bhc_peer_addr); + conn->bhc_peer_addr_type = evt->peer_addr_type; + memcpy(conn->bhc_our_rpa_addr, evt->local_rpa, + sizeof conn->bhc_our_rpa_addr); + memcpy(conn->bhc_peer_rpa_addr, evt->peer_rpa, + sizeof conn->bhc_peer_rpa_addr); conn->bhc_itvl = evt->conn_itvl; conn->bhc_latency = evt->conn_latency; conn->bhc_supervision_timeout = evt->supervision_timeout; + conn->bhc_master_clock_accuracy = evt->master_clk_acc; if (evt->role == BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER) { + conn->bhc_cb = ble_gap_master.cb; + conn->bhc_cb_arg = ble_gap_master.cb_arg; conn->bhc_flags |= BLE_HS_CONN_F_MASTER; - conn->bhc_cb = ble_gap_master.conn.cb; - conn->our_addr_type = ble_gap_master.conn.our_addr_type; - conn->bhc_cb_arg = ble_gap_master.conn.cb_arg; + conn->bhc_our_addr_type = ble_gap_master.conn.our_addr_type; ble_gap_master_reset_state(); } else { conn->bhc_cb = ble_gap_slave.cb; conn->bhc_cb_arg = ble_gap_slave.cb_arg; - conn->our_addr_type = ble_gap_slave.our_addr_type; - ble_gap_slave.op = BLE_GAP_OP_NULL; + conn->bhc_our_addr_type = ble_gap_slave.our_addr_type; + ble_gap_slave_reset_state(); } - memcpy(conn->our_rpa_addr, evt->local_rpa, 6); - memcpy(conn->peer_rpa_addr, evt->peer_rpa, 6); + memcpy(conn->bhc_our_rpa_addr, evt->local_rpa, 6); + memcpy(conn->bhc_peer_rpa_addr, evt->peer_rpa, 6); - ble_gap_conn_to_snapshot(conn, &snap); + ble_hs_lock(); + + memset(&event, 0, sizeof event); + ble_hs_conn_insert(conn); - ble_hs_atomic_conn_insert(conn); + ble_hs_unlock(); - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - memcpy(enhanced_conn.local_rpa, evt->local_rpa,6); - memcpy(enhanced_conn.peer_rpa, evt->peer_rpa,6); - ctxt.connect.enhanced_conn = &enhanced_conn; - ctxt.connect.status = 0; - ble_gap_call_event_cb(BLE_GAP_EVENT_CONNECT, &ctxt, snap.cb, snap.cb_arg); + event.type = BLE_GAP_EVENT_CONNECT; + event.connect.conn_handle = evt->connection_handle; + event.connect.status = 0; + ble_gap_call_conn_event_cb(&event, evt->connection_handle); return 0; } @@ -952,62 +1062,77 @@ int ble_gap_rx_l2cap_update_req(uint16_t conn_handle, struct ble_gap_upd_params *params) { - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; + struct ble_gap_event event; int rc; - rc = ble_gap_find_snapshot(conn_handle, &snap); - if (rc != 0) { - return rc; - } - - if (snap.cb != NULL) { - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - ctxt.conn_update_req.peer_params = params; - rc = snap.cb(BLE_GAP_EVENT_L2CAP_UPDATE_REQ, &ctxt, snap.cb_arg); - } else { - rc = 0; - } + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_L2CAP_UPDATE_REQ; + event.conn_update_req.conn_handle = conn_handle; + event.conn_update_req.peer_params = params; + rc = ble_gap_call_conn_event_cb(&event, conn_handle); return rc; } -static uint32_t -ble_gap_master_ticks_until_exp(void) +static int32_t +ble_gap_master_heartbeat(void) { - int32_t ticks; + uint32_t ticks_until_exp; + int rc; - if (ble_gap_master.op == BLE_GAP_OP_NULL || !ble_gap_master.exp_set) { - /* Timer not set; infinity ticks until next event. */ - return UINT32_MAX; + ticks_until_exp = ble_gap_master_ticks_until_exp(); + if (ticks_until_exp != 0) { + /* Timer not expired yet. */ + return ticks_until_exp; } - ticks = ble_gap_master.exp_os_ticks - os_time_get(); - if (ticks > 0) { - /* Timer not expired yet. */ - return ticks; + /*** Timer expired; process event. */ + + switch (ble_gap_master.op) { + case BLE_GAP_OP_M_CONN: + rc = ble_gap_conn_cancel_tx(); + if (rc != 0) { + /* Failed to stop connecting; try again in 100 ms. */ + return BLE_GAP_CANCEL_RETRY_RATE; + } else { + /* Stop the timer now that the cancel command has been acked. */ + ble_gap_master.exp_set = 0; + + /* Timeout gets reported when we receive a connection complete + * event indicating the connect procedure has been cancelled. + */ + /* XXX: Set a timer to reset the controller if a connection + * complete event isn't received within a reasonable interval. + */ + } + break; + + case BLE_GAP_OP_M_DISC: + /* When a discovery procedure times out, it is not a failure. */ + rc = ble_gap_disc_enable_tx(0, 0); + if (rc != 0) { + /* Failed to stop discovery; try again in 100 ms. */ + return BLE_GAP_CANCEL_RETRY_RATE; + } + + ble_gap_disc_complete(); + break; + + default: + BLE_HS_DBG_ASSERT(0); + break; } - /* Timer just expired. */ - return 0; + return BLE_HS_FOREVER; } -/** - * Handles timed-out master procedures. - * - * Called by the heartbeat timer; executed at least once a second. - * - * @return The number of ticks until this function should - * be called again. - */ -uint32_t -ble_gap_heartbeat(void) +static int32_t +ble_gap_slave_heartbeat(void) { uint32_t ticks_until_exp; int rc; - ticks_until_exp = ble_gap_master_ticks_until_exp(); + ticks_until_exp = ble_gap_slave_ticks_until_exp(); if (ticks_until_exp != 0) { /* Timer not expired yet. */ return ticks_until_exp; @@ -1015,23 +1140,40 @@ ble_gap_heartbeat(void) /*** Timer expired; process event. */ - /* Clear the timer. */ - ble_gap_master.exp_set = 0; + /* Stop advertising. */ + rc = ble_gap_adv_enable_tx(0); + if (rc != 0) { + /* Failed to stop advertising; try again in 100 ms. */ + return 100; + } - switch (ble_gap_master.op) { - case BLE_GAP_OP_M_DISC: - /* When a discovery procedure times out, it is not a failure. */ - rc = ble_gap_disc_tx_disable(); - ble_gap_call_master_disc_cb(BLE_GAP_EVENT_DISC_COMPLETE, rc, - NULL, NULL, 1); - break; + /* Clear the timer and cancel the current procedure. */ + ble_gap_slave_reset_state(); - default: - ble_gap_master_failed(BLE_HS_ETIMEOUT); - break; - } + /* Indicate to application that advertising has stopped. */ + ble_gap_adv_finished(); + + return BLE_HS_FOREVER; +} - return UINT32_MAX; +/** + * Handles timed-out master procedures. + * + * Called by the heartbeat timer; executed at least once a second. + * + * @return The number of ticks until this function should + * be called again. + */ +int32_t +ble_gap_heartbeat(void) +{ + int32_t master_ticks; + int32_t slave_ticks; + + master_ticks = ble_gap_master_heartbeat(); + slave_ticks = ble_gap_slave_heartbeat(); + + return min(master_ticks, slave_ticks); } /***************************************************************************** @@ -1053,18 +1195,18 @@ ble_gap_wl_busy(void) } static int -ble_gap_wl_tx_add(struct ble_gap_white_entry *entry) +ble_gap_wl_tx_add(const struct ble_gap_white_entry *entry) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_CHG_WHITE_LIST_LEN]; int rc; - rc = host_hci_cmd_build_le_add_to_whitelist(entry->addr, entry->addr_type, - buf, sizeof buf); + rc = ble_hs_hci_cmd_build_le_add_to_whitelist( + entry->addr, entry->addr_type, buf, sizeof buf); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1078,8 +1220,8 @@ ble_gap_wl_tx_clear(void) uint8_t buf[BLE_HCI_CMD_HDR_LEN]; int rc; - host_hci_cmd_build_le_clear_whitelist(buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_le_clear_whitelist(buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1087,8 +1229,16 @@ ble_gap_wl_tx_clear(void) return 0; } +/** + * Overwrites the controller's white list with the specified contents. + * + * @param white_list The entries to write to the white list. + * @param white_list_count The number of entries in the white list. + * + * @return 0 on success; nonzero on failure. + */ int -ble_gap_wl_set(struct ble_gap_white_entry *white_list, +ble_gap_wl_set(const struct ble_gap_white_entry *white_list, uint8_t white_list_count) { #if !NIMBLE_OPT(WHITELIST) @@ -1100,9 +1250,11 @@ ble_gap_wl_set(struct ble_gap_white_entry *white_list, STATS_INC(ble_gap_stats, wl_set); + ble_hs_lock(); + if (white_list_count == 0) { rc = BLE_HS_EINVAL; - goto err; + goto done; } for (i = 0; i < white_list_count; i++) { @@ -1110,13 +1262,13 @@ ble_gap_wl_set(struct ble_gap_white_entry *white_list, white_list[i].addr_type != BLE_ADDR_TYPE_RANDOM) { rc = BLE_HS_EINVAL; - goto err; + goto done; } } if (ble_gap_wl_busy()) { rc = BLE_HS_EBUSY; - goto err; + goto done; } BLE_HS_LOG(INFO, "GAP procedure initiated: set whitelist; "); @@ -1125,20 +1277,24 @@ ble_gap_wl_set(struct ble_gap_white_entry *white_list, rc = ble_gap_wl_tx_clear(); if (rc != 0) { - goto err; + goto done; } for (i = 0; i < white_list_count; i++) { rc = ble_gap_wl_tx_add(white_list + i); if (rc != 0) { - goto err; + goto done; } } - return 0; + rc = 0; -err: - STATS_INC(ble_gap_stats, wl_set_fail); +done: + ble_hs_unlock(); + + if (rc != 0) { + STATS_INC(ble_gap_stats, wl_set_fail); + } return rc; } @@ -1147,13 +1303,13 @@ err: *****************************************************************************/ static int -ble_gap_adv_disable_tx(void) +ble_gap_adv_enable_tx(int enable) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_ENABLE_LEN]; int rc; - host_hci_cmd_build_le_set_adv_enable(0, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_le_set_adv_enable(!!enable, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1161,6 +1317,16 @@ ble_gap_adv_disable_tx(void) return 0; } +/** + * Stops the currently-active advertising procedure. A success return + * code indicates that advertising has been fully aborted; a new advertising + * procedure can be initiated immediately. + * + * @return 0 on success; + * BLE_HS_EALREADY if there is no active + * advertising procedure; + * Other nonzero on error. + */ int ble_gap_adv_stop(void) { @@ -1172,25 +1338,31 @@ ble_gap_adv_stop(void) STATS_INC(ble_gap_stats, adv_stop); + ble_hs_lock(); + /* Do nothing if advertising is already disabled. */ - if (!ble_gap_currently_advertising()) { + if (!ble_gap_adv_active()) { rc = BLE_HS_EALREADY; - goto err; + goto done; } BLE_HS_LOG(INFO, "GAP procedure initiated: stop advertising.\n"); - rc = ble_gap_adv_disable_tx(); + rc = ble_gap_adv_enable_tx(0); if (rc != 0) { - goto err; + goto done; } - ble_gap_slave.op = BLE_GAP_OP_NULL; + ble_gap_slave_reset_state(); - return 0; + rc = 0; -err: - STATS_INC(ble_gap_stats, adv_set_fields_fail); +done: + ble_hs_unlock(); + + if (rc != 0) { + STATS_INC(ble_gap_stats, adv_set_fields_fail); + } return rc; } @@ -1198,62 +1370,20 @@ err: * $advertise * *****************************************************************************/ -static void -ble_gap_adv_itvls(uint8_t disc_mode, uint8_t conn_mode, - uint16_t *out_itvl_min, uint16_t *out_itvl_max) -{ - switch (conn_mode) { - case BLE_GAP_CONN_MODE_NON: - *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL2_MIN; - *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL2_MAX; - break; - - case BLE_GAP_CONN_MODE_UND: - *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; - *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX; - break; - - case BLE_GAP_CONN_MODE_DIR: - *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; - *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX; - break; - - default: - BLE_HS_DBG_ASSERT(0); - break; - } -} - -static int -ble_gap_adv_enable_tx(void) -{ - uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_PARAM_LEN]; - int rc; - - host_hci_cmd_build_le_set_adv_enable(1, buf, sizeof buf); - - rc = ble_hci_cmd_tx_empty_ack(buf); - if (rc != 0) { - return rc; - } - - return 0; -} - static int ble_gap_adv_rsp_data_tx(void) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_RSP_DATA_LEN]; int rc; - rc = host_hci_cmd_build_le_set_scan_rsp_data(ble_gap_slave.rsp_data, - ble_gap_slave.rsp_data_len, - buf, sizeof buf); + rc = ble_hs_hci_cmd_build_le_set_scan_rsp_data(ble_gap_slave.rsp_data, + ble_gap_slave.rsp_data_len, + buf, sizeof buf); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1261,11 +1391,9 @@ ble_gap_adv_rsp_data_tx(void) return 0; } -static int -ble_gap_adv_data_tx(void) +static void +ble_gap_adv_data_set_flags(void) { - uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_DATA_LEN]; - uint8_t adv_data_len; uint8_t flags; int rc; @@ -1290,31 +1418,38 @@ ble_gap_adv_data_tx(void) flags |= BLE_HS_ADV_F_BREDR_UNSUP; - /* Encode the flags AD field if it is nonzero. */ - adv_data_len = ble_gap_slave.adv_data_len; if (flags != 0) { rc = ble_hs_adv_set_flat(BLE_HS_ADV_TYPE_FLAGS, 1, &flags, - ble_gap_slave.adv_data, &adv_data_len, + ble_gap_slave.adv_data, + &ble_gap_slave.adv_data_len, BLE_HCI_MAX_ADV_DATA_LEN); - BLE_HS_DBG_ASSERT(rc == 0); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); } +} - /* Encode the transmit power AD field. */ - if (ble_gap_slave.adv_pwr_lvl) { - rc = ble_hs_adv_set_flat(BLE_HS_ADV_TYPE_TX_PWR_LVL, 1, - &ble_gap_slave.tx_pwr_lvl, - ble_gap_slave.adv_data, - &adv_data_len, BLE_HCI_MAX_ADV_DATA_LEN); - BLE_HS_DBG_ASSERT(rc == 0); +static int +ble_gap_adv_data_tx(void) +{ + uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_DATA_LEN]; + int rc; + + /* Calculate the flags AD field if requested by application. Clear the + * auto flag after encoding the flags so that we don't get repeated flags + * fields on subsequent advertising procedures. + */ + if (ble_gap_slave.adv_auto_flags) { + ble_gap_adv_data_set_flags(); + ble_gap_slave.adv_auto_flags = 0; } - rc = host_hci_cmd_build_le_set_adv_data(ble_gap_slave.adv_data, - adv_data_len, buf, sizeof buf); + rc = ble_hs_hci_cmd_build_le_set_adv_data(ble_gap_slave.adv_data, + ble_gap_slave.adv_data_len, + buf, sizeof buf); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1323,41 +1458,103 @@ ble_gap_adv_data_tx(void) } static int -ble_gap_adv_params_tx(const struct ble_gap_adv_params *adv_params, - uint8_t *peer_addr, uint8_t peer_addr_type) +ble_gap_adv_type(const struct ble_gap_adv_params *adv_params) +{ + switch (adv_params->conn_mode) { + case BLE_GAP_CONN_MODE_NON: + if (adv_params->disc_mode == BLE_GAP_DISC_MODE_NON) { + return BLE_HCI_ADV_TYPE_ADV_NONCONN_IND; + } else { + return BLE_HCI_ADV_TYPE_ADV_SCAN_IND; + } + + case BLE_GAP_CONN_MODE_UND: + return BLE_HCI_ADV_TYPE_ADV_IND; + + case BLE_GAP_CONN_MODE_DIR: + if (adv_params->high_duty_cycle) { + return BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD; + } else { + return BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD; + } + + default: + BLE_HS_DBG_ASSERT(0); + return BLE_HCI_ADV_TYPE_ADV_IND; + } +} + +static void +ble_gap_adv_dflt_itvls(uint8_t conn_mode, + uint16_t *out_itvl_min, uint16_t *out_itvl_max) +{ + switch (conn_mode) { + case BLE_GAP_CONN_MODE_NON: + *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL2_MIN; + *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL2_MAX; + break; + + case BLE_GAP_CONN_MODE_UND: + *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX; + break; + + case BLE_GAP_CONN_MODE_DIR: + *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX; + break; + + default: + BLE_HS_DBG_ASSERT(0); + break; + } +} + +static int +ble_gap_adv_params_tx(uint8_t own_addr_type, + uint8_t peer_addr_type, const uint8_t *peer_addr, + const struct ble_gap_adv_params *adv_params) + { struct hci_adv_params hci_adv_params; uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_PARAM_LEN]; int rc; - uint8_t peer[6]; - if(peer_addr) { - memcpy(peer, peer_addr, 6); - } else { - memset(peer, 0, 6); + if (peer_addr == NULL) { + peer_addr = ble_hs_misc_null_addr; } - hci_adv_params.adv_channel_map = adv_params->adv_channel_map; - hci_adv_params.own_addr_type = adv_params->own_addr_type; - hci_adv_params.adv_filter_policy = adv_params->adv_filter_policy; - hci_adv_params.adv_itvl_min = adv_params->adv_itvl_min; - hci_adv_params.adv_itvl_max = adv_params->adv_itvl_max; + hci_adv_params.own_addr_type = own_addr_type; hci_adv_params.peer_addr_type = peer_addr_type; - hci_adv_params.adv_type = adv_params->adv_type; - - if ((ble_gap_slave.conn_mode == BLE_GAP_CONN_MODE_DIR) || - (adv_params->own_addr_type == BLE_ADDR_TYPE_RPA_PUB_DEFAULT) || - (adv_params->own_addr_type == BLE_ADDR_TYPE_RPA_RND_DEFAULT)) { - memcpy(hci_adv_params.peer_addr,peer, - sizeof(hci_adv_params.peer_addr)); + memcpy(hci_adv_params.peer_addr, peer_addr, + sizeof hci_adv_params.peer_addr); + + /* Fill optional fields if application did not specify them. */ + if (adv_params->itvl_min == 0 && adv_params->itvl_max == 0) { + ble_gap_adv_dflt_itvls(adv_params->conn_mode, + &hci_adv_params.adv_itvl_min, + &hci_adv_params.adv_itvl_max); + } else { + hci_adv_params.adv_itvl_min = adv_params->itvl_min; + hci_adv_params.adv_itvl_max = adv_params->itvl_max; } + if (adv_params->channel_map == 0) { + hci_adv_params.adv_channel_map = BLE_GAP_ADV_DFLT_CHANNEL_MAP; + } else { + hci_adv_params.adv_channel_map = adv_params->channel_map; + } + + /* Zero is the default value for filter policy and high duty cycle */ + hci_adv_params.adv_filter_policy = adv_params->filter_policy; - rc = host_hci_cmd_build_le_set_adv_params(&hci_adv_params, buf, sizeof buf); + hci_adv_params.adv_type = ble_gap_adv_type(adv_params); + rc = ble_hs_hci_cmd_build_le_set_adv_params(&hci_adv_params, + buf, sizeof buf); if (rc != 0) { - return rc; + return BLE_HS_EINVAL; } - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1365,67 +1562,47 @@ ble_gap_adv_params_tx(const struct ble_gap_adv_params *adv_params, return 0; } -/** - * Enables the specified discoverable mode and connectable mode, and initiates - * the advertising process. - * - * @param discoverable_mode One of the following constants: - * o BLE_GAP_DISC_MODE_NON - * (non-discoverable; 3.C.9.2.2). - * o BLE_GAP_DISC_MODE_LTD - * (limited-discoverable; 3.C.9.2.3). - * o BLE_GAP_DISC_MODE_GEN - * (general-discoverable; 3.C.9.2.4). - * @param connectable_mode One of the following constants: - * o BLE_GAP_CONN_MODE_NON - * (non-connectable; 3.C.9.3.2). - * o BLE_GAP_CONN_MODE_DIR - * (directed-connectable; 3.C.9.3.3). - * o BLE_GAP_CONN_MODE_UND - * (undirected-connectable; 3.C.9.3.4). - * - * @return 0 on success; nonzero on failure. - */ -int -ble_gap_adv_start(uint8_t discoverable_mode, uint8_t connectable_mode, - uint8_t *peer_addr, uint8_t peer_addr_type, - const struct ble_gap_adv_params *adv_params, - ble_gap_event_fn *cb, void *cb_arg) +static int +ble_gap_adv_validate(uint8_t own_addr_type, uint8_t peer_addr_type, + const uint8_t *peer_addr, + const struct ble_gap_adv_params *adv_params) { -#if !NIMBLE_OPT(ADVERTISE) - return BLE_HS_ENOTSUP; -#endif - - struct ble_gap_adv_params gap_adv_params; - int rc; - - ble_hs_lock(); - - STATS_INC(ble_gap_stats, adv_start); - - if (ble_gap_slave.op != BLE_GAP_OP_NULL) { - rc = BLE_HS_EALREADY; - goto done; + if (adv_params == NULL) { + return BLE_HS_EINVAL; } - if (discoverable_mode >= BLE_GAP_DISC_MODE_MAX) { - rc = BLE_HS_EINVAL; - goto done; + if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { + return BLE_HS_EINVAL; } - /* Don't initiate a connection procedure if we won't be able to allocate a - * connection object on completion. - */ - if (connectable_mode != BLE_GAP_CONN_MODE_NON && - !ble_hs_conn_can_alloc()) { + if (adv_params->disc_mode >= BLE_GAP_DISC_MODE_MAX) { + return BLE_HS_EINVAL; + } - rc = BLE_HS_ENOMEM; - goto done; + if (ble_gap_slave.op != BLE_GAP_OP_NULL) { + return BLE_HS_EALREADY; } - switch (connectable_mode) { + switch (adv_params->conn_mode) { case BLE_GAP_CONN_MODE_NON: + /* High duty cycle only allowed for directed advertising. */ + if (adv_params->high_duty_cycle) { + return BLE_HS_EINVAL; + } + break; + case BLE_GAP_CONN_MODE_UND: + /* High duty cycle only allowed for directed advertising. */ + if (adv_params->high_duty_cycle) { + return BLE_HS_EINVAL; + } + + /* Don't allow connectable advertising if we won't be able to allocate + * a new connection. + */ + if (!ble_hs_conn_can_alloc()) { + return BLE_HS_ENOMEM; + } break; case BLE_GAP_CONN_MODE_DIR: @@ -1434,76 +1611,117 @@ ble_gap_adv_start(uint8_t discoverable_mode, uint8_t connectable_mode, peer_addr_type != BLE_ADDR_TYPE_RPA_PUB_DEFAULT && peer_addr_type != BLE_ADDR_TYPE_RPA_RND_DEFAULT) { - rc = BLE_HS_EINVAL; - goto done; + return BLE_HS_EINVAL; + } + if (peer_addr == NULL) { + return BLE_HS_EINVAL; + } + + /* Don't allow connectable advertising if we won't be able to allocate + * a new connection. + */ + if (!ble_hs_conn_can_alloc()) { + return BLE_HS_ENOMEM; } break; default: - rc = BLE_HS_EINVAL; - goto done; - } - - if(adv_params == NULL) { - gap_adv_params = ble_gap_adv_params_dflt; - } else { - gap_adv_params = *adv_params; + return BLE_HS_EINVAL; } - if(gap_adv_params.own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { - rc = BLE_HS_EINVAL; - goto done; - } + return 0; +} - ble_gap_slave.cb = cb; - ble_gap_slave.cb_arg = cb_arg; - ble_gap_slave.conn_mode = connectable_mode; - ble_gap_slave.disc_mode = discoverable_mode; - ble_gap_slave.our_addr_type = gap_adv_params.own_addr_type; +/** + * Initiates advertising. + * + * @param own_addr_type The type of address the stack should use for + * itself. Valid values are: + * o BLE_ADDR_TYPE_PUBLIC + * o BLE_ADDR_TYPE_RANDOM + * o BLE_ADDR_TYPE_RPA_PUB_DEFAULT + * o BLE_ADDR_TYPE_RPA_RND_DEFAULT + * @param peer_addr_type Address type of the peer's identity address. + * Valid values are: + * o BLE_ADDR_TYPE_PUBLIC + * o BLE_ADDR_TYPE_RANDOM + * This parameter is ignored unless directed + * advertising is being used. + * @param peer_addr The peer's six-byte identity address. + * This parameter is ignored unless directed + * advertising is being used. + * @param duration_ms The duration of the advertisement procedure. + * On expiration, the procedure ends and a + * BLE_GAP_EVENT_ADV_COMPLETE event is + * reported. Units are milliseconds. Specify + * BLE_HS_FOREVER for no expiration. + * @param adv_params Additional arguments specifying the particulars + * of the advertising procedure. + * @param cb The callback to associate with this advertising + * procedure. If advertising ends, the event + * is reported through this callback. If + * advertising results in a connection, the + * connection inherits this callback as its + * event-reporting mechanism. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. + */ +int +ble_gap_adv_start(uint8_t own_addr_type, uint8_t peer_addr_type, + const uint8_t *peer_addr, int32_t duration_ms, + const struct ble_gap_adv_params *adv_params, + ble_gap_event_fn *cb, void *cb_arg) +{ +#if !NIMBLE_OPT(ADVERTISE) + return BLE_HS_ENOTSUP; +#endif - ble_gap_adv_itvls(discoverable_mode, connectable_mode, - &gap_adv_params.adv_itvl_min, - &gap_adv_params.adv_itvl_max); + uint32_t duration_ticks; + int rc; - if (gap_adv_params.own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) { - ble_hs_pvcy_set_our_nrpa(); - } + STATS_INC(ble_gap_stats, adv_start); - switch (connectable_mode) { - case BLE_GAP_CONN_MODE_NON: - gap_adv_params.adv_type = BLE_HCI_ADV_TYPE_ADV_NONCONN_IND; - break; + ble_hs_lock(); - case BLE_GAP_CONN_MODE_DIR: - gap_adv_params.adv_type = BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD; - break; + rc = ble_gap_adv_validate(own_addr_type, peer_addr_type, peer_addr, + adv_params); + if (rc != 0) { + goto done; + } - case BLE_GAP_CONN_MODE_UND: - gap_adv_params.adv_type = BLE_HCI_ADV_TYPE_ADV_IND; - break; + if (duration_ms != BLE_HS_FOREVER) { + rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); + if (rc != 0) { + /* Duration too great. */ + rc = BLE_HS_EINVAL; + goto done; + } + } - default: - BLE_HS_DBG_ASSERT(0); - break; + rc = ble_hs_id_use_addr(own_addr_type); + if (rc != 0) { + return rc; } BLE_HS_LOG(INFO, "GAP procedure initiated: advertise; "); - ble_gap_log_adv(&gap_adv_params, peer_addr, peer_addr_type); + ble_gap_log_adv(own_addr_type, peer_addr_type, peer_addr, adv_params); BLE_HS_LOG(INFO, "\n"); - rc = ble_gap_adv_params_tx(&gap_adv_params, peer_addr, peer_addr_type); + ble_gap_slave.cb = cb; + ble_gap_slave.cb_arg = cb_arg; + ble_gap_slave.conn_mode = adv_params->conn_mode; + ble_gap_slave.disc_mode = adv_params->disc_mode; + ble_gap_slave.our_addr_type = own_addr_type; + + rc = ble_gap_adv_params_tx(own_addr_type, peer_addr_type, peer_addr, + adv_params); if (rc != 0) { goto done; } - if (ble_gap_slave.adv_pwr_lvl) { - rc = ble_hci_util_read_adv_tx_pwr(&ble_gap_slave.tx_pwr_lvl); - if (rc != 0) { - goto done; - } - } - - if (ble_gap_slave.conn_mode != BLE_GAP_CONN_MODE_DIR) { + if (adv_params->conn_mode != BLE_GAP_CONN_MODE_DIR) { rc = ble_gap_adv_data_tx(); if (rc != 0) { goto done; @@ -1515,27 +1733,42 @@ ble_gap_adv_start(uint8_t discoverable_mode, uint8_t connectable_mode, } } - rc = ble_gap_adv_enable_tx(); + ble_gap_slave.op = BLE_GAP_OP_S_ADV; + + rc = ble_gap_adv_enable_tx(1); if (rc != 0) { + ble_gap_slave_reset_state(); goto done; } - ble_gap_slave.op = BLE_GAP_OP_S_ADV; + if (duration_ms != BLE_HS_FOREVER) { + ble_gap_slave_set_timer(duration_ticks); + } rc = 0; done: + ble_hs_unlock(); + if (rc != 0) { STATS_INC(ble_gap_stats, adv_start_fail); } - - ble_hs_unlock(); - return rc; } +/** + * Configures the data to include in subsequent advertisements. + * + * @param adv_fields Specifies the advertisement data. + * + * @return 0 on success; + * BLE_HS_EBUSY if advertising is in progress; + * BLE_HS_EMSGSIZE if the specified data is too + * large to fit in an advertisement; + * Other nonzero on failure. + */ int -ble_gap_adv_set_fields(struct ble_hs_adv_fields *adv_fields) +ble_gap_adv_set_fields(const struct ble_hs_adv_fields *adv_fields) { #if !NIMBLE_OPT(ADVERTISE) return BLE_HS_ENOTSUP; @@ -1544,31 +1777,55 @@ ble_gap_adv_set_fields(struct ble_hs_adv_fields *adv_fields) int max_sz; int rc; + STATS_INC(ble_gap_stats, adv_set_fields); + ble_hs_lock(); - STATS_INC(ble_gap_stats, adv_set_fields); + /* Don't allow advertising fields to be set while advertising is active. */ + if (ble_gap_slave.op != BLE_GAP_OP_NULL) { + rc = BLE_HS_EBUSY; + goto done; + } - if (adv_fields->tx_pwr_lvl_is_present) { - max_sz = BLE_GAP_ADV_DATA_LIMIT_PWR; + /* If application has requested the stack to calculate the flags field + * automatically (flags == 0), there is less room for user data. + */ + if (adv_fields->flags_is_present && adv_fields->flags == 0) { + max_sz = BLE_GAP_ADV_DATA_LIMIT_FLAGS; + ble_gap_slave.adv_auto_flags = 1; } else { - max_sz = BLE_GAP_ADV_DATA_LIMIT_NO_PWR; + max_sz = BLE_GAP_ADV_DATA_LIMIT_NO_FLAGS; + ble_gap_slave.adv_auto_flags = 0; } rc = ble_hs_adv_set_fields(adv_fields, ble_gap_slave.adv_data, &ble_gap_slave.adv_data_len, max_sz); - if (rc == 0) { - ble_gap_slave.adv_pwr_lvl = adv_fields->tx_pwr_lvl_is_present; - } else { - STATS_INC(ble_gap_stats, adv_set_fields_fail); + if (rc != 0) { + goto done; } +done: ble_hs_unlock(); + if (rc != 0) { + STATS_INC(ble_gap_stats, adv_set_fields_fail); + } return rc; } +/** + * Configures the data to include in subsequent scan responses. + * + * @param adv_fields Specifies the scan response data. + * + * @return 0 on success; + * BLE_HS_EBUSY if advertising is in progress; + * BLE_HS_EMSGSIZE if the specified data is too + * large to fit in an advertisement; + * Other nonzero on failure. + */ int -ble_gap_adv_rsp_set_fields(struct ble_hs_adv_fields *rsp_fields) +ble_gap_adv_rsp_set_fields(const struct ble_hs_adv_fields *rsp_fields) { #if !NIMBLE_OPT(ADVERTISE) return BLE_HS_ENOTSUP; @@ -1576,34 +1833,58 @@ ble_gap_adv_rsp_set_fields(struct ble_hs_adv_fields *rsp_fields) int rc; + STATS_INC(ble_gap_stats, adv_rsp_set_fields); + ble_hs_lock(); - STATS_INC(ble_gap_stats, adv_rsp_set_fields); + /* Don't allow response fields to be set while advertising is active. */ + if (ble_gap_slave.op != BLE_GAP_OP_NULL) { + rc = BLE_HS_EBUSY; + goto done; + } rc = ble_hs_adv_set_fields(rsp_fields, ble_gap_slave.rsp_data, &ble_gap_slave.rsp_data_len, BLE_HCI_MAX_ADV_DATA_LEN); if (rc != 0) { - STATS_INC(ble_gap_stats, adv_rsp_set_fields_fail); + goto done; } +done: ble_hs_unlock(); + if (rc != 0) { + STATS_INC(ble_gap_stats, adv_rsp_set_fields_fail); + } return rc; } +/** + * Indicates whether an advertisement procedure is currently in progress. + * + * @return 0: No advertisement procedure in progress; + * 1: Advertisement procedure in progress. + */ +int +ble_gap_adv_active(void) +{ + /* Assume read is atomic; mutex not necessary. */ + return ble_gap_slave.op == BLE_GAP_OP_S_ADV; +} + /***************************************************************************** * $discovery procedures * *****************************************************************************/ static int -ble_gap_disc_tx_disable(void) +ble_gap_disc_enable_tx(int enable, int filter_duplicates) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_ENABLE_LEN]; int rc; - host_hci_cmd_build_le_set_scan_enable(0, 0, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_le_set_scan_enable(!!enable, !!filter_duplicates, + buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1612,37 +1893,30 @@ ble_gap_disc_tx_disable(void) } static int -ble_gap_disc_tx_enable(void) +ble_gap_disc_tx_params(uint8_t own_addr_type, + const struct ble_gap_disc_params *disc_params) { - uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_ENABLE_LEN]; + uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_PARAM_LEN]; + uint8_t scan_type; int rc; - host_hci_cmd_build_le_set_scan_enable(1, 0, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); - if (rc != 0) { - return rc; + if (disc_params->passive) { + scan_type = BLE_HCI_SCAN_TYPE_PASSIVE; + } else { + scan_type = BLE_HCI_SCAN_TYPE_ACTIVE; } - return 0; -} - -static int -ble_gap_disc_tx_params(uint8_t scan_type, uint8_t filter_policy, - uint8_t addr_mode) -{ - uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_PARAM_LEN]; - int rc; - - rc = host_hci_cmd_build_le_set_scan_params( - scan_type, - BLE_GAP_SCAN_FAST_INTERVAL_MIN, - BLE_GAP_SCAN_FAST_WINDOW, - addr_mode, - filter_policy, - buf, sizeof buf); - BLE_HS_DBG_ASSERT_EVAL(rc == 0); + rc = ble_hs_hci_cmd_build_le_set_scan_params(scan_type, + disc_params->itvl, + disc_params->window, + own_addr_type, + disc_params->filter_policy, + buf, sizeof buf); + if (rc != 0) { + return BLE_HS_EINVAL; + } - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1665,16 +1939,16 @@ ble_gap_disc_cancel(void) { int rc; - ble_hs_lock(); - STATS_INC(ble_gap_stats, discover_cancel); - if (ble_gap_master.op != BLE_GAP_OP_M_DISC) { + ble_hs_lock(); + + if (!ble_gap_disc_active()) { rc = BLE_HS_EALREADY; goto done; } - rc = ble_gap_disc_tx_disable(); + rc = ble_gap_disc_enable_tx(0, 0); if (rc != 0) { goto done; } @@ -1682,123 +1956,190 @@ ble_gap_disc_cancel(void) ble_gap_master_reset_state(); done: + ble_hs_unlock(); + if (rc != 0) { STATS_INC(ble_gap_stats, discover_cancel_fail); } - ble_hs_unlock(); - return rc; } +static void +ble_gap_disc_fill_dflts(struct ble_gap_disc_params *disc_params) +{ + if (disc_params->itvl == 0) { + if (disc_params->limited) { + disc_params->itvl = BLE_GAP_LIM_DISC_SCAN_INT; + } else { + disc_params->itvl = BLE_GAP_SCAN_FAST_INTERVAL_MIN; + } + } + + if (disc_params->window == 0) { + if (disc_params->limited) { + disc_params->window = BLE_GAP_LIM_DISC_SCAN_WINDOW; + } else { + disc_params->window = BLE_GAP_SCAN_FAST_WINDOW; + } + } +} + +static int +ble_gap_disc_validate(uint8_t own_addr_type, + const struct ble_gap_disc_params *disc_params) +{ + if (disc_params == NULL) { + return BLE_HS_EINVAL; + } + + if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { + return BLE_HS_EINVAL; + } + + if (ble_gap_conn_active()) { + return BLE_HS_EBUSY; + } + + if (ble_gap_disc_active()) { + return BLE_HS_EALREADY; + } + + return 0; +} + /** - * Performs the Limited or General Discovery Procedures, as described in - * vol. 3, part C, section 9.2.5 / 9.2.6. + * Performs the Limited or General Discovery Procedures. + * + * @param own_addr_type The type of address the stack should use for + * itself when sending scan requests. Valid + * values are: + * o BLE_ADDR_TYPE_PUBLIC + * o BLE_ADDR_TYPE_RANDOM + * o BLE_ADDR_TYPE_RPA_PUB_DEFAULT + * o BLE_ADDR_TYPE_RPA_RND_DEFAULT + * This parameter is ignored unless active + * scanning is being used. + * @param duration_ms The duration of the discovery procedure. + * On expiration, the procedure ends and a + * BLE_GAP_EVENT_DISC_COMPLETE event is + * reported. Units are milliseconds. Specify + * BLE_HS_FOREVER for no expiration. + * @param disc_params Additional arguments specifying the particulars + * of the discovery procedure. + * @param cb The callback to associate with this discovery + * procedure. Advertising reports and + * discovery termination events are reported + * through this callback. + * @param cb_arg The optional argument to pass to the callback + * function. * * @return 0 on success; nonzero on failure. */ int -ble_gap_disc(uint32_t duration_ms, uint8_t discovery_mode, - uint8_t scan_type, uint8_t filter_policy, uint8_t addr_mode, - ble_gap_disc_fn *cb, void *cb_arg) +ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, + const struct ble_gap_disc_params *disc_params, + ble_gap_event_fn *cb, void *cb_arg) { #if !NIMBLE_OPT(ROLE_OBSERVER) return BLE_HS_ENOTSUP; #endif + struct ble_gap_disc_params params; uint32_t duration_ticks; int rc; - ble_hs_lock(); - - if (ble_gap_master.op != BLE_GAP_OP_NULL) { - rc = BLE_HS_EALREADY; - goto done; - } - STATS_INC(ble_gap_stats, discover); - if (discovery_mode != BLE_GAP_DISC_MODE_LTD && - discovery_mode != BLE_GAP_DISC_MODE_GEN) { - - rc = BLE_HS_EINVAL; - goto done; - } + ble_hs_lock(); - if (scan_type != BLE_HCI_SCAN_TYPE_PASSIVE && - scan_type != BLE_HCI_SCAN_TYPE_ACTIVE) { + /* Make a copy of the parameter strcuture and fill unspecified values with + * defaults. + */ + params = *disc_params; + ble_gap_disc_fill_dflts(¶ms); - rc = BLE_HS_EINVAL; + rc = ble_gap_disc_validate(own_addr_type, ¶ms); + if (rc != 0) { goto done; } - if((addr_mode != BLE_HCI_ADV_OWN_ADDR_PUBLIC) && - (addr_mode != BLE_HCI_ADV_OWN_ADDR_RANDOM) && - (addr_mode != BLE_HCI_ADV_OWN_ADDR_PRIV_PUB) && - (addr_mode != BLE_HCI_ADV_OWN_ADDR_PRIV_RAND)) { - rc = BLE_HS_EINVAL; - goto done; - } - - if (filter_policy > BLE_HCI_SCAN_FILT_MAX) { - rc = BLE_HS_EINVAL; - goto done; + if (duration_ms == 0) { + duration_ms = BLE_GAP_DISC_DUR_DFLT; } - if (duration_ms == 0) { - duration_ms = BLE_GAP_GEN_DISC_SCAN_MIN; + if (duration_ms != BLE_HS_FOREVER) { + rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); + if (rc != 0) { + /* Duration too great. */ + rc = BLE_HS_EINVAL; + goto done; + } } - rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); - if (rc != 0) { - /* Duration too great. */ - rc = BLE_HS_EINVAL; - goto done; + if (!params.passive) { + rc = ble_hs_id_use_addr(own_addr_type); + if (rc != 0) { + return rc; + } } - ble_gap_master.disc.disc_mode = discovery_mode; - ble_gap_master.disc.cb = cb; - ble_gap_master.disc.cb_arg = cb_arg; + ble_gap_master.disc.limited = params.limited; + ble_gap_master.cb = cb; + ble_gap_master.cb_arg = cb_arg; BLE_HS_LOG(INFO, "GAP procedure initiated: discovery; "); - ble_gap_log_disc(scan_type, filter_policy, addr_mode); + ble_gap_log_disc(own_addr_type, duration_ms, ¶ms); BLE_HS_LOG(INFO, "\n"); - if (addr_mode == BLE_HCI_ADV_OWN_ADDR_RANDOM) { - ble_hs_pvcy_set_our_nrpa(); - } - - rc = ble_gap_disc_tx_params(scan_type, filter_policy, addr_mode); + rc = ble_gap_disc_tx_params(own_addr_type, ¶ms); if (rc != 0) { goto done; } - rc = ble_gap_disc_tx_enable(); + ble_gap_master.op = BLE_GAP_OP_M_DISC; + + rc = ble_gap_disc_enable_tx(1, params.filter_duplicates); if (rc != 0) { + ble_gap_master_reset_state(); goto done; } - ble_gap_master_set_timer(duration_ticks); - ble_gap_master.op = BLE_GAP_OP_M_DISC; + if (duration_ms != BLE_HS_FOREVER) { + ble_gap_master_set_timer(duration_ticks); + } rc = 0; done: + ble_hs_unlock(); + if (rc != 0) { STATS_INC(ble_gap_stats, discover_fail); } - - ble_hs_unlock(); - return rc; } +/** + * Indicates whether a discovery procedure is currently in progress. + * + * @return 0: No discovery procedure in progress; + * 1: Discovery procedure in progress. + */ +int +ble_gap_disc_active(void) +{ + /* Assume read is atomic; mutex not necessary. */ + return ble_gap_master.op == BLE_GAP_OP_M_DISC; +} + /***************************************************************************** * $connection establishment procedures * *****************************************************************************/ static int -ble_gap_conn_create_tx(int addr_type, uint8_t *addr, - struct ble_gap_crt_params *params) +ble_gap_conn_create_tx(uint8_t own_addr_type, + uint8_t peer_addr_type, const uint8_t *peer_addr, + const struct ble_gap_conn_params *params) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_CREATE_CONN_LEN]; struct hci_create_conn hcc; @@ -1807,18 +2148,21 @@ ble_gap_conn_create_tx(int addr_type, uint8_t *addr, hcc.scan_itvl = params->scan_itvl; hcc.scan_window = params->scan_window; - if (addr_type == BLE_GAP_ADDR_TYPE_WL) { + if (peer_addr_type == BLE_GAP_ADDR_TYPE_WL) { + /* Application wants to connect to any device in the white list. The + * peer address type and peer address fields are ignored by the + * controller; fill them with dummy values. + */ hcc.filter_policy = BLE_HCI_CONN_FILT_USE_WL; - hcc.peer_addr_type = BLE_HCI_ADV_PEER_ADDR_PUBLIC; + hcc.peer_addr_type = 0; memset(hcc.peer_addr, 0, sizeof hcc.peer_addr); } else { hcc.filter_policy = BLE_HCI_CONN_FILT_NO_WL; - hcc.peer_addr_type = addr_type; - memcpy(hcc.peer_addr, addr, sizeof hcc.peer_addr); + hcc.peer_addr_type = peer_addr_type; + memcpy(hcc.peer_addr, peer_addr, sizeof hcc.peer_addr); } - /* TODO error check our_addr_type */ - hcc.own_addr_type = params->our_addr_type; + hcc.own_addr_type = own_addr_type; hcc.conn_itvl_min = params->itvl_min; hcc.conn_itvl_max = params->itvl_max; hcc.conn_latency = params->latency; @@ -1826,12 +2170,12 @@ ble_gap_conn_create_tx(int addr_type, uint8_t *addr, hcc.min_ce_len = params->min_ce_len; hcc.max_ce_len = params->max_ce_len; - rc = host_hci_cmd_build_le_create_connection(&hcc, buf, sizeof buf); + rc = ble_hs_hci_cmd_build_le_create_connection(&hcc, buf, sizeof buf); if (rc != 0) { return BLE_HS_EUNKNOWN; } - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1840,108 +2184,193 @@ ble_gap_conn_create_tx(int addr_type, uint8_t *addr, } /** - * Performs the Direct Connection Establishment Procedure, as described in - * vol. 3, part C, section 9.3.8. + * Initiates a connect procedure. * - * @param addr_type The peer's address type; one of: - * o BLE_HCI_CONN_PEER_ADDR_PUBLIC - * o BLE_HCI_CONN_PEER_ADDR_RANDOM - * o BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT - * o BLE_HCI_CONN_PEER_ADDR_RANDOM_IDENT - * o BLE_GAP_ADDR_TYPE_WL - * @param addr The address of the peer to connect to. + * @param own_addr_type The type of address the stack should use for + * itself during connection establishment. + * o BLE_ADDR_TYPE_PUBLIC + * o BLE_ADDR_TYPE_RANDOM + * o BLE_ADDR_TYPE_RPA_PUB_DEFAULT + * o BLE_ADDR_TYPE_RPA_RND_DEFAULT + * @param peer_addr_type The peer's address type. One of: + * o BLE_HCI_CONN_PEER_ADDR_PUBLIC + * o BLE_HCI_CONN_PEER_ADDR_RANDOM + * o BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT + * o BLE_HCI_CONN_PEER_ADDR_RANDOM_IDENT + * o BLE_GAP_ADDR_TYPE_WL + * @param peer_addr The identity address of the peer to connect to. + * This parameter is ignored when the white + * list is used. + * @param duration_ms The duration of the discovery procedure. + * On expiration, the procedure ends and a + * BLE_GAP_EVENT_DISC_COMPLETE event is + * reported. Units are milliseconds. + * @param conn_params Additional arguments specifying the particulars + * of the connect procedure. Specify null for + * default values. + * @param cb The callback to associate with this connect + * procedure. When the connect procedure + * completes, the result is reported through + * this callback. If the connect procedure + * succeeds, the connection inherits this + * callback as its event-reporting mechanism. + * @param cb_arg The optional argument to pass to the callback + * function. * * @return 0 on success; nonzero on failure. */ int -ble_gap_conn_initiate(int addr_type, uint8_t *addr, - struct ble_gap_crt_params *params, - ble_gap_event_fn *cb, void *cb_arg) +ble_gap_connect(uint8_t own_addr_type, + uint8_t peer_addr_type, const uint8_t *peer_addr, + int32_t duration_ms, + const struct ble_gap_conn_params *conn_params, + ble_gap_event_fn *cb, void *cb_arg) { #if !NIMBLE_OPT(ROLE_CENTRAL) return BLE_HS_ENOTSUP; #endif + uint32_t duration_ticks; int rc; + STATS_INC(ble_gap_stats, initiate); + ble_hs_lock(); - if (ble_gap_master.op != BLE_GAP_OP_NULL) { + if (ble_gap_conn_active()) { rc = BLE_HS_EALREADY; goto done; } - STATS_INC(ble_gap_stats, initiate); + if (ble_gap_disc_active()) { + rc = BLE_HS_EBUSY; + goto done; + } - if (addr_type != BLE_HCI_CONN_PEER_ADDR_PUBLIC && - addr_type != BLE_HCI_CONN_PEER_ADDR_RANDOM && - addr_type != BLE_HCI_CONN_PEER_ADDR_PUB_ID && - addr_type != BLE_HCI_CONN_PEER_ADDR_RAND_ID && - addr_type != BLE_GAP_ADDR_TYPE_WL) { + if (!ble_hs_conn_can_alloc()) { + rc = BLE_HS_ENOMEM; + goto done; + } + + if (peer_addr_type != BLE_HCI_CONN_PEER_ADDR_PUBLIC && + peer_addr_type != BLE_HCI_CONN_PEER_ADDR_RANDOM && + peer_addr_type != BLE_HCI_CONN_PEER_ADDR_PUB_ID && + peer_addr_type != BLE_HCI_CONN_PEER_ADDR_RAND_ID && + peer_addr_type != BLE_GAP_ADDR_TYPE_WL) { rc = BLE_HS_EINVAL; goto done; } - if (params == NULL) { - params = (void *)&ble_gap_params_dflt; + if (conn_params == NULL) { + conn_params = &ble_gap_conn_params_dflt; + } + + if (duration_ms == 0) { + duration_ms = BLE_GAP_CONN_DUR_DFLT; + } + + if (duration_ms != BLE_HS_FOREVER) { + rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); + if (rc != 0) { + /* Duration too great. */ + rc = BLE_HS_EINVAL; + goto done; + } } - /* XXX: Verify params. */ + /* XXX: Verify conn_params. */ + + rc = ble_hs_id_use_addr(own_addr_type); + if (rc != 0) { + return rc; + } BLE_HS_LOG(INFO, "GAP procedure initiated: connect; "); - ble_gap_log_conn(addr_type, addr, params); + ble_gap_log_conn(own_addr_type, peer_addr_type, peer_addr, conn_params); BLE_HS_LOG(INFO, "\n"); - ble_gap_master.conn.cb = cb; - ble_gap_master.conn.cb_arg = cb_arg; - ble_gap_master.conn.using_wl = addr_type == BLE_GAP_ADDR_TYPE_WL; - ble_gap_master.conn.our_addr_type = params->our_addr_type; + ble_gap_master.cb = cb; + ble_gap_master.cb_arg = cb_arg; + ble_gap_master.conn.using_wl = peer_addr_type == BLE_GAP_ADDR_TYPE_WL; + ble_gap_master.conn.our_addr_type = own_addr_type; - rc = ble_gap_conn_create_tx(addr_type, addr, params); + ble_gap_master.op = BLE_GAP_OP_M_CONN; + + rc = ble_gap_conn_create_tx(own_addr_type, peer_addr_type, peer_addr, + conn_params); if (rc != 0) { + ble_gap_master_reset_state(); goto done; } - ble_gap_master.op = BLE_GAP_OP_M_CONN; + if (duration_ms != BLE_HS_FOREVER) { + ble_gap_master_set_timer(duration_ticks); + } rc = 0; done: + ble_hs_unlock(); + if (rc != 0) { STATS_INC(ble_gap_stats, initiate_fail); } - - ble_hs_unlock(); - return rc; } +/** + * Indicates whether a connect procedure is currently in progress. + * + * @return 0: No connect procedure in progress; + * 1: Connect procedure in progress. + */ +int +ble_gap_conn_active(void) +{ + /* Assume read is atomic; mutex not necessary. */ + return ble_gap_master.op == BLE_GAP_OP_M_CONN; +} + /***************************************************************************** * $terminate connection procedure * *****************************************************************************/ +/** + * Terminates an established connection. + * + * @param conn_handle The handle corresponding to the connection to + * terminate. + * @param hci_reason The HCI error code to indicate as the reason + * for termination. + * + * @return 0 on success; + * BLE_HS_ENOTCONN if there is no connection with + * the specified handle; + * Other nonzero on failure. + */ int -ble_gap_terminate(uint16_t conn_handle) +ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_DISCONNECT_CMD_LEN]; int rc; - ble_hs_lock(); - STATS_INC(ble_gap_stats, terminate); + ble_hs_lock(); + if (!ble_hs_conn_exists(conn_handle)) { rc = BLE_HS_ENOTCONN; goto done; } BLE_HS_LOG(INFO, "GAP procedure initiated: terminate connection; " - "conn_handle=%d\n", conn_handle); + "conn_handle=%d hci_reason=%d\n", + conn_handle, hci_reason); - host_hci_cmd_build_disconnect(conn_handle, BLE_ERR_REM_USER_CONN_TERM, - buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_disconnect(conn_handle, hci_reason, + buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { goto done; } @@ -1949,12 +2378,11 @@ ble_gap_terminate(uint16_t conn_handle) rc = 0; done: + ble_hs_unlock(); + if (rc != 0) { STATS_INC(ble_gap_stats, terminate_fail); } - - ble_hs_unlock(); - return rc; } @@ -1962,38 +2390,59 @@ done: * $cancel * *****************************************************************************/ -int -ble_gap_cancel(void) +static int +ble_gap_conn_cancel_tx(void) { uint8_t buf[BLE_HCI_CMD_HDR_LEN]; int rc; - ble_hs_lock(); + ble_hs_hci_cmd_build_le_create_conn_cancel(buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); + if (rc != 0) { + return rc; + } + + return 0; +} + +/** + * Aborts a connect procedure in progress. + * + * @return 0 on success; + * BLE_HS_EALREADY if there is no active connect + * procedure. + * Other nonzero on error. + */ +int +ble_gap_conn_cancel(void) +{ + int rc; STATS_INC(ble_gap_stats, cancel); - if (!ble_gap_master_in_progress()) { - rc = BLE_HS_ENOENT; + ble_hs_lock(); + + if (!ble_gap_conn_active()) { + rc = BLE_HS_EALREADY; goto done; } BLE_HS_LOG(INFO, "GAP procedure initiated: cancel connection\n"); - host_hci_cmd_build_le_create_conn_cancel(buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_gap_conn_cancel_tx(); if (rc != 0) { goto done; } + ble_gap_master.conn.cancel = 1; rc = 0; done: + ble_hs_unlock(); + if (rc != 0) { STATS_INC(ble_gap_stats, cancel_fail); } - - ble_hs_unlock(); - return rc; } @@ -2017,8 +2466,8 @@ ble_gap_tx_param_pos_reply(uint16_t conn_handle, pos_reply.min_ce_len = params->min_ce_len; pos_reply.max_ce_len = params->max_ce_len; - host_hci_cmd_build_le_conn_param_reply(&pos_reply, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_le_conn_param_reply(&pos_reply, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -2036,8 +2485,8 @@ ble_gap_tx_param_neg_reply(uint16_t conn_handle, uint8_t reject_reason) neg_reply.handle = conn_handle; neg_reply.reason = reject_reason; - host_hci_cmd_build_le_conn_param_neg_reply(&neg_reply, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_le_conn_param_neg_reply(&neg_reply, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -2054,18 +2503,13 @@ ble_gap_rx_param_req(struct hci_le_conn_param_req *evt) struct ble_gap_upd_params peer_params; struct ble_gap_upd_params self_params; - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; + struct ble_gap_event event; uint8_t reject_reason; int rc; reject_reason = 0; /* Silence warning. */ - rc = ble_gap_find_snapshot(evt->connection_handle, &snap); - if (rc != 0) { - /* We are not connected to the sender. */ - return; - } + memset(&event, 0, sizeof event); peer_params.itvl_min = evt->itvl_min; peer_params.itvl_max = evt->itvl_max; @@ -2080,12 +2524,12 @@ ble_gap_rx_param_req(struct hci_le_conn_param_req *evt) */ self_params = peer_params; - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - ctxt.conn_update_req.self_params = &self_params; - ctxt.conn_update_req.peer_params = &peer_params; - rc = ble_gap_call_event_cb(BLE_GAP_EVENT_CONN_UPDATE_REQ, &ctxt, - snap.cb, snap.cb_arg); + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_CONN_UPDATE_REQ; + event.conn_update_req.conn_handle = evt->connection_handle; + event.conn_update_req.self_params = &self_params; + event.conn_update_req.peer_params = &peer_params; + rc = ble_gap_call_conn_event_cb(&event, evt->connection_handle); if (rc != 0) { reject_reason = rc; } @@ -2104,7 +2548,8 @@ ble_gap_rx_param_req(struct hci_le_conn_param_req *evt) } static int -ble_gap_update_tx(uint16_t conn_handle, struct ble_gap_upd_params *params) +ble_gap_update_tx(uint16_t conn_handle, + const struct ble_gap_upd_params *params) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_UPDATE_LEN]; struct hci_conn_update cmd; @@ -2118,12 +2563,12 @@ ble_gap_update_tx(uint16_t conn_handle, struct ble_gap_upd_params *params) cmd.min_ce_len = params->min_ce_len; cmd.max_ce_len = params->max_ce_len; - rc = host_hci_cmd_build_le_conn_update(&cmd, buf, sizeof buf); + rc = ble_hs_hci_cmd_build_le_conn_update(&cmd, buf, sizeof buf); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -2131,8 +2576,25 @@ ble_gap_update_tx(uint16_t conn_handle, struct ble_gap_upd_params *params) return 0; } +/** + * Initiates a connection parameter update procedure. + * + * @param conn_handle The handle corresponding to the connection to + * update. + * @param params The connection parameters to attempt to update + * to. + * + * @return 0 on success; + * BLE_HS_ENOTCONN if the there is no connection + * with the specified handle; + * BLE_HS_EALREADY if a connection update + * procedure for this connection is already in + * progress; + * Other nonzero on error. + */ int -ble_gap_update_params(uint16_t conn_handle, struct ble_gap_upd_params *params) +ble_gap_update_params(uint16_t conn_handle, + const struct ble_gap_upd_params *params) { #if !NIMBLE_OPT(CONNECT) return BLE_HS_ENOTSUP; @@ -2141,10 +2603,10 @@ ble_gap_update_params(uint16_t conn_handle, struct ble_gap_upd_params *params) struct ble_hs_conn *conn; int rc; - ble_hs_lock(); - STATS_INC(ble_gap_stats, update); + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); if (conn == NULL) { rc = BLE_HS_ENOTCONN; @@ -2168,12 +2630,11 @@ ble_gap_update_params(uint16_t conn_handle, struct ble_gap_upd_params *params) conn->bhc_flags |= BLE_HS_CONN_F_UPDATE; done: + ble_hs_unlock(); + if (rc != 0) { STATS_INC(ble_gap_stats, update_fail); } - - ble_hs_unlock(); - return rc; } @@ -2181,6 +2642,19 @@ done: * $security * *****************************************************************************/ +/** + * Initiates the GAP encryption procedure. + * + * @param conn_handle The handle corresponding to the connection to + * encrypt. + * + * @return 0 on success; + * BLE_HS_ENOTCONN if the there is no connection + * with the specified handle; + * BLE_HS_EALREADY if an encrpytion procedure for + * this connection is already in progress; + * Other nonzero on error. + */ int ble_gap_security_initiate(uint16_t conn_handle) { @@ -2195,6 +2669,8 @@ ble_gap_security_initiate(uint16_t conn_handle) struct ble_hs_conn *conn; int rc; + STATS_INC(ble_gap_stats, security_initiate); + ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); if (conn != NULL) { @@ -2208,7 +2684,8 @@ ble_gap_security_initiate(uint16_t conn_handle) ble_hs_unlock(); if (conn == NULL) { - return BLE_HS_ENOTCONN; + rc = BLE_HS_ENOTCONN; + goto done; } if (conn_flags & BLE_HS_CONN_F_MASTER) { @@ -2221,11 +2698,27 @@ ble_gap_security_initiate(uint16_t conn_handle) rc = ble_sm_enc_initiate(conn_handle, value_sec.ltk, value_sec.ediv, value_sec.rand_num, value_sec.authenticated); + if (rc != 0) { + goto done; + } } else { rc = ble_sm_pair_initiate(conn_handle); + if (rc != 0) { + goto done; + } } } else { rc = ble_sm_slave_initiate(conn_handle); + if (rc != 0) { + goto done; + } + } + + rc = 0; + +done: + if (rc != 0) { + STATS_INC(ble_gap_stats, security_initiate_fail); } return rc; @@ -2243,7 +2736,7 @@ ble_gap_pair_initiate(uint16_t conn_handle) int ble_gap_encryption_initiate(uint16_t conn_handle, - uint8_t *ltk, + const uint8_t *ltk, uint16_t ediv, uint64_t rand_val, int auth) @@ -2270,38 +2763,22 @@ ble_gap_encryption_initiate(uint16_t conn_handle, void ble_gap_passkey_event(uint16_t conn_handle, - struct ble_gap_passkey_action *passkey_action) + struct ble_gap_passkey_params *passkey_params) { #if !NIMBLE_OPT(SM) return; #endif - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; - struct ble_hs_conn *conn; - - ble_hs_lock(); - - conn = ble_hs_conn_find(conn_handle); - if (conn != NULL) { - ble_gap_conn_to_snapshot(conn, &snap); - } - - ble_hs_unlock(); - - if (conn == NULL) { - /* No longer connected. */ - return; - } + struct ble_gap_event event; BLE_HS_LOG(DEBUG, "send passkey action request %d\n", - passkey_action->action); + passkey_params->action); - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - ctxt.passkey_action = *passkey_action; - ble_gap_call_event_cb(BLE_GAP_EVENT_PASSKEY_ACTION, &ctxt, - snap.cb, snap.cb_arg); + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_PASSKEY_ACTION; + event.passkey.conn_handle = conn_handle; + event.passkey.params = *passkey_params; + ble_gap_call_conn_event_cb(&event, conn_handle); } void @@ -2311,59 +2788,134 @@ ble_gap_enc_event(uint16_t conn_handle, int status, int security_restored) return; #endif - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; - int rc; - - rc = ble_gap_find_snapshot(conn_handle, &snap); - if (rc != 0) { - /* No longer connected. */ - return; - } + struct ble_gap_event event; - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - ctxt.enc_change.status = status; - ble_gap_call_event_cb(BLE_GAP_EVENT_ENC_CHANGE, &ctxt, - snap.cb, snap.cb_arg); + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_ENC_CHANGE; + event.enc_change.conn_handle = conn_handle; + event.enc_change.status = status; + ble_gap_call_conn_event_cb(&event, conn_handle); if (status == 0 && security_restored) { - BLE_HS_DBG_ASSERT(snap.desc.sec_state.bonded); ble_gatts_bonding_restored(conn_handle); } } /***************************************************************************** + * $rssi * + *****************************************************************************/ + +/** + * Retrieves the most-recently measured RSSI for the specified connection. A + * connection's RSSI is updated whenever a data channel PDU is received. + * + * @param conn_handle Specifies the connection to query. + * @param out_rssi On success, the retrieved RSSI is written here. + * + * @return 0 on success; + * A BLE host HCI return code if the controller + * rejected the request; + * A BLE host core return code on unexpected + * error. + */ +int +ble_gap_conn_rssi(uint16_t conn_handle, int8_t *out_rssi) +{ + int rc; + + rc = ble_hs_hci_util_read_rssi(conn_handle, out_rssi); + return rc; +} + +/***************************************************************************** * $notify * *****************************************************************************/ void -ble_gap_notify_event(uint16_t conn_handle, uint16_t attr_handle, - void *attr_data, uint16_t attr_len, int is_indication) +ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle, + struct os_mbuf *om, int is_indication) { - /* XXX: Early return if notifications and indications disabled. */ - struct ble_gap_conn_ctxt ctxt; - struct ble_gap_snapshot snap; - int rc; +#if !NIMBLE_OPT(GATT_NOTIFY) && !NIMBLE_OPT(GATT_INDICATE) + return; +#endif - rc = ble_gap_find_snapshot(conn_handle, &snap); - if (rc != 0) { - /* No longer connected. */ - return; - } + struct ble_gap_event event; - memset(&ctxt, 0, sizeof ctxt); - ctxt.desc = &snap.desc; - ctxt.notify.attr_handle = attr_handle; - ctxt.notify.attr_data = attr_data; - ctxt.notify.attr_len = attr_len; - ctxt.notify.indication = is_indication; - ble_gap_call_event_cb(BLE_GAP_EVENT_NOTIFY, &ctxt, snap.cb, snap.cb_arg); + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_NOTIFY_RX; + event.notify_rx.conn_handle = conn_handle; + event.notify_rx.attr_handle = attr_handle; + event.notify_rx.om = om; + event.notify_rx.indication = is_indication; + ble_gap_call_conn_event_cb(&event, conn_handle); + + os_mbuf_free_chain(event.notify_rx.om); } -void ble_gap_init_identity_addr(uint8_t *addr) +void +ble_gap_notify_tx_event(int status, uint16_t conn_handle, uint16_t attr_handle, + int is_indication) { - ble_hs_pvcy_set_our_id_addr(addr); +#if !NIMBLE_OPT(GATT_NOTIFY) && !NIMBLE_OPT(GATT_INDICATE) + return; +#endif + + struct ble_gap_event event; + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_NOTIFY_TX; + event.notify_tx.conn_handle = conn_handle; + event.notify_tx.status = status; + event.notify_tx.attr_handle = attr_handle; + event.notify_tx.indication = is_indication; + ble_gap_call_conn_event_cb(&event, conn_handle); +} + +/***************************************************************************** + * $subscribe * + *****************************************************************************/ + +void +ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle, + uint8_t reason, + uint8_t prev_notify, uint8_t cur_notify, + uint8_t prev_indicate, uint8_t cur_indicate) +{ + struct ble_gap_event event; + + BLE_HS_DBG_ASSERT(prev_notify != cur_notify || + prev_indicate != cur_indicate); + BLE_HS_DBG_ASSERT(reason == BLE_GAP_SUBSCRIBE_REASON_WRITE || + reason == BLE_GAP_SUBSCRIBE_REASON_TERM || + reason == BLE_GAP_SUBSCRIBE_REASON_RESTORE); + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_SUBSCRIBE; + event.subscribe.conn_handle = conn_handle; + event.subscribe.attr_handle = attr_handle; + event.subscribe.reason = reason; + event.subscribe.prev_notify = !!prev_notify; + event.subscribe.cur_notify = !!cur_notify; + event.subscribe.prev_indicate = !!prev_indicate; + event.subscribe.cur_indicate = !!cur_indicate; + ble_gap_call_conn_event_cb(&event, conn_handle); +} + +/***************************************************************************** + * $mtu * + *****************************************************************************/ + +void +ble_gap_mtu_event(uint16_t conn_handle, uint16_t cid, uint16_t mtu) +{ + struct ble_gap_event event; + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_MTU; + event.mtu.conn_handle = conn_handle; + event.mtu.channel_id = cid; + event.mtu.value = mtu; + ble_gap_call_conn_event_cb(&event, conn_handle); } /***************************************************************************** diff --git a/net/nimble/host/src/ble_gap_priv.h b/net/nimble/host/src/ble_gap_priv.h index 547dffb7..eed5a18f 100644 --- a/net/nimble/host/src/ble_gap_priv.h +++ b/net/nimble/host/src/ble_gap_priv.h @@ -28,7 +28,7 @@ struct hci_le_conn_param_req; struct hci_le_conn_complete; struct hci_disconn_complete; struct hci_encrypt_change; -struct ble_hci_ack; +struct ble_hs_hci_ack; struct ble_hs_adv; STATS_SECT_START(ble_gap_stats) @@ -61,6 +61,8 @@ STATS_SECT_START(ble_gap_stats) STATS_SECT_ENTRY(rx_conn_complete) STATS_SECT_ENTRY(discover_cancel) STATS_SECT_ENTRY(discover_cancel_fail) + STATS_SECT_ENTRY(security_initiate) + STATS_SECT_ENTRY(security_initiate_fail) STATS_SECT_END extern STATS_SECT_DECL(ble_gap_stats) ble_gap_stats; @@ -68,8 +70,7 @@ extern STATS_SECT_DECL(ble_gap_stats) ble_gap_stats; #define BLE_GAP_CONN_MODE_MAX 3 #define BLE_GAP_DISC_MODE_MAX 3 -int ble_gap_locked_by_cur_task(void); -void ble_gap_rx_adv_report(struct ble_hs_adv *adv); +void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc); int ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt); void ble_gap_rx_disconn_complete(struct hci_disconn_complete *evt); void ble_gap_rx_update_complete(struct hci_le_conn_upd_complete *evt); @@ -79,14 +80,20 @@ int ble_gap_rx_l2cap_update_req(uint16_t conn_handle, void ble_gap_enc_event(uint16_t conn_handle, int status, int security_restored); void ble_gap_passkey_event(uint16_t conn_handle, - struct ble_gap_passkey_action *passkey_action); -void ble_gap_notify_event(uint16_t conn_handle, uint16_t attr_handle, - void *attr_data, uint16_t attr_len, - int is_indication); + struct ble_gap_passkey_params *passkey_params); +void ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle, + struct os_mbuf *om, int is_indication); +void ble_gap_notify_tx_event(int status, uint16_t conn_handle, + uint16_t attr_handle, int is_indication); +void ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle, + uint8_t reason, + uint8_t prev_notify, uint8_t cur_notify, + uint8_t prev_indicate, uint8_t cur_indicate); +void ble_gap_mtu_event(uint16_t conn_handle, uint16_t cid, uint16_t mtu); int ble_gap_master_in_progress(void); -int ble_gap_slave_in_progress(void); -uint32_t ble_gap_heartbeat(void); +void ble_gap_conn_broken(uint16_t conn_handle, int reason); +int32_t ble_gap_heartbeat(void); int ble_gap_init(void); diff --git a/net/nimble/host/src/ble_gatt_priv.h b/net/nimble/host/src/ble_gatt_priv.h index 5955b913..7c0f020a 100644 --- a/net/nimble/host/src/ble_gatt_priv.h +++ b/net/nimble/host/src/ble_gatt_priv.h @@ -84,8 +84,6 @@ extern STATS_SECT_DECL(ble_gatts_stats) ble_gatts_stats; #define BLE_GATT_CHR_DECL_SZ_16 5 #define BLE_GATT_CHR_DECL_SZ_128 19 -#define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902 - typedef uint8_t ble_gatts_conn_flags; struct ble_gatts_conn { @@ -97,22 +95,19 @@ struct ble_gatts_conn { /*** @client. */ int ble_gattc_locked_by_cur_task(void); -int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, void *value, - uint16_t value_len, ble_gatt_attr_fn *cb, void *cb_arg); -int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle, - ble_gatt_attr_fn *cb, void *cb_arg); +void ble_gatts_indicate_fail_notconn(uint16_t conn_handle); void ble_gattc_rx_err(uint16_t conn_handle, struct ble_att_error_rsp *rsp); void ble_gattc_rx_mtu(uint16_t conn_handle, int status, uint16_t chan_mtu); void ble_gattc_rx_read_type_adata(uint16_t conn_handle, struct ble_att_read_type_adata *adata); void ble_gattc_rx_read_type_complete(uint16_t conn_handle, int status); -void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value, - int value_len); +void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, + struct os_mbuf **rxom); void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, - void *value, int value_len); + struct os_mbuf **rxom); void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, - void *value, int value_len); + struct os_mbuf **rxom); void ble_gattc_rx_read_group_type_adata( uint16_t conn_handle, struct ble_att_read_group_type_adata *adata); void ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int rc); @@ -122,7 +117,7 @@ void ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, int status); void ble_gattc_rx_write_rsp(uint16_t conn_handle); void ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status, struct ble_att_prep_write_cmd *rsp, - void *attr_data, uint16_t attr_data_len); + struct os_mbuf **rxom); void ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, int status); void ble_gattc_rx_indicate_rsp(uint16_t conn_handle); void ble_gattc_rx_find_info_idata(uint16_t conn_handle, @@ -130,7 +125,7 @@ void ble_gattc_rx_find_info_idata(uint16_t conn_handle, void ble_gattc_rx_find_info_complete(uint16_t conn_handle, int status); void ble_gattc_connection_txable(uint16_t conn_handle); void ble_gattc_connection_broken(uint16_t conn_handle); -uint32_t ble_gattc_heartbeat(void); +int32_t ble_gattc_heartbeat(void); int ble_gattc_any_jobs(void); int ble_gattc_init(void); @@ -138,7 +133,7 @@ int ble_gattc_init(void); /*** @server. */ #define BLE_GATTS_CLT_CFG_F_NOTIFY 0x0001 #define BLE_GATTS_CLT_CFG_F_INDICATE 0x0002 -#define BLE_GATTS_CLT_CFG_F_INDICATE_PENDING 0x0080 /* Internal only. */ +#define BLE_GATTS_CLT_CFG_F_MODIFIED 0x0080 /* Internal only. */ #define BLE_GATTS_CLT_CFG_F_RESERVED 0xfffc #define BLE_GATTS_INC_SVC_LEN_NO_UUID 4 @@ -146,10 +141,11 @@ int ble_gattc_init(void); int ble_gatts_rx_indicate_ack(uint16_t conn_handle, uint16_t chr_val_handle); int ble_gatts_send_next_indicate(uint16_t conn_handle); +void ble_gatts_tx_notifications(void); void ble_gatts_bonding_restored(uint16_t conn_handle); +void ble_gatts_connection_broken(uint16_t conn_handle); /*** @misc. */ -void ble_gatts_conn_deinit(struct ble_gatts_conn *gatts_conn); int ble_gatts_conn_can_alloc(void); int ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn); int ble_gatts_start(void); diff --git a/net/nimble/host/src/ble_gattc.c b/net/nimble/host/src/ble_gattc.c index 29e6b4ef..3dee6799 100644 --- a/net/nimble/host/src/ble_gattc.c +++ b/net/nimble/host/src/ble_gattc.c @@ -138,7 +138,7 @@ struct ble_gattc_proc { } disc_chr_uuid; struct { - uint16_t chr_def_handle; + uint16_t chr_val_handle; uint16_t prev_handle; uint16_t end_handle; ble_gatt_dsc_fn *cb; @@ -182,17 +182,16 @@ struct ble_gattc_proc { } write_long; struct { - struct ble_gatt_attr *attrs; - int num_attrs; - int cur_attr; + struct ble_gatt_attr attrs[NIMBLE_OPT(GATT_WRITE_MAX_ATTRS)]; + uint8_t num_attrs; + uint8_t cur_attr; + uint16_t length; ble_gatt_reliable_attr_fn *cb; void *cb_arg; } write_reliable; struct { - ble_gatt_attr_fn *cb; uint16_t chr_val_handle; - void *cb_arg; } indicate; }; }; @@ -248,10 +247,10 @@ typedef int ble_gattc_rx_adata_fn(struct ble_gattc_proc *proc, typedef int ble_gattc_rx_prep_fn(struct ble_gattc_proc *proc, int status, struct ble_att_prep_write_cmd *rsp, - void *attr_data, uint16_t attr_len); + struct os_mbuf **om); typedef int ble_gattc_rx_attr_fn(struct ble_gattc_proc *proc, int status, - void *value, int value_len); + struct os_mbuf **om); typedef int ble_gattc_rx_complete_fn(struct ble_gattc_proc *proc, int status); typedef int ble_gattc_rx_exec_fn(struct ble_gattc_proc *proc, int status); @@ -393,9 +392,9 @@ ble_gattc_log_proc_init(char *name) } static void -ble_gattc_log_uuid(void *uuid128) +ble_gattc_log_uuid(const void *uuid128) { - uint8_t *u8p; + const uint8_t *u8p; u8p = uuid128; BLE_HS_LOG(INFO, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" @@ -447,8 +446,8 @@ static void ble_gattc_log_disc_all_dscs(struct ble_gattc_proc *proc) { ble_gattc_log_proc_init("discover all descriptors; "); - BLE_HS_LOG(INFO, "chr_def_handle=%d end_handle=%d\n", - proc->disc_all_dscs.chr_def_handle, + BLE_HS_LOG(INFO, "chr_val_handle=%d end_handle=%d\n", + proc->disc_all_dscs.chr_val_handle, proc->disc_all_dscs.end_handle); } @@ -461,7 +460,7 @@ ble_gattc_log_read(uint16_t att_handle) static void ble_gattc_log_read_uuid(uint16_t start_handle, uint16_t end_handle, - uint8_t *uuid128) + const uint8_t *uuid128) { uint16_t uuid16; @@ -486,7 +485,7 @@ ble_gattc_log_read_long(struct ble_gattc_proc *proc) } static void -ble_gattc_log_read_mult(uint16_t *handles, uint8_t num_handles) +ble_gattc_log_read_mult(const uint16_t *handles, uint8_t num_handles) { int i; @@ -518,7 +517,8 @@ ble_gattc_log_write_long(struct ble_gattc_proc *proc) { ble_gattc_log_proc_init("write long; "); BLE_HS_LOG(INFO, "att_handle=%d len=%d\n", - proc->write_long.attr.handle, proc->write_long.attr.value_len); + proc->write_long.attr.handle, + OS_MBUF_PKTLEN(proc->write_long.attr.om)); } static void @@ -603,10 +603,26 @@ static void ble_gattc_proc_free(struct ble_gattc_proc *proc) { int rc; + int i; if (proc != NULL) { ble_gattc_dbg_assert_proc_not_inserted(proc); + switch (proc->op) { + case BLE_GATT_OP_WRITE_LONG: + os_mbuf_free_chain(proc->write_long.attr.om); + break; + + case BLE_GATT_OP_WRITE_RELIABLE: + for (i = 0; i < proc->write_reliable.num_attrs; i++) { + os_mbuf_free_chain(proc->write_reliable.attrs[i].om); + } + break; + + default: + break; + } + rc = os_memblock_put(&ble_gattc_proc_pool, proc); BLE_HS_DBG_ASSERT_EVAL(rc == 0); } @@ -618,7 +634,7 @@ ble_gattc_proc_insert(struct ble_gattc_proc *proc) ble_gattc_dbg_assert_proc_not_inserted(proc); ble_hs_lock(); - STAILQ_INSERT_HEAD(&ble_gattc_procs, proc, next); + STAILQ_INSERT_TAIL(&ble_gattc_procs, proc, next); ble_hs_unlock(); } @@ -707,9 +723,26 @@ ble_gattc_extract(uint16_t conn_handle, uint8_t op) return proc; } +static int +ble_gattc_conn_op_matches(struct ble_gattc_proc *proc, uint16_t conn_handle, + uint8_t op) +{ + if (conn_handle != BLE_HS_CONN_HANDLE_NONE && + conn_handle != proc->conn_handle) { + + return 0; + } + + if (op != BLE_GATT_OP_NONE && op != proc->op) { + return 0; + } + + return 1; +} + static void -ble_gattc_extract_by_conn(uint16_t conn_handle, - struct ble_gattc_proc_list *dst_list) +ble_gattc_extract_by_conn_op(uint16_t conn_handle, uint8_t op, + struct ble_gattc_proc_list *dst_list) { struct ble_gattc_proc *proc; struct ble_gattc_proc *prev; @@ -727,7 +760,7 @@ ble_gattc_extract_by_conn(uint16_t conn_handle, while (proc != NULL) { next = STAILQ_NEXT(proc, next); - if (proc->conn_handle == conn_handle) { + if (ble_gattc_conn_op_matches(proc, conn_handle, op)) { if (prev == NULL) { STAILQ_REMOVE_HEAD(&ble_gattc_procs, next); } else { @@ -842,6 +875,35 @@ ble_gattc_extract_with_rx_entry(uint16_t conn_handle, sizeof (rx_entries) / sizeof (rx_entries)[0], \ (const void **)(out_rx_entry)) + +/** + * Causes all GATT procedures matching the specified criteria to fail with the + * specified status code. + */ +static void +ble_gattc_fail_procs(uint16_t conn_handle, uint8_t op, int status) +{ + struct ble_gattc_proc_list temp_list; + struct ble_gattc_proc *proc; + ble_gattc_err_fn *err_cb; + + /* Remove all procs with the specified conn handle-op-pair and insert them + * into the temporary list. + */ + ble_gattc_extract_by_conn_op(conn_handle, op, &temp_list); + + /* Notify application of failed procedures and free the corresponding proc + * entries. + */ + while ((proc = STAILQ_FIRST(&temp_list)) != NULL) { + err_cb = ble_gattc_err_dispatch_get(proc->op); + err_cb(proc, status, 0); + + STAILQ_REMOVE_HEAD(&temp_list, next); + ble_gattc_proc_free(proc); + } +} + /** * Applies periodic checks and actions to all active procedures. * @@ -854,7 +916,7 @@ ble_gattc_extract_with_rx_entry(uint16_t conn_handle, * be called again; currently always * UINT32_MAX. */ -uint32_t +int32_t ble_gattc_heartbeat(void) { struct ble_gattc_proc_list exp_list; @@ -869,13 +931,13 @@ ble_gattc_heartbeat(void) /* Terminate the connection associated with each timed-out procedure. */ while ((proc = STAILQ_FIRST(&exp_list)) != NULL) { STATS_INC(ble_gattc_stats, proc_timeout); - ble_gap_terminate(proc->conn_handle); + ble_gap_terminate(proc->conn_handle, BLE_ERR_REM_USER_CONN_TERM); STAILQ_REMOVE_HEAD(&exp_list, next); ble_gattc_proc_free(proc); } - return UINT32_MAX; + return BLE_HS_FOREVER; } /** @@ -883,13 +945,14 @@ ble_gattc_heartbeat(void) * returned object is statically allocated, so this function is not reentrant. * This function should only ever be called by the ble_hs task. */ -struct ble_gatt_error * +static struct ble_gatt_error * ble_gattc_error(int status, uint16_t att_handle) { static struct ble_gatt_error error; - if (status == 0) { - return NULL; + /* For consistency, always indicate a handle of 0 on success. */ + if (status == 0 || status == BLE_HS_EDONE) { + att_handle = 0; } error.status = status; @@ -917,7 +980,7 @@ ble_gattc_mtu_cb(struct ble_gattc_proc *proc, int status, uint16_t att_handle, BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, mtu_fail); } @@ -949,7 +1012,10 @@ ble_gattc_mtu_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle) * procedure. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_exchange_mtu(uint16_t conn_handle, ble_gatt_mtu_fn *cb, void *cb_arg) @@ -976,16 +1042,10 @@ ble_gattc_exchange_mtu(uint16_t conn_handle, ble_gatt_mtu_fn *cb, void *cb_arg) ble_gattc_log_proc_init("exchange mtu\n"); ble_hs_lock(); - rc = ble_att_conn_chan_find(proc->conn_handle, &conn, &chan); - if (rc == 0) { - req.bamc_mtu = chan->blc_my_mtu; - } + ble_att_conn_chan_find(proc->conn_handle, &conn, &chan); + req.bamc_mtu = chan->blc_my_mtu; ble_hs_unlock(); - if (rc != 0) { - goto done; - } - rc = ble_att_clt_tx_mtu(proc->conn_handle, &req); if (rc != 0) { goto done; @@ -1019,9 +1079,10 @@ ble_gattc_disc_all_svcs_cb(struct ble_gattc_proc *proc, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(service != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, disc_all_svcs_fail); } @@ -1077,7 +1138,7 @@ ble_gattc_disc_all_svcs_err(struct ble_gattc_proc *proc, int status, if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) { /* Discovery is complete. */ - status = 0; + status = BLE_HS_EDONE; } ble_gattc_disc_all_svcs_cb(proc, status, att_handle, NULL); @@ -1149,19 +1210,24 @@ ble_gattc_disc_all_svcs_rx_complete(struct ble_gattc_proc *proc, int status) ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0 || proc->disc_all_svcs.prev_handle == 0xffff) { - /* Error or all svcs discovered. */ + if (status != 0) { ble_gattc_disc_all_svcs_cb(proc, status, 0, NULL); return BLE_HS_EDONE; - } else { - /* Send follow-up request. */ - rc = ble_gattc_disc_all_svcs_go(proc, 1); - if (rc != 0) { - return BLE_HS_EDONE; - } + } - return 0; + if (proc->disc_all_svcs.prev_handle == 0xffff) { + /* Service discovery complete. */ + ble_gattc_disc_all_svcs_cb(proc, BLE_HS_EDONE, 0, NULL); + return BLE_HS_EDONE; } + + /* Send follow-up request. */ + rc = ble_gattc_disc_all_svcs_go(proc, 1); + if (rc != 0) { + return BLE_HS_EDONE; + } + + return 0; } /** @@ -1171,7 +1237,8 @@ ble_gattc_disc_all_svcs_rx_complete(struct ble_gattc_proc *proc, int status) * procedure. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. */ int ble_gattc_disc_all_svcs(uint16_t conn_handle, ble_gatt_disc_svc_fn *cb, @@ -1233,9 +1300,10 @@ ble_gattc_disc_svc_uuid_cb(struct ble_gattc_proc *proc, int status, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(service != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, disc_svc_uuid_fail); } @@ -1289,7 +1357,7 @@ ble_gattc_disc_svc_uuid_err(struct ble_gattc_proc *proc, int status, if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) { /* Discovery is complete. */ - status = 0; + status = BLE_HS_EDONE; } ble_gattc_disc_svc_uuid_cb(proc, status, att_handle, NULL); @@ -1343,18 +1411,24 @@ ble_gattc_disc_svc_uuid_rx_complete(struct ble_gattc_proc *proc, int status) ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0 || proc->disc_svc_uuid.prev_handle == 0xffff) { - /* Error or all svcs discovered. */ + if (status != 0) { ble_gattc_disc_svc_uuid_cb(proc, status, 0, NULL); return BLE_HS_EDONE; - } else { - /* Send follow-up request. */ - rc = ble_gattc_disc_svc_uuid_go(proc, 1); - if (rc != 0) { - return BLE_HS_EDONE; - } - return 0; } + + if (proc->disc_svc_uuid.prev_handle == 0xffff) { + /* Service discovery complete. */ + ble_gattc_disc_svc_uuid_cb(proc, BLE_HS_EDONE, 0, NULL); + return BLE_HS_EDONE; + } + + /* Send follow-up request. */ + rc = ble_gattc_disc_svc_uuid_go(proc, 1); + if (rc != 0) { + return BLE_HS_EDONE; + } + + return 0; } /** @@ -1365,10 +1439,13 @@ ble_gattc_disc_svc_uuid_rx_complete(struct ble_gattc_proc *proc, int status) * @param service_uuid128 The 128-bit UUID of the service to discover. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int -ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, void *service_uuid128, +ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const void *svc_uuid128, ble_gatt_disc_svc_fn *cb, void *cb_arg) { #if !NIMBLE_OPT(GATT_DISC_SVC_UUID) @@ -1388,7 +1465,7 @@ ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, void *service_uuid128, proc->op = BLE_GATT_OP_DISC_SVC_UUID; proc->conn_handle = conn_handle; - memcpy(proc->disc_svc_uuid.service_uuid, service_uuid128, 16); + memcpy(proc->disc_svc_uuid.service_uuid, svc_uuid128, 16); proc->disc_svc_uuid.prev_handle = 0x0000; proc->disc_svc_uuid.cb = cb; proc->disc_svc_uuid.cb_arg = cb_arg; @@ -1428,9 +1505,10 @@ ble_gattc_find_inc_svcs_cb(struct ble_gattc_proc *proc, int status, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(service != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, find_inc_svcs_fail); } @@ -1499,7 +1577,7 @@ ble_gattc_find_inc_svcs_err(struct ble_gattc_proc *proc, int status, status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) { /* Discovery is complete. */ - status = 0; + status = BLE_HS_EDONE; } ble_gattc_find_inc_svcs_cb(proc, status, att_handle, NULL); @@ -1511,52 +1589,57 @@ ble_gattc_find_inc_svcs_err(struct ble_gattc_proc *proc, int status, */ static int ble_gattc_find_inc_svcs_rx_read_rsp(struct ble_gattc_proc *proc, int status, - void *value, int value_len) + struct os_mbuf **om) { struct ble_gatt_svc service; - int cbrc; + uint16_t om_len; int rc; ble_gattc_dbg_assert_proc_not_inserted(proc); + rc = ble_hs_mbuf_to_flat(*om, service.uuid128, 16, &om_len); + os_mbuf_free_chain(*om); + *om = NULL; + + if (rc != 0 || om_len != 16) { + /* Invalid UUID. */ + rc = BLE_HS_EBADDATA; + goto err; + } + if (proc->find_inc_svcs.cur_start == 0) { /* Unexpected read response; terminate procedure. */ rc = BLE_HS_EBADDATA; - goto done; + goto err; } if (status != 0) { rc = status; - goto done; - } - - if (value_len != 16) { - /* Invalid UUID. */ - rc = BLE_HS_EBADDATA; - goto done; + goto err; } + /* Report discovered service to application. */ service.start_handle = proc->find_inc_svcs.cur_start; service.end_handle = proc->find_inc_svcs.cur_end; - memcpy(service.uuid128, value, 16); + rc = ble_gattc_find_inc_svcs_cb(proc, 0, 0, &service); + if (rc != 0) { + /* Application has indicated that the procedure should be aborted. */ + return BLE_HS_EDONE; + } - /* We are done with this service; proceed to the next. */ + /* Proceed to the next service. */ proc->find_inc_svcs.cur_start = 0; proc->find_inc_svcs.cur_end = 0; rc = ble_gattc_find_inc_svcs_go(proc, 1); if (rc != 0) { - goto done; + goto err; } - rc = 0; + return 0; -done: - cbrc = ble_gattc_find_inc_svcs_cb(proc, rc, 0, &service); - if (rc != 0 || cbrc != 0) { - return BLE_HS_EDONE; - } else { - return 0; - } +err: + ble_gattc_find_inc_svcs_cb(proc, rc, 0, NULL); + return BLE_HS_EDONE; } /** @@ -1646,18 +1729,23 @@ ble_gattc_find_inc_svcs_rx_complete(struct ble_gattc_proc *proc, int status) ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0 || proc->find_inc_svcs.prev_handle == 0xffff) { - /* Error or all svcs discovered. */ + if (status != 0) { ble_gattc_find_inc_svcs_cb(proc, status, 0, NULL); return BLE_HS_EDONE; - } else { - /* Send follow-up request. */ - rc = ble_gattc_find_inc_svcs_go(proc, 1); - if (rc != 0) { - return BLE_HS_EDONE; - } - return 0; } + + if (proc->find_inc_svcs.prev_handle == 0xffff) { + /* Procedure complete. */ + ble_gattc_find_inc_svcs_cb(proc, BLE_HS_EDONE, 0, NULL); + return BLE_HS_EDONE; + } + + /* Send follow-up request. */ + rc = ble_gattc_find_inc_svcs_go(proc, 1); + if (rc != 0) { + return BLE_HS_EDONE; + } + return 0; } /** @@ -1671,7 +1759,10 @@ ble_gattc_find_inc_svcs_rx_complete(struct ble_gattc_proc *proc, int status) * last handle in the service). * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle, @@ -1734,9 +1825,10 @@ ble_gattc_disc_all_chrs_cb(struct ble_gattc_proc *proc, int status, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(chr != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, disc_all_chrs_fail); } @@ -1794,7 +1886,7 @@ ble_gattc_disc_all_chrs_err(struct ble_gattc_proc *proc, int status, if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) { /* Discovery is complete. */ - status = 0; + status = BLE_HS_EDONE; } ble_gattc_disc_all_chrs_cb(proc, status, att_handle, NULL); @@ -1869,20 +1961,23 @@ ble_gattc_disc_all_chrs_rx_complete(struct ble_gattc_proc *proc, int status) ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0 || - proc->disc_all_chrs.prev_handle == proc->disc_all_chrs.end_handle) { - - /* Error or all svcs discovered. */ + if (status != 0) { ble_gattc_disc_all_chrs_cb(proc, status, 0, NULL); return BLE_HS_EDONE; - } else { - /* Send follow-up request. */ - rc = ble_gattc_disc_all_chrs_go(proc, 1); - if (rc != 0) { - return BLE_HS_EDONE; - } - return 0; } + + if (proc->disc_all_chrs.prev_handle == proc->disc_all_chrs.end_handle) { + /* Characteristic discovery complete. */ + ble_gattc_disc_all_chrs_cb(proc, BLE_HS_EDONE, 0, NULL); + return BLE_HS_EDONE; + } + + /* Send follow-up request. */ + rc = ble_gattc_disc_all_chrs_go(proc, 1); + if (rc != 0) { + return BLE_HS_EDONE; + } + return 0; } /** @@ -1896,7 +1991,10 @@ ble_gattc_disc_all_chrs_rx_complete(struct ble_gattc_proc *proc, int status) * last handle in the service). * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle, @@ -1959,9 +2057,10 @@ ble_gattc_disc_chr_uuid_cb(struct ble_gattc_proc *proc, int status, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(chr != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, disc_chrs_uuid_fail); } @@ -2019,7 +2118,7 @@ ble_gattc_disc_chr_uuid_err(struct ble_gattc_proc *proc, int status, if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) { /* Discovery is complete. */ - status = 0; + status = BLE_HS_EDONE; } ble_gattc_disc_chr_uuid_cb(proc, status, att_handle, NULL); @@ -2076,11 +2175,14 @@ ble_gattc_disc_chr_uuid_rx_adata(struct ble_gattc_proc *proc, rc = 0; done: - if (rc != 0 || - memcmp(chr.uuid128, proc->disc_chr_uuid.chr_uuid, 16) == 0) { - - cbrc = ble_gattc_disc_chr_uuid_cb(proc, rc, 0, &chr); + if (rc != 0) { + /* Failure. */ + cbrc = ble_gattc_disc_chr_uuid_cb(proc, rc, 0, NULL); + } else if (memcmp(chr.uuid128, proc->disc_chr_uuid.chr_uuid, 16) == 0) { + /* Requested characteristic discovered. */ + cbrc = ble_gattc_disc_chr_uuid_cb(proc, 0, 0, &chr); } else { + /* Uninteresting characteristic; ignore. */ cbrc = 0; } @@ -2102,20 +2204,23 @@ ble_gattc_disc_chr_uuid_rx_complete(struct ble_gattc_proc *proc, int status) ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0 || - proc->disc_chr_uuid.prev_handle == proc->disc_chr_uuid.end_handle) { - - /* Error or all svcs discovered. */ + if (status != 0) { ble_gattc_disc_chr_uuid_cb(proc, status, 0, NULL); return BLE_HS_EDONE; - } else { - /* Send follow-up request. */ - rc = ble_gattc_disc_chr_uuid_go(proc, 1); - if (rc != 0) { - return BLE_HS_EDONE; - } - return 0; } + + if (proc->disc_chr_uuid.prev_handle == proc->disc_chr_uuid.end_handle) { + /* Characteristic discovery complete. */ + ble_gattc_disc_chr_uuid_cb(proc, BLE_HS_EDONE, 0, NULL); + return BLE_HS_EDONE; + } + + /* Send follow-up request. */ + rc = ble_gattc_disc_chr_uuid_go(proc, 1); + if (rc != 0) { + return BLE_HS_EDONE; + } + return 0; } /** @@ -2131,11 +2236,14 @@ ble_gattc_disc_chr_uuid_rx_complete(struct ble_gattc_proc *proc, int status) * discover. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, void *uuid128, + uint16_t end_handle, const void *uuid128, ble_gatt_chr_fn *cb, void *cb_arg) { #if !NIMBLE_OPT(GATT_DISC_CHR_UUID) @@ -2195,9 +2303,10 @@ ble_gattc_disc_all_dscs_cb(struct ble_gattc_proc *proc, int status, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(dsc != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, disc_all_dscs_fail); } @@ -2206,7 +2315,7 @@ ble_gattc_disc_all_dscs_cb(struct ble_gattc_proc *proc, int status, } else { rc = proc->disc_all_dscs.cb(proc->conn_handle, ble_gattc_error(status, att_handle), - proc->disc_all_dscs.chr_def_handle, + proc->disc_all_dscs.chr_val_handle, dsc, proc->disc_all_dscs.cb_arg); } @@ -2250,7 +2359,7 @@ ble_gattc_disc_all_dscs_err(struct ble_gattc_proc *proc, int status, if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) { /* Discovery is complete. */ - status = 0; + status = BLE_HS_EDONE; } ble_gattc_disc_all_dscs_cb(proc, status, att_handle, NULL); @@ -2302,20 +2411,24 @@ ble_gattc_disc_all_dscs_rx_complete(struct ble_gattc_proc *proc, int status) ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0 || - proc->disc_all_dscs.prev_handle == proc->disc_all_dscs.end_handle) { - - /* Error or all descriptors discovered. */ + if (status != 0) { ble_gattc_disc_all_dscs_cb(proc, status, 0, NULL); return BLE_HS_EDONE; - } else { - /* Send follow-up request. */ - rc = ble_gattc_disc_all_dscs_go(proc, 1); - if (rc != 0) { - return BLE_HS_EDONE; - } - return 0; } + + if (proc->disc_all_dscs.prev_handle == proc->disc_all_dscs.end_handle) { + /* All descriptors discovered. */ + ble_gattc_disc_all_dscs_cb(proc, BLE_HS_EDONE, 0, NULL); + return BLE_HS_EDONE; + } + + /* Send follow-up request. */ + rc = ble_gattc_disc_all_dscs_go(proc, 1); + if (rc != 0) { + return BLE_HS_EDONE; + } + + return 0; } /** @@ -2323,16 +2436,19 @@ ble_gattc_disc_all_dscs_rx_complete(struct ble_gattc_proc *proc, int status) * * @param conn_handle The connection over which to execute the * procedure. - * @param chr_def_handle The handle of the characteristic definition + * @param chr_val_handle The handle of the characteristic value * attribute. * @param chr_end_handle The last handle in the characteristic * definition. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int -ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t chr_def_handle, +ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t chr_val_handle, uint16_t chr_end_handle, ble_gatt_dsc_fn *cb, void *cb_arg) { @@ -2353,8 +2469,8 @@ ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t chr_def_handle, proc->op = BLE_GATT_OP_DISC_ALL_DSCS; proc->conn_handle = conn_handle; - proc->disc_all_dscs.chr_def_handle = chr_def_handle; - proc->disc_all_dscs.prev_handle = chr_def_handle + 1; + proc->disc_all_dscs.chr_val_handle = chr_val_handle; + proc->disc_all_dscs.prev_handle = chr_val_handle; proc->disc_all_dscs.end_handle = chr_end_handle; proc->disc_all_dscs.cb = cb; proc->disc_all_dscs.cb_arg = cb_arg; @@ -2393,9 +2509,10 @@ ble_gattc_read_cb(struct ble_gattc_proc *proc, int status, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(attr != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, read_fail); } @@ -2428,7 +2545,7 @@ ble_gattc_read_err(struct ble_gattc_proc *proc, int status, */ static int ble_gattc_read_rx_read_rsp(struct ble_gattc_proc *proc, int status, - void *value, int value_len) + struct os_mbuf **om) { struct ble_gatt_attr attr; @@ -2436,11 +2553,13 @@ ble_gattc_read_rx_read_rsp(struct ble_gattc_proc *proc, int status, attr.handle = proc->read.handle; attr.offset = 0; - attr.value_len = value_len; - attr.value = value; + attr.om = *om; ble_gattc_read_cb(proc, status, 0, &attr); + /* Indicate to the caller whether the application consumed the mbuf. */ + *om = attr.om; + /* The read operation only has a single request / response exchange. */ return BLE_HS_EDONE; } @@ -2453,7 +2572,10 @@ ble_gattc_read_rx_read_rsp(struct ble_gattc_proc *proc, int status, * @param attr_handle The handle of the characteristic value to read. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle, @@ -2516,9 +2638,10 @@ ble_gattc_read_uuid_cb(struct ble_gattc_proc *proc, int status, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(attr != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, read_uuid_fail); } @@ -2565,10 +2688,18 @@ ble_gattc_read_uuid_rx_adata(struct ble_gattc_proc *proc, attr.handle = adata->att_handle; attr.offset = 0; - attr.value_len = adata->value_len; - attr.value = adata->value; + attr.om = ble_hs_mbuf_from_flat(adata->value, adata->value_len); + if (attr.om == NULL) { + rc = BLE_HS_ENOMEM; + } else { + rc = 0; + } + + rc = ble_gattc_read_uuid_cb(proc, rc, 0, &attr); + + /* Free the attribute mbuf if the application has not consumed it. */ + os_mbuf_free_chain(attr.om); - rc = ble_gattc_read_uuid_cb(proc, 0, 0, &attr); if (rc != 0) { return BLE_HS_EDONE; } @@ -2584,7 +2715,16 @@ static int ble_gattc_read_uuid_rx_complete(struct ble_gattc_proc *proc, int status) { ble_gattc_dbg_assert_proc_not_inserted(proc); - ble_gattc_read_uuid_cb(proc, status, 0, NULL); + + if (status != 0) { + ble_gattc_read_uuid_cb(proc, status, 0, NULL); + return BLE_HS_EDONE; + } + + /* XXX: We may need to send a follow-up request to address the possibility + * of multiple characteristics with identical UUIDs. + */ + ble_gattc_read_uuid_cb(proc, BLE_HS_EDONE, 0, NULL); return BLE_HS_EDONE; } @@ -2599,11 +2739,14 @@ ble_gattc_read_uuid_rx_complete(struct ble_gattc_proc *proc, int status) * last handle in the service definition). * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, void *uuid128, + uint16_t end_handle, const void *uuid128, ble_gatt_attr_fn *cb, void *cb_arg) { #if !NIMBLE_OPT(GATT_READ_UUID) @@ -2663,9 +2806,10 @@ ble_gattc_read_long_cb(struct ble_gattc_proc *proc, int status, int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(attr != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, read_long_fail); } @@ -2729,21 +2873,27 @@ ble_gattc_read_long_err(struct ble_gattc_proc *proc, int status, */ static int ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status, - void *value, int value_len) + struct os_mbuf **om) { struct ble_gatt_attr attr; + uint16_t data_len; uint16_t mtu; int rc; ble_gattc_dbg_assert_proc_not_inserted(proc); + data_len = OS_MBUF_PKTLEN(*om); + attr.handle = proc->read_long.handle; attr.offset = proc->read_long.offset; - attr.value_len = value_len; - attr.value = value; + attr.om = *om; /* Report partial payload to application. */ rc = ble_gattc_read_long_cb(proc, status, 0, &attr); + + /* Indicate to the caller whether the application consumed the mbuf. */ + *om = attr.om; + if (rc != 0 || status != 0) { return BLE_HS_EDONE; } @@ -2755,13 +2905,14 @@ ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status, return BLE_HS_EDONE; } - if (value_len < mtu - 1) { - ble_gattc_read_long_cb(proc, 0, 0, NULL); + if (data_len < mtu - 1) { + /* Response shorter than maximum allowed; read complete. */ + ble_gattc_read_long_cb(proc, BLE_HS_EDONE, 0, NULL); return BLE_HS_EDONE; } /* Send follow-up request. */ - proc->read_long.offset += value_len; + proc->read_long.offset += data_len; rc = ble_gattc_read_long_go(proc, 1); if (rc != 0) { return BLE_HS_EDONE; @@ -2778,7 +2929,10 @@ ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status, * @param handle The handle of the characteristic value to read. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_read_long(uint16_t conn_handle, uint16_t handle, @@ -2835,38 +2989,40 @@ done: */ static int ble_gattc_read_mult_cb(struct ble_gattc_proc *proc, int status, - uint16_t att_handle, uint8_t *attr_data, - uint16_t attr_data_len) + uint16_t att_handle, struct os_mbuf **om) { - struct ble_gatt_attr *attrp; struct ble_gatt_attr attr; int rc; BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); + BLE_HS_DBG_ASSERT(om != NULL || status != 0); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, read_mult_fail); } + attr.handle = 0; + attr.offset = 0; + if (om == NULL) { + attr.om = NULL; + } else { + attr.om = *om; + } + if (proc->read_mult.cb == NULL) { rc = 0; } else { - if (status != 0) { - attrp = NULL; - } else { - attrp = &attr; - attr.handle = 0; - attr.offset = 0; - attr.value_len = attr_data_len; - attr.value = attr_data; - } - rc = proc->read_mult.cb(proc->conn_handle, - ble_gattc_error(status, att_handle), attrp, + ble_gattc_error(status, att_handle), &attr, proc->read_mult.cb_arg); } + /* Indicate to the caller whether the application consumed the mbuf. */ + if (om != NULL) { + *om = attr.om; + } + return rc; } @@ -2879,7 +3035,7 @@ ble_gattc_read_mult_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle) { ble_gattc_dbg_assert_proc_not_inserted(proc); - ble_gattc_read_mult_cb(proc, status, att_handle, NULL, 0); + ble_gattc_read_mult_cb(proc, status, att_handle, NULL); } /** @@ -2891,10 +3047,13 @@ ble_gattc_read_mult_err(struct ble_gattc_proc *proc, int status, * @param num_handles The number of entries in the "handles" array. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int -ble_gattc_read_mult(uint16_t conn_handle, uint16_t *handles, +ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, uint8_t num_handles, ble_gatt_attr_fn *cb, void *cb_arg) { @@ -2939,21 +3098,20 @@ done: *****************************************************************************/ /** - * Initiates GATT procedure: Write Without Response. + * Initiates GATT procedure: Write Without Response. This function consumes + * the supplied mbuf regardless of the outcome. * * @param conn_handle The connection over which to execute the * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param txom The value to write to the characteristic. + * + * @return 0 on success; nonzero on failure. */ int -ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, void *value, - uint16_t value_len) +ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, + struct os_mbuf *txom) { #if !NIMBLE_OPT(GATT_WRITE_NO_RSP) return BLE_HS_ENOTSUP; @@ -2964,10 +3122,10 @@ ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, void *value, STATS_INC(ble_gattc_stats, write_no_rsp); - ble_gattc_log_write(attr_handle, value_len, 0); + ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(txom), 0); req.bawq_handle = attr_handle; - rc = ble_att_clt_tx_write_cmd(conn_handle, &req, value, value_len); + rc = ble_att_clt_tx_write_cmd(conn_handle, &req, txom); if (rc != 0) { STATS_INC(ble_gattc_stats, write); } @@ -2975,6 +3133,39 @@ ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, void *value, return rc; } +/** + * Initiates GATT procedure: Write Without Response. This function consumes + * the supplied mbuf regardless of the outcome. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param attr_handle The handle of the characteristic value to write + * to. + * @param value The value to write to the characteristic. + * @param value_len The number of bytes to write. + * + * @return 0 on success; nonzero on failure. + */ +int +ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle, + const void *data, uint16_t data_len) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_mbuf_from_flat(data, data_len); + if (om == NULL) { + return BLE_HS_ENOMEM; + } + + rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, om); + if (rc != 0) { + return rc; + } + + return 0; +} + /***************************************************************************** * $write * *****************************************************************************/ @@ -2996,7 +3187,7 @@ ble_gattc_write_cb(struct ble_gattc_proc *proc, int status, BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, write_fail); } @@ -3026,21 +3217,24 @@ ble_gattc_write_err(struct ble_gattc_proc *proc, int status, } /** - * Initiates GATT procedure: Write Characteristic Value. + * Initiates GATT procedure: Write Characteristic Value. This function + * consumes the supplied mbuf regardless of the outcome. * * @param conn_handle The connection over which to execute the * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. + * @param txom The value to write to the characteristic. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int -ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, void *value, - uint16_t value_len, ble_gatt_attr_fn *cb, void *cb_arg) +ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, + struct os_mbuf *txom, ble_gatt_attr_fn *cb, void *cb_arg) { #if !NIMBLE_OPT(GATT_WRITE) return BLE_HS_ENOTSUP; @@ -3064,10 +3258,11 @@ ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, void *value, proc->write.cb = cb; proc->write.cb_arg = cb_arg; - ble_gattc_log_write(attr_handle, value_len, 1); + ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(txom), 1); req.bawq_handle = attr_handle; - rc = ble_att_clt_tx_write_req(conn_handle, &req, value, value_len); + rc = ble_att_clt_tx_write_req(conn_handle, &req, txom); + txom = NULL; if (rc != 0) { goto done; } @@ -3077,10 +3272,50 @@ done: STATS_INC(ble_gattc_stats, write_fail); } + /* Free the mbuf in case the send failed. */ + os_mbuf_free_chain(txom); + ble_gattc_process_status(proc, rc); return rc; } +/** + * Initiates GATT procedure: Write Characteristic Value (flat buffer version). + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param attr_handle The handle of the characteristic value to write + * to. + * @param value The value to write to the characteristic. + * @param value_len The number of bytes to write. + * @param cb The function to call to report procedure status + * updates; null for no callback. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. + */ +int +ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_mbuf_from_flat(data, data_len); + if (om == NULL) { + return BLE_HS_ENOMEM; + } + + rc = ble_gattc_write(conn_handle, attr_handle, om, cb, cb_arg); + if (rc != 0) { + return rc; + } + + return 0; +} + /***************************************************************************** * $write long * *****************************************************************************/ @@ -3101,7 +3336,7 @@ ble_gattc_write_long_cb(struct ble_gattc_proc *proc, int status, BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, write_long_fail); } @@ -3126,48 +3361,65 @@ ble_gattc_write_long_go(struct ble_gattc_proc *proc, int cb_on_err) { struct ble_att_prep_write_cmd prep_req; struct ble_att_exec_write_req exec_req; - void *value; + struct os_mbuf *om; + int write_len; int max_sz; int rc; ble_gattc_dbg_assert_proc_not_inserted(proc); - if (proc->write_long.attr.offset < proc->write_long.attr.value_len) { - max_sz = ble_att_mtu(proc->conn_handle) - - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; - if (max_sz == 0) { - /* Not connected. */ - rc = BLE_HS_ENOTCONN; - } else { - if (proc->write_long.attr.offset + max_sz > - proc->write_long.attr.value_len) { + om = NULL; - proc->write_long.length = proc->write_long.attr.value_len - - proc->write_long.attr.offset; - } else { - proc->write_long.length = max_sz; - } + max_sz = ble_att_mtu(proc->conn_handle) - + BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + if (max_sz <= 0) { + /* Not connected. */ + rc = BLE_HS_ENOTCONN; + goto done; + } - prep_req.bapc_handle = proc->write_long.attr.handle; - prep_req.bapc_offset = proc->write_long.attr.offset; - value = proc->write_long.attr.value + proc->write_long.attr.offset; - rc = ble_att_clt_tx_prep_write(proc->conn_handle, - &prep_req, value, - proc->write_long.length); - } - } else { + write_len = min(max_sz, + OS_MBUF_PKTLEN(proc->write_long.attr.om) - + proc->write_long.attr.offset); + + if (write_len <= 0) { exec_req.baeq_flags = BLE_ATT_EXEC_WRITE_F_CONFIRM; rc = ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req); + goto done; + } + + proc->write_long.length = write_len; + om = ble_hs_mbuf_att_pkt(); + if (om == NULL) { + rc = BLE_HS_ENOMEM; + goto done; } + rc = os_mbuf_appendfrom(om, proc->write_long.attr.om, + proc->write_long.attr.offset, + proc->write_long.length); if (rc != 0) { - if (cb_on_err) { - ble_gattc_write_long_cb(proc, rc, 0); - } - return rc; + rc = BLE_HS_ENOMEM; + goto done; } - return 0; + prep_req.bapc_handle = proc->write_long.attr.handle; + prep_req.bapc_offset = proc->write_long.attr.offset; + + rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req, om); + om = NULL; + if (rc != 0) { + goto done; + } + +done: + os_mbuf_free_chain(om); + + if (rc != 0 && cb_on_err) { + ble_gattc_write_long_cb(proc, rc, 0); + } + + return rc; } /** @@ -3181,17 +3433,20 @@ ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status, struct ble_att_exec_write_req exec_req; ble_gattc_dbg_assert_proc_not_inserted(proc); - ble_gattc_write_long_cb(proc, status, att_handle); /* If we have successfully queued any data, and the failure occurred before * we could send the execute write command, then erase all queued data. */ if (proc->write_long.attr.offset > 0 && - proc->write_long.attr.offset < proc->write_long.attr.value_len) { + proc->write_long.attr.offset < + OS_MBUF_PKTLEN(proc->write_long.attr.om)) { exec_req.baeq_flags = 0; ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req); } + + /* Report failure. */ + ble_gattc_write_long_cb(proc, status, att_handle); } /** @@ -3201,18 +3456,31 @@ ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status, static int ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc, int status, struct ble_att_prep_write_cmd *rsp, - void *attr_data, uint16_t attr_len) + struct os_mbuf **rxom) { + struct os_mbuf *om; int rc; ble_gattc_dbg_assert_proc_not_inserted(proc); + /* Let the caller free the mbuf. */ + om = *rxom; + if (status != 0) { rc = status; goto err; } /* Verify the response. */ + if (proc->write_long.attr.offset >= + OS_MBUF_PKTLEN(proc->write_long.attr.om)) { + + /* Expecting a prepare write response, not an execute write + * response. + */ + rc = BLE_HS_EBADDATA; + goto err; + } if (rsp->bapc_handle != proc->write_long.attr.handle) { rc = BLE_HS_EBADDATA; goto err; @@ -3221,22 +3489,26 @@ ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc, rc = BLE_HS_EBADDATA; goto err; } - if (rsp->bapc_offset + attr_len > proc->write_long.attr.value_len) { + if (rsp->bapc_offset + OS_MBUF_PKTLEN(om) > + OS_MBUF_PKTLEN(proc->write_long.attr.om)) { + rc = BLE_HS_EBADDATA; goto err; } - if (attr_len != proc->write_long.length) { + if (OS_MBUF_PKTLEN(om) != proc->write_long.length) { rc = BLE_HS_EBADDATA; goto err; } - if (memcmp(attr_data, proc->write_long.attr.value + rsp->bapc_offset, - attr_len) != 0) { + if (os_mbuf_cmpm(om, 0, + proc->write_long.attr.om, rsp->bapc_offset, + proc->write_long.length) != 0) { + rc = BLE_HS_EBADDATA; goto err; } /* Send follow-up request. */ - proc->write_long.attr.offset += attr_len; + proc->write_long.attr.offset += OS_MBUF_PKTLEN(om); rc = ble_gattc_write_long_go(proc, 1); if (rc != 0) { goto err; @@ -3258,26 +3530,39 @@ static int ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc, int status) { ble_gattc_dbg_assert_proc_not_inserted(proc); + + if (proc->write_long.attr.offset < + OS_MBUF_PKTLEN(proc->write_long.attr.om)) { + + /* Expecting an execute write response, not a prepare write + * response. + */ + return BLE_HS_EBADDATA; + } + ble_gattc_write_long_cb(proc, status, 0); return BLE_HS_EDONE; } /** - * Initiates GATT procedure: Write Long Characteristic Values. + * Initiates GATT procedure: Write Long Characteristic Values. This function + * consumes the supplied mbuf regardless of the outcome. * * @param conn_handle The connection over which to execute the * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. + * @param txom The value to write to the characteristic. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. */ int -ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle, void *value, - uint16_t value_len, ble_gatt_attr_fn *cb, void *cb_arg) +ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle, + struct os_mbuf *txom, ble_gatt_attr_fn *cb, void *cb_arg) { #if !NIMBLE_OPT(GATT_WRITE_LONG) return BLE_HS_ENOTSUP; @@ -3298,11 +3583,13 @@ ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle, void *value, proc->conn_handle = conn_handle; proc->write_long.attr.handle = attr_handle; proc->write_long.attr.offset = 0; - proc->write_long.attr.value = value; - proc->write_long.attr.value_len = value_len; + proc->write_long.attr.om = txom; proc->write_long.cb = cb; proc->write_long.cb_arg = cb_arg; + /* The mbuf is consumed by the procedure. */ + txom = NULL; + ble_gattc_log_write_long(proc); rc = ble_gattc_write_long_go(proc, 0); @@ -3315,6 +3602,9 @@ done: STATS_INC(ble_gattc_stats, write_long_fail); } + /* Free the mbuf in case of failure. */ + os_mbuf_free_chain(txom); + ble_gattc_process_status(proc, rc); return rc; } @@ -3339,7 +3629,7 @@ ble_gattc_write_reliable_cb(struct ble_gattc_proc *proc, int status, BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { + if (status != 0 && status != BLE_HS_EDONE) { STATS_INC(ble_gattc_stats, write_reliable_fail); } @@ -3366,31 +3656,65 @@ ble_gattc_write_reliable_go(struct ble_gattc_proc *proc, int cb_on_err) struct ble_att_prep_write_cmd prep_req; struct ble_att_exec_write_req exec_req; struct ble_gatt_attr *attr; + struct os_mbuf *om; + uint16_t max_sz; int attr_idx; int rc; ble_gattc_dbg_assert_proc_not_inserted(proc); + om = NULL; + attr_idx = proc->write_reliable.cur_attr; - if (attr_idx < proc->write_reliable.num_attrs) { - attr = proc->write_reliable.attrs + attr_idx; - prep_req.bapc_handle = attr->handle; - prep_req.bapc_offset = 0; - rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req, - attr->value, attr->value_len); - } else { + + if (attr_idx >= proc->write_reliable.num_attrs) { exec_req.baeq_flags = BLE_ATT_EXEC_WRITE_F_CONFIRM; rc = ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req); + goto done; + } + + attr = proc->write_reliable.attrs + attr_idx; + + max_sz = ble_att_mtu(proc->conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + if (max_sz <= 0) { + /* Not connected. */ + rc = BLE_HS_ENOTCONN; + goto done; + } + + proc->write_reliable.length = + min(max_sz, OS_MBUF_PKTLEN(attr->om) - attr->offset); + + om = ble_hs_mbuf_att_pkt(); + if (om == NULL) { + rc = BLE_HS_ENOMEM; + goto done; } + rc = os_mbuf_appendfrom(om, attr->om, attr->offset, + proc->write_reliable.length); if (rc != 0) { - if (cb_on_err) { - ble_gattc_write_reliable_cb(proc, rc, 0); - } - return rc; + rc = BLE_HS_ENOMEM; + goto done; } - return 0; + prep_req.bapc_handle = attr->handle; + prep_req.bapc_offset = attr->offset; + + rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req, om); + om = NULL; + if (rc != 0) { + goto done; + } + +done: + os_mbuf_free_chain(om); + + if (rc != 0 && cb_on_err) { + ble_gattc_write_reliable_cb(proc, rc, 0); + } + + return rc; } /** @@ -3425,19 +3749,26 @@ static int ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc, int status, struct ble_att_prep_write_cmd *rsp, - void *attr_data, uint16_t attr_len) + struct os_mbuf **rxom) { struct ble_gatt_attr *attr; + struct os_mbuf *om; int rc; ble_gattc_dbg_assert_proc_not_inserted(proc); + /* Let the caller free the mbuf. */ + om = *rxom; + if (status != 0) { rc = status; goto err; } if (proc->write_reliable.cur_attr >= proc->write_reliable.num_attrs) { + /* Expecting an execute write response, not a prepare write + * response. + */ rc = BLE_HS_EBADDATA; goto err; } @@ -3448,21 +3779,23 @@ ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc, rc = BLE_HS_EBADDATA; goto err; } - if (rsp->bapc_offset != 0) { + if (rsp->bapc_offset != attr->offset) { rc = BLE_HS_EBADDATA; goto err; } - if (attr_len != attr->value_len) { - rc = BLE_HS_EBADDATA; - goto err; - } - if (memcmp(attr_data, attr->value, attr_len) != 0) { + if (os_mbuf_cmpm(attr->om, rsp->bapc_offset, om, 0, + proc->write_reliable.length) != 0) { + rc = BLE_HS_EBADDATA; goto err; } /* Send follow-up request. */ - proc->write_reliable.cur_attr++; + attr->offset += proc->write_reliable.length; + if (attr->offset >= OS_MBUF_PKTLEN(attr->om)) { + attr->offset = 0; + proc->write_reliable.cur_attr++; + } rc = ble_gattc_write_reliable_go(proc, 1); if (rc != 0) { goto err; @@ -3489,22 +3822,29 @@ ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc *proc, int status) } /** - * Initiates GATT procedure: Write Long Characteristic Values. + * Initiates GATT procedure: Reliable Writes. This function consumes the + * supplied mbufs regardless of the outcome. * * @param conn_handle The connection over which to execute the * procedure. - * @param attr_handle The handle of the characteristic value to write - * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. + * @param attrs An array of attribute descriptors; specifies + * which characteristics to write to and what + * data to write to them. The mbuf pointer in + * each attribute is set to NULL by this + * function. + * @param num_attrs The number of characteristics to write; equal + * to the number of elements in the 'attrs' + * array. * @param cb The function to call to report procedure status * updates; null for no callback. - * @param cb_arg The argument to pass to the callback function. + * @param cb_arg The optional argument to pass to the callback + * function. */ int -ble_gattc_write_reliable(uint16_t conn_handle, struct ble_gatt_attr *attrs, - int num_attrs, ble_gatt_reliable_attr_fn *cb, - void *cb_arg) +ble_gattc_write_reliable(uint16_t conn_handle, + struct ble_gatt_attr *attrs, + int num_attrs, + ble_gatt_reliable_attr_fn *cb, void *cb_arg) { #if !NIMBLE_OPT(GATT_WRITE_RELIABLE) return BLE_HS_ENOTSUP; @@ -3512,9 +3852,17 @@ ble_gattc_write_reliable(uint16_t conn_handle, struct ble_gatt_attr *attrs, struct ble_gattc_proc *proc; int rc; + int i; + + proc = NULL; STATS_INC(ble_gattc_stats, write_reliable); + if (num_attrs > NIMBLE_OPT(GATT_WRITE_MAX_ATTRS)) { + rc = BLE_HS_EINVAL; + goto done; + } + proc = ble_gattc_proc_alloc(); if (proc == NULL) { rc = BLE_HS_ENOMEM; @@ -3523,12 +3871,19 @@ ble_gattc_write_reliable(uint16_t conn_handle, struct ble_gatt_attr *attrs, proc->op = BLE_GATT_OP_WRITE_RELIABLE; proc->conn_handle = conn_handle; - proc->write_reliable.attrs = attrs; proc->write_reliable.num_attrs = num_attrs; proc->write_reliable.cur_attr = 0; proc->write_reliable.cb = cb; proc->write_reliable.cb_arg = cb_arg; + for (i = 0; i < num_attrs; i++) { + proc->write_reliable.attrs[i] = attrs[i]; + proc->write_reliable.attrs[i].offset = 0; + + /* Consume mbuf from caller. */ + attrs[i].om = NULL; + } + ble_gattc_log_write_reliable(proc); rc = ble_gattc_write_reliable_go(proc, 1); @@ -3541,6 +3896,12 @@ done: STATS_INC(ble_gattc_stats, write_reliable_fail); } + /* Free supplied mbufs in case something failed. */ + for (i = 0; i < num_attrs; i++) { + os_mbuf_free_chain(attrs[i].om); + attrs[i].om = NULL; + } + ble_gattc_process_status(proc, rc); return rc; } @@ -3550,45 +3911,53 @@ done: *****************************************************************************/ /** - * Sends an attribute notification. The content of the message is specified - * in the attr parameter. + * Sends a "free-form" characteristic notification. This function consumes the + * supplied mbuf regardless of the outcome. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param chr_val_handle The attribute handle to indicate in the + * outgoing notification. + * @param txom The value to write to the characteristic. + * + * @return 0 on success; nonzero on failure. */ int -ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle, - void *attr_data, uint16_t attr_data_len) +ble_gattc_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle, + struct os_mbuf *txom) { #if !NIMBLE_OPT(GATT_NOTIFY) return BLE_HS_ENOTSUP; #endif - struct ble_att_svr_access_ctxt ctxt; struct ble_att_notify_req req; int rc; STATS_INC(ble_gattc_stats, notify); - ble_gattc_log_notify(att_handle); + ble_gattc_log_notify(chr_val_handle); - if (attr_data == NULL) { + if (txom == NULL) { /* No custom attribute data; read the value from the specified * attribute. */ + txom = ble_hs_mbuf_att_pkt(); + if (txom == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, - att_handle, &ctxt, NULL); + chr_val_handle, 0, txom, NULL); if (rc != 0) { /* Fatal error; application disallowed attribute read. */ rc = BLE_HS_EAPP; goto err; } - } else { - ctxt.attr_data = attr_data; - ctxt.data_len = attr_data_len; - ctxt.offset = 0; } - req.banq_handle = att_handle; - rc = ble_att_clt_tx_notify(conn_handle, &req, - ctxt.attr_data, ctxt.data_len); + req.banq_handle = chr_val_handle; + rc = ble_att_clt_tx_notify(conn_handle, &req, txom); + txom = NULL; if (rc != 0) { goto err; } @@ -3596,13 +3965,26 @@ ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle, return 0; err: - STATS_INC(ble_gattc_stats, notify_fail); + if (rc != 0) { + STATS_INC(ble_gattc_stats, notify_fail); + } + + os_mbuf_free_chain(txom); + return rc; } /** - * Sends an attribute notification. The content of the message is read from - * the specified characteristic. + * Sends a characteristic notification. The content of the message is read + * from the specified characteristic. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param chr_val_handle The value attribute handle of the + * characteristic to include in the outgoing + * notification. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle) @@ -3613,12 +3995,12 @@ ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle) int rc; - rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, NULL, 0); - if (rc != 0) { - return rc; - } + rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, NULL); - return 0; + /* Tell the application that a notification transmission was attempted. */ + ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 0); + + return rc; } /***************************************************************************** @@ -3626,48 +4008,33 @@ ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle) *****************************************************************************/ /** - * Calls an indication proc's callback with the specified parameters. If the - * proc has no callback, this function is a no-op. - * - * @return The return code of the callback (or 0 if there - * is no callback). + * Handles an incoming ATT error response for the specified indication proc. + * A device should never send an error in response to an indication. If this + * happens, we treat it like a confirmation (indication ack), but report the + * error status to the application. */ -static int -ble_gattc_indicate_cb(struct ble_gattc_proc *proc, int status, - uint16_t att_handle) +static void +ble_gattc_indicate_err(struct ble_gattc_proc *proc, int status, + uint16_t att_handle) { - struct ble_gatt_attr attr; int rc; - BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); ble_gattc_dbg_assert_proc_not_inserted(proc); - if (status != 0) { - STATS_INC(ble_gattc_stats, indicate_fail); - } - - if (proc->indicate.cb == NULL) { - rc = 0; - } else { - memset(&attr, 0, sizeof attr); - attr.handle = proc->indicate.chr_val_handle; - rc = proc->indicate.cb(proc->conn_handle, - ble_gattc_error(status, att_handle), - &attr, proc->indicate.cb_arg); + if (status != BLE_HS_ENOTCONN) { + rc = ble_gatts_rx_indicate_ack(proc->conn_handle, + proc->indicate.chr_val_handle); + if (rc != 0) { + return; + } } - return rc; -} + /* Tell the application about the received acknowledgment. */ + ble_gap_notify_tx_event(status, proc->conn_handle, + proc->indicate.chr_val_handle, 1); -/** - * Handles an incoming ATT error response for the specified indication proc. - */ -static void -ble_gattc_indicate_err(struct ble_gattc_proc *proc, int status, - uint16_t att_handle) -{ - ble_gattc_dbg_assert_proc_not_inserted(proc); - ble_gattc_indicate_cb(proc, status, att_handle); + /* Send the next indication if one is pending. */ + ble_gatts_send_next_indicate(proc->conn_handle); } /** @@ -3683,33 +4050,57 @@ ble_gattc_indicate_rx_rsp(struct ble_gattc_proc *proc) rc = ble_gatts_rx_indicate_ack(proc->conn_handle, proc->indicate.chr_val_handle); - if (rc != BLE_HS_ENOTCONN && rc != BLE_HS_ENOENT) { - ble_gattc_indicate_cb(proc, rc, 0); + if (rc != 0) { + return; } + /* Tell the application about the received acknowledgment. */ + ble_gap_notify_tx_event(BLE_HS_EDONE, proc->conn_handle, + proc->indicate.chr_val_handle, 1); + /* Send the next indication if one is pending. */ ble_gatts_send_next_indicate(proc->conn_handle); } /** - * Sends an attribute indication. + * Causes the indication in progress for the specified connection (if any) to + * fail with a status code of BLE_HS_ENOTCONN; + */ +void +ble_gatts_indicate_fail_notconn(uint16_t conn_handle) +{ + ble_gattc_fail_procs(conn_handle, BLE_GATT_OP_INDICATE, BLE_HS_ENOTCONN); +} + +/** + * Sends a characteristic indication. The content of the message is read from + * the specified characteristic. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param chr_val_handle The value attribute handle of the + * characteristic to include in the outgoing + * indication. + * + * @return 0 on success; nonzero on failure. */ int -ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle, - ble_gatt_attr_fn *cb, void *cb_arg) +ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle) { #if !NIMBLE_OPT(GATT_INDICATE) return BLE_HS_ENOTSUP; #endif - struct ble_att_svr_access_ctxt ctxt; struct ble_att_indicate_req req; struct ble_gattc_proc *proc; struct ble_hs_conn *conn; + struct os_mbuf *om; int rc; STATS_INC(ble_gattc_stats, indicate); + om = NULL; + proc = ble_gattc_proc_alloc(); if (proc == NULL) { rc = BLE_HS_ENOMEM; @@ -3719,13 +4110,17 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle, proc->op = BLE_GATT_OP_INDICATE; proc->conn_handle = conn_handle; proc->indicate.chr_val_handle = chr_val_handle; - proc->indicate.cb = cb; - proc->indicate.cb_arg = cb_arg; ble_gattc_log_indicate(chr_val_handle); - rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, chr_val_handle, - &ctxt, NULL); + om = ble_hs_mbuf_att_pkt(); + if (om == NULL) { + rc = BLE_HS_ENOMEM; + goto done; + } + + rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, chr_val_handle, 0, + om, NULL); if (rc != 0) { /* Fatal error; application disallowed attribute read. */ BLE_HS_DBG_ASSERT(0); @@ -3734,9 +4129,8 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle, } req.baiq_handle = chr_val_handle; - rc = ble_att_clt_tx_indicate(conn_handle, &req, - ctxt.attr_data, ctxt.data_len); - + rc = ble_att_clt_tx_indicate(conn_handle, &req, om); + om = NULL; if (rc != 0) { goto done; } @@ -3755,7 +4149,11 @@ done: STATS_INC(ble_gattc_stats, indicate_fail); } + /* Tell the application that an indication transmission was attempted. */ + ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 1); + ble_gattc_process_status(proc, rc); + os_mbuf_free_chain(om); return rc; } @@ -3983,8 +4381,7 @@ ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int status) * procedure. */ void -ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value, - int value_len) +ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, struct os_mbuf **om) { #if !NIMBLE_OPT(ATT_CLT_READ) return; @@ -3998,7 +4395,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value, ble_gattc_rx_read_rsp_entries, &rx_entry); if (proc != NULL) { - rc = rx_entry->cb(proc, status, value, value_len); + rc = rx_entry->cb(proc, status, om); ble_gattc_process_status(proc, rc); } } @@ -4009,7 +4406,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value, */ void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, - void *value, int value_len) + struct os_mbuf **om) { #if !NIMBLE_OPT(ATT_CLT_READ_BLOB) return; @@ -4020,7 +4417,7 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, proc = ble_gattc_extract(conn_handle, BLE_GATT_OP_READ_LONG); if (proc != NULL) { - rc = ble_gattc_read_long_rx_read_rsp(proc, status, value, value_len); + rc = ble_gattc_read_long_rx_read_rsp(proc, status, om); ble_gattc_process_status(proc, rc); } } @@ -4031,7 +4428,7 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, */ void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, - void *value, int value_len) + struct os_mbuf **om) { #if !NIMBLE_OPT(ATT_CLT_READ_MULT) return; @@ -4041,7 +4438,7 @@ ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, proc = ble_gattc_extract(conn_handle, BLE_GATT_OP_READ_MULT); if (proc != NULL) { - ble_gattc_read_mult_cb(proc, status, 0, value, value_len); + ble_gattc_read_mult_cb(proc, status, 0, om); ble_gattc_process_status(proc, BLE_HS_EDONE); } } @@ -4073,7 +4470,7 @@ ble_gattc_rx_write_rsp(uint16_t conn_handle) void ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status, struct ble_att_prep_write_cmd *rsp, - void *attr_data, uint16_t attr_data_len) + struct os_mbuf **om) { #if !NIMBLE_OPT(ATT_CLT_PREP_WRITE) return; @@ -4087,7 +4484,7 @@ ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status, ble_gattc_rx_prep_entries, &rx_entry); if (proc != NULL) { - rc = rx_entry->cb(proc, status, rsp, attr_data, attr_data_len); + rc = rx_entry->cb(proc, status, rsp, om); ble_gattc_process_status(proc, rc); } } @@ -4150,25 +4547,7 @@ ble_gattc_rx_indicate_rsp(uint16_t conn_handle) void ble_gattc_connection_broken(uint16_t conn_handle) { - struct ble_gattc_proc_list temp_list; - struct ble_gattc_proc *proc; - ble_gattc_err_fn *err_cb; - - /* Remove all procs with the specified conn handle and insert them into the - * temporary list. - */ - ble_gattc_extract_by_conn(conn_handle, &temp_list); - - /* Notify application of failed procedures and free the corresponding proc - * entries. - */ - while ((proc = STAILQ_FIRST(&temp_list)) != NULL) { - err_cb = ble_gattc_err_dispatch_get(proc->op); - err_cb(proc, BLE_HS_ENOTCONN, 0); - - STAILQ_REMOVE_HEAD(&temp_list, next); - ble_gattc_proc_free(proc); - } + ble_gattc_fail_procs(conn_handle, BLE_GATT_OP_NONE, BLE_HS_ENOTCONN); } /** diff --git a/net/nimble/host/src/ble_gatts.c b/net/nimble/host/src/ble_gatts.c index 3f73e015..e6ff2031 100644 --- a/net/nimble/host/src/ble_gatts.c +++ b/net/nimble/host/src/ble_gatts.c @@ -28,6 +28,9 @@ #define BLE_GATTS_INCLUDE_SZ 6 #define BLE_GATTS_CHR_MAX_SZ 19 +static const struct ble_gatt_svc_def **ble_gatts_svc_defs; +static int ble_gatts_num_svc_defs; + struct ble_gatts_svc_entry { const struct ble_gatt_svc_def *svc; uint16_t handle; /* 0 means unregistered. */ @@ -35,7 +38,7 @@ struct ble_gatts_svc_entry { }; static struct ble_gatts_svc_entry *ble_gatts_svc_entries; -static int ble_gatts_num_svc_entries; +static uint16_t ble_gatts_num_svc_entries; static os_membuf_t *ble_gatts_clt_cfg_mem; static struct os_mempool ble_gatts_clt_cfg_pool; @@ -66,11 +69,13 @@ STATS_NAME_END(ble_gatts_stats) static int ble_gatts_svc_access(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, void *arg) + uint8_t op, uint16_t offset, struct os_mbuf **om, + void *arg) { const struct ble_gatt_svc_def *svc; - static uint16_t uuid16; + uint16_t uuid16; + uint8_t *buf; + int rc; STATS_INC(ble_gatts_stats, svc_def_reads); @@ -80,12 +85,16 @@ ble_gatts_svc_access(uint16_t conn_handle, uint16_t attr_handle, uuid16 = ble_uuid_128_to_16(svc->uuid128); if (uuid16 != 0) { - htole16(&uuid16, uuid16); - ctxt->attr_data = &uuid16; - ctxt->data_len = 2; + buf = os_mbuf_extend(*om, 2); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + htole16(buf, uuid16); } else { - ctxt->attr_data = svc->uuid128; - ctxt->data_len = 16; + rc = os_mbuf_append(*om, svc->uuid128, 16); + if (rc != 0) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } } return 0; @@ -93,13 +102,12 @@ ble_gatts_svc_access(uint16_t conn_handle, uint16_t attr_handle, static int ble_gatts_inc_access(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, void *arg) + uint8_t op, uint16_t offset, struct os_mbuf **om, + void *arg) { - static uint8_t buf[BLE_GATTS_INCLUDE_SZ]; - const struct ble_gatts_svc_entry *entry; uint16_t uuid16; + uint8_t *buf; STATS_INC(ble_gatts_stats, svc_inc_reads); @@ -107,18 +115,22 @@ ble_gatts_inc_access(uint16_t conn_handle, uint16_t attr_handle, entry = arg; + buf = os_mbuf_extend(*om, 4); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } htole16(buf + 0, entry->handle); htole16(buf + 2, entry->end_group_handle); /* Only include the service UUID if it has a 16-bit representation. */ uuid16 = ble_uuid_128_to_16(entry->svc->uuid128); if (uuid16 != 0) { - htole16(buf + 4, uuid16); - ctxt->data_len = 6; - } else { - ctxt->data_len = 4; + buf = os_mbuf_extend(*om, 2); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + htole16(buf, uuid16); } - ctxt->attr_data = buf; return 0; } @@ -212,12 +224,12 @@ ble_gatts_chr_properties(const struct ble_gatt_chr_def *chr) static int ble_gatts_chr_def_access(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, void *arg) + uint8_t op, uint16_t offset, struct os_mbuf **om, + void *arg) { - static uint8_t buf[BLE_GATTS_CHR_MAX_SZ]; const struct ble_gatt_chr_def *chr; uint16_t uuid16; + uint8_t *buf; STATS_INC(ble_gatts_stats, chr_def_reads); @@ -225,6 +237,11 @@ ble_gatts_chr_def_access(uint16_t conn_handle, uint16_t attr_handle, chr = arg; + buf = os_mbuf_extend(*om, 3); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + buf[0] = ble_gatts_chr_properties(chr); /* The value attribute is always immediately after the declaration. */ @@ -232,13 +249,18 @@ ble_gatts_chr_def_access(uint16_t conn_handle, uint16_t attr_handle, uuid16 = ble_uuid_128_to_16(chr->uuid128); if (uuid16 != 0) { - htole16(buf + 3, uuid16); - ctxt->data_len = 5; + buf = os_mbuf_extend(*om, 2); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + htole16(buf, uuid16); } else { - memcpy(buf + 3, chr->uuid128, 16); - ctxt->data_len = 19; + buf = os_mbuf_extend(*om, 16); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + memcpy(buf, chr->uuid128, 16); } - ctxt->attr_data = buf; return 0; } @@ -293,45 +315,70 @@ ble_gatts_chr_inc_val_stat(uint8_t gatt_op) } static int -ble_gatts_chr_val_access(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t att_op, - struct ble_att_svr_access_ctxt *att_ctxt, void *arg) +ble_gatts_val_access(uint16_t conn_handle, uint16_t attr_handle, + uint16_t offset, struct ble_gatt_access_ctxt *gatt_ctxt, + struct os_mbuf **om, ble_gatt_access_fn *access_cb, + void *cb_arg) { - const struct ble_gatt_chr_def *chr; - union ble_gatt_access_ctxt gatt_ctxt; - uint8_t gatt_op; + int attr_len; int rc; - chr = arg; - BLE_HS_DBG_ASSERT(chr != NULL && chr->access_cb != NULL); + switch (gatt_ctxt->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + case BLE_GATT_ACCESS_OP_READ_DSC: + gatt_ctxt->om = os_msys_get_pkthdr(0, 0); + if (gatt_ctxt->om == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } - gatt_op = ble_gatts_chr_op(att_op); - gatt_ctxt.chr_access.chr = chr; - gatt_ctxt.chr_access.data = att_ctxt->attr_data; - gatt_ctxt.chr_access.len = att_ctxt->data_len; + rc = access_cb(conn_handle, attr_handle, gatt_ctxt, cb_arg); + if (rc == 0) { + attr_len = OS_MBUF_PKTLEN(gatt_ctxt->om) - offset; + if (attr_len > 0) { + os_mbuf_appendfrom(*om, gatt_ctxt->om, offset, attr_len); + } + } - ble_gatts_chr_inc_val_stat(gatt_op); + os_mbuf_free_chain(gatt_ctxt->om); + return rc; - rc = chr->access_cb(conn_handle, attr_handle, gatt_op, &gatt_ctxt, - chr->arg); - if (rc != 0) { + case BLE_GATT_ACCESS_OP_WRITE_CHR: + case BLE_GATT_ACCESS_OP_WRITE_DSC: + gatt_ctxt->om = *om; + rc = access_cb(conn_handle, attr_handle, gatt_ctxt, cb_arg); + *om = gatt_ctxt->om; return rc; + + default: + BLE_HS_DBG_ASSERT(0); + return BLE_ATT_ERR_UNLIKELY; } +} + +static int +ble_gatts_chr_val_access(uint16_t conn_handle, uint16_t attr_handle, + uint8_t att_op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + const struct ble_gatt_chr_def *chr_def; + struct ble_gatt_access_ctxt gatt_ctxt; + int rc; - if (att_op == BLE_ATT_ACCESS_OP_WRITE && - ble_gatts_chr_clt_cfg_allowed(chr)) { + chr_def = arg; + BLE_HS_DBG_ASSERT(chr_def != NULL && chr_def->access_cb != NULL); - ble_gatts_chr_updated(attr_handle - 1); - } + gatt_ctxt.op = ble_gatts_chr_op(att_op); + gatt_ctxt.chr = chr_def; - att_ctxt->attr_data = gatt_ctxt.chr_access.data; - att_ctxt->data_len = gatt_ctxt.chr_access.len; + ble_gatts_chr_inc_val_stat(gatt_ctxt.op); + rc = ble_gatts_val_access(conn_handle, attr_handle, offset, &gatt_ctxt, om, + chr_def->access_cb, chr_def->arg); - return 0; + return rc; } static int -ble_gatts_find_svc(const struct ble_gatt_svc_def *svc) +ble_gatts_find_svc_entry_idx(const struct ble_gatt_svc_def *svc) { int i; @@ -356,7 +403,7 @@ ble_gatts_svc_incs_satisfied(const struct ble_gatt_svc_def *svc) } for (i = 0; svc->includes[i] != NULL; i++) { - idx = ble_gatts_find_svc(svc->includes[i]); + idx = ble_gatts_find_svc_entry_idx(svc->includes[i]); if (idx == -1 || ble_gatts_svc_entries[idx].handle == 0) { return 0; } @@ -418,34 +465,24 @@ ble_gatts_dsc_inc_stat(uint8_t gatt_op) static int ble_gatts_dsc_access(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t att_op, - struct ble_att_svr_access_ctxt *att_ctxt, void *arg) + uint8_t att_op, uint16_t offset, struct os_mbuf **om, + void *arg) { - const struct ble_gatt_dsc_def *dsc; - union ble_gatt_access_ctxt gatt_ctxt; - uint8_t gatt_op; + const struct ble_gatt_dsc_def *dsc_def; + struct ble_gatt_access_ctxt gatt_ctxt; int rc; - dsc = arg; - BLE_HS_DBG_ASSERT(dsc != NULL && dsc->access_cb != NULL); + dsc_def = arg; + BLE_HS_DBG_ASSERT(dsc_def != NULL && dsc_def->access_cb != NULL); - gatt_op = ble_gatts_dsc_op(att_op); - gatt_ctxt.dsc_access.dsc = dsc; - gatt_ctxt.dsc_access.data = att_ctxt->attr_data; - gatt_ctxt.dsc_access.len = att_ctxt->data_len; - - ble_gatts_dsc_inc_stat(gatt_op); - - rc = dsc->access_cb(conn_handle, attr_handle, gatt_op, &gatt_ctxt, - dsc->arg); - if (rc != 0) { - return rc; - } + gatt_ctxt.op = ble_gatts_dsc_op(att_op); + gatt_ctxt.dsc = dsc_def; - att_ctxt->attr_data = gatt_ctxt.dsc_access.data; - att_ctxt->data_len = gatt_ctxt.dsc_access.len; + ble_gatts_dsc_inc_stat(gatt_ctxt.op); + rc = ble_gatts_val_access(conn_handle, attr_handle, offset, &gatt_ctxt, om, + dsc_def->access_cb, dsc_def->arg); - return 0; + return rc; } static int @@ -463,12 +500,13 @@ ble_gatts_dsc_is_sane(const struct ble_gatt_dsc_def *dsc) } static int -ble_gatts_register_dsc(const struct ble_gatt_dsc_def *dsc, +ble_gatts_register_dsc(const struct ble_gatt_svc_def *svc, const struct ble_gatt_chr_def *chr, + const struct ble_gatt_dsc_def *dsc, uint16_t chr_def_handle, ble_gatt_register_fn *register_cb, void *cb_arg) { - union ble_gatt_register_ctxt register_ctxt; + struct ble_gatt_register_ctxt register_ctxt; uint16_t dsc_handle; int rc; @@ -483,11 +521,12 @@ ble_gatts_register_dsc(const struct ble_gatt_dsc_def *dsc, } if (register_cb != NULL) { - register_ctxt.dsc_reg.dsc_handle = dsc_handle; - register_ctxt.dsc_reg.dsc = dsc; - register_ctxt.dsc_reg.chr_def_handle = chr_def_handle; - register_ctxt.dsc_reg.chr = chr; - register_cb(BLE_GATT_REGISTER_OP_DSC, ®ister_ctxt, cb_arg); + register_ctxt.op = BLE_GATT_REGISTER_OP_DSC; + register_ctxt.dsc.handle = dsc_handle; + register_ctxt.dsc.svc_def = svc; + register_ctxt.dsc.chr_def = chr; + register_ctxt.dsc.dsc_def = dsc; + register_cb(®ister_ctxt, cb_arg); } STATS_INC(ble_gatts_stats, dscs); @@ -527,6 +566,22 @@ ble_gatts_clt_cfg_find(struct ble_gatts_clt_cfg *cfgs, } } +static void +ble_gatts_subscribe_event(uint16_t conn_handle, uint16_t attr_handle, + uint8_t reason, + uint8_t prev_flags, uint8_t cur_flags) +{ + if (prev_flags != cur_flags) { + ble_gap_subscribe_event(conn_handle, + attr_handle, + reason, + prev_flags & BLE_GATTS_CLT_CFG_F_NOTIFY, + cur_flags & BLE_GATTS_CLT_CFG_F_NOTIFY, + prev_flags & BLE_GATTS_CLT_CFG_F_INDICATE, + cur_flags & BLE_GATTS_CLT_CFG_F_INDICATE); + } +} + /** * Performs a read or write access on a client characteritic configuration * descriptor (CCCD). @@ -549,16 +604,17 @@ ble_gatts_clt_cfg_find(struct ble_gatts_clt_cfg *cfgs, */ static int ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle, - uint8_t att_op, - struct ble_att_svr_access_ctxt *ctxt, - struct ble_store_value_cccd *out_cccd) + uint8_t att_op, uint16_t offset, + struct os_mbuf *om, + struct ble_store_value_cccd *out_cccd, + uint8_t *out_prev_clt_cfg_flags, + uint8_t *out_cur_clt_cfg_flags) { struct ble_gatts_clt_cfg *clt_cfg; uint16_t chr_val_handle; uint16_t flags; uint8_t gatt_op; - - static uint8_t buf[2]; + uint8_t *buf; /* Assume nothing needs to be persisted. */ out_cccd->chr_val_handle = 0; @@ -578,37 +634,49 @@ ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle, return BLE_ATT_ERR_UNLIKELY; } + /* Assume no change in flags. */ + *out_prev_clt_cfg_flags = clt_cfg->flags; + *out_cur_clt_cfg_flags = clt_cfg->flags; + gatt_op = ble_gatts_dsc_op(att_op); ble_gatts_dsc_inc_stat(gatt_op); switch (gatt_op) { case BLE_GATT_ACCESS_OP_READ_DSC: STATS_INC(ble_gatts_stats, dsc_reads); + buf = os_mbuf_extend(om, 2); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } htole16(buf, clt_cfg->flags & ~BLE_GATTS_CLT_CFG_F_RESERVED); - ctxt->attr_data = buf; - ctxt->data_len = sizeof buf; break; case BLE_GATT_ACCESS_OP_WRITE_DSC: STATS_INC(ble_gatts_stats, dsc_writes); - if (ctxt->data_len != 2) { + if (OS_MBUF_PKTLEN(om) != 2) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - flags = le16toh(ctxt->attr_data); + om = os_mbuf_pullup(om, 2); + BLE_HS_DBG_ASSERT(om != NULL); + + flags = le16toh(om->om_data); if ((flags & ~clt_cfg->allowed) != 0) { - return BLE_ATT_ERR_WRITE_NOT_PERMITTED; + return BLE_ATT_ERR_REQ_NOT_SUPPORTED; } - clt_cfg->flags = flags; - - /* Successful writes get persisted for bonded connections. */ - if (conn->bhc_sec_state.bonded) { - out_cccd->peer_addr_type = conn->bhc_addr_type; - memcpy(out_cccd->peer_addr, conn->bhc_addr, 6); - out_cccd->chr_val_handle = chr_val_handle; - out_cccd->flags = clt_cfg->flags; - out_cccd->value_changed = 0; + if (clt_cfg->flags != flags) { + clt_cfg->flags = flags; + *out_cur_clt_cfg_flags = flags; + + /* Successful writes get persisted for bonded connections. */ + if (conn->bhc_sec_state.bonded) { + out_cccd->peer_addr_type = conn->bhc_peer_addr_type; + memcpy(out_cccd->peer_addr, conn->bhc_peer_addr, 6); + out_cccd->chr_val_handle = chr_val_handle; + out_cccd->flags = clt_cfg->flags; + out_cccd->value_changed = 0; + } } break; @@ -622,13 +690,15 @@ ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle, static int ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, + uint8_t op, uint16_t offset, struct os_mbuf **om, void *arg) { struct ble_store_value_cccd cccd_value; struct ble_store_key_cccd cccd_key; struct ble_hs_conn *conn; + uint16_t chr_val_handle; + uint8_t prev_flags; + uint8_t cur_flags; int rc; ble_hs_lock(); @@ -637,14 +707,27 @@ ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle, if (conn == NULL) { rc = BLE_ATT_ERR_UNLIKELY; } else { - rc = ble_gatts_clt_cfg_access_locked(conn, attr_handle, op, ctxt, - &cccd_value); + rc = ble_gatts_clt_cfg_access_locked(conn, attr_handle, op, offset, + *om, &cccd_value, &prev_flags, + &cur_flags); } ble_hs_unlock(); + if (rc != 0) { + return rc; + } + + /* The value attribute is always immediately after the declaration. */ + chr_val_handle = attr_handle - 1; + + /* Tell the application if the peer changed its subscription state. */ + ble_gatts_subscribe_event(conn_handle, chr_val_handle, + BLE_GAP_SUBSCRIBE_REASON_WRITE, + prev_flags, cur_flags); + /* Persist the CCCD if required. */ - if (rc == 0 && cccd_value.chr_val_handle != 0) { + if (cccd_value.chr_val_handle != 0) { if (cccd_value.flags == 0) { ble_store_key_from_value_cccd(&cccd_key, &cccd_value); rc = ble_store_delete_cccd(&cccd_key); @@ -679,10 +762,11 @@ ble_gatts_register_clt_cfg_dsc(uint16_t *att_handle) } static int -ble_gatts_register_chr(const struct ble_gatt_chr_def *chr, +ble_gatts_register_chr(const struct ble_gatt_svc_def *svc, + const struct ble_gatt_chr_def *chr, ble_gatt_register_fn *register_cb, void *cb_arg) { - union ble_gatt_register_ctxt register_ctxt; + struct ble_gatt_register_ctxt register_ctxt; struct ble_gatt_dsc_def *dsc; uint16_t def_handle; uint16_t val_handle; @@ -694,7 +778,14 @@ ble_gatts_register_chr(const struct ble_gatt_chr_def *chr, return BLE_HS_EINVAL; } - /* Register characteristic declaration attribute (cast away const on + if (ble_gatts_chr_clt_cfg_allowed(chr) != 0) { + if (ble_gatts_num_cfgable_chrs > ble_hs_cfg.max_client_configs) { + return BLE_HS_ENOMEM; + } + ble_gatts_num_cfgable_chrs++; + } + + /* Register characteristic definition attribute (cast away const on * callback arg). */ rc = ble_att_svr_register_uuid16(BLE_ATT_UUID_CHARACTERISTIC, @@ -715,11 +806,17 @@ ble_gatts_register_chr(const struct ble_gatt_chr_def *chr, } BLE_HS_DBG_ASSERT(val_handle == def_handle + 1); + if (chr->val_handle != NULL) { + *chr->val_handle = val_handle; + } + if (register_cb != NULL) { - register_ctxt.chr_reg.def_handle = def_handle; - register_ctxt.chr_reg.val_handle = val_handle; - register_ctxt.chr_reg.chr = chr; - register_cb(BLE_GATT_REGISTER_OP_CHR, ®ister_ctxt, cb_arg); + register_ctxt.op = BLE_GATT_REGISTER_OP_CHR; + register_ctxt.chr.def_handle = def_handle; + register_ctxt.chr.val_handle = val_handle; + register_ctxt.chr.svc_def = svc; + register_ctxt.chr.chr_def = chr; + register_cb(®ister_ctxt, cb_arg); } if (ble_gatts_chr_clt_cfg_allowed(chr) != 0) { @@ -733,7 +830,7 @@ ble_gatts_register_chr(const struct ble_gatt_chr_def *chr, /* Register each descriptor. */ if (chr->descriptors != NULL) { for (dsc = chr->descriptors; dsc->uuid128 != NULL; dsc++) { - rc = ble_gatts_register_dsc(dsc, chr, def_handle, register_cb, + rc = ble_gatts_register_dsc(svc, chr, dsc, def_handle, register_cb, cb_arg); if (rc != 0) { return rc; @@ -785,7 +882,7 @@ ble_gatts_register_svc(const struct ble_gatt_svc_def *svc, ble_gatt_register_fn *register_cb, void *cb_arg) { const struct ble_gatt_chr_def *chr; - union ble_gatt_register_ctxt register_ctxt; + struct ble_gatt_register_ctxt register_ctxt; uint16_t uuid16; int idx; int rc; @@ -815,15 +912,16 @@ ble_gatts_register_svc(const struct ble_gatt_svc_def *svc, } if (register_cb != NULL) { - register_ctxt.svc_reg.handle = *out_handle; - register_ctxt.svc_reg.svc = svc; - register_cb(BLE_GATT_REGISTER_OP_SVC, ®ister_ctxt, cb_arg); + register_ctxt.op = BLE_GATT_REGISTER_OP_SVC; + register_ctxt.svc.handle = *out_handle; + register_ctxt.svc.svc_def = svc; + register_cb(®ister_ctxt, cb_arg); } /* Register each include. */ if (svc->includes != NULL) { for (i = 0; svc->includes[i] != NULL; i++) { - idx = ble_gatts_find_svc(svc->includes[i]); + idx = ble_gatts_find_svc_entry_idx(svc->includes[i]); BLE_HS_DBG_ASSERT_EVAL(idx != -1); rc = ble_gatts_register_inc(ble_gatts_svc_entries + idx); @@ -836,7 +934,7 @@ ble_gatts_register_svc(const struct ble_gatt_svc_def *svc, /* Register each characteristic. */ if (svc->characteristics != NULL) { for (chr = svc->characteristics; chr->uuid128 != NULL; chr++) { - rc = ble_gatts_register_chr(chr, register_cb, cb_arg); + rc = ble_gatts_register_chr(svc, chr, register_cb, cb_arg); if (rc != 0) { return rc; } @@ -873,7 +971,7 @@ ble_gatts_register_round(int *out_num_registered, ble_gatt_register_fn *cb, case BLE_HS_EAGAIN: /* Service could not be registered due to unsatisfied includes. - * Try again on the next itereation. + * Try again on the next iteration. */ break; @@ -891,28 +989,50 @@ ble_gatts_register_round(int *out_num_registered, ble_gatt_register_fn *cb, return 0; } +/** + * Registers a set of services, characteristics, and descriptors to be accessed + * by GATT clients. + * + * @param svcs A table of the service definitions to be + * registered. + * @param cb The function to call for each service, + * characteristic, and descriptor that gets + * registered. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; + * BLE_HS_ENOMEM if registration failed due to + * resource exhaustion; + * BLE_HS_EINVAL if the service definition table + * contains an invalid element. + */ int ble_gatts_register_svcs(const struct ble_gatt_svc_def *svcs, ble_gatt_register_fn *cb, void *cb_arg) { int total_registered; int cur_registered; + int num_svcs; + int idx; int rc; int i; for (i = 0; svcs[i].type != BLE_GATT_SVC_TYPE_END; i++) { - ble_gatts_svc_entries[i].svc = svcs + i; - ble_gatts_svc_entries[i].handle = 0; - ble_gatts_svc_entries[i].end_group_handle = 0xffff; - } - if (i > ble_hs_cfg.max_services) { - return BLE_HS_ENOMEM; - } + idx = ble_gatts_num_svc_entries + i; + if (idx >= ble_hs_cfg.max_services) { + return BLE_HS_ENOMEM; + } - ble_gatts_num_svc_entries = i; + ble_gatts_svc_entries[idx].svc = svcs + i; + ble_gatts_svc_entries[idx].handle = 0; + ble_gatts_svc_entries[idx].end_group_handle = 0xffff; + } + num_svcs = i; + ble_gatts_num_svc_entries += num_svcs; total_registered = 0; - while (total_registered < ble_gatts_num_svc_entries) { + while (total_registered < num_svcs) { rc = ble_gatts_register_round(&cur_registered, cb, cb_arg); if (rc != 0) { return rc; @@ -923,23 +1043,71 @@ ble_gatts_register_svcs(const struct ble_gatt_svc_def *svcs, return 0; } +static int +ble_gatts_clt_cfg_size(void) +{ + return ble_gatts_num_cfgable_chrs * sizeof (struct ble_gatts_clt_cfg); +} + +/** + * Handles GATT server clean up for a terminated connection: + * o Informs the application that the peer is no longer subscribed to any + * characteristic updates. + * o Frees GATT server resources consumed by the connection (CCCDs). + */ void -ble_gatts_conn_deinit(struct ble_gatts_conn *gatts_conn) +ble_gatts_connection_broken(uint16_t conn_handle) { + struct ble_gatts_clt_cfg *clt_cfgs; + struct ble_hs_conn *conn; + int num_clt_cfgs; int rc; + int i; - if (gatts_conn->clt_cfgs != NULL) { - rc = os_memblock_put(&ble_gatts_clt_cfg_pool, gatts_conn->clt_cfgs); - BLE_HS_DBG_ASSERT_EVAL(rc == 0); + /* Find the specified connection and extract its CCCD entries. Extracting + * the clt_cfg pointer and setting the original to null is done for two + * reasons: + * 1. So that the CCCD entries can be safely processed after unlocking + * the mutex. + * 2. To ensure a subsequent indicate procedure for this peer is not + * attempted, as the connection is about to be terminated. This + * avoids a spurious notify-tx GAP event callback to the + * application. By setting the clt_cfg pointer to null, it is + * assured that the connection has no pending indications to send. + */ + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + if (conn != NULL) { + clt_cfgs = conn->bhc_gatt_svr.clt_cfgs; + num_clt_cfgs = conn->bhc_gatt_svr.num_clt_cfgs; - gatts_conn->clt_cfgs = NULL; + conn->bhc_gatt_svr.clt_cfgs = NULL; + conn->bhc_gatt_svr.num_clt_cfgs = 0; } -} + ble_hs_unlock(); -static int -ble_gatts_clt_cfg_size(void) -{ - return ble_gatts_num_cfgable_chrs * sizeof (struct ble_gatts_clt_cfg); + if (conn == NULL) { + return; + } + + /* If there is an indicate procedure in progress for this connection, + * inform the application that it has failed. + */ + ble_gatts_indicate_fail_notconn(conn_handle); + + /* Now that the mutex is unlocked, inform the application that the peer is + * no longer subscribed to any characteristic updates. + */ + if (clt_cfgs != NULL) { + for (i = 0; i < num_clt_cfgs; i++) { + ble_gatts_subscribe_event(conn_handle, clt_cfgs[i].chr_val_handle, + BLE_GAP_SUBSCRIBE_REASON_TERM, + clt_cfgs[i].flags, 0); + } + + rc = os_memblock_put(&ble_gatts_clt_cfg_pool, clt_cfgs); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); + } } int @@ -953,26 +1121,10 @@ ble_gatts_start(void) int idx; int rc; - rc = ble_uuid_16_to_128(BLE_ATT_UUID_CHARACTERISTIC, uuid128); - BLE_HS_DBG_ASSERT_EVAL(rc == 0); - - /* Count the number of client-configurable characteristics. */ - ble_gatts_num_cfgable_chrs = 0; - ha = NULL; - while ((ha = ble_att_svr_find_by_uuid(ha, uuid128)) != NULL) { - chr = ha->ha_cb_arg; - if (ble_gatts_chr_clt_cfg_allowed(chr) != 0) { - ble_gatts_num_cfgable_chrs++; - } - } if (ble_gatts_num_cfgable_chrs == 0) { return 0; } - if (ble_gatts_num_cfgable_chrs > ble_hs_cfg.max_client_configs) { - return BLE_HS_ENOMEM; - } - /* Initialize client-configuration memory pool. */ num_elems = ble_hs_cfg.max_client_configs / ble_gatts_num_cfgable_chrs; rc = os_mempool_init(&ble_gatts_clt_cfg_pool, num_elems, @@ -991,9 +1143,11 @@ ble_gatts_start(void) } /* Fill the cache. */ + rc = ble_uuid_16_to_128(BLE_ATT_UUID_CHARACTERISTIC, uuid128); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); idx = 0; ha = NULL; - while ((ha = ble_att_svr_find_by_uuid(ha, uuid128)) != NULL) { + while ((ha = ble_att_svr_find_by_uuid(ha, uuid128, 0xffff)) != NULL) { chr = ha->ha_cb_arg; allowed_flags = ble_gatts_chr_clt_cfg_allowed(chr); if (allowed_flags != 0) { @@ -1020,16 +1174,19 @@ int ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn) { if (ble_gatts_num_cfgable_chrs > 0) { - ble_gatts_conn_deinit(gatts_conn); gatts_conn->clt_cfgs = os_memblock_get(&ble_gatts_clt_cfg_pool); if (gatts_conn->clt_cfgs == NULL) { return BLE_HS_ENOMEM; } - } - /* Initialize the client configuration with a copy of the cache. */ - memcpy(gatts_conn->clt_cfgs, ble_gatts_clt_cfgs, ble_gatts_clt_cfg_size()); - gatts_conn->num_clt_cfgs = ble_gatts_num_cfgable_chrs; + /* Initialize the client configuration with a copy of the cache. */ + memcpy(gatts_conn->clt_cfgs, ble_gatts_clt_cfgs, + ble_gatts_clt_cfg_size()); + gatts_conn->num_clt_cfgs = ble_gatts_num_cfgable_chrs; + } else { + gatts_conn->clt_cfgs = NULL; + gatts_conn->num_clt_cfgs = 0; + } return 0; } @@ -1037,9 +1194,7 @@ ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn) /** * Schedules a notification or indication for the specified peer-CCCD pair. If - * the udpate should be sent immediately, it is indicated in the return code. - * If the update can only be sent in the future, the appropriate flags are set - * to ensure this happens. + * the update should be sent immediately, it is indicated in the return code. * * @param conn The connection to schedule the update for. * @param clt_cfg The client config entry corresponding to the @@ -1054,7 +1209,10 @@ ble_gatts_schedule_update(struct ble_hs_conn *conn, { uint8_t att_op; - if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_NOTIFY) { + if (!(clt_cfg->flags & BLE_GATTS_CLT_CFG_F_MODIFIED)) { + /* Characteristic not modified. Nothing to send. */ + att_op = 0; + } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_NOTIFY) { /* Notifications always get sent immediately. */ att_op = BLE_ATT_OP_NOTIFY_REQ; } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE) { @@ -1064,16 +1222,24 @@ ble_gatts_schedule_update(struct ble_hs_conn *conn, * If there isn't an outstanding indication, send this one now. */ if (conn->bhc_gatt_svr.indicate_val_handle != 0) { - clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_INDICATE_PENDING; att_op = 0; } else { att_op = BLE_ATT_OP_INDICATE_REQ; } } else { - BLE_HS_DBG_ASSERT(0); + /* Peer isn't subscribed to notifications or indications. Nothing to + * send. + */ att_op = 0; } + /* If we will be sending an update, clear the modified flag so that we + * don't double-send. + */ + if (att_op != 0) { + clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_MODIFIED; + } + return att_op; } @@ -1095,14 +1261,14 @@ ble_gatts_send_next_indicate(uint16_t conn_handle) if (conn != NULL) { for (i = 0; i < conn->bhc_gatt_svr.num_clt_cfgs; i++) { clt_cfg = conn->bhc_gatt_svr.clt_cfgs + i; - if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE_PENDING) { + if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_MODIFIED) { BLE_HS_DBG_ASSERT(clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE); chr_val_handle = clt_cfg->chr_val_handle; /* Clear pending flag in anticipation of indication tx. */ - clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_INDICATE_PENDING; + clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_MODIFIED; break; } } @@ -1118,7 +1284,7 @@ ble_gatts_send_next_indicate(uint16_t conn_handle) return BLE_HS_ENOENT; } - rc = ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL); + rc = ble_gattc_indicate(conn_handle, chr_val_handle); if (rc != 0) { return rc; } @@ -1170,16 +1336,16 @@ ble_gatts_rx_indicate_ack(uint16_t conn_handle, uint16_t chr_val_handle) BLE_HS_DBG_ASSERT(clt_cfg->chr_val_handle == chr_val_handle); persist = conn->bhc_sec_state.bonded && - !(clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE_PENDING); + !(clt_cfg->flags & BLE_GATTS_CLT_CFG_F_MODIFIED); if (persist) { - cccd_value.peer_addr_type = conn->bhc_addr_type; - memcpy(cccd_value.peer_addr, conn->bhc_addr, 6); + cccd_value.peer_addr_type = conn->bhc_peer_addr_type; + memcpy(cccd_value.peer_addr, conn->bhc_peer_addr, 6); cccd_value.chr_val_handle = chr_val_handle; cccd_value.flags = clt_cfg->flags; cccd_value.value_changed = 0; } } else { - /* This acknowledgement doesn't correspnod to the outstanding + /* This acknowledgement doesn't correspond to the outstanding * indication; ignore it. */ rc = BLE_HS_ENOENT; @@ -1194,7 +1360,7 @@ ble_gatts_rx_indicate_ack(uint16_t conn_handle, uint16_t chr_val_handle) if (persist) { rc = ble_store_write_cccd(&cccd_value); if (rc != 0) { - return rc; + /* XXX: How should this error get reported? */ } } @@ -1208,15 +1374,14 @@ ble_gatts_chr_updated(uint16_t chr_val_handle) struct ble_store_key_cccd cccd_key; struct ble_gatts_clt_cfg *clt_cfg; struct ble_hs_conn *conn; - uint16_t conn_handle; - uint8_t att_op; + int new_notifications; int clt_cfg_idx; int persist; int rc; int i; - /* Determine if notifications / indications are enabled for this - * characteristic. + /* Determine if notifications or indications are allowed for this + * characteristic. If not, return immediately. */ clt_cfg_idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs, chr_val_handle); @@ -1224,47 +1389,31 @@ ble_gatts_chr_updated(uint16_t chr_val_handle) return; } - /* Handle the connected devices. */ - for (i = 0; ; i++) { - ble_hs_lock(); + /*** Send notifications and indications to connected devices. */ + ble_hs_lock(); + for (i = 0; ; i++) { + /* XXX: This is inefficient when there are a lot of connections. + * Consider using a "foreach" function to walk the connection list. + */ conn = ble_hs_conn_find_by_idx(i); - if (conn != NULL) { - BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs > - clt_cfg_idx); - clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx; - BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_val_handle == chr_val_handle); - - /* Determine what kind of update should get sent immediately (if - * any). - */ - att_op = ble_gatts_schedule_update(conn, clt_cfg); - conn_handle = conn->bhc_handle; - } else { - /* Silence some spurious gcc warnings. */ - att_op = 0; - conn_handle = BLE_HS_CONN_HANDLE_NONE; - } - ble_hs_unlock(); - if (conn == NULL) { - /* No more connected devices. */ break; } - switch (att_op) { - case 0: - break; - case BLE_ATT_OP_NOTIFY_REQ: - ble_gattc_notify(conn_handle, chr_val_handle); - break; - case BLE_ATT_OP_INDICATE_REQ: - ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL); - break; - default: - BLE_HS_DBG_ASSERT(0); - break; - } + BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs > + clt_cfg_idx); + clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx; + BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_val_handle == chr_val_handle); + + /* Mark the CCCD entry as modified. */ + clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_MODIFIED; + new_notifications = 1; + } + ble_hs_unlock(); + + if (new_notifications) { + ble_hs_notifications_sched(); } /*** Persist updated flag for unconnected and not-yet-bonded devices. */ @@ -1319,6 +1468,92 @@ ble_gatts_chr_updated(uint16_t chr_val_handle) } /** + * Sends notifications or indications for the specified characteristic to all + * connected devices. The bluetooth spec does not allow more than one + * concurrent indication for a single peer, so this function will hold off on + * sending such indications. + */ +static void +ble_gatts_tx_notifications_one_chr(uint16_t chr_val_handle) +{ + struct ble_gatts_clt_cfg *clt_cfg; + struct ble_hs_conn *conn; + uint16_t conn_handle; + uint8_t att_op; + int clt_cfg_idx; + int i; + + /* Determine if notifications / indications are enabled for this + * characteristic. + */ + clt_cfg_idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs, + chr_val_handle); + if (clt_cfg_idx == -1) { + return; + } + + for (i = 0; ; i++) { + ble_hs_lock(); + + conn = ble_hs_conn_find_by_idx(i); + if (conn != NULL) { + BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs > + clt_cfg_idx); + clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx; + BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_val_handle == chr_val_handle); + + /* Determine what type of command should get sent, if any. */ + att_op = ble_gatts_schedule_update(conn, clt_cfg); + conn_handle = conn->bhc_handle; + } else { + /* Silence some spurious gcc warnings. */ + att_op = 0; + conn_handle = BLE_HS_CONN_HANDLE_NONE; + } + ble_hs_unlock(); + + if (conn == NULL) { + /* No more connected devices. */ + break; + } + + switch (att_op) { + case 0: + break; + + case BLE_ATT_OP_NOTIFY_REQ: + ble_gattc_notify(conn_handle, chr_val_handle); + break; + + case BLE_ATT_OP_INDICATE_REQ: + ble_gattc_indicate(conn_handle, chr_val_handle); + break; + + default: + BLE_HS_DBG_ASSERT(0); + break; + } + } +} + +/** + * Sends all pending notifications and indications. The bluetooth spec does + * not allow more than one concurrent indication for a single peer, so this + * function will hold off on sending such indications. + */ +void +ble_gatts_tx_notifications(void) +{ + uint16_t chr_val_handle; + int i; + + for (i = 0; i < ble_gatts_num_cfgable_chrs; i++) { + chr_val_handle = ble_gatts_clt_cfgs[i].chr_val_handle; + ble_gatts_tx_notifications_one_chr(chr_val_handle); + } +} + +/** * Called when bonding has been restored via the encryption procedure. This * function: * o Restores persisted CCCD entries for the connected peer. @@ -1342,8 +1577,8 @@ ble_gatts_bonding_restored(uint16_t conn_handle) BLE_HS_DBG_ASSERT(conn != NULL); BLE_HS_DBG_ASSERT(conn->bhc_sec_state.bonded); - cccd_key.peer_addr_type = conn->bhc_addr_type; - memcpy(cccd_key.peer_addr, conn->bhc_addr, 6); + cccd_key.peer_addr_type = conn->bhc_peer_addr_type; + memcpy(cccd_key.peer_addr, conn->bhc_peer_addr, 6); cccd_key.chr_val_handle = 0; cccd_key.idx = 0; @@ -1355,7 +1590,7 @@ ble_gatts_bonding_restored(uint16_t conn_handle) break; } - /* Assume no immediate send for this characteristic. */ + /* Assume no notification or indication will get sent. */ att_op = 0; ble_hs_lock(); @@ -1367,16 +1602,30 @@ ble_gatts_bonding_restored(uint16_t conn_handle) cccd_value.chr_val_handle); if (clt_cfg != NULL) { clt_cfg->flags = cccd_value.flags; + if (cccd_value.value_changed) { + /* The characteristic's value changed while the device was + * disconnected or unbonded. Schedule the notification or + * indication now. + */ + clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_MODIFIED; att_op = ble_gatts_schedule_update(conn, clt_cfg); } } ble_hs_unlock(); + /* Tell the application if the peer changed its subscription state + * when it was restored from persistence. + */ + ble_gatts_subscribe_event(conn_handle, cccd_value.chr_val_handle, + BLE_GAP_SUBSCRIBE_REASON_RESTORE, + 0, cccd_value.flags); + switch (att_op) { case 0: break; + case BLE_ATT_OP_NOTIFY_REQ: rc = ble_gattc_notify(conn_handle, cccd_value.chr_val_handle); if (rc == 0) { @@ -1384,10 +1633,11 @@ ble_gatts_bonding_restored(uint16_t conn_handle) ble_store_write_cccd(&cccd_value); } break; + case BLE_ATT_OP_INDICATE_REQ: - ble_gattc_indicate(conn_handle, cccd_value.chr_val_handle, - NULL, NULL); + ble_gattc_indicate(conn_handle, cccd_value.chr_val_handle); break; + default: BLE_HS_DBG_ASSERT(0); break; @@ -1397,6 +1647,384 @@ ble_gatts_bonding_restored(uint16_t conn_handle) } } +static struct ble_gatts_svc_entry * +ble_gatts_find_svc_entry(const void *uuid128) +{ + struct ble_gatts_svc_entry *entry; + int i; + + for (i = 0; i < ble_gatts_num_svc_entries; i++) { + entry = ble_gatts_svc_entries + i; + if (memcmp(uuid128, entry->svc->uuid128, 16) == 0) { + return entry; + } + } + + return NULL; +} + +static int +ble_gatts_find_svc_chr_attr(const void *svc_uuid128, const void *chr_uuid128, + struct ble_gatts_svc_entry **out_svc_entry, + struct ble_att_svr_entry **out_att_chr) +{ + struct ble_gatts_svc_entry *svc_entry; + struct ble_att_svr_entry *att_svc; + struct ble_att_svr_entry *next; + struct ble_att_svr_entry *cur; + uint16_t uuid16; + + svc_entry = ble_gatts_find_svc_entry(svc_uuid128); + if (svc_entry == NULL) { + return BLE_HS_ENOENT; + } + + att_svc = ble_att_svr_find_by_handle(svc_entry->handle); + if (att_svc == NULL) { + return BLE_HS_EUNKNOWN; + } + + cur = STAILQ_NEXT(att_svc, ha_next); + while (1) { + if (cur == NULL) { + /* Reached end of attribute list without a match. */ + return BLE_HS_ENOENT; + } + next = STAILQ_NEXT(cur, ha_next); + + if (cur->ha_handle_id == svc_entry->end_group_handle) { + /* Reached end of service without a match. */ + return BLE_HS_ENOENT; + } + + uuid16 = ble_uuid_128_to_16(cur->ha_uuid); + if (uuid16 == BLE_ATT_UUID_CHARACTERISTIC && + next != NULL && + memcmp(next->ha_uuid, chr_uuid128, 16) == 0) { + + if (out_svc_entry != NULL) { + *out_svc_entry = svc_entry; + } + if (out_att_chr != NULL) { + *out_att_chr = next; + } + return 0; + } + + cur = next; + } +} + +/** + * Retrieves the attribute handle associated with a local GATT service. + * + * @param uuid128 The UUID of the service to look up. + * @param out_handle On success, populated with the handle of the + * service attribute. Pass null if you don't + * need this value. + * + * @return 0 on success; + * BLE_HS_ENOENT if the specified service could + * not be found. + */ +int +ble_gatts_find_svc(const void *uuid128, uint16_t *out_handle) +{ + struct ble_gatts_svc_entry *entry; + + entry = ble_gatts_find_svc_entry(uuid128); + if (entry == NULL) { + return BLE_HS_ENOENT; + } + + if (out_handle != NULL) { + *out_handle = entry->handle; + } + return 0; +} + +/** + * Retrieves the pair of attribute handles associated with a local GATT + * characteristic. + * + * @param svc_uuid128 The UUID of the parent service. + * @param chr_uuid128 The UUID of the characteristic to look up. + * @param out_def_handle On success, populated with the handle + * of the characteristic definition attribute. + * Pass null if you don't need this value. + * @param out_val_handle On success, populated with the handle + * of the characteristic value attribute. + * Pass null if you don't need this value. + * + * @return 0 on success; + * BLE_HS_ENOENT if the specified service or + * characteristic could not be found. + */ +int +ble_gatts_find_chr(const void *svc_uuid128, const void *chr_uuid128, + uint16_t *out_def_handle, uint16_t *out_val_handle) +{ + struct ble_att_svr_entry *att_chr; + int rc; + + rc = ble_gatts_find_svc_chr_attr(svc_uuid128, chr_uuid128, NULL, &att_chr); + if (rc != 0) { + return rc; + } + + if (out_def_handle) { + *out_def_handle = att_chr->ha_handle_id - 1; + } + if (out_val_handle) { + *out_val_handle = att_chr->ha_handle_id; + } + return 0; +} + +/** + * Retrieves the attribute handle associated with a local GATT descriptor. + * + * @param svc_uuid128 The UUID of the grandparent service. + * @param chr_uuid128 The UUID of the parent characteristic. + * @param dsc_uuid128 The UUID of the descriptor ro look up. + * @param out_handle On success, populated with the handle + * of the descripytor attribute. Pass null if + * you don't need this value. + * + * @return 0 on success; + * BLE_HS_ENOENT if the specified service, + * characteristic, or descriptor could not be + * found. + */ +int +ble_gatts_find_dsc(const void *svc_uuid128, const void *chr_uuid128, + const void *dsc_uuid128, uint16_t *out_handle) +{ + struct ble_gatts_svc_entry *svc_entry; + struct ble_att_svr_entry *att_chr; + struct ble_att_svr_entry *cur; + uint16_t uuid16; + int rc; + + rc = ble_gatts_find_svc_chr_attr(svc_uuid128, chr_uuid128, &svc_entry, + &att_chr); + if (rc != 0) { + return rc; + } + + cur = STAILQ_NEXT(att_chr, ha_next); + while (1) { + if (cur == NULL) { + /* Reached end of attribute list without a match. */ + return BLE_HS_ENOENT; + } + + if (cur->ha_handle_id == svc_entry->end_group_handle) { + /* Reached end of service without a match. */ + return BLE_HS_ENOENT; + } + + uuid16 = ble_uuid_128_to_16(cur->ha_uuid); + if (uuid16 == BLE_ATT_UUID_CHARACTERISTIC) { + /* Reached end of characteristic without a match. */ + return BLE_HS_ENOENT; + } + + if (memcmp(cur->ha_uuid, dsc_uuid128, 16) == 0) { + if (out_handle != NULL) { + *out_handle = cur->ha_handle_id; + return 0; + } + } + cur = STAILQ_NEXT(cur, ha_next); + } +} + +/** + * Queues a set of service definitions for registration. All services queued + * in this manner get registered when ble_hs_init() is called. + * + * @param svcs An array of service definitions to queue for + * registration. This array must be + * terminated with an entry whose 'type' + * equals 0. + * + * @return 0 on success; + * BLE_HS_ENOMEM on heap exhaustion. + */ +int +ble_gatts_add_svcs(const struct ble_gatt_svc_def *svcs) +{ + void *p; + + p = realloc(ble_gatts_svc_defs, + (ble_gatts_num_svc_defs + 1) * sizeof *ble_gatts_svc_defs); + if (p == NULL) { + return BLE_HS_ENOMEM; + } + + ble_gatts_svc_defs = p; + ble_gatts_svc_defs[ble_gatts_num_svc_defs] = svcs; + ble_gatts_num_svc_defs++; + + return 0; +} + +/** + * Accumulates counts of each resource type required by the specified service + * definition array. This function is generally used to calculate some host + * configuration values prior to initialization. This function adds the counts + * to the appropriate fields in the supplied ble_gatt_resources object without + * clearing them first, so it can be called repeatedly with different inputs to + * calculate totals. Be sure to zero the resource struct prior to the first + * call to this function. + * + * @param svcs The service array containing the resource + * definitions to be counted. + * @param res The resource counts are accumulated in this + * struct. + * + * @return 0 on success; + * BLE_HS_EINVAL if the svcs array contains an + * invalid resource definition. + */ +int +ble_gatts_count_resources(const struct ble_gatt_svc_def *svcs, + struct ble_gatt_resources *res) +{ + const struct ble_gatt_svc_def *svc; + const struct ble_gatt_chr_def *chr; + int s; + int i; + int c; + int d; + + for (s = 0; svcs[s].type != BLE_GATT_SVC_TYPE_END; s++) { + svc = svcs + s; + + if (!ble_gatts_svc_is_sane(svc)) { + BLE_HS_DBG_ASSERT(0); + return BLE_HS_EINVAL; + } + + /* Each service requires: + * o 1 service + * o 1 attribute + */ + res->svcs++; + res->attrs++; + + if (svc->includes != NULL) { + for (i = 0; svc->includes[i] != NULL; i++) { + /* Each include requires: + * o 1 include + * o 1 attribute + */ + res->incs++; + res->attrs++; + } + } + + if (svc->characteristics != NULL) { + for (c = 0; svc->characteristics[c].uuid128 != NULL; c++) { + chr = svc->characteristics + c; + + if (!ble_gatts_chr_is_sane(chr)) { + BLE_HS_DBG_ASSERT(0); + return BLE_HS_EINVAL; + } + + /* Each characteristic requires: + * o 1 characteristic + * o 2 attributes + */ + res->chrs++; + res->attrs += 2; + + /* If the characteristic permits notifications or indications, + * it has a CCCD. + */ + if (chr->flags & BLE_GATT_CHR_F_NOTIFY || + chr->flags & BLE_GATT_CHR_F_INDICATE) { + + /* Each CCCD requires: + * o 1 descriptor + * o 1 CCCD + * o 1 attribute + */ + res->dscs++; + res->cccds++; + res->attrs++; + } + + if (chr->descriptors != NULL) { + for (d = 0; chr->descriptors[d].uuid128 != NULL; d++) { + if (!ble_gatts_dsc_is_sane(chr->descriptors + d)) { + BLE_HS_DBG_ASSERT(0); + return BLE_HS_EINVAL; + } + + /* Each descriptor requires: + * o 1 descriptor + * o 1 attribute + */ + res->dscs++; + res->attrs++; + } + } + } + } + } + + return 0; +} + +/** + * Adjusts a host configuration object's settings to accommodate the specified + * service definition array. This function adds the counts to the appropriate + * fields in the supplied configuration object without clearing them first, so + * it can be called repeatedly with different inputs to calculate totals. Be + * sure to zero the GATT server settings prior to the first call to this + * function. + * + * @param defs The service array containing the resource + * definitions to be counted. + * @param cfg The resource counts are accumulated in this + * configuration object. + * + * @return 0 on success; + * BLE_HS_EINVAL if the svcs array contains an + * invalid resource definition. + */ +int +ble_gatts_count_cfg(const struct ble_gatt_svc_def *defs, + struct ble_hs_cfg *cfg) +{ + struct ble_gatt_resources res = { 0 }; + int rc; + + rc = ble_gatts_count_resources(defs, &res); + if (rc != 0) { + return rc; + } + + cfg->max_services += res.svcs; + cfg->max_attrs += res.attrs; + + /* Reserve an extra CCCD for the cache. */ + cfg->max_client_configs += res.cccds * (cfg->max_connections + 1); + + return 0; +} + +static void +ble_gatts_free_svc_defs(void) +{ + free(ble_gatts_svc_defs); + ble_gatts_svc_defs = NULL; + ble_gatts_num_svc_defs = 0; +} + static void ble_gatts_free_mem(void) { @@ -1411,6 +2039,7 @@ int ble_gatts_init(void) { int rc; + int i; ble_gatts_free_mem(); ble_gatts_num_cfgable_chrs = 0; @@ -1435,6 +2064,17 @@ ble_gatts_init(void) } } + ble_gatts_num_svc_entries = 0; + for (i = 0; i < ble_gatts_num_svc_defs; i++) { + rc = ble_gatts_register_svcs(ble_gatts_svc_defs[i], + ble_hs_cfg.gatts_register_cb, + ble_hs_cfg.gatts_register_arg); + if (rc != 0) { + goto err; + } + } + ble_gatts_free_svc_defs(); + rc = stats_init_and_reg( STATS_HDR(ble_gatts_stats), STATS_SIZE_INIT_PARMS(ble_gatts_stats, STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_gatts_stats), "ble_gatts"); @@ -1447,5 +2087,6 @@ ble_gatts_init(void) err: ble_gatts_free_mem(); + ble_gatts_free_svc_defs(); return rc; } diff --git a/net/nimble/host/src/ble_hci_cmd.c b/net/nimble/host/src/ble_hci_cmd.c deleted file mode 100644 index 23eaba37..00000000 --- a/net/nimble/host/src/ble_hci_cmd.c +++ /dev/null @@ -1,298 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <stdio.h> -#include "os/os.h" -#include "ble_hs_priv.h" -#include "host_dbg_priv.h" - -#define BLE_HCI_CMD_TIMEOUT (OS_TICKS_PER_SEC) - -static struct os_mutex ble_hci_cmd_mutex; -static struct os_sem ble_hci_cmd_sem; - -#if PHONY_HCI_ACKS -static ble_hci_cmd_phony_ack_fn *ble_hci_cmd_phony_ack_cb; -#endif - -#if PHONY_HCI_ACKS -void -ble_hci_set_phony_ack_cb(ble_hci_cmd_phony_ack_fn *cb) -{ - ble_hci_cmd_phony_ack_cb = cb; -} -#endif - -static void -ble_hci_cmd_lock(void) -{ - int rc; - - rc = os_mutex_pend(&ble_hci_cmd_mutex, 0xffffffff); - BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED); -} - -static void -ble_hci_cmd_unlock(void) -{ - int rc; - - rc = os_mutex_release(&ble_hci_cmd_mutex); - BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED); -} - -static int -ble_hci_cmd_rx_cmd_complete(uint8_t event_code, uint8_t *data, int len, - struct ble_hci_ack *out_ack) -{ - uint16_t opcode; - uint8_t *params; - uint8_t params_len; - uint8_t num_pkts; - - if (len < BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN) { - /* XXX: Increment stat. */ - return BLE_HS_ECONTROLLER; - } - - num_pkts = data[2]; - opcode = le16toh(data + 3); - params = data + 5; - - /* XXX: Process num_pkts field. */ - (void)num_pkts; - - out_ack->bha_opcode = opcode; - - params_len = len - BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN; - if (params_len > 0) { - out_ack->bha_status = BLE_HS_HCI_ERR(params[0]); - } else if (opcode == BLE_HCI_OPCODE_NOP) { - out_ack->bha_status = 0; - } else { - out_ack->bha_status = BLE_HS_ECONTROLLER; - } - - /* Don't include the status byte in the parameters blob. */ - if (params_len > 1) { - out_ack->bha_params = params + 1; - out_ack->bha_params_len = params_len - 1; - } else { - out_ack->bha_params = NULL; - out_ack->bha_params_len = 0; - } - - return 0; -} - -static int -ble_hci_cmd_rx_cmd_status(uint8_t event_code, uint8_t *data, int len, - struct ble_hci_ack *out_ack) -{ - uint16_t opcode; - uint8_t num_pkts; - uint8_t status; - - if (len < BLE_HCI_EVENT_CMD_STATUS_LEN) { - /* XXX: Increment stat. */ - return BLE_HS_ECONTROLLER; - } - - status = data[2]; - num_pkts = data[3]; - opcode = le16toh(data + 4); - - /* XXX: Process num_pkts field. */ - (void)num_pkts; - - out_ack->bha_opcode = opcode; - out_ack->bha_params = NULL; - out_ack->bha_params_len = 0; - out_ack->bha_status = BLE_HS_HCI_ERR(status); - - return 0; -} - -static int -ble_hci_cmd_process_ack(uint8_t *params_buf, uint8_t params_buf_len, - struct ble_hci_ack *out_ack) -{ - uint8_t event_code; - uint8_t param_len; - uint8_t event_len; - int rc; - - /*** - * The controller always reuses the command buffer for its acknowledgement - * events. This function processes the acknowledgement event contained in - * the command buffer. - */ - - /* Count events received */ - STATS_INC(ble_hs_stats, hci_event); - - /* Display to console */ - host_hci_dbg_event_disp(host_hci_cmd_buf); - - event_code = host_hci_cmd_buf[0]; - param_len = host_hci_cmd_buf[1]; - event_len = param_len + 2; - - /* Clear ack fields up front to silence spurious gcc warnings. */ - memset(out_ack, 0, sizeof *out_ack); - - switch (event_code) { - case BLE_HCI_EVCODE_COMMAND_COMPLETE: - rc = ble_hci_cmd_rx_cmd_complete(event_code, host_hci_cmd_buf, - event_len, out_ack); - break; - - case BLE_HCI_EVCODE_COMMAND_STATUS: - rc = ble_hci_cmd_rx_cmd_status(event_code, host_hci_cmd_buf, - event_len, out_ack); - break; - - default: - BLE_HS_DBG_ASSERT(0); - rc = BLE_HS_EUNKNOWN; - break; - } - - if (rc == 0) { - if (params_buf == NULL) { - out_ack->bha_params_len = 0; - } else { - if (out_ack->bha_params_len > params_buf_len) { - out_ack->bha_params_len = params_buf_len; - rc = BLE_HS_ECONTROLLER; - } - memcpy(params_buf, out_ack->bha_params, out_ack->bha_params_len); - } - out_ack->bha_params = params_buf; - } - - return rc; -} - -static int -ble_hci_cmd_wait_for_ack(void) -{ - int rc; - -#if PHONY_HCI_ACKS - if (ble_hci_cmd_phony_ack_cb == NULL) { - rc = BLE_HS_ETIMEOUT_HCI; - } else { - rc = ble_hci_cmd_phony_ack_cb(host_hci_cmd_buf, 260); - } -#else - rc = os_sem_pend(&ble_hci_cmd_sem, BLE_HCI_CMD_TIMEOUT); - switch (rc) { - case 0: - break; - case OS_TIMEOUT: - rc = BLE_HS_ETIMEOUT_HCI; - break; - default: - rc = BLE_HS_EOS; - break; - } -#endif - - return rc; -} - -int -ble_hci_cmd_tx(void *cmd, void *evt_buf, uint8_t evt_buf_len, - uint8_t *out_evt_buf_len) -{ - struct ble_hci_ack ack; - int rc; - - ble_hci_cmd_lock(); - - rc = host_hci_cmd_send_buf(cmd); - if (rc != 0) { - goto done; - } - - rc = ble_hci_cmd_wait_for_ack(); - if (rc != 0) { - goto done; - } - - rc = ble_hci_cmd_process_ack(evt_buf, evt_buf_len, &ack); - if (rc != 0) { - goto done; - } - - if (out_evt_buf_len != NULL) { - *out_evt_buf_len = ack.bha_params_len; - } - - rc = ack.bha_status; - -done: - ble_hci_cmd_unlock(); - return rc; -} - -int -ble_hci_cmd_tx_empty_ack(void *cmd) -{ - int rc; - - rc = ble_hci_cmd_tx(cmd, NULL, 0, NULL); - if (rc != 0) { - return rc; - } - - return 0; -} - -void -ble_hci_cmd_rx_ack(uint8_t *ack_ev) -{ - /* The controller should always reuse the command buffer for its acks. */ - BLE_HS_DBG_ASSERT(ack_ev == host_hci_cmd_buf); - - if (ble_hci_cmd_sem.sem_tokens != 0) { - /* This ack is unexpected; ignore it. */ - return; - } - - /* Unblock the application now that the HCI command buffer is populated - * with the acknowledgement. - */ - os_sem_release(&ble_hci_cmd_sem); -} - -void -ble_hci_cmd_init(void) -{ - int rc; - - rc = os_sem_init(&ble_hci_cmd_sem, 0); - BLE_HS_DBG_ASSERT_EVAL(rc == 0); - - rc = os_mutex_init(&ble_hci_cmd_mutex); - BLE_HS_DBG_ASSERT_EVAL(rc == 0); -} diff --git a/net/nimble/host/src/ble_hs.c b/net/nimble/host/src/ble_hs.c index bd092173..8d4b0473 100644 --- a/net/nimble/host/src/ble_hs.c +++ b/net/nimble/host/src/ble_hs.c @@ -23,38 +23,44 @@ #include "stats/stats.h" #include "util/tpq.h" #include "os/os.h" -#include "nimble/hci_transport.h" -#include "host/host_hci.h" +#include "nimble/ble_hci_trans.h" #include "ble_hs_priv.h" -#ifdef PHONY_TRANSPORT -#include "host/ble_hs_test.h" -#endif -#ifdef ARCH_sim -#define BLE_HS_STACK_SIZE (1024) -#else -#define BLE_HS_STACK_SIZE (512)//(250) -#endif +/** + * The maximum number of events the host will process in a row before returning + * control to the parent task. + */ +#define BLE_HS_MAX_EVS_IN_A_ROW 2 static struct log_handler ble_hs_log_console_handler; -struct log ble_hs_log; -struct os_mempool g_hci_cmd_pool; -static void *ble_hs_hci_cmd_buf; +struct os_mempool ble_hs_hci_ev_pool; +static void *ble_hs_hci_os_event_buf; -/* XXX: this might be transport layer */ -#define HCI_OS_EVENT_BUF_SIZE (sizeof(struct os_event)) +/** OS event - triggers tx of pending notifications and indications. */ +static struct os_event ble_hs_event_tx_notifications = { + .ev_type = BLE_HS_EVENT_TX_NOTIFICATIONS, + .ev_arg = NULL, +}; -struct os_mempool g_hci_os_event_pool; -static void *ble_hs_hci_os_event_buf; +/** OS event - triggers a full reset. */ +static struct os_event ble_hs_event_reset = { + .ev_type = BLE_HS_EVENT_RESET, + .ev_arg = NULL, +}; + +uint8_t ble_hs_sync_state; +static int ble_hs_reset_reason; #if MYNEWT_SELFTEST /** Use a higher frequency timer to allow tests to run faster. */ -#define BLE_HS_HEARTBEAT_OS_TICKS (OS_TICKS_PER_SEC / 10) +#define BLE_HS_HEARTBEAT_OS_TICKS (OS_TICKS_PER_SEC / 10) #else -#define BLE_HS_HEARTBEAT_OS_TICKS OS_TICKS_PER_SEC +#define BLE_HS_HEARTBEAT_OS_TICKS OS_TICKS_PER_SEC #endif +#define BLE_HS_SYNC_RETRY_RATE (OS_TICKS_PER_SEC / 10) + /** * Handles unresponsive timeouts and periodic retries in case of resource * shortage. @@ -86,6 +92,9 @@ STATS_NAME_START(ble_hs_stats) STATS_NAME(ble_hs_stats, hci_event) STATS_NAME(ble_hs_stats, hci_invalid_ack) STATS_NAME(ble_hs_stats, hci_unknown_event) + STATS_NAME(ble_hs_stats, hci_timeout) + STATS_NAME(ble_hs_stats, reset) + STATS_NAME(ble_hs_stats, sync) STATS_NAME_END(ble_hs_stats) int @@ -153,24 +162,31 @@ ble_hs_process_tx_data_queue(void) struct os_mbuf *om; while ((om = os_mqueue_get(&ble_hs_tx_q)) != NULL) { -#ifdef PHONY_TRANSPORT - ble_hs_test_pkt_txed(om); -#else - ble_hci_transport_host_acl_data_send(om); -#endif + ble_hci_trans_hs_acl_tx(om); } } -static void +void ble_hs_process_rx_data_queue(void) { struct os_mbuf *om; while ((om = os_mqueue_get(&ble_hs_rx_q)) != NULL) { - host_hci_data_rx(om); + ble_hs_hci_evt_acl_process(om); + } +} + +static void +ble_hs_clear_data_queue(struct os_mqueue *mqueue) +{ + struct os_mbuf *om; + + while ((om = os_mqueue_get(mqueue)) != NULL) { + os_mbuf_free_chain(om); } } + static void ble_hs_heartbeat_timer_reset(uint32_t ticks) { @@ -180,6 +196,102 @@ ble_hs_heartbeat_timer_reset(uint32_t ticks) BLE_HS_DBG_ASSERT_EVAL(rc == 0); } +void +ble_hs_heartbeat_sched(int32_t ticks_from_now) +{ + if (ticks_from_now == BLE_HS_FOREVER) { + return; + } + + /* Reset heartbeat timer if it is not currently scheduled or if the + * specified time is sooner than the current expiration time. + */ + if (!os_callout_queued(&ble_hs_heartbeat_timer.cf_c) || + OS_TIME_TICK_LT(ticks_from_now, ble_hs_heartbeat_timer.cf_c.c_ticks)) { + + ble_hs_heartbeat_timer_reset(ticks_from_now); + } +} + +/** + * Indicates whether the host has synchronized with the controller. + * Synchronization must occur before any host procedures can be performed. + * + * @return 1 if the host and controller are in sync; + * 0 if the host and controller our out of sync. + */ +int +ble_hs_synced(void) +{ + return ble_hs_sync_state == BLE_HS_SYNC_STATE_GOOD; +} + +static int +ble_hs_sync(void) +{ + int rc; + + /* Set the sync state to "bringup." This allows the parent task to send + * the startup sequence to the controller. No other tasks are allowed to + * send any commands. + */ + ble_hs_sync_state = BLE_HS_SYNC_STATE_BRINGUP; + + rc = ble_hs_startup_go(); + if (rc == 0) { + ble_hs_sync_state = BLE_HS_SYNC_STATE_GOOD; + if (ble_hs_cfg.sync_cb != NULL) { + ble_hs_cfg.sync_cb(); + } + } else { + ble_hs_sync_state = BLE_HS_SYNC_STATE_BAD; + } + + ble_hs_heartbeat_sched(BLE_HS_SYNC_RETRY_RATE); + + if (rc == 0) { + STATS_INC(ble_hs_stats, sync); + } + + return rc; +} + +static int +ble_hs_reset(void) +{ + uint16_t conn_handle; + int rc; + + STATS_INC(ble_hs_stats, reset); + + ble_hs_sync_state = 0; + + rc = ble_hci_trans_reset(); + if (rc != 0) { + return rc; + } + + ble_hs_clear_data_queue(&ble_hs_tx_q); + ble_hs_clear_data_queue(&ble_hs_rx_q); + + while (1) { + conn_handle = ble_hs_atomic_first_conn_handle(); + if (conn_handle == BLE_HS_CONN_HANDLE_NONE) { + break; + } + + ble_gap_conn_broken(conn_handle, ble_hs_reset_reason); + } + + if (ble_hs_cfg.reset_cb != NULL && ble_hs_reset_reason != 0) { + ble_hs_cfg.reset_cb(ble_hs_reset_reason); + } + ble_hs_reset_reason = 0; + + rc = ble_hs_sync(); + return rc; +} + /** * Called once a second by the ble_hs heartbeat timer. Handles unresponsive * timeouts and periodic retries in case of resource shortage. @@ -187,43 +299,62 @@ ble_hs_heartbeat_timer_reset(uint32_t ticks) static void ble_hs_heartbeat(void *unused) { - uint32_t lcl_ticks_until_next; - uint32_t ticks_until_next; + int32_t ticks_until_next; - ticks_until_next = BLE_HS_HEARTBEAT_OS_TICKS; + if (!ble_hs_sync_state) { + ble_hs_reset(); + return; + } - lcl_ticks_until_next = ble_gattc_heartbeat(); - ticks_until_next = min(ticks_until_next, lcl_ticks_until_next); + /* Ensure the timer expires at least once in the next second. + * XXX: This is not very power efficient. We will need separate timers for + * each module. + */ + ticks_until_next = BLE_HS_HEARTBEAT_OS_TICKS; + ble_hs_heartbeat_sched(ticks_until_next); - lcl_ticks_until_next = ble_gap_heartbeat(); - ticks_until_next = min(ticks_until_next, lcl_ticks_until_next); + ticks_until_next = ble_gattc_heartbeat(); + ble_hs_heartbeat_sched(ticks_until_next); - lcl_ticks_until_next = ble_l2cap_sig_heartbeat(); - ticks_until_next = min(ticks_until_next, lcl_ticks_until_next); + ticks_until_next = ble_gap_heartbeat(); + ble_hs_heartbeat_sched(ticks_until_next); - lcl_ticks_until_next = ble_sm_heartbeat(); - ticks_until_next = min(ticks_until_next, lcl_ticks_until_next); + ticks_until_next = ble_l2cap_sig_heartbeat(); + ble_hs_heartbeat_sched(ticks_until_next); - ble_hs_heartbeat_timer_reset(ticks_until_next); + ticks_until_next = ble_sm_heartbeat(); + ble_hs_heartbeat_sched(ticks_until_next); } static void ble_hs_event_handle(void *unused) { struct os_callout_func *cf; + struct os_eventq *evqp; struct os_event *ev; - os_sr_t sr; + uint8_t *hci_evt; + int rc; + int i; + evqp = &ble_hs_evq; + + i = 0; while (1) { - OS_ENTER_CRITICAL(sr); - ev = STAILQ_FIRST(&ble_hs_evq.evq_list); - OS_EXIT_CRITICAL(sr); + /* If the host has already processed several consecutive events, stop + * and return control to the parent task. Put an event on the parent + * task's eventq to indicate that more host events are enqueued. + */ + if (i >= BLE_HS_MAX_EVS_IN_A_ROW) { + os_eventq_put(ble_hs_parent_evq, &ble_hs_event_co.cf_c.c_ev); + break; + } + i++; + ev = os_eventq_poll(&evqp, 1, 0); if (ev == NULL) { break; } - ev = os_eventq_get(&ble_hs_evq); switch (ev->ev_type) { case OS_EVENT_T_TIMER: cf = (struct os_callout_func *)ev; @@ -232,8 +363,16 @@ ble_hs_event_handle(void *unused) break; case BLE_HOST_HCI_EVENT_CTLR_EVENT: - /* Process HCI event from controller */ - host_hci_os_event_proc(ev); + hci_evt = ev->ev_arg; + rc = os_memblock_put(&ble_hs_hci_ev_pool, ev); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); + + ble_hs_hci_evt_process(hci_evt); + break; + + case BLE_HS_EVENT_TX_NOTIFICATIONS: + BLE_HS_DBG_ASSERT(ev == &ble_hs_event_tx_notifications); + ble_gatts_tx_notifications(); break; case OS_EVENT_T_MQUEUE_DATA: @@ -241,6 +380,11 @@ ble_hs_event_handle(void *unused) ble_hs_process_rx_data_queue(); break; + case BLE_HS_EVENT_RESET: + BLE_HS_DBG_ASSERT(ev == &ble_hs_event_reset); + ble_hs_reset(); + break; + default: BLE_HS_DBG_ASSERT(0); break; @@ -255,6 +399,67 @@ ble_hs_event_enqueue(struct os_event *ev) os_eventq_put(ble_hs_parent_evq, &ble_hs_event_co.cf_c.c_ev); } +void +ble_hs_enqueue_hci_event(uint8_t *hci_evt) +{ + struct os_event *ev; + + ev = os_memblock_get(&ble_hs_hci_ev_pool); + if (ev == NULL) { + ble_hci_trans_buf_free(hci_evt); + } else { + ev->ev_queued = 0; + ev->ev_type = BLE_HOST_HCI_EVENT_CTLR_EVENT; + ev->ev_arg = hci_evt; + ble_hs_event_enqueue(ev); + } +} + +/** + * Schedules for all pending notifications and indications to be sent in the + * host parent task. + */ +void +ble_hs_notifications_sched(void) +{ +#if MYNEWT_SELFTEST + if (!os_started()) { + ble_gatts_tx_notifications(); + return; + } +#endif + + ble_hs_event_enqueue(&ble_hs_event_tx_notifications); +} + +void +ble_hs_sched_reset(int reason) +{ + BLE_HS_DBG_ASSERT(ble_hs_reset_reason == 0); + + ble_hs_reset_reason = reason; + ble_hs_event_enqueue(&ble_hs_event_reset); +} + +void +ble_hs_hw_error(uint8_t hw_code) +{ + ble_hs_sched_reset(BLE_HS_HW_ERR(hw_code)); +} + +/** + * Synchronizes the host with the controller by sending a sequence of HCI + * commands. This function must be called before any other host functionality + * is used, but it must be called after both the host and controller are + * initialized. Typically, the host-parent-task calls this function at the top + * of its task routine. + * + * If the host fails to synchronize with the controller (if the controller is + * not fully booted, for example), the host will attempt to resynchronize every + * 100 ms. For this reason, an error return code is not necessarily fatal. + * + * @return 0 on success; nonzero on error. + */ int ble_hs_start(void) { @@ -262,11 +467,9 @@ ble_hs_start(void) ble_hs_parent_task = os_sched_get_current_task(); - ble_hs_heartbeat_timer_reset(BLE_HS_HEARTBEAT_OS_TICKS); - ble_gatts_start(); - rc = ble_hs_startup_go(); + rc = ble_hs_sync(); return rc; } @@ -280,19 +483,29 @@ ble_hs_start(void) * @return 0 on success; nonzero on failure. */ int -ble_hs_rx_data(struct os_mbuf *om) +ble_hs_rx_data(struct os_mbuf *om, void *arg) { int rc; rc = os_mqueue_put(&ble_hs_rx_q, &ble_hs_evq, om); - if (rc != 0) { - return BLE_HS_EOS; + if (rc == 0) { + os_eventq_put(ble_hs_parent_evq, &ble_hs_event_co.cf_c.c_ev); + } else { + os_mbuf_free_chain(om); + rc = BLE_HS_EOS; } - os_eventq_put(ble_hs_parent_evq, &ble_hs_event_co.cf_c.c_ev); - - return 0; + return rc; } +/** + * Enqueues an ACL data packet for transmission. This function consumes the + * supplied mbuf, regardless of the outcome. + * + * @param om The outgoing data packet, beginning with the + * HCI ACL data header. + * + * @return 0 on success; nonzero on failure. + */ int ble_hs_tx_data(struct os_mbuf *om) { @@ -300,6 +513,7 @@ ble_hs_tx_data(struct os_mbuf *om) rc = os_mqueue_put(&ble_hs_tx_q, &ble_hs_evq, om); if (rc != 0) { + os_mbuf_free_chain(om); return BLE_HS_EOS; } os_eventq_put(ble_hs_parent_evq, &ble_hs_event_co.cf_c.c_ev); @@ -310,15 +524,26 @@ ble_hs_tx_data(struct os_mbuf *om) static void ble_hs_free_mem(void) { - free(ble_hs_hci_cmd_buf); - ble_hs_hci_cmd_buf = NULL; - free(ble_hs_hci_os_event_buf); ble_hs_hci_os_event_buf = NULL; } /** - * Initializes the host portion of the BLE stack. + * Initializes the NimBLE host. This function must be called before the OS is + * started. The NimBLE stack requires an application task to function. One + * application task in particular is designated as the "host parent task". In + * addition to application-specific work, the host parent task does work for + * NimBLE by processing events generated by the host. + * + * @param app_evq The event queue associated with the host parent + * task. + * @param cfg The set of configuration settings to initialize + * the host with. Specify null for defaults. + * + * @return 0 on success; + * BLE_HS_ENOMEM if initialization failed due to + * resource exhaustion. + * Other nonzero on error. */ int ble_hs_init(struct os_eventq *app_evq, struct ble_hs_cfg *cfg) @@ -339,30 +564,17 @@ ble_hs_init(struct os_eventq *app_evq, struct ble_hs_cfg *cfg) log_console_handler_init(&ble_hs_log_console_handler); log_register("ble_hs", &ble_hs_log, &ble_hs_log_console_handler); - ble_hs_hci_cmd_buf = malloc(OS_MEMPOOL_BYTES(ble_hs_cfg.max_hci_bufs, - HCI_CMD_BUF_SIZE)); - if (ble_hs_hci_cmd_buf == NULL) { - rc = BLE_HS_ENOMEM; - goto err; - } - - /* Create memory pool of command buffers */ - rc = os_mempool_init(&g_hci_cmd_pool, ble_hs_cfg.max_hci_bufs, - HCI_CMD_BUF_SIZE, ble_hs_hci_cmd_buf, - "HCICmdPool"); - assert(rc == 0); - - ble_hs_hci_os_event_buf = malloc(OS_MEMPOOL_BYTES(ble_hs_cfg.max_hci_bufs, - HCI_OS_EVENT_BUF_SIZE)); + ble_hs_hci_os_event_buf = malloc( + OS_MEMPOOL_BYTES(ble_hs_cfg.max_hci_bufs, sizeof (struct os_event))); if (ble_hs_hci_os_event_buf == NULL) { rc = BLE_HS_ENOMEM; goto err; } /* Create memory pool of OS events */ - rc = os_mempool_init(&g_hci_os_event_pool, ble_hs_cfg.max_hci_bufs, - HCI_OS_EVENT_BUF_SIZE, ble_hs_hci_os_event_buf, - "HCIOsEventPool"); + rc = os_mempool_init(&ble_hs_hci_ev_pool, ble_hs_cfg.max_hci_bufs, + sizeof (struct os_event), ble_hs_hci_os_event_buf, + "ble_hs_hci_ev_pool"); assert(rc == 0); /* Initialize eventq */ @@ -375,7 +587,7 @@ ble_hs_init(struct os_eventq *app_evq, struct ble_hs_cfg *cfg) goto err; } - ble_hci_cmd_init(); + ble_hs_hci_init(); rc = ble_hs_conn_init(); if (rc != 0) { @@ -437,6 +649,9 @@ ble_hs_init(struct os_eventq *app_evq, struct ble_hs_cfg *cfg) ble_hs_dbg_mutex_locked = 0; #endif + /* Configure the HCI transport to communicate with a host. */ + ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); + return 0; err: diff --git a/net/nimble/host/src/ble_hs_adv.c b/net/nimble/host/src/ble_hs_adv.c index c56bb194..fd7bfafb 100644 --- a/net/nimble/host/src/ble_hs_adv.c +++ b/net/nimble/host/src/ble_hs_adv.c @@ -20,8 +20,12 @@ #include <string.h> #include <errno.h> #include "nimble/ble.h" +#include "host/ble_hs_adv.h" #include "ble_hs_priv.h" +static uint16_t ble_hs_adv_uuids16[BLE_HS_ADV_MAX_FIELD_SZ / 2]; +static uint32_t ble_hs_adv_uuids32[BLE_HS_ADV_MAX_FIELD_SZ / 4]; + static int ble_hs_adv_set_hdr(uint8_t type, uint8_t data_len, uint8_t max_len, uint8_t *dst, uint8_t *dst_len) @@ -39,7 +43,7 @@ ble_hs_adv_set_hdr(uint8_t type, uint8_t data_len, uint8_t max_len, } int -ble_hs_adv_set_flat(uint8_t type, int data_len, void *data, +ble_hs_adv_set_flat(uint8_t type, int data_len, const void *data, uint8_t *dst, uint8_t *dst_len, uint8_t max_len) { #if !NIMBLE_OPT(ADVERTISE) @@ -62,7 +66,7 @@ ble_hs_adv_set_flat(uint8_t type, int data_len, void *data, } static int -ble_hs_adv_set_array16(uint8_t type, uint8_t num_elems, uint16_t *elems, +ble_hs_adv_set_array16(uint8_t type, uint8_t num_elems, const uint16_t *elems, uint8_t *dst, uint8_t *dst_len, uint8_t max_len) { int rc; @@ -83,7 +87,7 @@ ble_hs_adv_set_array16(uint8_t type, uint8_t num_elems, uint16_t *elems, } static int -ble_hs_adv_set_array32(uint8_t type, uint8_t num_elems, uint32_t *elems, +ble_hs_adv_set_array32(uint8_t type, uint8_t num_elems, const uint32_t *elems, uint8_t *dst, uint8_t *dst_len, uint8_t max_len) { int rc; @@ -106,10 +110,10 @@ ble_hs_adv_set_array32(uint8_t type, uint8_t num_elems, uint32_t *elems, /** * Sets the significant part of the data in outgoing advertisements. * - * @return 0 on success; on failure. + * @return 0 on success; nonzero on failure. */ int -ble_hs_adv_set_fields(struct ble_hs_adv_fields *adv_fields, +ble_hs_adv_set_fields(const struct ble_hs_adv_fields *adv_fields, uint8_t *dst, uint8_t *dst_len, uint8_t max_len) { #if !NIMBLE_OPT(ADVERTISE) @@ -117,11 +121,28 @@ ble_hs_adv_set_fields(struct ble_hs_adv_fields *adv_fields, #endif uint8_t type; + int8_t tx_pwr_lvl; int rc; *dst_len = 0; - /*** 0x01 - Flags (written automatically by GAP). */ + /*** 0x01 - Flags. */ + /* The application has three options concerning the flags field: + * 1. Don't include it in advertisements (!flags_is_present). + * 2. Explicitly specify the value (flags_is_present && flags != 0). + * 3. Let stack calculate the value (flags_is_present && flags == 0). + * + * For option 3, the calculation is delayed until advertising is enabled. + * The delay is necessary because the flags value depends on the type of + * advertising being performed which is not known at this time. + * + * Note: The CSS prohibits advertising a flags value of 0, so this method + * of specifying option 2 vs. 3 is sound. + */ + if (adv_fields->flags_is_present && adv_fields->flags != 0) { + rc = ble_hs_adv_set_flat(BLE_HS_ADV_TYPE_FLAGS, 1, &adv_fields->flags, + dst, dst_len, max_len); + } /*** 0x02,0x03 - 16-bit service class UUIDs. */ if (adv_fields->uuids16 != NULL && adv_fields->num_uuids16) { @@ -185,7 +206,26 @@ ble_hs_adv_set_fields(struct ble_hs_adv_fields *adv_fields, } } - /*** 0x0a - Tx power level (written automatically by GAP). */ + /*** 0x0a - Tx power level. */ + if (adv_fields->tx_pwr_lvl_is_present) { + /* Read the power level from the controller if requested; otherwise use + * the explicitly specified value. + */ + if (adv_fields->tx_pwr_lvl == BLE_HS_ADV_TX_PWR_LVL_AUTO) { + rc = ble_hs_hci_util_read_adv_tx_pwr(&tx_pwr_lvl); + if (rc != 0) { + return rc; + } + } else { + tx_pwr_lvl = adv_fields->tx_pwr_lvl; + } + + rc = ble_hs_adv_set_flat(BLE_HS_ADV_TYPE_TX_PWR_LVL, 1, &tx_pwr_lvl, + dst, dst_len, max_len); + if (rc != 0) { + return rc; + } + } /*** 0x0d - Class of device. */ if (adv_fields->device_class != NULL) { @@ -321,12 +361,53 @@ ble_hs_adv_set_fields(struct ble_hs_adv_fields *adv_fields, } static int +ble_hs_adv_parse_uuids16(struct ble_hs_adv_fields *adv_fields, + const uint8_t *data, uint8_t data_len) +{ + int i; + + if (data_len % 2 != 0) { + return BLE_HS_EBADDATA; + } + + adv_fields->uuids16 = ble_hs_adv_uuids16; + adv_fields->num_uuids16 = data_len / 2; + + for (i = 0; i < adv_fields->num_uuids16; i++) { + adv_fields->uuids16[i] = le16toh(data + i * 2); + } + + return 0; +} + +static int +ble_hs_adv_parse_uuids32(struct ble_hs_adv_fields *adv_fields, + const uint8_t *data, uint8_t data_len) +{ + int i; + + if (data_len % 4 != 0) { + return BLE_HS_EBADDATA; + } + + adv_fields->uuids32 = ble_hs_adv_uuids32; + adv_fields->num_uuids32 = data_len / 4; + + for (i = 0; i < adv_fields->num_uuids32; i++) { + adv_fields->uuids32[i] = le32toh(data + i * 4); + } + + return 0; +} + +static int ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields, uint8_t *total_len, uint8_t *src, uint8_t src_len) { uint8_t data_len; uint8_t type; uint8_t *data; + int rc; if (src_len < 1) { return BLE_HS_EMSGSIZE; @@ -341,6 +422,10 @@ ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields, data = src + 2; data_len = *total_len - 2; + if (data_len > BLE_HS_ADV_MAX_FIELD_SZ) { + return BLE_HS_EBADDATA; + } + switch (type) { case BLE_HS_ADV_TYPE_FLAGS: if (data_len != BLE_HS_ADV_FLAGS_LEN) { @@ -351,39 +436,35 @@ ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields, break; case BLE_HS_ADV_TYPE_INCOMP_UUIDS16: - if (data_len % 2 != 0) { - return BLE_HS_EBADDATA; + rc = ble_hs_adv_parse_uuids16(adv_fields, data, data_len); + if (rc != 0) { + return rc; } - adv_fields->uuids16 = data; - adv_fields->num_uuids16 = data_len / 2; adv_fields->uuids16_is_complete = 0; break; case BLE_HS_ADV_TYPE_COMP_UUIDS16: - if (data_len % 2 != 0) { - return BLE_HS_EBADDATA; + rc = ble_hs_adv_parse_uuids16(adv_fields, data, data_len); + if (rc != 0) { + return rc; } - adv_fields->uuids16 = data; - adv_fields->num_uuids16 = data_len / 2; adv_fields->uuids16_is_complete = 1; break; case BLE_HS_ADV_TYPE_INCOMP_UUIDS32: - if (data_len % 4 != 0) { - return BLE_HS_EBADDATA; + rc = ble_hs_adv_parse_uuids32(adv_fields, data, data_len); + if (rc != 0) { + return rc; } - adv_fields->uuids32 = data; - adv_fields->num_uuids32 = data_len / 4; - adv_fields->uuids32_is_complete = 0; + adv_fields->uuids16_is_complete = 0; break; case BLE_HS_ADV_TYPE_COMP_UUIDS32: - if (data_len % 4 != 0) { - return BLE_HS_EBADDATA; + rc = ble_hs_adv_parse_uuids32(adv_fields, data, data_len); + if (rc != 0) { + return rc; } - adv_fields->uuids32 = data; - adv_fields->num_uuids32 = data_len / 4; - adv_fields->uuids32_is_complete = 1; + adv_fields->uuids16_is_complete = 1; break; case BLE_HS_ADV_TYPE_INCOMP_UUIDS128: @@ -443,6 +524,7 @@ ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields, return BLE_HS_EBADDATA; } adv_fields->svc_data_uuid16 = data; + adv_fields->svc_data_uuid16_len = data_len; break; case BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR: @@ -490,6 +572,7 @@ ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields, return BLE_HS_EBADDATA; } adv_fields->svc_data_uuid32 = data; + adv_fields->svc_data_uuid32_len = data_len; break; case BLE_HS_ADV_TYPE_SVC_DATA_UUID128: @@ -497,6 +580,7 @@ ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields, return BLE_HS_EBADDATA; } adv_fields->svc_data_uuid128 = data; + adv_fields->svc_data_uuid128_len = data_len; break; case BLE_HS_ADV_TYPE_URI: diff --git a/net/nimble/host/src/ble_hs_adv_priv.h b/net/nimble/host/src/ble_hs_adv_priv.h index 5b853740..3ad4f49c 100644 --- a/net/nimble/host/src/ble_hs_adv_priv.h +++ b/net/nimble/host/src/ble_hs_adv_priv.h @@ -6,7 +6,7 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, @@ -20,16 +20,11 @@ #ifndef H_BLE_HS_ADV_PRIV_ #define H_BLE_HS_ADV_PRIV_ -#include "host/ble_hs_adv.h" - -struct ble_hs_adv { - uint8_t event_type; - uint8_t addr_type; - uint8_t length_data; - int8_t rssi; - uint8_t addr[6]; - uint8_t *data; - struct ble_hs_adv_fields *fields; -}; +int ble_hs_adv_set_flat(uint8_t type, int data_len, const void *data, + uint8_t *dst, uint8_t *dst_len, uint8_t max_len); +int ble_hs_adv_set_fields(const struct ble_hs_adv_fields *adv_fields, + uint8_t *dst, uint8_t *dst_len, uint8_t max_len); +int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields, uint8_t *src, + uint8_t src_len); #endif diff --git a/net/nimble/host/src/ble_hs_atomic.c b/net/nimble/host/src/ble_hs_atomic.c index 36a603dd..9c933fce 100644 --- a/net/nimble/host/src/ble_hs_atomic.c +++ b/net/nimble/host/src/ble_hs_atomic.c @@ -93,3 +93,23 @@ ble_hs_atomic_conn_set_flags(uint16_t conn_handle, ble_hs_conn_flags_t flags, return rc; } + +uint16_t +ble_hs_atomic_first_conn_handle(void) +{ + const struct ble_hs_conn *conn; + uint16_t conn_handle; + + ble_hs_lock(); + + conn = ble_hs_conn_first(); + if (conn != NULL) { + conn_handle = conn->bhc_handle; + } else { + conn_handle = BLE_HS_CONN_HANDLE_NONE; + } + + ble_hs_unlock(); + + return conn_handle; +} diff --git a/net/nimble/host/src/ble_hs_atomic_priv.h b/net/nimble/host/src/ble_hs_atomic_priv.h index a08b7ca7..d82eeabc 100644 --- a/net/nimble/host/src/ble_hs_atomic_priv.h +++ b/net/nimble/host/src/ble_hs_atomic_priv.h @@ -28,5 +28,6 @@ int ble_hs_atomic_conn_flags(uint16_t conn_handle, ble_hs_conn_flags_t *out_flags); int ble_hs_atomic_conn_set_flags(uint16_t conn_handle, ble_hs_conn_flags_t flags, int on); +uint16_t ble_hs_atomic_first_conn_handle(void); #endif diff --git a/net/nimble/host/src/ble_hs_cfg.c b/net/nimble/host/src/ble_hs_cfg.c index 6fe02365..eca8407e 100644 --- a/net/nimble/host/src/ble_hs_cfg.c +++ b/net/nimble/host/src/ble_hs_cfg.c @@ -19,31 +19,38 @@ #include "ble_hs_priv.h" +#if NIMBLE_OPT(CONNECT) +#define BLE_HS_CFG_MAX_CONNECTIONS NIMBLE_OPT(MAX_CONNECTIONS) +#else +#define BLE_HS_CFG_MAX_CONNECTIONS 0 +#endif + const struct ble_hs_cfg ble_hs_cfg_dflt = { /** HCI settings. */ - .max_hci_bufs = 8, + .max_hci_bufs = 14, /** Connection settings. */ -#if NIMBLE_OPT(CONNECT) - .max_connections = NIMBLE_OPT(MAX_CONNECTIONS), -#else - .max_connections = 0, -#endif + .max_connections = BLE_HS_CFG_MAX_CONNECTIONS, /** GATT server settings. */ - .max_services = 16, - .max_client_configs = 32, + /* These get set to zero with the expectation that they will be increased + * as needed when each supported GATT service is initialized. + */ + .max_services = 0, + .max_client_configs = 0, /** GATT client settings. */ - .max_gattc_procs = 16, + .max_gattc_procs = 4, /** ATT server settings. */ - .max_attrs = 64, + /* This is set to 0; see note above re: GATT server settings. */ + .max_attrs = 0, .max_prep_entries = 6, /** L2CAP settings. */ - .max_l2cap_chans = 16, - .max_l2cap_sig_procs = 8, + /* Three channels per connection (sig, att, and sm). */ + .max_l2cap_chans = 3 * BLE_HS_CFG_MAX_CONNECTIONS, + .max_l2cap_sig_procs = 1, .max_l2cap_sm_procs = 1, /** Security manager settings. */ @@ -55,7 +62,8 @@ const struct ble_hs_cfg ble_hs_cfg_dflt = { .sm_keypress = 0, .sm_our_key_dist = 0, .sm_their_key_dist = 0, - /** privacy info */ + + /** Privacy settings. */ .rpa_timeout = 300, }; diff --git a/net/nimble/host/src/ble_hs_conn.c b/net/nimble/host/src/ble_hs_conn.c index a4b0f16b..34d95903 100644 --- a/net/nimble/host/src/ble_hs_conn.c +++ b/net/nimble/host/src/ble_hs_conn.c @@ -20,7 +20,7 @@ #include <string.h> #include <errno.h> #include "os/os.h" -#include "host/host_hci.h" +#include "host/ble_hs_id.h" #include "ble_hs_priv.h" /** At least three channels required per connection (sig, att, sm). */ @@ -187,8 +187,6 @@ ble_hs_conn_free(struct ble_hs_conn *conn) return; } - ble_gatts_conn_deinit(&conn->bhc_gatt_svr); - ble_att_svr_prep_clear(&conn->bhc_att_svr.basc_prep_list); while ((chan = SLIST_FIRST(&conn->bhc_channels)) != NULL) { @@ -247,6 +245,17 @@ ble_hs_conn_find(uint16_t conn_handle) } struct ble_hs_conn * +ble_hs_conn_find_assert(uint16_t conn_handle) +{ + struct ble_hs_conn *conn; + + conn = ble_hs_conn_find(conn_handle); + BLE_HS_DBG_ASSERT(conn != NULL); + + return conn; +} + +struct ble_hs_conn * ble_hs_conn_find_by_addr(uint8_t addr_type, uint8_t *addr) { #if !NIMBLE_OPT(CONNECT) @@ -258,8 +267,8 @@ ble_hs_conn_find_by_addr(uint8_t addr_type, uint8_t *addr) BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task()); SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) { - if (conn->bhc_addr_type == addr_type && - memcmp(conn->bhc_addr, addr, 6) == 0) { + if (conn->bhc_peer_addr_type == addr_type && + memcmp(conn->bhc_peer_addr, addr, 6) == 0) { return conn; } @@ -316,59 +325,52 @@ ble_hs_conn_first(void) } void -ble_hs_conn_addrs(struct ble_hs_conn *conn, +ble_hs_conn_addrs(const struct ble_hs_conn *conn, struct ble_hs_conn_addrs *addrs) { + int rc; + /* Determine our address information. */ - addrs->our_id_addr = - ble_hs_pvcy_our_id_addr(&addrs->our_id_addr_type); - if (memcmp(conn->our_rpa_addr, ble_hs_conn_null_addr, 6) == 0) { + addrs->our_id_addr_type = + ble_hs_misc_addr_type_to_id(conn->bhc_our_addr_type); + rc = ble_hs_id_addr(addrs->our_id_addr_type, &addrs->our_id_addr, NULL); + assert(rc == 0); + + if (memcmp(conn->bhc_our_rpa_addr, ble_hs_conn_null_addr, 6) == 0) { addrs->our_ota_addr_type = addrs->our_id_addr_type; addrs->our_ota_addr = addrs->our_id_addr; } else { - switch (addrs->our_id_addr_type) { - case BLE_ADDR_TYPE_PUBLIC: - addrs->our_ota_addr_type = BLE_ADDR_TYPE_RPA_PUB_DEFAULT; - break; - - case BLE_ADDR_TYPE_RANDOM: - addrs->our_ota_addr_type = BLE_ADDR_TYPE_RPA_RND_DEFAULT; - break; - - default: - BLE_HS_DBG_ASSERT(0); - } - - addrs->our_ota_addr = conn->our_rpa_addr; + addrs->our_ota_addr_type = conn->bhc_our_addr_type; + addrs->our_ota_addr = conn->bhc_our_rpa_addr; } /* Determine peer address information. */ - addrs->peer_ota_addr_type = conn->bhc_addr_type; - addrs->peer_id_addr = conn->bhc_addr; - switch (conn->bhc_addr_type) { + addrs->peer_ota_addr_type = conn->bhc_peer_addr_type; + addrs->peer_id_addr = conn->bhc_peer_addr; + switch (conn->bhc_peer_addr_type) { case BLE_ADDR_TYPE_PUBLIC: addrs->peer_id_addr_type = BLE_ADDR_TYPE_PUBLIC; - addrs->peer_ota_addr = conn->bhc_addr; + addrs->peer_ota_addr = conn->bhc_peer_addr; break; case BLE_ADDR_TYPE_RANDOM: addrs->peer_id_addr_type = BLE_ADDR_TYPE_RANDOM; - addrs->peer_ota_addr = conn->bhc_addr; + addrs->peer_ota_addr = conn->bhc_peer_addr; break; case BLE_ADDR_TYPE_RPA_PUB_DEFAULT: addrs->peer_id_addr_type = BLE_ADDR_TYPE_PUBLIC; - addrs->peer_ota_addr = conn->peer_rpa_addr; + addrs->peer_ota_addr = conn->bhc_peer_rpa_addr; break; case BLE_ADDR_TYPE_RPA_RND_DEFAULT: addrs->peer_id_addr_type = BLE_ADDR_TYPE_RANDOM; - addrs->peer_ota_addr = conn->peer_rpa_addr; + addrs->peer_ota_addr = conn->bhc_peer_rpa_addr; break; default: BLE_HS_DBG_ASSERT(0); - return; + break; } } diff --git a/net/nimble/host/src/ble_hs_conn_priv.h b/net/nimble/host/src/ble_hs_conn_priv.h index 36b483dc..da8d2fc4 100644 --- a/net/nimble/host/src/ble_hs_conn_priv.h +++ b/net/nimble/host/src/ble_hs_conn_priv.h @@ -36,15 +36,16 @@ typedef uint8_t ble_hs_conn_flags_t; struct ble_hs_conn { SLIST_ENTRY(ble_hs_conn) bhc_next; uint16_t bhc_handle; - uint8_t bhc_addr_type; - uint8_t our_addr_type; - uint8_t bhc_addr[6]; - uint8_t our_rpa_addr[6]; - uint8_t peer_rpa_addr[6]; + uint8_t bhc_peer_addr_type; + uint8_t bhc_our_addr_type; + uint8_t bhc_peer_addr[6]; + uint8_t bhc_our_rpa_addr[6]; + uint8_t bhc_peer_rpa_addr[6]; uint16_t bhc_itvl; uint16_t bhc_latency; uint16_t bhc_supervision_timeout; + uint8_t bhc_master_clock_accuracy; ble_hs_conn_flags_t bhc_flags; @@ -66,10 +67,10 @@ struct ble_hs_conn_addrs { uint8_t our_id_addr_type; uint8_t peer_ota_addr_type; uint8_t peer_id_addr_type; - uint8_t *our_ota_addr; - uint8_t *our_id_addr; - uint8_t *peer_ota_addr; - uint8_t *peer_id_addr; + const uint8_t *our_ota_addr; + const uint8_t *our_id_addr; + const uint8_t *peer_ota_addr; + const uint8_t *peer_id_addr; }; int ble_hs_conn_can_alloc(void); @@ -78,6 +79,7 @@ void ble_hs_conn_free(struct ble_hs_conn *conn); void ble_hs_conn_insert(struct ble_hs_conn *conn); void ble_hs_conn_remove(struct ble_hs_conn *conn); struct ble_hs_conn *ble_hs_conn_find(uint16_t conn_handle); +struct ble_hs_conn *ble_hs_conn_find_assert(uint16_t conn_handle); struct ble_hs_conn *ble_hs_conn_find_by_addr(uint8_t addr_type, uint8_t *addr); struct ble_hs_conn *ble_hs_conn_find_by_idx(int idx); int ble_hs_conn_exists(uint16_t conn_handle); @@ -86,7 +88,7 @@ struct ble_l2cap_chan *ble_hs_conn_chan_find(struct ble_hs_conn *conn, uint16_t cid); int ble_hs_conn_chan_insert(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan); -void ble_hs_conn_addrs(struct ble_hs_conn *conn, +void ble_hs_conn_addrs(const struct ble_hs_conn *conn, struct ble_hs_conn_addrs *addrs); int ble_hs_conn_init(void); diff --git a/net/nimble/host/src/host_dbg.c b/net/nimble/host/src/ble_hs_dbg.c index 6b58624d..bb6ebdf9 100644 --- a/net/nimble/host/src/host_dbg.c +++ b/net/nimble/host/src/ble_hs_dbg.c @@ -23,11 +23,11 @@ #include "os/os.h" #include "console/console.h" #include "nimble/hci_common.h" -#include "nimble/hci_transport.h" +#include "nimble/ble_hci_trans.h" #include "ble_hs_priv.h" static void -host_hci_dbg_le_event_disp(uint8_t subev, uint8_t len, uint8_t *evdata) +ble_hs_dbg_le_event_disp(uint8_t subev, uint8_t len, uint8_t *evdata) { int8_t rssi; uint8_t advlen; @@ -158,7 +158,7 @@ host_hci_dbg_le_event_disp(uint8_t subev, uint8_t len, uint8_t *evdata) * @param len */ static void -host_hci_dbg_disconn_comp_disp(uint8_t *evdata, uint8_t len) +ble_hs_dbg_disconn_comp_disp(uint8_t *evdata, uint8_t len) { uint8_t status; uint8_t reason; @@ -183,7 +183,7 @@ host_hci_dbg_disconn_comp_disp(uint8_t *evdata, uint8_t len) * @param len */ static void -host_hci_dbg_encrypt_chg_disp(uint8_t *evdata, uint8_t len) +ble_hs_dbg_encrypt_chg_disp(uint8_t *evdata, uint8_t len) { uint8_t status; uint8_t enabled; @@ -209,7 +209,7 @@ host_hci_dbg_encrypt_chg_disp(uint8_t *evdata, uint8_t len) * @param len */ static void -host_hci_dbg_encrypt_refresh_disp(uint8_t *evdata, uint8_t len) +ble_hs_dbg_encrypt_refresh_disp(uint8_t *evdata, uint8_t len) { uint8_t status; uint16_t handle; @@ -228,7 +228,7 @@ host_hci_dbg_encrypt_refresh_disp(uint8_t *evdata, uint8_t len) * @param len */ static void -host_hci_dbg_rd_rem_ver_disp(uint8_t *evdata, uint8_t len) +ble_hs_dbg_rd_rem_ver_disp(uint8_t *evdata, uint8_t len) { BLE_HS_LOG(DEBUG, "Remote Version Info: status=%u handle=%u vers_nr=%u " "compid=%u subver=%u\n", @@ -243,7 +243,7 @@ host_hci_dbg_rd_rem_ver_disp(uint8_t *evdata, uint8_t len) * @param len */ static void -host_hci_dbg_num_comp_pkts_disp(uint8_t *evdata, uint8_t len) +ble_hs_dbg_num_comp_pkts_disp(uint8_t *evdata, uint8_t len) { uint8_t handles; uint8_t *handle_ptr; @@ -282,7 +282,7 @@ host_hci_dbg_num_comp_pkts_disp(uint8_t *evdata, uint8_t len) * @param len */ static void -host_hci_dbg_auth_pyld_tmo_disp(uint8_t *evdata, uint8_t len) +ble_hs_dbg_auth_pyld_tmo_disp(uint8_t *evdata, uint8_t len) { uint16_t handle; @@ -298,7 +298,7 @@ host_hci_dbg_auth_pyld_tmo_disp(uint8_t *evdata, uint8_t len) static void -host_hci_dbg_cmd_comp_info_params(uint8_t status, uint8_t ocf, uint8_t *evdata) +ble_hs_dbg_cmd_comp_info_params(uint8_t status, uint8_t ocf, uint8_t *evdata) { int i; uint8_t *dptr; @@ -339,7 +339,7 @@ host_hci_dbg_cmd_comp_info_params(uint8_t status, uint8_t ocf, uint8_t *evdata) } static void -host_hci_dbg_cmd_complete_disp(uint8_t *evdata, uint8_t len) +ble_hs_dbg_cmd_complete_disp(uint8_t *evdata, uint8_t len) { uint8_t cmd_pkts; uint8_t ogf; @@ -374,7 +374,7 @@ host_hci_dbg_cmd_complete_disp(uint8_t *evdata, uint8_t len) /* Display parameters based on command. */ switch (ogf) { case BLE_HCI_OGF_INFO_PARAMS: - host_hci_dbg_cmd_comp_info_params(status, ocf, evdata); + ble_hs_dbg_cmd_comp_info_params(status, ocf, evdata); break; case BLE_HCI_OGF_STATUS_PARAMS: switch (ocf) { @@ -438,7 +438,7 @@ done: } static void -host_hci_dbg_cmd_status_disp(uint8_t *evdata, uint8_t len) +ble_hs_dbg_cmd_status_disp(uint8_t *evdata, uint8_t len) { uint8_t ogf; uint8_t ocf; @@ -453,7 +453,7 @@ host_hci_dbg_cmd_status_disp(uint8_t *evdata, uint8_t len) } void -host_hci_dbg_event_disp(uint8_t *evbuf) +ble_hs_dbg_event_disp(uint8_t *evbuf) { #if LOG_LEVEL > LOG_LEVEL_DEBUG return; @@ -470,34 +470,40 @@ host_hci_dbg_event_disp(uint8_t *evbuf) switch (evcode) { case BLE_HCI_EVCODE_DISCONN_CMP: - host_hci_dbg_disconn_comp_disp(evdata, len); + ble_hs_dbg_disconn_comp_disp(evdata, len); break; case BLE_HCI_EVCODE_ENC_KEY_REFRESH: - host_hci_dbg_encrypt_refresh_disp(evdata, len); + ble_hs_dbg_encrypt_refresh_disp(evdata, len); break; case BLE_HCI_EVCODE_ENCRYPT_CHG: - host_hci_dbg_encrypt_chg_disp(evdata, len); + ble_hs_dbg_encrypt_chg_disp(evdata, len); break; case BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP: - host_hci_dbg_rd_rem_ver_disp(evdata, len); + ble_hs_dbg_rd_rem_ver_disp(evdata, len); break; case BLE_HCI_EVCODE_COMMAND_COMPLETE: - host_hci_dbg_cmd_complete_disp(evdata, len); + ble_hs_dbg_cmd_complete_disp(evdata, len); break; case BLE_HCI_EVCODE_COMMAND_STATUS: - host_hci_dbg_cmd_status_disp(evdata, len); + ble_hs_dbg_cmd_status_disp(evdata, len); break; case BLE_HCI_EVCODE_NUM_COMP_PKTS: - host_hci_dbg_num_comp_pkts_disp(evdata, len); + ble_hs_dbg_num_comp_pkts_disp(evdata, len); break; case BLE_HCI_EVCODE_LE_META: - host_hci_dbg_le_event_disp(evdata[0], len, evdata + 1); + ble_hs_dbg_le_event_disp(evdata[0], len, evdata + 1); break; case BLE_HCI_EVCODE_AUTH_PYLD_TMO: - host_hci_dbg_auth_pyld_tmo_disp(evdata, len); + ble_hs_dbg_auth_pyld_tmo_disp(evdata, len); break; default: BLE_HS_LOG(DEBUG, "Unknown event 0x%x len=%u\n", evcode, len); break; } } + +void +ble_hs_dbg_set_sync_state(uint8_t sync_state) +{ + ble_hs_sync_state = sync_state; +} diff --git a/net/nimble/include/nimble/hci_transport.h b/net/nimble/host/src/ble_hs_dbg_priv.h index 7de737c7..cf8d2039 100644 --- a/net/nimble/include/nimble/hci_transport.h +++ b/net/nimble/host/src/ble_hs_dbg_priv.h @@ -17,16 +17,10 @@ * under the License. */ -#ifndef H_HCI_TRANSPORT_ -#define H_HCI_TRANSPORT_ +#ifndef H_BLE_HS_DBG_PRIV_ +#define H_BLE_HS_DBG_PRIV_ -/* Send a HCI command from the host to the controller */ -int ble_hci_transport_host_cmd_send(uint8_t *cmd); +void ble_hs_dbg_event_disp(uint8_t *evbuf); +void ble_hs_dbg_set_sync_state(uint8_t sync_state); -/* Send a HCI event from the controller to the host */ -int ble_hci_transport_ctlr_event_send(uint8_t *hci_ev); - -/* Send ACL data from host to contoller */ -int ble_hci_transport_host_acl_data_send(struct os_mbuf *om); - -#endif /* H_HCI_TRANSPORT_ */ +#endif /* H_HOST_DBG_ */ diff --git a/net/nimble/host/src/ble_hs_hci.c b/net/nimble/host/src/ble_hs_hci.c new file mode 100644 index 00000000..433c2e09 --- /dev/null +++ b/net/nimble/host/src/ble_hs_hci.c @@ -0,0 +1,518 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include "os/os.h" +#include "nimble/ble_hci_trans.h" +#include "ble_hs_priv.h" +#include "ble_hs_dbg_priv.h" + +#define BLE_HCI_CMD_TIMEOUT (OS_TICKS_PER_SEC) + +static struct os_mutex ble_hs_hci_mutex; +static struct os_sem ble_hs_hci_sem; + +static uint8_t *ble_hs_hci_ack; +static uint16_t ble_hs_hci_buf_sz; +static uint8_t ble_hs_hci_max_pkts; + +#if PHONY_HCI_ACKS +static ble_hs_hci_phony_ack_fn *ble_hs_hci_phony_ack_cb; +#endif + +#if PHONY_HCI_ACKS +void +ble_hs_hci_set_phony_ack_cb(ble_hs_hci_phony_ack_fn *cb) +{ + ble_hs_hci_phony_ack_cb = cb; +} +#endif + +static void +ble_hs_hci_lock(void) +{ + int rc; + + rc = os_mutex_pend(&ble_hs_hci_mutex, 0xffffffff); + BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED); +} + +static void +ble_hs_hci_unlock(void) +{ + int rc; + + rc = os_mutex_release(&ble_hs_hci_mutex); + BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED); +} + +int +ble_hs_hci_set_buf_sz(uint16_t pktlen, uint8_t max_pkts) +{ + if (pktlen == 0 || max_pkts == 0) { + return BLE_HS_EINVAL; + } + + ble_hs_hci_buf_sz = pktlen; + ble_hs_hci_max_pkts = max_pkts; + + return 0; +} + +static int +ble_hs_hci_rx_cmd_complete(uint8_t event_code, uint8_t *data, int len, + struct ble_hs_hci_ack *out_ack) +{ + uint16_t opcode; + uint8_t *params; + uint8_t params_len; + uint8_t num_pkts; + + if (len < BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN) { + return BLE_HS_ECONTROLLER; + } + + num_pkts = data[2]; + opcode = le16toh(data + 3); + params = data + 5; + + /* XXX: Process num_pkts field. */ + (void)num_pkts; + + out_ack->bha_opcode = opcode; + + params_len = len - BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN; + if (params_len > 0) { + out_ack->bha_status = BLE_HS_HCI_ERR(params[0]); + } else if (opcode == BLE_HCI_OPCODE_NOP) { + out_ack->bha_status = 0; + } else { + out_ack->bha_status = BLE_HS_ECONTROLLER; + } + + /* Don't include the status byte in the parameters blob. */ + if (params_len > 1) { + out_ack->bha_params = params + 1; + out_ack->bha_params_len = params_len - 1; + } else { + out_ack->bha_params = NULL; + out_ack->bha_params_len = 0; + } + + return 0; +} + +static int +ble_hs_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len, + struct ble_hs_hci_ack *out_ack) +{ + uint16_t opcode; + uint8_t num_pkts; + uint8_t status; + + if (len < BLE_HCI_EVENT_CMD_STATUS_LEN) { + return BLE_HS_ECONTROLLER; + } + + status = data[2]; + num_pkts = data[3]; + opcode = le16toh(data + 4); + + /* XXX: Process num_pkts field. */ + (void)num_pkts; + + out_ack->bha_opcode = opcode; + out_ack->bha_params = NULL; + out_ack->bha_params_len = 0; + out_ack->bha_status = BLE_HS_HCI_ERR(status); + + return 0; +} + +static int +ble_hs_hci_process_ack(uint16_t expected_opcode, + uint8_t *params_buf, uint8_t params_buf_len, + struct ble_hs_hci_ack *out_ack) +{ + uint8_t event_code; + uint8_t param_len; + uint8_t event_len; + int rc; + + BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL); + + /* Count events received */ + STATS_INC(ble_hs_stats, hci_event); + + /* Display to console */ + ble_hs_dbg_event_disp(ble_hs_hci_ack); + + event_code = ble_hs_hci_ack[0]; + param_len = ble_hs_hci_ack[1]; + event_len = param_len + 2; + + /* Clear ack fields up front to silence spurious gcc warnings. */ + memset(out_ack, 0, sizeof *out_ack); + + switch (event_code) { + case BLE_HCI_EVCODE_COMMAND_COMPLETE: + rc = ble_hs_hci_rx_cmd_complete(event_code, ble_hs_hci_ack, + event_len, out_ack); + break; + + case BLE_HCI_EVCODE_COMMAND_STATUS: + rc = ble_hs_hci_rx_cmd_status(event_code, ble_hs_hci_ack, + event_len, out_ack); + break; + + default: + BLE_HS_DBG_ASSERT(0); + rc = BLE_HS_EUNKNOWN; + break; + } + + if (rc == 0) { + if (params_buf == NULL) { + out_ack->bha_params_len = 0; + } else { + if (out_ack->bha_params_len > params_buf_len) { + out_ack->bha_params_len = params_buf_len; + rc = BLE_HS_ECONTROLLER; + } + memcpy(params_buf, out_ack->bha_params, out_ack->bha_params_len); + } + out_ack->bha_params = params_buf; + + if (out_ack->bha_opcode != expected_opcode) { + rc = BLE_HS_ECONTROLLER; + } + } + + if (rc != 0) { + STATS_INC(ble_hs_stats, hci_invalid_ack); + } + + return rc; +} + +static int +ble_hs_hci_wait_for_ack(void) +{ + int rc; + +#if PHONY_HCI_ACKS + if (ble_hs_hci_phony_ack_cb == NULL) { + rc = BLE_HS_ETIMEOUT_HCI; + } else { + ble_hs_hci_ack = + ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL); + rc = ble_hs_hci_phony_ack_cb(ble_hs_hci_ack, 260); + } +#else + rc = os_sem_pend(&ble_hs_hci_sem, BLE_HCI_CMD_TIMEOUT); + switch (rc) { + case 0: + BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL); + break; + case OS_TIMEOUT: + rc = BLE_HS_ETIMEOUT_HCI; + STATS_INC(ble_hs_stats, hci_timeout); + break; + default: + rc = BLE_HS_EOS; + break; + } +#endif + + return rc; +} + +int +ble_hs_hci_cmd_tx(void *cmd, void *evt_buf, uint8_t evt_buf_len, + uint8_t *out_evt_buf_len) +{ + struct ble_hs_hci_ack ack; + uint16_t opcode; + int rc; + + opcode = le16toh(cmd); + + BLE_HS_DBG_ASSERT(ble_hs_hci_ack == NULL); + ble_hs_hci_lock(); + + rc = ble_hs_hci_cmd_send_buf(cmd); + if (rc != 0) { + goto done; + } + + rc = ble_hs_hci_wait_for_ack(); + if (rc != 0) { + ble_hs_sched_reset(rc); + goto done; + } + + rc = ble_hs_hci_process_ack(opcode, evt_buf, evt_buf_len, &ack); + if (rc != 0) { + ble_hs_sched_reset(rc); + goto done; + } + + if (out_evt_buf_len != NULL) { + *out_evt_buf_len = ack.bha_params_len; + } + + rc = ack.bha_status; + +done: + if (ble_hs_hci_ack != NULL) { + ble_hci_trans_buf_free(ble_hs_hci_ack); + ble_hs_hci_ack = NULL; + } + + ble_hs_hci_unlock(); + return rc; +} + +int +ble_hs_hci_cmd_tx_empty_ack(void *cmd) +{ + int rc; + + rc = ble_hs_hci_cmd_tx(cmd, NULL, 0, NULL); + if (rc != 0) { + return rc; + } + + return 0; +} + +void +ble_hs_hci_rx_ack(uint8_t *ack_ev) +{ + if (ble_hs_hci_sem.sem_tokens != 0) { + /* This ack is unexpected; ignore it. */ + ble_hci_trans_buf_free(ack_ev); + return; + } + BLE_HS_DBG_ASSERT(ble_hs_hci_ack == NULL); + + /* Unblock the application now that the HCI command buffer is populated + * with the acknowledgement. + */ + ble_hs_hci_ack = ack_ev; + os_sem_release(&ble_hs_hci_sem); +} + +int +ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg) +{ + int enqueue; + + BLE_HS_DBG_ASSERT(hci_ev != NULL); + + switch (hci_ev[0]) { + case BLE_HCI_EVCODE_COMMAND_COMPLETE: + case BLE_HCI_EVCODE_COMMAND_STATUS: + if (hci_ev[3] == 0 && hci_ev[4] == 0) { + enqueue = 1; + } else { + ble_hs_hci_rx_ack(hci_ev); + enqueue = 0; + } + break; + + default: + enqueue = 1; + break; + } + + if (enqueue) { + ble_hs_enqueue_hci_event(hci_ev); + } + + return 0; +} + + +/** + * Splits an appropriately-sized fragment from the front of an outgoing ACL + * data packet, if necessary. If the packet size is within the controller's + * buffer size requirements, no splitting is performed. The fragment data is + * removed from the data packet mbuf. + * + * @param om The ACL data packet. If this constitutes a + * single fragment, it gets set to NULL on + * success. + * @param out_frag On success, this points to the fragment to + * send. If the entire packet can fit within + * a single fragment, this will point to the + * ACL data packet itself ('om'). + * + * @return 0 on success; + * BLE host core return code on error. + */ +static int +ble_hs_hci_split_frag(struct os_mbuf **om, struct os_mbuf **out_frag) +{ + struct os_mbuf *frag; + int rc; + + /* Assume failure. */ + *out_frag = NULL; + + if (OS_MBUF_PKTLEN(*om) <= ble_hs_hci_buf_sz) { + /* Final fragment. */ + *out_frag = *om; + *om = NULL; + return 0; + } + + frag = ble_hs_mbuf_acm_pkt(); + if (frag == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } + + /* Move data from the front of the packet into the fragment mbuf. */ + rc = os_mbuf_appendfrom(frag, *om, 0, ble_hs_hci_buf_sz); + if (rc != 0) { + rc = BLE_HS_ENOMEM; + goto err; + } + os_mbuf_adj(*om, ble_hs_hci_buf_sz); + + /* More fragments to follow. */ + *out_frag = frag; + return 0; + +err: + os_mbuf_free_chain(frag); + return rc; +} + +static struct os_mbuf * +ble_hs_hci_acl_hdr_prepend(struct os_mbuf *om, uint16_t handle, + uint8_t pb_flag) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om2; + + hci_hdr.hdh_handle_pb_bc = + ble_hs_hci_util_handle_pb_bc_join(handle, pb_flag, 0); + htole16(&hci_hdr.hdh_len, OS_MBUF_PKTHDR(om)->omp_len); + + om2 = os_mbuf_prepend(om, sizeof hci_hdr); + if (om2 == NULL) { + return NULL; + } + + om = om2; + om = os_mbuf_pullup(om, sizeof hci_hdr); + if (om == NULL) { + return NULL; + } + + memcpy(om->om_data, &hci_hdr, sizeof hci_hdr); + + BLE_HS_LOG(DEBUG, "host tx hci data; handle=%d length=%d\n", handle, + le16toh(&hci_hdr.hdh_len)); + + return om; +} + +/** + * Transmits an HCI ACL data packet. This function consumes the supplied mbuf, + * regardless of the outcome. + * + * XXX: Ensure the controller has sufficient buffer capacity for the outgoing + * fragments. + */ +int +ble_hs_hci_acl_tx(struct ble_hs_conn *connection, struct os_mbuf *txom) +{ + struct os_mbuf *frag; + uint8_t pb; + int rc; + + /* The first fragment uses the first-non-flush packet boundary value. + * After sending the first fragment, pb gets set appropriately for all + * subsequent fragments in this packet. + */ + pb = BLE_HCI_PB_FIRST_NON_FLUSH; + + /* Send fragments until the entire packet has been sent. */ + while (txom != NULL) { + rc = ble_hs_hci_split_frag(&txom, &frag); + if (rc != 0) { + goto err; + } + + frag = ble_hs_hci_acl_hdr_prepend(frag, connection->bhc_handle, pb); + if (frag == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } + pb = BLE_HCI_PB_MIDDLE; + + BLE_HS_LOG(DEBUG, "ble_hs_hci_acl_tx(): "); + ble_hs_log_mbuf(frag); + BLE_HS_LOG(DEBUG, "\n"); + + /* XXX: Try to pullup the entire fragment. The controller currently + * requires the entire fragment to fit in a single buffer. When this + * restriction is removed from the controller, this operation can be + * removed. + */ + frag = os_mbuf_pullup(frag, OS_MBUF_PKTLEN(frag)); + if (frag == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } + + rc = ble_hs_tx_data(frag); + if (rc != 0) { + goto err; + } + + connection->bhc_outstanding_pkts++; + } + + return 0; + +err: + BLE_HS_DBG_ASSERT(rc != 0); + + os_mbuf_free_chain(txom); + return rc; +} + +void +ble_hs_hci_init(void) +{ + int rc; + + rc = os_sem_init(&ble_hs_hci_sem, 0); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); + + rc = os_mutex_init(&ble_hs_hci_mutex); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); +} diff --git a/net/nimble/host/src/host_hci_cmd.c b/net/nimble/host/src/ble_hs_hci_cmd.c index baebed3e..82b442dd 100644 --- a/net/nimble/host/src/host_hci_cmd.c +++ b/net/nimble/host/src/ble_hs_hci_cmd.c @@ -24,26 +24,16 @@ #include "os/os.h" #include "console/console.h" #include "nimble/hci_common.h" -#include "nimble/hci_transport.h" -#include "host/host_hci.h" -#include "host_dbg_priv.h" +#include "nimble/ble_hci_trans.h" +#include "ble_hs_dbg_priv.h" #include "ble_hs_priv.h" -#ifdef PHONY_TRANSPORT -#include "host/ble_hs_test.h" -#endif - -uint8_t host_hci_cmd_buf[HCI_CMD_BUF_SIZE]; static int -host_hci_cmd_transport(uint8_t *cmdbuf) +ble_hs_hci_cmd_transport(uint8_t *cmdbuf) { -#ifdef PHONY_TRANSPORT - ble_hs_test_hci_txed(cmdbuf); - return 0; -#else int rc; - rc = ble_hci_transport_host_cmd_send(cmdbuf); + rc = ble_hci_trans_hs_cmd_tx(cmdbuf); switch (rc) { case 0: return 0; @@ -54,11 +44,10 @@ host_hci_cmd_transport(uint8_t *cmdbuf) default: return BLE_HS_EUNKNOWN; } -#endif } void -host_hci_write_hdr(uint8_t ogf, uint8_t ocf, uint8_t len, void *buf) +ble_hs_hci_cmd_write_hdr(uint8_t ogf, uint8_t ocf, uint8_t len, void *buf) { uint16_t opcode; uint8_t *u8ptr; @@ -71,44 +60,68 @@ host_hci_write_hdr(uint8_t ogf, uint8_t ocf, uint8_t len, void *buf) } int -host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata) +ble_hs_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, const void *cmddata) { + uint8_t *buf; int rc; - htole16(host_hci_cmd_buf, ogf << 10 | ocf); - host_hci_cmd_buf[2] = len; + buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + BLE_HS_DBG_ASSERT(buf != NULL); + + htole16(buf, ogf << 10 | ocf); + buf[2] = len; if (len != 0) { - memcpy(host_hci_cmd_buf + BLE_HCI_CMD_HDR_LEN, cmddata, len); + memcpy(buf + BLE_HCI_CMD_HDR_LEN, cmddata, len); } - rc = host_hci_cmd_transport(host_hci_cmd_buf); - BLE_HS_LOG(DEBUG, "host_hci_cmd_send: ogf=0x%02x ocf=0x%02x len=%d " - "rc=%d\n", ogf, ocf, len, rc); - ble_hs_misc_log_flat_buf(host_hci_cmd_buf, len + BLE_HCI_CMD_HDR_LEN); + BLE_HS_LOG(DEBUG, "ble_hs_hci_cmd_send: ogf=0x%02x ocf=0x%02x len=%d\n", + ogf, ocf, len); + ble_hs_log_flat_buf(buf, len + BLE_HCI_CMD_HDR_LEN); BLE_HS_LOG(DEBUG, "\n"); + rc = ble_hs_hci_cmd_transport(buf); if (rc == 0) { STATS_INC(ble_hs_stats, hci_cmd); + } else { + BLE_HS_LOG(DEBUG, "ble_hs_hci_cmd_send failure; rc=%d\n", rc); } return rc; } int -host_hci_cmd_send_buf(void *buf) +ble_hs_hci_cmd_send_buf(void *buf) { uint16_t opcode; uint8_t *u8ptr; uint8_t len; int rc; + switch (ble_hs_sync_state) { + case BLE_HS_SYNC_STATE_BAD: + return BLE_HS_ENOTSYNCED; + + case BLE_HS_SYNC_STATE_BRINGUP: + if (!ble_hs_is_parent_task()) { + return BLE_HS_ENOTSYNCED; + } + break; + + case BLE_HS_SYNC_STATE_GOOD: + break; + + default: + BLE_HS_DBG_ASSERT(0); + return BLE_HS_EUNKNOWN; + } + u8ptr = buf; opcode = le16toh(u8ptr + 0); len = u8ptr[2]; - rc = host_hci_cmd_send(BLE_HCI_OGF(opcode), BLE_HCI_OCF(opcode), len, - u8ptr + BLE_HCI_CMD_HDR_LEN); + rc = ble_hs_hci_cmd_send(BLE_HCI_OGF(opcode), BLE_HCI_OCF(opcode), len, + u8ptr + BLE_HCI_CMD_HDR_LEN); return rc; } @@ -123,16 +136,31 @@ host_hci_cmd_send_buf(void *buf) * @return int */ static int -host_hci_le_cmd_send(uint16_t ocf, uint8_t len, void *cmddata) +ble_hs_hci_cmd_le_send(uint16_t ocf, uint8_t len, void *cmddata) { int rc; - rc = host_hci_cmd_send(BLE_HCI_OGF_LE, ocf, len, cmddata); + rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_LE, ocf, len, cmddata); return rc; } +/** + * Read BD_ADDR + * + * OGF = 0x04 (Informational parameters) + * OCF = 0x0009 + */ +void +ble_hs_hci_cmd_build_read_bd_addr(uint8_t *dst, int dst_len) +{ + BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_INFO_PARAMS, + BLE_HCI_OCF_IP_RD_BD_ADDR, + 0, dst); +} + static int -host_hci_cmd_body_le_whitelist_chg(uint8_t *addr, uint8_t addr_type, - uint8_t *dst) +ble_hs_hci_cmd_body_le_whitelist_chg(const uint8_t *addr, uint8_t addr_type, + uint8_t *dst) { if (addr_type > BLE_ADDR_TYPE_RANDOM) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -145,7 +173,8 @@ host_hci_cmd_body_le_whitelist_chg(uint8_t *addr, uint8_t addr_type, } static int -host_hci_cmd_body_le_set_adv_params(struct hci_adv_params *adv, uint8_t *dst) +ble_hs_hci_cmd_body_le_set_adv_params(const struct hci_adv_params *adv, + uint8_t *dst) { uint16_t itvl; @@ -192,19 +221,19 @@ host_hci_cmd_body_le_set_adv_params(struct hci_adv_params *adv, uint8_t *dst) } int -host_hci_cmd_build_le_set_adv_params(struct hci_adv_params *adv, uint8_t *dst, - int dst_len) +ble_hs_hci_cmd_build_le_set_adv_params(const struct hci_adv_params *adv, + uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_PARAM_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_PARAMS, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_PARAMS, BLE_HCI_SET_ADV_PARAM_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - rc = host_hci_cmd_body_le_set_adv_params(adv, dst); + rc = ble_hs_hci_cmd_body_le_set_adv_params(adv, dst); if (rc != 0) { return rc; } @@ -225,7 +254,8 @@ host_hci_cmd_build_le_set_adv_params(struct hci_adv_params *adv, uint8_t *dst, * @return int */ static int -host_hci_cmd_body_le_set_adv_data(uint8_t *data, uint8_t len, uint8_t *dst) +ble_hs_hci_cmd_body_le_set_adv_data(const uint8_t *data, uint8_t len, + uint8_t *dst) { /* Check for valid parameters */ if (((data == NULL) && (len != 0)) || (len > BLE_HCI_MAX_ADV_DATA_LEN)) { @@ -252,19 +282,19 @@ host_hci_cmd_body_le_set_adv_data(uint8_t *data, uint8_t len, uint8_t *dst) * @return int */ int -host_hci_cmd_build_le_set_adv_data(uint8_t *data, uint8_t len, uint8_t *dst, - int dst_len) +ble_hs_hci_cmd_build_le_set_adv_data(const uint8_t *data, uint8_t len, + uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_DATA_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_DATA, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_DATA, BLE_HCI_SET_ADV_DATA_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - rc = host_hci_cmd_body_le_set_adv_data(data, len, dst); + rc = ble_hs_hci_cmd_body_le_set_adv_data(data, len, dst); if (rc != 0) { return rc; } @@ -273,8 +303,8 @@ host_hci_cmd_build_le_set_adv_data(uint8_t *data, uint8_t len, uint8_t *dst, } static int -host_hci_cmd_body_le_set_scan_rsp_data(uint8_t *data, uint8_t len, - uint8_t *dst) +ble_hs_hci_cmd_body_le_set_scan_rsp_data(const uint8_t *data, uint8_t len, + uint8_t *dst) { /* Check for valid parameters */ if (((data == NULL) && (len != 0)) || @@ -290,19 +320,19 @@ host_hci_cmd_body_le_set_scan_rsp_data(uint8_t *data, uint8_t len, } int -host_hci_cmd_build_le_set_scan_rsp_data(uint8_t *data, uint8_t len, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_set_scan_rsp_data(const uint8_t *data, uint8_t len, + uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_RSP_DATA_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA, BLE_HCI_SET_SCAN_RSP_DATA_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - rc = host_hci_cmd_body_le_set_scan_rsp_data(data, len, dst); + rc = ble_hs_hci_cmd_body_le_set_scan_rsp_data(data, len, dst); if (rc != 0) { return rc; } @@ -311,70 +341,70 @@ host_hci_cmd_build_le_set_scan_rsp_data(uint8_t *data, uint8_t len, } static void -host_hci_cmd_body_set_event_mask(uint64_t event_mask, uint8_t *dst) +ble_hs_hci_cmd_body_set_event_mask(uint64_t event_mask, uint8_t *dst) { htole64(dst, event_mask); } void -host_hci_cmd_build_set_event_mask(uint64_t event_mask, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_set_event_mask(uint64_t event_mask, + uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_EVENT_MASK_LEN); - host_hci_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_SET_EVENT_MASK, BLE_HCI_SET_EVENT_MASK_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_set_event_mask(event_mask, dst); + ble_hs_hci_cmd_body_set_event_mask(event_mask, dst); } void -host_hci_cmd_build_set_event_mask2(uint64_t event_mask, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_set_event_mask2(uint64_t event_mask, + uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_EVENT_MASK_LEN); - host_hci_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_SET_EVENT_MASK2, BLE_HCI_SET_EVENT_MASK_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_set_event_mask(event_mask, dst); + ble_hs_hci_cmd_body_set_event_mask(event_mask, dst); } static void -host_hci_cmd_body_disconnect(uint16_t handle, uint8_t reason, uint8_t *dst) +ble_hs_hci_cmd_body_disconnect(uint16_t handle, uint8_t reason, uint8_t *dst) { htole16(dst + 0, handle); dst[2] = reason; } void -host_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason, + uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_DISCONNECT_CMD_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD, BLE_HCI_DISCONNECT_CMD_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_disconnect(handle, reason, dst); + ble_hs_hci_cmd_body_disconnect(handle, reason, dst); } int -host_hci_cmd_disconnect(uint16_t handle, uint8_t reason) +ble_hs_hci_cmd_disconnect(uint16_t handle, uint8_t reason) { uint8_t cmd[BLE_HCI_DISCONNECT_CMD_LEN]; int rc; - host_hci_cmd_body_disconnect(handle, reason, cmd); - rc = host_hci_cmd_send(BLE_HCI_OGF_LINK_CTRL, + ble_hs_hci_cmd_body_disconnect(handle, reason, cmd); + rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD, BLE_HCI_DISCONNECT_CMD_LEN, cmd); @@ -382,24 +412,24 @@ host_hci_cmd_disconnect(uint16_t handle, uint8_t reason) } static void -host_hci_cmd_body_le_set_event_mask(uint64_t event_mask, uint8_t *dst) +ble_hs_hci_cmd_body_le_set_event_mask(uint64_t event_mask, uint8_t *dst) { htole64(dst, event_mask); } void -host_hci_cmd_build_le_set_event_mask(uint64_t event_mask, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_set_event_mask(uint64_t event_mask, + uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_LE_EVENT_MASK_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_EVENT_MASK, BLE_HCI_SET_LE_EVENT_MASK_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_le_set_event_mask(event_mask, dst); + ble_hs_hci_cmd_body_le_set_event_mask(event_mask, dst); } /** @@ -411,10 +441,11 @@ host_hci_cmd_build_le_set_event_mask(uint64_t event_mask, * @return int */ void -host_hci_cmd_build_le_read_buffer_size(uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_read_buffer_size(uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_BUF_SIZE, 0, dst); + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_BUF_SIZE, + 0, dst); } /** @@ -426,11 +457,11 @@ host_hci_cmd_build_le_read_buffer_size(uint8_t *dst, int dst_len) * @return int */ int -host_hci_cmd_le_read_buffer_size(void) +ble_hs_hci_cmd_le_read_buffer_size(void) { int rc; - rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_RD_BUF_SIZE, 0, NULL); + rc = ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_RD_BUF_SIZE, 0, NULL); return rc; } @@ -438,35 +469,35 @@ host_hci_cmd_le_read_buffer_size(void) * OGF=LE, OCF=0x0003 */ void -host_hci_cmd_build_le_read_loc_supp_feat(uint8_t *dst, uint8_t dst_len) +ble_hs_hci_cmd_build_le_read_loc_supp_feat(uint8_t *dst, uint8_t dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT, 0, dst); } static void -host_hci_cmd_body_le_set_adv_enable(uint8_t enable, uint8_t *dst) +ble_hs_hci_cmd_body_le_set_adv_enable(uint8_t enable, uint8_t *dst) { dst[0] = enable; } void -host_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst, - int dst_len) +ble_hs_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst, + int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_ENABLE_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE, BLE_HCI_SET_ADV_ENABLE_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_le_set_adv_enable(enable, dst); + ble_hs_hci_cmd_body_le_set_adv_enable(enable, dst); } static int -host_hci_cmd_body_le_set_scan_params( +ble_hs_hci_cmd_body_le_set_scan_params( uint8_t scan_type, uint16_t scan_itvl, uint16_t scan_window, uint8_t own_addr_type, uint8_t filter_policy, uint8_t *dst) { @@ -505,24 +536,25 @@ host_hci_cmd_body_le_set_scan_params( } int -host_hci_cmd_build_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl, - uint16_t scan_window, - uint8_t own_addr_type, - uint8_t filter_policy, - uint8_t *cmd, int cmd_len) +ble_hs_hci_cmd_build_le_set_scan_params(uint8_t scan_type, + uint16_t scan_itvl, + uint16_t scan_window, + uint8_t own_addr_type, + uint8_t filter_policy, + uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( - cmd_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_PARAM_LEN); + dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_PARAM_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_PARAMS, - BLE_HCI_SET_SCAN_PARAM_LEN, cmd); - cmd += BLE_HCI_CMD_HDR_LEN; + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_PARAMS, + BLE_HCI_SET_SCAN_PARAM_LEN, dst); + dst += BLE_HCI_CMD_HDR_LEN; - rc = host_hci_cmd_body_le_set_scan_params(scan_type, scan_itvl, + rc = ble_hs_hci_cmd_body_le_set_scan_params(scan_type, scan_itvl, scan_window, own_addr_type, - filter_policy, cmd); + filter_policy, dst); if (rc != 0) { return rc; } @@ -531,30 +563,30 @@ host_hci_cmd_build_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl, } static void -host_hci_cmd_body_le_set_scan_enable(uint8_t enable, uint8_t filter_dups, - uint8_t *dst) +ble_hs_hci_cmd_body_le_set_scan_enable(uint8_t enable, uint8_t filter_dups, + uint8_t *dst) { dst[0] = enable; dst[1] = filter_dups; } void -host_hci_cmd_build_le_set_scan_enable(uint8_t enable, uint8_t filter_dups, - uint8_t *dst, uint8_t dst_len) +ble_hs_hci_cmd_build_le_set_scan_enable(uint8_t enable, uint8_t filter_dups, + uint8_t *dst, uint8_t dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_ENABLE_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_ENABLE, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_ENABLE, BLE_HCI_SET_SCAN_ENABLE_LEN, dst); - host_hci_cmd_body_le_set_scan_enable(enable, filter_dups, + ble_hs_hci_cmd_body_le_set_scan_enable(enable, filter_dups, dst + BLE_HCI_CMD_HDR_LEN); } static int -host_hci_cmd_body_le_create_connection(struct hci_create_conn *hcc, - uint8_t *cmd) +ble_hs_hci_cmd_body_le_create_connection(const struct hci_create_conn *hcc, + uint8_t *cmd) { /* Check scan interval and scan window */ if ((hcc->scan_itvl < BLE_HCI_SCAN_ITVL_MIN) || @@ -627,18 +659,18 @@ host_hci_cmd_body_le_create_connection(struct hci_create_conn *hcc, } int -host_hci_cmd_build_le_create_connection(struct hci_create_conn *hcc, - uint8_t *cmd, int cmd_len) +ble_hs_hci_cmd_build_le_create_connection(const struct hci_create_conn *hcc, + uint8_t *cmd, int cmd_len) { int rc; BLE_HS_DBG_ASSERT( cmd_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CREATE_CONN_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN, BLE_HCI_CREATE_CONN_LEN, cmd); - rc = host_hci_cmd_body_le_create_connection(hcc, + rc = ble_hs_hci_cmd_body_le_create_connection(hcc, cmd + BLE_HCI_CMD_HDR_LEN); if (rc != 0) { return rc; @@ -648,27 +680,28 @@ host_hci_cmd_build_le_create_connection(struct hci_create_conn *hcc, } void -host_hci_cmd_build_le_clear_whitelist(uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_clear_whitelist(uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLEAR_WHITE_LIST, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLEAR_WHITE_LIST, 0, dst); } int -host_hci_cmd_build_le_add_to_whitelist(uint8_t *addr, uint8_t addr_type, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_add_to_whitelist(const uint8_t *addr, + uint8_t addr_type, + uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CHG_WHITE_LIST_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_WHITE_LIST, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_WHITE_LIST, BLE_HCI_CHG_WHITE_LIST_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - rc = host_hci_cmd_body_le_whitelist_chg(addr, addr_type, dst); + rc = ble_hs_hci_cmd_body_le_whitelist_chg(addr, addr_type, dst); if (rc != 0) { return rc; } @@ -677,10 +710,10 @@ host_hci_cmd_build_le_add_to_whitelist(uint8_t *addr, uint8_t addr_type, } void -host_hci_cmd_build_reset(uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_reset(uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET, 0, dst); } @@ -690,21 +723,21 @@ host_hci_cmd_build_reset(uint8_t *dst, int dst_len) * @return int */ int -host_hci_cmd_reset(void) +ble_hs_hci_cmd_reset(void) { int rc; - rc = host_hci_cmd_send(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET, 0, - NULL); + rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET, + 0, NULL); return rc; } void -host_hci_cmd_build_read_adv_pwr(uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_read_adv_pwr(uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR, - 0, dst); + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR, + 0, dst); } /** @@ -713,35 +746,36 @@ host_hci_cmd_build_read_adv_pwr(uint8_t *dst, int dst_len) * @return int */ int -host_hci_cmd_read_adv_pwr(void) +ble_hs_hci_cmd_read_adv_pwr(void) { int rc; - rc = host_hci_cmd_send(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR, 0, - NULL); + rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR, + 0, NULL); return rc; } void -host_hci_cmd_build_le_create_conn_cancel(uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_create_conn_cancel(uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN_CANCEL, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN_CANCEL, 0, dst); } int -host_hci_cmd_le_create_conn_cancel(void) +ble_hs_hci_cmd_le_create_conn_cancel(void) { int rc; - rc = host_hci_cmd_send(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN_CANCEL, + rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN_CANCEL, 0, NULL); return rc; } static int -host_hci_cmd_body_le_conn_update(struct hci_conn_update *hcu, uint8_t *dst) +ble_hs_hci_cmd_body_le_conn_update(const struct hci_conn_update *hcu, + uint8_t *dst) { /* XXX: add parameter checking later */ htole16(dst + 0, hcu->handle); @@ -756,19 +790,19 @@ host_hci_cmd_body_le_conn_update(struct hci_conn_update *hcu, uint8_t *dst) } int -host_hci_cmd_build_le_conn_update(struct hci_conn_update *hcu, uint8_t *dst, - int dst_len) +ble_hs_hci_cmd_build_le_conn_update(const struct hci_conn_update *hcu, + uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_UPDATE_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CONN_UPDATE, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CONN_UPDATE, BLE_HCI_CONN_UPDATE_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - rc = host_hci_cmd_body_le_conn_update(hcu, dst); + rc = ble_hs_hci_cmd_body_le_conn_update(hcu, dst); if (rc != 0) { return rc; } @@ -777,17 +811,17 @@ host_hci_cmd_build_le_conn_update(struct hci_conn_update *hcu, uint8_t *dst, } int -host_hci_cmd_le_conn_update(struct hci_conn_update *hcu) +ble_hs_hci_cmd_le_conn_update(const struct hci_conn_update *hcu) { uint8_t cmd[BLE_HCI_CONN_UPDATE_LEN]; int rc; - rc = host_hci_cmd_body_le_conn_update(hcu, cmd); + rc = ble_hs_hci_cmd_body_le_conn_update(hcu, cmd); if (rc != 0) { return rc; } - rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_CONN_UPDATE, + rc = ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_CONN_UPDATE, BLE_HCI_CONN_UPDATE_LEN, cmd); if (rc != 0) { return rc; @@ -797,8 +831,8 @@ host_hci_cmd_le_conn_update(struct hci_conn_update *hcu) } static void -host_hci_cmd_body_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr, - uint8_t *dst) +ble_hs_hci_cmd_body_le_lt_key_req_reply(const struct hci_lt_key_req_reply *hkr, + uint8_t *dst) { htole16(dst + 0, hkr->conn_handle); memcpy(dst + 2, hkr->long_term_key, sizeof hkr->long_term_key); @@ -819,36 +853,37 @@ host_hci_cmd_body_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr, * @return int */ void -host_hci_cmd_build_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_lt_key_req_reply( + const struct hci_lt_key_req_reply *hkr, uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_LT_KEY_REQ_REPLY_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY, BLE_HCI_LT_KEY_REQ_REPLY_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_le_lt_key_req_reply(hkr, dst); + ble_hs_hci_cmd_body_le_lt_key_req_reply(hkr, dst); } void -host_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle, + uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY, - BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN, dst); + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY, + BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; htole16(dst + 0, conn_handle); } static void -host_hci_cmd_body_le_conn_param_reply(struct hci_conn_param_reply *hcr, - uint8_t *dst) +ble_hs_hci_cmd_body_le_conn_param_reply(const struct hci_conn_param_reply *hcr, + uint8_t *dst) { htole16(dst + 0, hcr->handle); htole16(dst + 2, hcr->conn_itvl_min); @@ -860,21 +895,21 @@ host_hci_cmd_body_le_conn_param_reply(struct hci_conn_param_reply *hcr, } void -host_hci_cmd_build_le_conn_param_reply(struct hci_conn_param_reply *hcr, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_conn_param_reply( + const struct hci_conn_param_reply *hcr, uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_PARAM_REPLY_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_RR, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_RR, BLE_HCI_CONN_PARAM_REPLY_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_le_conn_param_reply(hcr, dst); + ble_hs_hci_cmd_body_le_conn_param_reply(hcr, dst); } int -host_hci_cmd_le_conn_param_reply(struct hci_conn_param_reply *hcr) +ble_hs_hci_cmd_le_conn_param_reply(const struct hci_conn_param_reply *hcr) { uint8_t cmd[BLE_HCI_CONN_PARAM_REPLY_LEN]; int rc; @@ -887,14 +922,14 @@ host_hci_cmd_le_conn_param_reply(struct hci_conn_param_reply *hcr) htole16(cmd + 10, hcr->min_ce_len); htole16(cmd + 12, hcr->max_ce_len); - rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_RR, + rc = ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_RR, BLE_HCI_CONN_PARAM_REPLY_LEN, cmd); return rc; } static void -host_hci_cmd_body_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn, - uint8_t *dst) +ble_hs_hci_cmd_body_le_conn_param_neg_reply( + const struct hci_conn_param_neg_reply *hcn, uint8_t *dst) { htole16(dst + 0, hcn->handle); dst[2] = hcn->reason; @@ -902,28 +937,29 @@ host_hci_cmd_body_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn, void -host_hci_cmd_build_le_conn_param_neg_reply( - struct hci_conn_param_neg_reply *hcn, uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_conn_param_neg_reply( + const struct hci_conn_param_neg_reply *hcn, uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_PARAM_NEG_REPLY_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR, BLE_HCI_CONN_PARAM_NEG_REPLY_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_le_conn_param_neg_reply(hcn, dst); + ble_hs_hci_cmd_body_le_conn_param_neg_reply(hcn, dst); } int -host_hci_cmd_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn) +ble_hs_hci_cmd_le_conn_param_neg_reply( + const struct hci_conn_param_neg_reply *hcn) { uint8_t cmd[BLE_HCI_CONN_PARAM_NEG_REPLY_LEN]; int rc; - host_hci_cmd_body_le_conn_param_neg_reply(hcn, cmd); + ble_hs_hci_cmd_body_le_conn_param_neg_reply(hcn, cmd); - rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR, + rc = ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR, BLE_HCI_CONN_PARAM_NEG_REPLY_LEN, cmd); return rc; } @@ -937,14 +973,15 @@ host_hci_cmd_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn) * @return int */ void -host_hci_cmd_build_le_rand(uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_rand(uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RAND, 0, dst); + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RAND, 0, dst); } static void -host_hci_cmd_body_le_start_encrypt(struct hci_start_encrypt *cmd, uint8_t *dst) +ble_hs_hci_cmd_body_le_start_encrypt(const struct hci_start_encrypt *cmd, + uint8_t *dst) { htole16(dst + 0, cmd->connection_handle); htole64(dst + 2, cmd->random_number); @@ -956,17 +993,17 @@ host_hci_cmd_body_le_start_encrypt(struct hci_start_encrypt *cmd, uint8_t *dst) * OGF=0x08 OCF=0x0019 */ void -host_hci_cmd_build_le_start_encrypt(struct hci_start_encrypt *cmd, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_le_start_encrypt(const struct hci_start_encrypt *cmd, + uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_LE_START_ENCRYPT_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_START_ENCRYPT, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_START_ENCRYPT, BLE_HCI_LE_START_ENCRYPT_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_le_start_encrypt(cmd, dst); + ble_hs_hci_cmd_body_le_start_encrypt(cmd, dst); } /** @@ -979,27 +1016,28 @@ host_hci_cmd_build_le_start_encrypt(struct hci_start_encrypt *cmd, * @return int */ static void -host_hci_cmd_body_read_rssi(uint16_t handle, uint8_t *dst) +ble_hs_hci_cmd_body_read_rssi(uint16_t handle, uint8_t *dst) { htole16(dst, handle); } void -host_hci_cmd_build_read_rssi(uint16_t handle, uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_read_rssi(uint16_t handle, uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_READ_RSSI_LEN); - host_hci_write_hdr(BLE_HCI_OGF_STATUS_PARAMS, BLE_HCI_OCF_RD_RSSI, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_STATUS_PARAMS, BLE_HCI_OCF_RD_RSSI, BLE_HCI_READ_RSSI_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - host_hci_cmd_body_read_rssi(handle, dst); + ble_hs_hci_cmd_body_read_rssi(handle, dst); } static int -host_hci_cmd_body_set_data_len(uint16_t connection_handle, uint16_t tx_octets, - uint16_t tx_time, uint8_t *dst) +ble_hs_hci_cmd_body_set_data_len(uint16_t connection_handle, + uint16_t tx_octets, + uint16_t tx_time, uint8_t *dst) { if (tx_octets < BLE_HCI_SET_DATALEN_TX_OCTETS_MIN || @@ -1025,21 +1063,21 @@ host_hci_cmd_body_set_data_len(uint16_t connection_handle, uint16_t tx_octets, * OGF=0x08 OCF=0x0022 */ int -host_hci_cmd_build_set_data_len(uint16_t connection_handle, - uint16_t tx_octets, uint16_t tx_time, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_set_data_len(uint16_t connection_handle, + uint16_t tx_octets, uint16_t tx_time, + uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_DATALEN_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_DATA_LEN, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_DATA_LEN, BLE_HCI_SET_DATALEN_LEN, dst); dst += BLE_HCI_CMD_HDR_LEN; - rc = host_hci_cmd_body_set_data_len(connection_handle, tx_octets, tx_time, - dst); + rc = ble_hs_hci_cmd_body_set_data_len(connection_handle, tx_octets, + tx_time, dst); if (rc != 0) { return rc; } @@ -1051,9 +1089,10 @@ host_hci_cmd_build_set_data_len(uint16_t connection_handle, * IRKs are in little endian. */ static int -host_hci_cmd_body_add_to_resolv_list(uint8_t addr_type, uint8_t *addr, - uint8_t *peer_irk, uint8_t *local_irk, - uint8_t *dst) +ble_hs_hci_cmd_body_add_to_resolv_list(uint8_t addr_type, const uint8_t *addr, + const uint8_t *peer_irk, + const uint8_t *local_irk, + uint8_t *dst) { if (addr_type > BLE_ADDR_TYPE_RANDOM) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -1073,8 +1112,8 @@ host_hci_cmd_body_add_to_resolv_list(uint8_t addr_type, uint8_t *addr, * IRKs are in little endian. */ int -host_hci_cmd_build_add_to_resolv_list( - struct hci_add_dev_to_resolving_list *padd, +ble_hs_hci_cmd_build_add_to_resolv_list( + const struct hci_add_dev_to_resolving_list *padd, uint8_t *dst, int dst_len) { @@ -1083,10 +1122,10 @@ host_hci_cmd_build_add_to_resolv_list( BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_ADD_TO_RESOLV_LIST_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST, BLE_HCI_ADD_TO_RESOLV_LIST_LEN, dst); - rc = host_hci_cmd_body_add_to_resolv_list( + rc = ble_hs_hci_cmd_body_add_to_resolv_list( padd->addr_type, padd->addr, padd->peer_irk, padd->local_irk, dst + BLE_HCI_CMD_HDR_LEN); if (rc != 0) { @@ -1097,8 +1136,9 @@ host_hci_cmd_build_add_to_resolv_list( } static int -host_hci_cmd_body_remove_from_resolv_list(uint8_t addr_type, uint8_t *addr, - uint8_t *dst) +ble_hs_hci_cmd_body_remove_from_resolv_list(uint8_t addr_type, + const uint8_t *addr, + uint8_t *dst) { if (addr_type > BLE_ADDR_TYPE_RANDOM) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -1111,18 +1151,19 @@ host_hci_cmd_body_remove_from_resolv_list(uint8_t addr_type, uint8_t *addr, int -host_hci_cmd_build_remove_from_resolv_list(uint8_t addr_type, uint8_t *addr, - uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_remove_from_resolv_list(uint8_t addr_type, + const uint8_t *addr, + uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_RMV_FROM_RESOLV_LIST_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RMV_RESOLV_LIST, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RMV_RESOLV_LIST, BLE_HCI_RMV_FROM_RESOLV_LIST_LEN, dst); - rc = host_hci_cmd_body_remove_from_resolv_list(addr_type, addr, + rc = ble_hs_hci_cmd_body_remove_from_resolv_list(addr_type, addr, dst + BLE_HCI_CMD_HDR_LEN); if (rc != 0) { return rc; @@ -1131,31 +1172,32 @@ host_hci_cmd_build_remove_from_resolv_list(uint8_t addr_type, uint8_t *addr, } int -host_hci_cmd_build_clear_resolv_list(uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_clear_resolv_list(uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLR_RESOLV_LIST, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLR_RESOLV_LIST, 0, dst); return 0; } int -host_hci_cmd_build_read_resolv_list_size(uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_read_resolv_list_size(uint8_t *dst, int dst_len) { BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_RESOLV_LIST_SIZE, - 0, dst); + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_RESOLV_LIST_SIZE, + 0, dst); return 0; } static int -host_hci_cmd_body_read_peer_resolv_addr(uint8_t peer_identity_addr_type, - uint8_t *peer_identity_addr, - uint8_t *dst) +ble_hs_hci_cmd_body_read_peer_resolv_addr(uint8_t peer_identity_addr_type, + const uint8_t *peer_identity_addr, + uint8_t *dst) { if (peer_identity_addr_type > BLE_ADDR_TYPE_RANDOM) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -1167,22 +1209,23 @@ host_hci_cmd_body_read_peer_resolv_addr(uint8_t peer_identity_addr_type, } int -host_hci_cmd_build_read_peer_resolv_addr(uint8_t peer_identity_addr_type, - uint8_t *peer_identity_addr, - uint8_t *dst, - int dst_len) +ble_hs_hci_cmd_build_read_peer_resolv_addr(uint8_t peer_identity_addr_type, + const uint8_t *peer_identity_addr, + uint8_t *dst, + int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_RD_PEER_RESOLV_ADDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_PEER_RESOLV_ADDR, - BLE_HCI_RD_PEER_RESOLV_ADDR_LEN, dst); + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_PEER_RESOLV_ADDR, + BLE_HCI_RD_PEER_RESOLV_ADDR_LEN, dst); - rc = host_hci_cmd_body_read_peer_resolv_addr(peer_identity_addr_type, - peer_identity_addr, - dst + BLE_HCI_CMD_HDR_LEN); + rc = ble_hs_hci_cmd_body_read_peer_resolv_addr(peer_identity_addr_type, + peer_identity_addr, + dst + BLE_HCI_CMD_HDR_LEN); if (rc != 0) { return rc; } @@ -1190,9 +1233,9 @@ host_hci_cmd_build_read_peer_resolv_addr(uint8_t peer_identity_addr_type, } static int -host_hci_cmd_body_read_lcl_resolv_addr( +ble_hs_hci_cmd_body_read_lcl_resolv_addr( uint8_t local_identity_addr_type, - uint8_t *local_identity_addr, + const uint8_t *local_identity_addr, uint8_t *dst) { if (local_identity_addr_type > BLE_ADDR_TYPE_RANDOM) { @@ -1208,22 +1251,23 @@ host_hci_cmd_body_read_lcl_resolv_addr( * OGF=0x08 OCF=0x002c */ int -host_hci_cmd_build_read_lcl_resolv_addr(uint8_t local_identity_addr_type, - uint8_t *local_identity_addr, - uint8_t *dst, - int dst_len) +ble_hs_hci_cmd_build_read_lcl_resolv_addr(uint8_t local_identity_addr_type, + const uint8_t *local_identity_addr, + uint8_t *dst, + int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_RD_LOC_RESOLV_ADDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_LOCAL_RESOLV_ADDR, - BLE_HCI_RD_LOC_RESOLV_ADDR_LEN, dst); + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_LOCAL_RESOLV_ADDR, + BLE_HCI_RD_LOC_RESOLV_ADDR_LEN, dst); - rc = host_hci_cmd_body_read_lcl_resolv_addr(local_identity_addr_type, - local_identity_addr, - dst + BLE_HCI_CMD_HDR_LEN); + rc = ble_hs_hci_cmd_body_read_lcl_resolv_addr(local_identity_addr_type, + local_identity_addr, + dst + BLE_HCI_CMD_HDR_LEN); if (rc != 0) { return rc; } @@ -1231,7 +1275,7 @@ host_hci_cmd_build_read_lcl_resolv_addr(uint8_t local_identity_addr_type, } static int -host_hci_cmd_body_set_addr_res_en(uint8_t enable, uint8_t *dst) +ble_hs_hci_cmd_body_set_addr_res_en(uint8_t enable, uint8_t *dst) { if (enable > 1) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -1245,17 +1289,18 @@ host_hci_cmd_body_set_addr_res_en(uint8_t enable, uint8_t *dst) * OGF=0x08 OCF=0x002d */ int -host_hci_cmd_build_set_addr_res_en(uint8_t enable, uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_set_addr_res_en(uint8_t enable, uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADDR_RESOL_ENA_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN, BLE_HCI_SET_ADDR_RESOL_ENA_LEN, dst); - rc = host_hci_cmd_body_set_addr_res_en(enable, dst + BLE_HCI_CMD_HDR_LEN); + rc = ble_hs_hci_cmd_body_set_addr_res_en(enable, + dst + BLE_HCI_CMD_HDR_LEN); if (rc != 0) { return rc; } @@ -1263,7 +1308,8 @@ host_hci_cmd_build_set_addr_res_en(uint8_t enable, uint8_t *dst, int dst_len) } static int -host_hci_cmd_body_set_resolv_priv_addr_timeout(uint16_t timeout, uint8_t *dst) +ble_hs_hci_cmd_body_set_resolv_priv_addr_timeout(uint16_t timeout, + uint8_t *dst) { if (timeout == 0 || timeout > 0xA1B8) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -1277,18 +1323,18 @@ host_hci_cmd_body_set_resolv_priv_addr_timeout(uint16_t timeout, uint8_t *dst) * OGF=0x08 OCF=0x002e */ int -host_hci_cmd_build_set_resolv_priv_addr_timeout(uint16_t timeout, uint8_t *dst, - int dst_len) +ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout( + uint16_t timeout, uint8_t *dst, int dst_len) { int rc; BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RPA_TMO, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RPA_TMO, BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN, dst); - rc = host_hci_cmd_body_set_resolv_priv_addr_timeout( + rc = ble_hs_hci_cmd_body_set_resolv_priv_addr_timeout( timeout, dst + BLE_HCI_CMD_HDR_LEN); if (rc != 0) { return rc; @@ -1297,14 +1343,16 @@ host_hci_cmd_build_set_resolv_priv_addr_timeout(uint16_t timeout, uint8_t *dst, } static int -host_hci_cmd_body_set_random_addr(struct hci_rand_addr *paddr, uint8_t *dst) +ble_hs_hci_cmd_body_set_random_addr(const struct hci_rand_addr *paddr, + uint8_t *dst) { memcpy(dst, paddr->addr, BLE_DEV_ADDR_LEN); return 0; } int -host_hci_cmd_build_set_random_addr(uint8_t *addr, uint8_t *dst, int dst_len) +ble_hs_hci_cmd_build_set_random_addr(const uint8_t *addr, + uint8_t *dst, int dst_len) { struct hci_rand_addr r_addr; int rc; @@ -1314,10 +1362,11 @@ host_hci_cmd_build_set_random_addr(uint8_t *addr, uint8_t *dst, int dst_len) BLE_HS_DBG_ASSERT( dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RAND_ADDR_LEN); - host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RAND_ADDR, + ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RAND_ADDR, BLE_HCI_SET_RAND_ADDR_LEN, dst); - rc = host_hci_cmd_body_set_random_addr(&r_addr, dst + BLE_HCI_CMD_HDR_LEN); + rc = ble_hs_hci_cmd_body_set_random_addr(&r_addr, + dst + BLE_HCI_CMD_HDR_LEN); if (rc != 0) { return rc; } diff --git a/net/nimble/host/src/host_hci.c b/net/nimble/host/src/ble_hs_hci_evt.c index 4452dcc3..3d382dc1 100644 --- a/net/nimble/host/src/host_hci.c +++ b/net/nimble/host/src/ble_hs_hci_evt.c @@ -23,30 +23,29 @@ #include "os/os.h" #include "console/console.h" #include "nimble/hci_common.h" -#include "nimble/hci_transport.h" -#include "host/host_hci.h" +#include "nimble/ble_hci_trans.h" +#include "host/ble_gap.h" #include "ble_hs_priv.h" -#include "host_dbg_priv.h" +#include "ble_hs_dbg_priv.h" _Static_assert(sizeof (struct hci_data_hdr) == BLE_HCI_DATA_HDR_SZ, "struct hci_data_hdr must be 4 bytes"); -typedef int host_hci_event_fn(uint8_t event_code, uint8_t *data, int len); -static host_hci_event_fn host_hci_rx_disconn_complete; -static host_hci_event_fn host_hci_rx_encrypt_change; -static host_hci_event_fn host_hci_rx_num_completed_pkts; -static host_hci_event_fn host_hci_rx_enc_key_refresh; -static host_hci_event_fn host_hci_rx_le_meta; - -typedef int host_hci_le_event_fn(uint8_t subevent, uint8_t *data, int len); -static host_hci_le_event_fn host_hci_rx_le_conn_complete; -static host_hci_le_event_fn host_hci_rx_le_adv_rpt; -static host_hci_le_event_fn host_hci_rx_le_conn_upd_complete; -static host_hci_le_event_fn host_hci_rx_le_lt_key_req; -static host_hci_le_event_fn host_hci_rx_le_conn_parm_req; - -static uint16_t host_hci_buffer_sz; -static uint8_t host_hci_max_pkts; +typedef int ble_hs_hci_evt_fn(uint8_t event_code, uint8_t *data, int len); +static ble_hs_hci_evt_fn ble_hs_hci_evt_disconn_complete; +static ble_hs_hci_evt_fn ble_hs_hci_evt_encrypt_change; +static ble_hs_hci_evt_fn ble_hs_hci_evt_hw_error; +static ble_hs_hci_evt_fn ble_hs_hci_evt_num_completed_pkts; +static ble_hs_hci_evt_fn ble_hs_hci_evt_enc_key_refresh; +static ble_hs_hci_evt_fn ble_hs_hci_evt_le_meta; + +typedef int ble_hs_hci_evt_le_fn(uint8_t subevent, uint8_t *data, int len); +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_complete; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_adv_rpt; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_upd_complete; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_lt_key_req; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_parm_req; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_dir_adv_rpt; /* Statistics */ struct host_hci_stats @@ -57,71 +56,56 @@ struct host_hci_stats uint32_t unknown_events_rxd; }; -#define HOST_HCI_TIMEOUT 50 /* Milliseconds. */ +#define BLE_HS_HCI_EVT_TIMEOUT 50 /* Milliseconds. */ /** Dispatch table for incoming HCI events. Sorted by event code field. */ -struct host_hci_event_dispatch_entry { - uint8_t hed_event_code; - host_hci_event_fn *hed_fn; +struct ble_hs_hci_evt_dispatch_entry { + uint8_t event_code; + ble_hs_hci_evt_fn *cb; }; -static const struct host_hci_event_dispatch_entry host_hci_event_dispatch[] = { - { BLE_HCI_EVCODE_DISCONN_CMP, host_hci_rx_disconn_complete }, - { BLE_HCI_EVCODE_ENCRYPT_CHG, host_hci_rx_encrypt_change }, - { BLE_HCI_EVCODE_NUM_COMP_PKTS, host_hci_rx_num_completed_pkts }, - { BLE_HCI_EVCODE_ENC_KEY_REFRESH, host_hci_rx_enc_key_refresh }, - { BLE_HCI_EVCODE_LE_META, host_hci_rx_le_meta }, +static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = { + { BLE_HCI_EVCODE_DISCONN_CMP, ble_hs_hci_evt_disconn_complete }, + { BLE_HCI_EVCODE_ENCRYPT_CHG, ble_hs_hci_evt_encrypt_change }, + { BLE_HCI_EVCODE_HW_ERROR, ble_hs_hci_evt_hw_error }, + { BLE_HCI_EVCODE_NUM_COMP_PKTS, ble_hs_hci_evt_num_completed_pkts }, + { BLE_HCI_EVCODE_ENC_KEY_REFRESH, ble_hs_hci_evt_enc_key_refresh }, + { BLE_HCI_EVCODE_LE_META, ble_hs_hci_evt_le_meta }, }; -#define HOST_HCI_EVENT_DISPATCH_SZ \ - (sizeof host_hci_event_dispatch / sizeof host_hci_event_dispatch[0]) +#define BLE_HS_HCI_EVT_DISPATCH_SZ \ + (sizeof ble_hs_hci_evt_dispatch / sizeof ble_hs_hci_evt_dispatch[0]) /** Dispatch table for incoming LE meta events. Sorted by subevent field. */ -struct host_hci_le_event_dispatch_entry { - uint8_t hmd_subevent; - host_hci_le_event_fn *hmd_fn; +struct ble_hs_hci_evt_le_dispatch_entry { + uint8_t subevent; + ble_hs_hci_evt_le_fn *cb; }; -static const struct host_hci_le_event_dispatch_entry - host_hci_le_event_dispatch[] = { - { BLE_HCI_LE_SUBEV_CONN_COMPLETE, host_hci_rx_le_conn_complete }, - { BLE_HCI_LE_SUBEV_ADV_RPT, host_hci_rx_le_adv_rpt }, - { BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE, host_hci_rx_le_conn_upd_complete }, - { BLE_HCI_LE_SUBEV_LT_KEY_REQ, host_hci_rx_le_lt_key_req }, - { BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ, host_hci_rx_le_conn_parm_req }, - { BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE, host_hci_rx_le_conn_complete }, +static const struct ble_hs_hci_evt_le_dispatch_entry + ble_hs_hci_evt_le_dispatch[] = { + { BLE_HCI_LE_SUBEV_CONN_COMPLETE, ble_hs_hci_evt_le_conn_complete }, + { BLE_HCI_LE_SUBEV_ADV_RPT, ble_hs_hci_evt_le_adv_rpt }, + { BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE, + ble_hs_hci_evt_le_conn_upd_complete }, + { BLE_HCI_LE_SUBEV_LT_KEY_REQ, ble_hs_hci_evt_le_lt_key_req }, + { BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ, ble_hs_hci_evt_le_conn_parm_req }, + { BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE, ble_hs_hci_evt_le_conn_complete }, + { BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT, ble_hs_hci_evt_le_dir_adv_rpt }, }; -#define HOST_HCI_LE_EVENT_DISPATCH_SZ \ - (sizeof host_hci_le_event_dispatch / sizeof host_hci_le_event_dispatch[0]) - -uint16_t -host_hci_opcode_join(uint8_t ogf, uint16_t ocf) -{ - return (ogf << 10) | ocf; -} - -uint16_t -host_hci_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc) -{ - BLE_HS_DBG_ASSERT(handle <= 0x0fff); - BLE_HS_DBG_ASSERT(pb <= 0x03); - BLE_HS_DBG_ASSERT(bc <= 0x03); - - return (handle << 0) | - (pb << 12) | - (bc << 14); -} +#define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \ + (sizeof ble_hs_hci_evt_le_dispatch / sizeof ble_hs_hci_evt_le_dispatch[0]) -static const struct host_hci_event_dispatch_entry * -host_hci_dispatch_entry_find(uint8_t event_code) +static const struct ble_hs_hci_evt_dispatch_entry * +ble_hs_hci_evt_dispatch_find(uint8_t event_code) { - const struct host_hci_event_dispatch_entry *entry; + const struct ble_hs_hci_evt_dispatch_entry *entry; int i; - for (i = 0; i < HOST_HCI_EVENT_DISPATCH_SZ; i++) { - entry = host_hci_event_dispatch + i; - if (entry->hed_event_code == event_code) { + for (i = 0; i < BLE_HS_HCI_EVT_DISPATCH_SZ; i++) { + entry = ble_hs_hci_evt_dispatch + i; + if (entry->event_code == event_code) { return entry; } } @@ -129,15 +113,15 @@ host_hci_dispatch_entry_find(uint8_t event_code) return NULL; } -static const struct host_hci_le_event_dispatch_entry * -host_hci_le_dispatch_entry_find(uint8_t event_code) +static const struct ble_hs_hci_evt_le_dispatch_entry * +ble_hs_hci_evt_le_dispatch_find(uint8_t event_code) { - const struct host_hci_le_event_dispatch_entry *entry; + const struct ble_hs_hci_evt_le_dispatch_entry *entry; int i; - for (i = 0; i < HOST_HCI_LE_EVENT_DISPATCH_SZ; i++) { - entry = host_hci_le_event_dispatch + i; - if (entry->hmd_subevent == event_code) { + for (i = 0; i < BLE_HS_HCI_EVT_LE_DISPATCH_SZ; i++) { + entry = ble_hs_hci_evt_le_dispatch + i; + if (entry->subevent == event_code) { return entry; } } @@ -146,7 +130,7 @@ host_hci_le_dispatch_entry_find(uint8_t event_code) } static int -host_hci_rx_disconn_complete(uint8_t event_code, uint8_t *data, int len) +ble_hs_hci_evt_disconn_complete(uint8_t event_code, uint8_t *data, int len) { struct hci_disconn_complete evt; @@ -164,7 +148,7 @@ host_hci_rx_disconn_complete(uint8_t event_code, uint8_t *data, int len) } static int -host_hci_rx_encrypt_change(uint8_t event_code, uint8_t *data, int len) +ble_hs_hci_evt_encrypt_change(uint8_t event_code, uint8_t *data, int len) { struct hci_encrypt_change evt; @@ -182,7 +166,22 @@ host_hci_rx_encrypt_change(uint8_t event_code, uint8_t *data, int len) } static int -host_hci_rx_enc_key_refresh(uint8_t event_code, uint8_t *data, int len) +ble_hs_hci_evt_hw_error(uint8_t event_code, uint8_t *data, int len) +{ + uint8_t hw_code; + + if (len < BLE_HCI_EVENT_HW_ERROR_LEN) { + return BLE_HS_ECONTROLLER; + } + + hw_code = data[0]; + ble_hs_hw_error(hw_code); + + return 0; +} + +static int +ble_hs_hci_evt_enc_key_refresh(uint8_t event_code, uint8_t *data, int len) { struct hci_encrypt_key_refresh evt; @@ -199,7 +198,7 @@ host_hci_rx_enc_key_refresh(uint8_t event_code, uint8_t *data, int len) } static int -host_hci_rx_num_completed_pkts(uint8_t event_code, uint8_t *data, int len) +ble_hs_hci_evt_num_completed_pkts(uint8_t event_code, uint8_t *data, int len) { uint16_t num_pkts; uint16_t handle; @@ -232,21 +231,20 @@ host_hci_rx_num_completed_pkts(uint8_t event_code, uint8_t *data, int len) } static int -host_hci_rx_le_meta(uint8_t event_code, uint8_t *data, int len) +ble_hs_hci_evt_le_meta(uint8_t event_code, uint8_t *data, int len) { - const struct host_hci_le_event_dispatch_entry *entry; + const struct ble_hs_hci_evt_le_dispatch_entry *entry; uint8_t subevent; int rc; if (len < BLE_HCI_EVENT_HDR_LEN + BLE_HCI_LE_MIN_LEN) { - /* XXX: Increment stat. */ return BLE_HS_ECONTROLLER; } subevent = data[2]; - entry = host_hci_le_dispatch_entry_find(subevent); + entry = ble_hs_hci_evt_le_dispatch_find(subevent); if (entry != NULL) { - rc = entry->hmd_fn(subevent, data + BLE_HCI_EVENT_HDR_LEN, + rc = entry->cb(subevent, data + BLE_HCI_EVENT_HDR_LEN, len - BLE_HCI_EVENT_HDR_LEN); if (rc != 0) { return rc; @@ -257,7 +255,7 @@ host_hci_rx_le_meta(uint8_t event_code, uint8_t *data, int len) } static int -host_hci_rx_le_conn_complete(uint8_t subevent, uint8_t *data, int len) +ble_hs_hci_evt_le_conn_complete(uint8_t subevent, uint8_t *data, int len) { struct hci_le_conn_complete evt; int extended_offset = 0; @@ -313,8 +311,9 @@ host_hci_rx_le_conn_complete(uint8_t subevent, uint8_t *data, int len) } static int -host_hci_le_adv_rpt_first_pass(uint8_t *data, int len, - uint8_t *out_num_reports, int *out_rssi_off) +ble_hs_hci_evt_le_adv_rpt_first_pass(uint8_t *data, int len, + uint8_t *out_num_reports, + int *out_rssi_off) { uint8_t num_reports; int data_len; @@ -361,50 +360,117 @@ host_hci_le_adv_rpt_first_pass(uint8_t *data, int len, } static int -host_hci_rx_le_adv_rpt(uint8_t subevent, uint8_t *data, int len) +ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, uint8_t *data, int len) { - struct ble_hs_adv adv; + struct ble_gap_disc_desc desc; uint8_t num_reports; int rssi_off; int data_off; + int suboff; int off; int rc; int i; - rc = host_hci_le_adv_rpt_first_pass(data, len, &num_reports, &rssi_off); + rc = ble_hs_hci_evt_le_adv_rpt_first_pass(data, len, &num_reports, + &rssi_off); if (rc != 0) { return rc; } + /* Direct address fields not present in a standard advertising report. */ + desc.direct_addr_type = BLE_GAP_ADDR_TYPE_NONE; + memset(desc.direct_addr, 0, sizeof desc.direct_addr); + data_off = 0; for (i = 0; i < num_reports; i++) { - off = 2 + 0 * num_reports + i; - adv.event_type = data[2 + 0 * num_reports + i]; + suboff = 0; + + off = 2 + suboff * num_reports + i; + desc.event_type = data[off]; + suboff++; - off = 2 + 1 * num_reports + i; - adv.addr_type = data[2 + 1 * num_reports + i]; + off = 2 + suboff * num_reports + i; + desc.addr_type = data[off]; + suboff++; - off = 2 + 2 * num_reports + i * 6; - memcpy(adv.addr, data + off, 6); + off = 2 + suboff * num_reports + i * 6; + memcpy(desc.addr, data + off, 6); + suboff += 6; - off = 2 + 8 * num_reports + i; - adv.length_data = data[off]; + off = 2 + suboff * num_reports + i; + desc.length_data = data[off]; + suboff++; - off = 2 + 9 * num_reports + data_off; - adv.data = data + off; - data_off += adv.length_data; + off = 2 + suboff * num_reports + data_off; + desc.data = data + off; + data_off += desc.length_data; off = rssi_off + 1 * i; - adv.rssi = data[off]; + desc.rssi = data[off]; - ble_gap_rx_adv_report(&adv); + ble_gap_rx_adv_report(&desc); } return 0; } static int -host_hci_rx_le_conn_upd_complete(uint8_t subevent, uint8_t *data, int len) +ble_hs_hci_evt_le_dir_adv_rpt(uint8_t subevent, uint8_t *data, int len) +{ + struct ble_gap_disc_desc desc; + uint8_t num_reports; + int suboff; + int off; + int i; + + if (len < BLE_HCI_LE_ADV_DIRECT_RPT_LEN) { + return BLE_HS_ECONTROLLER; + } + + num_reports = data[1]; + if (len != 2 + num_reports * BLE_HCI_LE_ADV_DIRECT_RPT_SUB_LEN) { + return BLE_HS_ECONTROLLER; + } + + /* Data fields not present in a direct advertising report. */ + desc.data = NULL; + desc.fields = NULL; + + for (i = 0; i < num_reports; i++) { + suboff = 0; + + off = 2 + suboff * num_reports + i; + desc.event_type = data[off]; + suboff++; + + off = 2 + suboff * num_reports + i; + desc.addr_type = data[off]; + suboff++; + + off = 2 + suboff * num_reports + i * 6; + memcpy(desc.addr, data + off, 6); + suboff += 6; + + off = 2 + suboff * num_reports + i; + desc.direct_addr_type = data[off]; + suboff++; + + off = 2 + suboff * num_reports + i * 6; + memcpy(desc.direct_addr, data + off, 6); + suboff += 6; + + off = 2 + suboff * num_reports + i; + desc.rssi = data[off]; + suboff++; + + ble_gap_rx_adv_report(&desc); + } + + return 0; +} + +static int +ble_hs_hci_evt_le_conn_upd_complete(uint8_t subevent, uint8_t *data, int len) { struct hci_le_conn_upd_complete evt; @@ -443,7 +509,7 @@ host_hci_rx_le_conn_upd_complete(uint8_t subevent, uint8_t *data, int len) } static int -host_hci_rx_le_lt_key_req(uint8_t subevent, uint8_t *data, int len) +ble_hs_hci_evt_le_lt_key_req(uint8_t subevent, uint8_t *data, int len) { struct hci_le_lt_key_req evt; @@ -462,7 +528,7 @@ host_hci_rx_le_lt_key_req(uint8_t subevent, uint8_t *data, int len) } static int -host_hci_rx_le_conn_parm_req(uint8_t subevent, uint8_t *data, int len) +ble_hs_hci_evt_le_conn_parm_req(uint8_t subevent, uint8_t *data, int len) { struct hci_le_conn_param_req evt; @@ -500,22 +566,9 @@ host_hci_rx_le_conn_parm_req(uint8_t subevent, uint8_t *data, int len) } int -host_hci_set_buf_size(uint16_t pktlen, uint8_t max_pkts) -{ - if (pktlen == 0 || max_pkts == 0) { - return BLE_HS_EINVAL; - } - - host_hci_buffer_sz = pktlen; - host_hci_max_pkts = max_pkts; - - return 0; -} - -int -host_hci_event_rx(uint8_t *data) +ble_hs_hci_evt_process(uint8_t *data) { - const struct host_hci_event_dispatch_entry *entry; + const struct ble_hs_hci_evt_dispatch_entry *entry; uint8_t event_code; uint8_t param_len; int event_len; @@ -525,7 +578,7 @@ host_hci_event_rx(uint8_t *data) STATS_INC(ble_hs_stats, hci_event); /* Display to console */ - host_hci_dbg_event_disp(data); + ble_hs_dbg_event_disp(data); /* Process the event */ event_code = data[0]; @@ -533,100 +586,19 @@ host_hci_event_rx(uint8_t *data) event_len = param_len + 2; - entry = host_hci_dispatch_entry_find(event_code); + entry = ble_hs_hci_evt_dispatch_find(event_code); if (entry == NULL) { - STATS_INC(ble_hs_stats, hci_invalid_ack); + STATS_INC(ble_hs_stats, hci_unknown_event); rc = BLE_HS_ENOTSUP; } else { - rc = entry->hed_fn(event_code, data, event_len); + rc = entry->cb(event_code, data, event_len); } - return rc; -} - -int -host_hci_os_event_proc(struct os_event *ev) -{ - os_error_t err; - int rc; - - rc = host_hci_event_rx(ev->ev_arg); - - /* Free the command buffer */ - err = os_memblock_put(&g_hci_cmd_pool, ev->ev_arg); - BLE_HS_DBG_ASSERT_EVAL(err == OS_OK); - - /* Free the event */ - err = os_memblock_put(&g_hci_os_event_pool, ev); - BLE_HS_DBG_ASSERT_EVAL(err == OS_OK); + ble_hci_trans_buf_free(data); return rc; } -/* XXX: For now, put this here */ -int -ble_hci_transport_ctlr_event_send(uint8_t *hci_ev) -{ - struct os_event *ev; - os_error_t err; - int enqueue; - - BLE_HS_DBG_ASSERT(hci_ev != NULL); - - switch (hci_ev[0]) { - case BLE_HCI_EVCODE_COMMAND_COMPLETE: - case BLE_HCI_EVCODE_COMMAND_STATUS: - if (hci_ev[3] == 0 && hci_ev[4] == 0) { - enqueue = 1; - } else { - ble_hci_cmd_rx_ack(hci_ev); - enqueue = 0; - } - break; - - default: - enqueue = 1; - break; - } - - if (enqueue) { - /* Get an event structure off the queue */ - ev = (struct os_event *)os_memblock_get(&g_hci_os_event_pool); - if (!ev) { - err = os_memblock_put(&g_hci_cmd_pool, hci_ev); - BLE_HS_DBG_ASSERT_EVAL(err == OS_OK); - return -1; - } - - /* Fill out the event and post to host task. */ - ev->ev_queued = 0; - ev->ev_type = BLE_HOST_HCI_EVENT_CTLR_EVENT; - ev->ev_arg = hci_ev; - ble_hs_event_enqueue(ev); - } - - return 0; -} - -static int -host_hci_data_hdr_strip(struct os_mbuf *om, struct hci_data_hdr *hdr) -{ - int rc; - - rc = os_mbuf_copydata(om, 0, BLE_HCI_DATA_HDR_SZ, hdr); - if (rc != 0) { - return BLE_HS_ECONTROLLER; - } - - /* Strip HCI ACL data header from the front of the packet. */ - os_mbuf_adj(om, BLE_HCI_DATA_HDR_SZ); - - hdr->hdh_handle_pb_bc = le16toh(&hdr->hdh_handle_pb_bc); - hdr->hdh_len = le16toh(&hdr->hdh_len); - - return 0; -} - /** * Called when a data packet is received from the controller. This function * consumes the supplied mbuf, regardless of the outcome. @@ -637,7 +609,7 @@ host_hci_data_hdr_strip(struct os_mbuf *om, struct hci_data_hdr *hdr) * @return 0 on success; nonzero on failure. */ int -host_hci_data_rx(struct os_mbuf *om) +ble_hs_hci_evt_acl_process(struct os_mbuf *om) { struct hci_data_hdr hci_hdr; struct ble_hs_conn *conn; @@ -646,100 +618,60 @@ host_hci_data_rx(struct os_mbuf *om) uint16_t handle; int rc; - rc = host_hci_data_hdr_strip(om, &hci_hdr); - if (rc == 0) { + rc = ble_hs_hci_util_data_hdr_strip(om, &hci_hdr); + if (rc != 0) { + goto err; + } + #if (BLETEST_THROUGHPUT_TEST == 0) - BLE_HS_LOG(DEBUG, "host_hci_data_rx(): handle=%u pb=%x len=%u data=", - BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc), - BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc), - hci_hdr.hdh_len); - ble_hs_misc_log_mbuf(om); - BLE_HS_LOG(DEBUG, "\n"); + BLE_HS_LOG(DEBUG, "ble_hs_hci_evt_acl_process(): handle=%u pb=%x len=%u " + "data=", + BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc), + BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc), + hci_hdr.hdh_len); + ble_hs_log_mbuf(om); + BLE_HS_LOG(DEBUG, "\n"); #endif - if (hci_hdr.hdh_len != OS_MBUF_PKTHDR(om)->omp_len) { - rc = BLE_HS_EBADDATA; - } else { - handle = BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc); + if (hci_hdr.hdh_len != OS_MBUF_PKTHDR(om)->omp_len) { + rc = BLE_HS_EBADDATA; + goto err; + } - ble_hs_lock(); + handle = BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc); - conn = ble_hs_conn_find(handle); - if (conn == NULL) { - rc = BLE_HS_ENOTCONN; - } else { - rc = ble_l2cap_rx(conn, &hci_hdr, om, &rx_cb, &rx_buf); - om = NULL; - } + ble_hs_lock(); - ble_hs_unlock(); - } + conn = ble_hs_conn_find(handle); + if (conn == NULL) { + rc = BLE_HS_ENOTCONN; + } else { + rc = ble_l2cap_rx(conn, &hci_hdr, om, &rx_cb, &rx_buf); + om = NULL; } - os_mbuf_free_chain(om); + ble_hs_unlock(); - if (rc == 0) { + switch (rc) { + case 0: + /* Final fragment received. */ BLE_HS_DBG_ASSERT(rx_cb != NULL); BLE_HS_DBG_ASSERT(rx_buf != NULL); rc = rx_cb(handle, &rx_buf); os_mbuf_free_chain(rx_buf); - } else if (rc == BLE_HS_EAGAIN) { - /* More fragments on the way. */ - rc = 0; - } - - return rc; -} - -static struct os_mbuf * -host_hci_data_hdr_prepend(struct os_mbuf *om, uint16_t handle, uint8_t pb_flag) -{ - struct hci_data_hdr hci_hdr; - - hci_hdr.hdh_handle_pb_bc = host_hci_handle_pb_bc_join(handle, pb_flag, 0); - htole16(&hci_hdr.hdh_len, OS_MBUF_PKTHDR(om)->omp_len); - - om = os_mbuf_prepend(om, sizeof hci_hdr); - if (om == NULL) { - return NULL; - } - - memcpy(om->om_data, &hci_hdr, sizeof hci_hdr); - - BLE_HS_LOG(DEBUG, "host tx hci data; handle=%d length=%d\n", handle, - le16toh(&hci_hdr.hdh_len)); - - return om; -} - -/** - * Transmits an HCI ACL data packet. This function consumes the supplied mbuf, - * regardless of the outcome. - */ -int -host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf *om) -{ - int rc; - - /* XXX: Different transport mechanisms have different fragmentation - * requirements. For now, never fragment. - */ - om = host_hci_data_hdr_prepend(om, connection->bhc_handle, - BLE_HCI_PB_FIRST_NON_FLUSH); - if (om == NULL) { - return BLE_HS_ENOMEM; - } + break; - BLE_HS_LOG(DEBUG, "host_hci_data_tx(): "); - ble_hs_misc_log_mbuf(om); - BLE_HS_LOG(DEBUG, "\n"); + case BLE_HS_EAGAIN: + /* More fragments on the way. */ + break; - rc = ble_hs_tx_data(om); - if (rc != 0) { - return rc; + default: + goto err; } - connection->bhc_outstanding_pkts++; - return 0; + +err: + os_mbuf_free_chain(om); + return rc; } diff --git a/net/nimble/host/src/ble_hs_hci_priv.h b/net/nimble/host/src/ble_hs_hci_priv.h new file mode 100644 index 00000000..7d2fb120 --- /dev/null +++ b/net/nimble/host/src/ble_hs_hci_priv.h @@ -0,0 +1,158 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_HS_HCI_PRIV_ +#define H_BLE_HS_HCI_PRIV_ + +#include "nimble/hci_common.h" +struct ble_hs_conn; +struct os_mbuf; + +struct ble_hs_hci_ack { + int bha_status; /* A BLE_HS_E<...> error; NOT a naked HCI code. */ + uint8_t *bha_params; + int bha_params_len; + uint16_t bha_opcode; + uint8_t bha_hci_handle; +}; + +int ble_hs_hci_cmd_tx(void *cmd, void *evt_buf, uint8_t evt_buf_len, + uint8_t *out_evt_buf_len); +int ble_hs_hci_cmd_tx_empty_ack(void *cmd); +void ble_hs_hci_rx_ack(uint8_t *ack_ev); +void ble_hs_hci_init(void); + +#if PHONY_HCI_ACKS +typedef int ble_hs_hci_phony_ack_fn(uint8_t *ack, int ack_buf_len); +void ble_hs_hci_set_phony_ack_cb(ble_hs_hci_phony_ack_fn *cb); +#endif + +int ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_pwr); +int ble_hs_hci_util_rand(void *dst, int len); +int ble_hs_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi); +int ble_hs_hci_util_set_random_addr(const uint8_t *addr); +int ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, + uint16_t tx_time); +int ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om, + struct hci_data_hdr *out_hdr); + +int ble_hs_hci_evt_process(uint8_t *data); +uint16_t ble_hs_hci_util_opcode_join(uint8_t ogf, uint16_t ocf); +void ble_hs_hci_cmd_write_hdr(uint8_t ogf, uint8_t ocf, uint8_t len, + void *buf); +int ble_hs_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, + const void *cmddata); +int ble_hs_hci_cmd_send_buf(void *cmddata); +void ble_hs_hci_cmd_build_read_bd_addr(uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_set_event_mask(uint64_t event_mask, + uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_set_event_mask2(uint64_t event_mask, uint8_t *dst, + int dst_len); +void ble_hs_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason, + uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_disconnect(uint16_t handle, uint8_t reason); +void ble_hs_hci_cmd_build_read_rssi(uint16_t handle, uint8_t *dst, + int dst_len); +int ble_hs_hci_cmd_read_rssi(uint16_t handle); +int ble_hs_hci_cmd_build_le_set_scan_rsp_data(const uint8_t *data, uint8_t len, + uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_le_set_adv_data(const uint8_t *data, uint8_t len, + uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_le_set_adv_params(const struct hci_adv_params *adv, + uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_le_set_event_mask(uint64_t event_mask, + uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_le_read_buffer_size(uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_le_read_buffer_size(void); +void ble_hs_hci_cmd_build_le_read_loc_supp_feat(uint8_t *dst, uint8_t dst_len); +void ble_hs_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst, + int dst_len); +int ble_hs_hci_cmd_le_set_adv_enable(uint8_t enable); +int ble_hs_hci_cmd_build_le_set_scan_params(uint8_t scan_type, + uint16_t scan_itvl, + uint16_t scan_window, + uint8_t own_addr_type, + uint8_t filter_policy, + uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_le_set_scan_enable(uint8_t enable, + uint8_t filter_dups, + uint8_t *dst, uint8_t dst_len); +int ble_hs_hci_cmd_le_set_scan_enable(uint8_t enable, uint8_t filter_dups); +int ble_hs_hci_cmd_build_le_create_connection( + const struct hci_create_conn *hcc, uint8_t *cmd, int cmd_len); +int ble_hs_hci_cmd_le_create_connection(const struct hci_create_conn *hcc); +void ble_hs_hci_cmd_build_le_clear_whitelist(uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_le_add_to_whitelist(const uint8_t *addr, + uint8_t addr_type, + uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_reset(uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_reset(void); +void ble_hs_hci_cmd_build_read_adv_pwr(uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_read_adv_pwr(void); +void ble_hs_hci_cmd_build_le_create_conn_cancel(uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_le_create_conn_cancel(void); +int ble_hs_hci_cmd_build_le_conn_update(const struct hci_conn_update *hcu, + uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_le_conn_update(const struct hci_conn_update *hcu); +void ble_hs_hci_cmd_build_le_lt_key_req_reply( + const struct hci_lt_key_req_reply *hkr, uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle, + uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_le_conn_param_reply( + const struct hci_conn_param_reply *hcr, uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_le_conn_param_reply(const struct hci_conn_param_reply *hcr); +void ble_hs_hci_cmd_build_le_conn_param_neg_reply( + const struct hci_conn_param_neg_reply *hcn, uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_le_conn_param_neg_reply( + const struct hci_conn_param_neg_reply *hcn); +void ble_hs_hci_cmd_build_le_rand(uint8_t *dst, int dst_len); +void ble_hs_hci_cmd_build_le_start_encrypt(const struct hci_start_encrypt *cmd, + uint8_t *dst, int dst_len); +int ble_hs_hci_set_buf_sz(uint16_t pktlen, uint8_t max_pkts); + +uint16_t ble_hs_hci_util_handle_pb_bc_join(uint16_t handle, uint8_t pb, + uint8_t bc); + +int ble_hs_hci_acl_tx(struct ble_hs_conn *connection, struct os_mbuf *txom); + +int ble_hs_hci_cmd_build_set_data_len(uint16_t connection_handle, + uint16_t tx_octets, uint16_t tx_time, + uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_add_to_resolv_list( + const struct hci_add_dev_to_resolving_list *padd, + uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_remove_from_resolv_list( + uint8_t addr_type, const uint8_t *addr, uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_read_resolv_list_size(uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_clear_resolv_list(uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_read_peer_resolv_addr( + uint8_t peer_identity_addr_type, const uint8_t *peer_identity_addr, + uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_read_lcl_resolv_addr( + uint8_t local_identity_addr_type, const uint8_t *local_identity_addr, + uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_set_addr_res_en( + uint8_t enable, uint8_t *dst, int dst_len); +int ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout( + uint16_t timeout, uint8_t *dst, int dst_len); + +int ble_hs_hci_cmd_build_set_random_addr(const uint8_t *addr, + uint8_t *dst, int dst_len); + +#endif diff --git a/net/nimble/host/src/ble_hci_util.c b/net/nimble/host/src/ble_hs_hci_util.c index f9ed2c52..0d9f625e 100644 --- a/net/nimble/host/src/ble_hci_util.c +++ b/net/nimble/host/src/ble_hs_hci_util.c @@ -19,18 +19,35 @@ #include <string.h> #include "nimble/hci_common.h" -#include "host/host_hci.h" #include "ble_hs_priv.h" +uint16_t +ble_hs_hci_util_opcode_join(uint8_t ogf, uint16_t ocf) +{ + return (ogf << 10) | ocf; +} + +uint16_t +ble_hs_hci_util_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc) +{ + BLE_HS_DBG_ASSERT(handle <= 0x0fff); + BLE_HS_DBG_ASSERT(pb <= 0x03); + BLE_HS_DBG_ASSERT(bc <= 0x03); + + return (handle << 0) | + (pb << 12) | + (bc << 14); +} + int -ble_hci_util_read_adv_tx_pwr(int8_t *out_tx_pwr) +ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_tx_pwr) { uint8_t buf[BLE_HCI_CMD_HDR_LEN]; uint8_t params_len; int rc; - host_hci_cmd_build_read_adv_pwr(buf, sizeof buf); - rc = ble_hci_cmd_tx(buf, out_tx_pwr, 1, ¶ms_len); + ble_hs_hci_cmd_build_read_adv_pwr(buf, sizeof buf); + rc = ble_hs_hci_cmd_tx(buf, out_tx_pwr, 1, ¶ms_len); if (rc != 0) { return rc; } @@ -46,7 +63,7 @@ ble_hci_util_read_adv_tx_pwr(int8_t *out_tx_pwr) } int -ble_hci_util_rand(void *dst, int len) +ble_hs_hci_util_rand(void *dst, int len) { uint8_t rsp_buf[BLE_HCI_LE_RAND_LEN]; uint8_t req_buf[BLE_HCI_CMD_HDR_LEN]; @@ -55,11 +72,11 @@ ble_hci_util_rand(void *dst, int len) int chunk_sz; int rc; - host_hci_cmd_build_le_rand(req_buf, sizeof req_buf); + ble_hs_hci_cmd_build_le_rand(req_buf, sizeof req_buf); u8ptr = dst; while (len > 0) { - rc = ble_hci_cmd_tx(req_buf, rsp_buf, sizeof rsp_buf, ¶ms_len); + rc = ble_hs_hci_cmd_tx(req_buf, rsp_buf, sizeof rsp_buf, ¶ms_len); if (rc != 0) { return rc; } @@ -78,7 +95,7 @@ ble_hci_util_rand(void *dst, int len) } int -ble_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi) +ble_hs_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_READ_RSSI_LEN]; uint8_t params[BLE_HCI_READ_RSSI_ACK_PARAM_LEN]; @@ -86,8 +103,8 @@ ble_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi) uint8_t params_len; int rc; - host_hci_cmd_build_read_rssi(conn_handle, buf, sizeof buf); - rc = ble_hci_cmd_tx(buf, params, sizeof params, ¶ms_len); + ble_hs_hci_cmd_build_read_rssi(conn_handle, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx(buf, params, sizeof params, ¶ms_len); if (rc != 0) { return rc; } @@ -107,25 +124,25 @@ ble_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi) } int -ble_hs_util_set_random_addr(uint8_t *addr) +ble_hs_hci_util_set_random_addr(const uint8_t *addr) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RAND_ADDR_LEN]; int rc; /* set the address in the controller */ - rc = host_hci_cmd_build_set_random_addr(addr, buf, sizeof(buf)); + rc = ble_hs_hci_cmd_build_set_random_addr(addr, buf, sizeof(buf)); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx_empty_ack(buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); return rc; } int -ble_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, - uint16_t tx_time) +ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, + uint16_t tx_time) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_DATALEN_LEN]; @@ -134,14 +151,14 @@ ble_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, uint8_t params_len; int rc; - rc = host_hci_cmd_build_set_data_len(conn_handle, tx_octets, tx_time, buf, - sizeof buf); + rc = ble_hs_hci_cmd_build_set_data_len(conn_handle, tx_octets, tx_time, + buf, sizeof buf); if (rc != 0) { return BLE_HS_HCI_ERR(rc); } - rc = ble_hci_cmd_tx(buf, params, BLE_HCI_SET_DATALEN_ACK_PARAM_LEN, - ¶ms_len); + rc = ble_hs_hci_cmd_tx(buf, params, BLE_HCI_SET_DATALEN_ACK_PARAM_LEN, + ¶ms_len); if (rc != 0) { return rc; } @@ -157,3 +174,23 @@ ble_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, return 0; } + +int +ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om, + struct hci_data_hdr *out_hdr) +{ + int rc; + + rc = os_mbuf_copydata(om, 0, BLE_HCI_DATA_HDR_SZ, out_hdr); + if (rc != 0) { + return BLE_HS_ECONTROLLER; + } + + /* Strip HCI ACL data header from the front of the packet. */ + os_mbuf_adj(om, BLE_HCI_DATA_HDR_SZ); + + out_hdr->hdh_handle_pb_bc = le16toh(&out_hdr->hdh_handle_pb_bc); + out_hdr->hdh_len = le16toh(&out_hdr->hdh_len); + + return 0; +} diff --git a/net/nimble/host/src/ble_hs_id.c b/net/nimble/host/src/ble_hs_id.c new file mode 100644 index 00000000..9ef384b9 --- /dev/null +++ b/net/nimble/host/src/ble_hs_id.c @@ -0,0 +1,248 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <string.h> +#include "host/ble_hs_id.h" +#include "ble_hs_priv.h" + +static uint8_t ble_hs_id_pub[6]; +static uint8_t ble_hs_id_rnd[6]; + +void +ble_hs_id_set_pub(const uint8_t *pub_addr) +{ + ble_hs_lock(); + memcpy(ble_hs_id_pub, pub_addr, 6); + ble_hs_unlock(); +} + +/** + * Generates a new random address. This function does not configure the device + * with the new address; the caller can use the address in subsequent + * operations. + * + * @param nrpa The type of random address to generate: + * 0: static + * 1: non-resolvable private + * @param out_addr On success, the generated address gets written + * here. + * + * @return 0 on success; nonzero on failure. + */ +int +ble_hs_id_gen_rnd(int nrpa, uint8_t *out_addr) +{ + int rc; + + rc = ble_hs_hci_util_rand(out_addr, 6); + if (rc != 0) { + return rc; + } + + if (nrpa) { + out_addr[5] &= ~0xc0; + } else { + out_addr[5] |= 0xc0; + } + + return 0; +} + +/** + * Sets the device's random address. The address type (static vs. + * non-resolvable private) is inferred from the most-significant byte of the + * address. The address is specified in host byte order (little-endian!). + * + * @param rnd_addr The random address to set. + * + * @return 0 on success; + * BLE_HS_EINVAL if the specified address is not a + * valid static random or non-resolvable + * private address. + * Other nonzero on error. + */ +int +ble_hs_id_set_rnd(const uint8_t *rnd_addr) +{ + uint8_t addr_type_byte; + int rc; + + ble_hs_lock(); + + addr_type_byte = rnd_addr[5] & 0xc0; + if (addr_type_byte != 0x00 && addr_type_byte != 0xc0) { + rc = BLE_HS_EINVAL; + goto done; + } + + rc = ble_hs_hci_util_set_random_addr(rnd_addr); + if (rc != 0) { + goto done; + } + + memcpy(ble_hs_id_rnd, rnd_addr, 6); + + rc = 0; + +done: + ble_hs_unlock(); + return rc; +} + +/** + * Retrieves one of the device's identity addresses. The device can have two + * identity addresses: one public and one random. The id_addr_type argument + * specifies which of these two addresses to retrieve. + * + * @param id_addr_type The type of identity address to retrieve. + * Valid values are: + * o BLE_ADDR_TYPE_PUBLIC + * o BLE_ADDR_TYPE_RANDOM + * @param out_id_addr On success, this is reseated to point to the + * retrieved 6-byte identity address. + * @param out_is_nrpa On success, the pointed-to value indicates + * whether the retrieved address is a + * non-resolvable private address. + * + * @return 0 on success; + * BLE_HS_EINVAL if an invalid address type was + * specified; + * BLE_HS_ENOADDR if the device does not have an + * identity address of the requested type; + * Other BLE host core code on error. + */ +int +ble_hs_id_addr(uint8_t id_addr_type, const uint8_t **out_id_addr, + int *out_is_nrpa) +{ + const uint8_t *id_addr; + int nrpa; + + BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task()); + + switch (id_addr_type) { + case BLE_ADDR_TYPE_PUBLIC: + id_addr = ble_hs_id_pub; + nrpa = 0; + break; + + case BLE_ADDR_TYPE_RANDOM: + id_addr = ble_hs_id_rnd; + nrpa = (ble_hs_id_rnd[5] & 0xc0) == 0; + break; + + default: + return BLE_HS_EINVAL; + } + + if (memcmp(id_addr, ble_hs_misc_null_addr, 6) == 0) { + return BLE_HS_ENOADDR; + } + + if (out_id_addr != NULL) { + *out_id_addr = id_addr; + } + if (out_is_nrpa != NULL) { + *out_is_nrpa = nrpa; + } + + return 0; +} + +/** + * Retrieves one of the device's identity addresses. The device can have two + * identity addresses: one public and one random. The id_addr_type argument + * specifies which of these two addresses to retrieve. + * + * @param id_addr_type The type of identity address to retrieve. + * Valid values are: + * o BLE_ADDR_TYPE_PUBLIC + * o BLE_ADDR_TYPE_RANDOM + * @param out_id_addr On success, the requested identity address is + * copied into this buffer. The buffer must + * be at least six bytes in size. + * @param out_is_nrpa On success, the pointed-to value indicates + * whether the retrieved address is a + * non-resolvable private address. + * + * @return 0 on success; + * BLE_HS_EINVAL if an invalid address type was + * specified; + * BLE_HS_ENOADDR if the device does not have an + * identity address of the requested type; + * Other BLE host core code on error. + */ +int +ble_hs_id_copy_addr(uint8_t id_addr_type, uint8_t *out_id_addr, + int *out_is_nrpa) +{ + const uint8_t *addr; + int rc; + + ble_hs_lock(); + + rc = ble_hs_id_addr(id_addr_type, &addr, out_is_nrpa); + if (rc == 0) { + memcpy(out_id_addr, addr, 6); + } + + ble_hs_unlock(); + + return rc; +} + +int +ble_hs_id_use_addr(uint8_t addr_type) +{ + uint8_t id_addr_type; + int nrpa; + int rc; + + switch (addr_type) { + case BLE_ADDR_TYPE_PUBLIC: + case BLE_ADDR_TYPE_RANDOM: + rc = ble_hs_id_addr(addr_type, NULL, NULL); + if (rc != 0) { + return rc; + } + break; + + case BLE_ADDR_TYPE_RPA_PUB_DEFAULT: + case BLE_ADDR_TYPE_RPA_RND_DEFAULT: + id_addr_type = ble_hs_misc_addr_type_to_id(addr_type); + rc = ble_hs_id_addr(id_addr_type, NULL, &nrpa); + if (rc != 0) { + return rc; + } + if (nrpa) { + return BLE_HS_ENOADDR; + } + + rc = ble_hs_pvcy_ensure_started(); + if (rc != 0) { + return rc; + } + break; + + default: + return BLE_HS_EINVAL; + } + + return 0; +} diff --git a/net/nimble/host/src/ble_hs_id_priv.h b/net/nimble/host/src/ble_hs_id_priv.h new file mode 100644 index 00000000..5c0728c5 --- /dev/null +++ b/net/nimble/host/src/ble_hs_id_priv.h @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_HS_ID_PRIV_ +#define H_BLE_HS_ID_PRIV_ + +#include <inttypes.h> + +void ble_hs_id_set_pub(const uint8_t *pub_addr); +int ble_hs_id_addr(uint8_t id_addr_type, const uint8_t **out_id_addr, + int *out_is_nrpa); +int ble_hs_id_use_addr(uint8_t addr_type); + +#endif diff --git a/net/nimble/host/src/ble_hs_log.c b/net/nimble/host/src/ble_hs_log.c new file mode 100644 index 00000000..39294830 --- /dev/null +++ b/net/nimble/host/src/ble_hs_log.c @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/os.h" +#include "host/ble_hs.h" + +struct log ble_hs_log; + +void +ble_hs_log_mbuf(const struct os_mbuf *om) +{ + uint8_t u8; + int i; + + for (i = 0; i < OS_MBUF_PKTLEN(om); i++) { + os_mbuf_copydata(om, i, 1, &u8); + BLE_HS_LOG(DEBUG, "0x%02x ", u8); + } +} + +void +ble_hs_log_flat_buf(const void *data, int len) +{ + const uint8_t *u8ptr; + int i; + + u8ptr = data; + for (i = 0; i < len; i++) { + BLE_HS_LOG(DEBUG, "0x%02x ", u8ptr[i]); + } +} diff --git a/net/nimble/host/src/ble_hs_mbuf.c b/net/nimble/host/src/ble_hs_mbuf.c new file mode 100644 index 00000000..870c88bd --- /dev/null +++ b/net/nimble/host/src/ble_hs_mbuf.c @@ -0,0 +1,198 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "host/ble_hs.h" +#include "ble_hs_priv.h" + +/** + * Allocates an mbuf for use by the nimble host. + */ +static struct os_mbuf * +ble_hs_mbuf_gen_pkt(uint16_t leading_space) +{ + struct os_mbuf *om; + int rc; + + om = os_msys_get_pkthdr(0, 0); + if (om == NULL) { + return NULL; + } + + if (om->om_omp->omp_databuf_len < leading_space) { + rc = os_mbuf_free_chain(om); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); + return NULL; + } + + om->om_data += leading_space; + + return om; +} + +/** + * Allocates an mbuf with no leading space. + * + * @return An empty mbuf on success; null on memory + * exhaustion. + */ +struct os_mbuf * +ble_hs_mbuf_bare_pkt(void) +{ + return ble_hs_mbuf_gen_pkt(0); +} + +/** + * Allocates an mbuf suitable for an HCI ACM data packet. + * + * @return An empty mbuf on success; null on memory + * exhaustion. + */ +struct os_mbuf * +ble_hs_mbuf_acm_pkt(void) +{ + return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ); +} + +/** + * Allocates an mbuf suitable for an L2CAP data packet. The resulting packet + * has sufficient leading space for: + * o ACM data header + * o L2CAP B-frame header + * + * @return An empty mbuf on success; null on memory + * exhaustion. + */ +struct os_mbuf * +ble_hs_mbuf_l2cap_pkt(void) +{ + return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + BLE_L2CAP_HDR_SZ); +} + +/** + * Allocates an mbuf suitable for an ATT command packet. The resulting packet + * has sufficient leading space for: + * o ACM data header + * o L2CAP B-frame header + * o Largest ATT command base (prepare write request / response). + * + * @return An empty mbuf on success; null on memory + * exhaustion. + */ +struct os_mbuf * +ble_hs_mbuf_att_pkt(void) +{ + /* Prepare write request and response are the larget ATT commands which + * contain attribute data. + */ + return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + + BLE_L2CAP_HDR_SZ + + BLE_ATT_PREP_WRITE_CMD_BASE_SZ); +} + +/** + * Allocates a an mbuf and fills it with the contents of the specified flat + * buffer. + * + * @param buf The flat buffer to copy from. + * @param len The length of the flat buffer. + * + * @return A newly-allocated mbuf on success; + * NULL on memory exhaustion. + */ +struct os_mbuf * +ble_hs_mbuf_from_flat(const void *buf, uint16_t len) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_mbuf_att_pkt(); + if (om == NULL) { + return NULL; + } + + rc = os_mbuf_copyinto(om, 0, buf, len); + if (rc != 0) { + os_mbuf_free_chain(om); + return NULL; + } + + return om; +} + +/** + * Copies the contents of an mbuf into the specified flat buffer. If the flat + * buffer is too small to contain the mbuf's contents, it is filled to capacity + * and BLE_HS_EMSGSIZE is returned. + * + * @param om The mbuf to copy from. + * @param flat The destination flat buffer. + * @param max_len The size of the flat buffer. + * @param out_copy_len The number of bytes actually copied gets + * written here. + * + * @return 0 on success; + * BLE_HS_EMSGSIZE if the flat buffer is too small + * to contain the mbuf's contents; + * A BLE host core return code on unexpected + * error. + */ +int +ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len, + uint16_t *out_copy_len) +{ + uint16_t copy_len; + int rc; + + if (OS_MBUF_PKTLEN(om) <= max_len) { + copy_len = OS_MBUF_PKTLEN(om); + } else { + copy_len = max_len; + } + + rc = os_mbuf_copydata(om, 0, copy_len, flat); + if (rc != 0) { + return BLE_HS_EUNKNOWN; + } + + if (copy_len > max_len) { + rc = BLE_HS_EMSGSIZE; + } else { + rc = 0; + } + + if (out_copy_len != NULL) { + *out_copy_len = copy_len; + } + return rc; +} + +int +ble_hs_mbuf_pullup_base(struct os_mbuf **om, int base_len) +{ + if (OS_MBUF_PKTLEN(*om) < base_len) { + return BLE_HS_EBADDATA; + } + + *om = os_mbuf_pullup(*om, base_len); + if (*om == NULL) { + return BLE_HS_ENOMEM; + } + + return 0; +} diff --git a/net/nimble/host/src/ble_hs_mbuf_priv.h b/net/nimble/host/src/ble_hs_mbuf_priv.h new file mode 100644 index 00000000..f0ea9b52 --- /dev/null +++ b/net/nimble/host/src/ble_hs_mbuf_priv.h @@ -0,0 +1,11 @@ +#ifndef H_BLE_HS_MBUF_PRIV_ +#define H_BLE_HS_MBUF_PRIV_ + +struct os_mbuf; + +struct os_mbuf *ble_hs_mbuf_bare_pkt(void); +struct os_mbuf *ble_hs_mbuf_acm_pkt(void); +struct os_mbuf *ble_hs_mbuf_l2cap_pkt(void); +int ble_hs_mbuf_pullup_base(struct os_mbuf **om, int base_len); + +#endif diff --git a/net/nimble/host/src/ble_hs_misc.c b/net/nimble/host/src/ble_hs_misc.c index 9575ae39..649fc05e 100644 --- a/net/nimble/host/src/ble_hs_misc.c +++ b/net/nimble/host/src/ble_hs_misc.c @@ -23,6 +23,8 @@ #include "console/console.h" #include "ble_hs_priv.h" +const uint8_t ble_hs_misc_null_addr[6]; + int ble_hs_misc_malloc_mempool(void **mem, struct os_mempool *pool, int num_entries, int entry_size, char *name) @@ -43,71 +45,6 @@ ble_hs_misc_malloc_mempool(void **mem, struct os_mempool *pool, return 0; } -void -ble_hs_misc_log_mbuf(struct os_mbuf *om) -{ - uint8_t u8; - int i; - - for (i = 0; i < OS_MBUF_PKTLEN(om); i++) { - os_mbuf_copydata(om, i, 1, &u8); - BLE_HS_LOG(DEBUG, "0x%02x ", u8); - } -} - -void -ble_hs_misc_log_flat_buf(void *data, int len) -{ - uint8_t *u8ptr; - int i; - - u8ptr = data; - for (i = 0; i < len; i++) { - BLE_HS_LOG(DEBUG, "0x%02x ", u8ptr[i]); - } -} - -/** - * Allocates an mbuf for use by the nimble host. - */ -struct os_mbuf * -ble_hs_misc_pkthdr(void) -{ - struct os_mbuf *om; - int rc; - - om = os_msys_get_pkthdr(0, 0); - if (om == NULL) { - return NULL; - } - - /* Make room in the buffer for various headers. XXX Check this number. */ - if (om->om_omp->omp_databuf_len < 8) { - rc = os_mbuf_free_chain(om); - BLE_HS_DBG_ASSERT_EVAL(rc == 0); - return NULL; - } - - om->om_data += 8; - - return om; -} - -int -ble_hs_misc_pullup_base(struct os_mbuf **om, int base_len) -{ - if (OS_MBUF_PKTLEN(*om) < base_len) { - return BLE_HS_EBADDATA; - } - - *om = os_mbuf_pullup(*om, base_len); - if (*om == NULL) { - return BLE_HS_ENOMEM; - } - - return 0; -} - int ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid, struct ble_hs_conn **out_conn, @@ -140,7 +77,7 @@ ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid, return rc; } -int +void ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid, struct ble_hs_conn **out_conn, struct ble_l2cap_chan **out_chan) @@ -150,7 +87,7 @@ ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid, int rc; rc = ble_hs_misc_conn_chan_find(conn_handle, cid, &conn, &chan); - BLE_HS_DBG_ASSERT(conn == NULL || chan != NULL); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); if (out_conn != NULL) { *out_conn = conn; @@ -158,8 +95,6 @@ ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid, if (out_chan != NULL) { *out_chan = chan; } - - return rc; } uint8_t diff --git a/net/nimble/host/src/ble_hs_priv.h b/net/nimble/host/src/ble_hs_priv.h index 1be119a1..6bebec9c 100644 --- a/net/nimble/host/src/ble_hs_priv.h +++ b/net/nimble/host/src/ble_hs_priv.h @@ -26,25 +26,37 @@ #include "ble_att_priv.h" #include "ble_gap_priv.h" #include "ble_gatt_priv.h" -#include "ble_hci_util_priv.h" -#include "ble_hs_adv_priv.h" +#include "ble_hs_dbg_priv.h" +#include "ble_hs_hci_priv.h" #include "ble_hs_atomic_priv.h" #include "ble_hs_conn_priv.h" +#include "ble_hs_atomic_priv.h" #include "ble_hs_endian_priv.h" +#include "ble_hs_mbuf_priv.h" #include "ble_hs_startup_priv.h" #include "ble_l2cap_priv.h" #include "ble_l2cap_sig_priv.h" #include "ble_sm_priv.h" +#include "ble_hs_adv_priv.h" +#include "ble_hs_pvcy_priv.h" +#include "ble_hs_id_priv.h" +#include "ble_uuid_priv.h" #include "host/ble_hs.h" -#include "log/log.h" #include "nimble/nimble_opt.h" #include "stats/stats.h" struct ble_hs_conn; struct ble_l2cap_chan; struct os_mbuf; struct os_mempool; +struct os_event; #define BLE_HOST_HCI_EVENT_CTLR_EVENT (OS_EVENT_T_PERUSER + 0) +#define BLE_HS_EVENT_TX_NOTIFICATIONS (OS_EVENT_T_PERUSER + 1) +#define BLE_HS_EVENT_RESET (OS_EVENT_T_PERUSER + 2) + +#define BLE_HS_SYNC_STATE_BAD 0 +#define BLE_HS_SYNC_STATE_BRINGUP 1 +#define BLE_HS_SYNC_STATE_GOOD 2 STATS_SECT_START(ble_hs_stats) STATS_SECT_ENTRY(conn_create) @@ -53,38 +65,35 @@ STATS_SECT_START(ble_hs_stats) STATS_SECT_ENTRY(hci_event) STATS_SECT_ENTRY(hci_invalid_ack) STATS_SECT_ENTRY(hci_unknown_event) + STATS_SECT_ENTRY(hci_timeout) + STATS_SECT_ENTRY(reset) + STATS_SECT_ENTRY(sync) STATS_SECT_END extern STATS_SECT_DECL(ble_hs_stats) ble_hs_stats; -struct ble_hci_ack { - int bha_status; /* A BLE_HS_E<...> error; NOT a naked HCI code. */ - uint8_t *bha_params; - int bha_params_len; - uint16_t bha_opcode; - uint8_t bha_hci_handle; -}; - -extern struct ble_hs_dev ble_hs_our_dev; extern struct ble_hs_cfg ble_hs_cfg; - extern struct os_mbuf_pool ble_hs_mbuf_pool; +extern uint8_t ble_hs_sync_state; -extern struct log ble_hs_log; +extern const uint8_t ble_hs_misc_null_addr[6]; void ble_hs_process_tx_data_queue(void); -int ble_hs_rx_data(struct os_mbuf *om); +void ble_hs_process_rx_data_queue(void); int ble_hs_tx_data(struct os_mbuf *om); +void ble_hs_enqueue_hci_event(uint8_t *hci_evt); +void ble_hs_event_enqueue(struct os_event *ev); + +int ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg); +int ble_hs_hci_evt_acl_process(struct os_mbuf *om); int ble_hs_misc_malloc_mempool(void **mem, struct os_mempool *pool, int num_entries, int entry_size, char *name); -void ble_hs_misc_log_mbuf(struct os_mbuf *om); -void ble_hs_misc_log_flat_buf(void *data, int len); int ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid, struct ble_hs_conn **out_conn, struct ble_l2cap_chan **out_chan); -int ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid, - struct ble_hs_conn **out_conn, - struct ble_l2cap_chan **out_chan); +void ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid, + struct ble_hs_conn **out_conn, + struct ble_l2cap_chan **out_chan); uint8_t ble_hs_misc_addr_type_to_id(uint8_t addr_type); void ble_hs_cfg_init(struct ble_hs_cfg *cfg); @@ -93,37 +102,10 @@ int ble_hs_locked_by_cur_task(void); int ble_hs_is_parent_task(void); void ble_hs_lock(void); void ble_hs_unlock(void); - -struct os_mbuf *ble_hs_misc_pkthdr(void); - -int ble_hs_misc_pullup_base(struct os_mbuf **om, int base_len); - -int ble_hci_cmd_tx(void *cmd, void *evt_buf, uint8_t evt_buf_len, - uint8_t *out_evt_buf_len); -int ble_hci_cmd_tx_empty_ack(void *cmd); -void ble_hci_cmd_rx_ack(uint8_t *ack_ev); -void ble_hci_cmd_init(void); -int ble_hs_pvcy_set_our_nrpa(void); -void ble_hs_pvcy_our_nrpa(uint8_t *addr); -void ble_hs_pvcy_set_our_id_addr(uint8_t *addr); -void ble_hs_pvcy_set_our_irk(uint8_t *irk); -uint8_t *ble_hs_pvcy_our_id_addr(uint8_t *type); -uint8_t *ble_hs_pvcy_our_irk(void); -int ble_hs_pvcy_remove_entry(uint8_t addr_type, uint8_t *addr); -int ble_hs_pvcy_add_entry(uint8_t *addr, uint8_t addrtype, uint8_t *irk); -#if PHONY_HCI_ACKS -typedef int ble_hci_cmd_phony_ack_fn(uint8_t *ack, int ack_buf_len); - -void ble_hci_set_phony_ack_cb(ble_hci_cmd_phony_ack_fn *cb); -#endif - -#define BLE_HS_LOG(lvl, ...) \ - LOG_ ## lvl(&ble_hs_log, LOG_MODULE_NIMBLE_HOST, __VA_ARGS__) - -#define BLE_HS_LOG_ADDR(lvl, addr) \ - BLE_HS_LOG(lvl, "%02x:%02x:%02x:%02x:%02x:%02x", \ - (addr)[5], (addr)[4], (addr)[3], \ - (addr)[2], (addr)[1], (addr)[0]) +void ble_hs_sched_reset(int reason); +void ble_hs_hw_error(uint8_t hw_code); +void ble_hs_heartbeat_sched(int32_t ticks); +void ble_hs_notifications_sched(void); #if LOG_LEVEL <= LOG_LEVEL_DEBUG diff --git a/net/nimble/host/src/ble_hs_pvcy.c b/net/nimble/host/src/ble_hs_pvcy.c index 1ea2f918..ad3fa0c3 100644 --- a/net/nimble/host/src/ble_hs_pvcy.c +++ b/net/nimble/host/src/ble_hs_pvcy.c @@ -21,13 +21,9 @@ #include <string.h> #include "ble_hs_priv.h" -static int ble_hs_pvcy_initialized; -static uint8_t ble_hs_pvcy_id_addr[6]; -static uint8_t ble_hs_pvcy_id_addr_type; -static uint8_t ble_hs_pvcy_nrpa[6]; +static uint8_t ble_hs_pvcy_started; uint8_t ble_hs_pvcy_irk[16]; - /** Use this as a default IRK if none gets set. */ const uint8_t default_irk[16] = { 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, @@ -35,24 +31,12 @@ const uint8_t default_irk[16] = { }; static int -ble_hs_pvcy_gen_static_random_addr(uint8_t *addr) -{ - int rc; - - rc = ble_hci_util_rand(addr, 6); - /* TODO -- set bits properly */ - addr[5] |= 0xc0; - - return rc; -} - -static int ble_hs_pvcy_set_addr_timeout(uint16_t timeout) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN]; int rc; - rc = host_hci_cmd_build_set_resolv_priv_addr_timeout( + rc = ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout( timeout, buf, sizeof(buf)); return rc; @@ -64,12 +48,12 @@ ble_hs_pvcy_set_resolve_enabled(int enable) uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADDR_RESOL_ENA_LEN]; int rc; - rc = host_hci_cmd_build_set_addr_res_en(enable, buf, sizeof(buf)); + rc = ble_hs_hci_cmd_build_set_addr_res_en(enable, buf, sizeof(buf)); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx(buf, NULL, 0, NULL); + rc = ble_hs_hci_cmd_tx(buf, NULL, 0, NULL); if (rc != 0) { return rc; } @@ -83,13 +67,13 @@ ble_hs_pvcy_remove_entry(uint8_t addr_type, uint8_t *addr) uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_RMV_FROM_RESOLV_LIST_LEN]; int rc; - rc = host_hci_cmd_build_remove_from_resolv_list( + rc = ble_hs_hci_cmd_build_remove_from_resolv_list( addr_type, addr, buf, sizeof(buf)); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx(buf, NULL, 0, NULL); + rc = ble_hs_hci_cmd_tx(buf, NULL, 0, NULL); if (rc != 0) { return rc; } @@ -103,12 +87,12 @@ ble_hs_pvcy_clear_entries(void) uint8_t buf[BLE_HCI_CMD_HDR_LEN ]; int rc; - rc = host_hci_cmd_build_clear_resolv_list(buf, sizeof(buf)); + rc = ble_hs_hci_cmd_build_clear_resolv_list(buf, sizeof(buf)); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx(buf, NULL, 0, NULL); + rc = ble_hs_hci_cmd_tx(buf, NULL, 0, NULL); if (rc != 0) { return rc; } @@ -125,15 +109,15 @@ ble_hs_pvcy_add_entry(uint8_t *addr, uint8_t addr_type, uint8_t *irk) add.addr_type = addr_type; memcpy(add.addr, addr, 6); - memcpy(add.local_irk, ble_hs_pvcy_our_irk(), 16); + memcpy(add.local_irk, ble_hs_pvcy_irk, 16); memcpy(add.peer_irk, irk, 16); - rc = host_hci_cmd_build_add_to_resolv_list(&add, buf, sizeof(buf)); + rc = ble_hs_hci_cmd_build_add_to_resolv_list(&add, buf, sizeof(buf)); if (rc != 0) { return rc; } - rc = ble_hci_cmd_tx(buf, NULL, 0, NULL); + rc = ble_hs_hci_cmd_tx(buf, NULL, 0, NULL); if (rc != 0) { return rc; } @@ -141,73 +125,32 @@ ble_hs_pvcy_add_entry(uint8_t *addr, uint8_t addr_type, uint8_t *irk) return 0; } -void -ble_hs_pvcy_our_nrpa(uint8_t *addr) -{ - memcpy(addr, ble_hs_pvcy_nrpa, 6); -} - -int -ble_hs_pvcy_set_our_nrpa(void) +int +ble_hs_pvcy_ensure_started(void) { int rc; - uint8_t addr[6]; - - rc = ble_hci_util_rand(addr, 6); - assert(rc == 0); - addr[5] &= ~(0xc0); - memcpy(ble_hs_pvcy_nrpa, addr, 6); - - return ble_hs_util_set_random_addr(addr); -} -uint8_t * -ble_hs_pvcy_our_id_addr(uint8_t *type) -{ - if (!ble_hs_pvcy_initialized) { - ble_hs_pvcy_set_our_id_addr(NULL); + if (ble_hs_pvcy_started) { + return 0; } - if (type != NULL) { - *type = ble_hs_pvcy_id_addr_type; - } - - return ble_hs_pvcy_id_addr; -} - -void -ble_hs_pvcy_set_our_id_addr(uint8_t *addr) -{ - uint8_t random_addr[6]; - int rc; - - if (!ble_hs_pvcy_initialized) { - /* Set up the periodic change of our RPA. */ - rc = ble_hs_pvcy_set_addr_timeout(ble_hs_cfg.rpa_timeout); - assert(rc == 0); + /* Set up the periodic change of our RPA. */ + rc = ble_hs_pvcy_set_addr_timeout(ble_hs_cfg.rpa_timeout); + if (rc != 0) { + return rc; } - if (addr != NULL) { - memcpy(ble_hs_pvcy_id_addr, addr, 6); - ble_hs_pvcy_id_addr_type = BLE_HCI_ADV_OWN_ADDR_PUBLIC; - } else { - /* Generate a new static random address. */ - ble_hs_pvcy_gen_static_random_addr(random_addr); - rc = ble_hs_util_set_random_addr(random_addr); - assert(rc == 0); + ble_hs_pvcy_started = 1; - ble_hs_pvcy_id_addr_type = BLE_HCI_ADV_OWN_ADDR_RANDOM; - memcpy(ble_hs_pvcy_id_addr, random_addr, 6); - } - - ble_hs_pvcy_initialized = 1; + return 0; } -void -ble_hs_pvcy_set_our_irk(uint8_t *irk) +int +ble_hs_pvcy_set_our_irk(const uint8_t *irk) { uint8_t tmp_addr[6]; uint8_t new_irk[16]; + int rc; memset(new_irk, 0, sizeof(new_irk)); @@ -221,25 +164,40 @@ ble_hs_pvcy_set_our_irk(uint8_t *irk) if (memcmp(ble_hs_pvcy_irk, new_irk, 16) != 0) { memcpy(ble_hs_pvcy_irk, new_irk, 16); - ble_hs_pvcy_set_resolve_enabled(0); - ble_hs_pvcy_clear_entries(); - ble_hs_pvcy_set_resolve_enabled(1); + rc = ble_hs_pvcy_set_resolve_enabled(0); + if (rc != 0) { + return rc; + } + + rc = ble_hs_pvcy_clear_entries(); + if (rc != 0) { + return rc; + } - /* Push our identity to the controller as a keycache entry with a null - * MAC address. The controller uses this entry to generate an RPA when - * we do advertising with own-addr-type = rpa. + rc = ble_hs_pvcy_set_resolve_enabled(1); + if (rc != 0) { + return rc; + } + + /* Push a null address identity to the controller. The controller uses + * this entry to generate an RPA when we do advertising with + * own-addr-type = rpa. */ memset(tmp_addr, 0, 6); - ble_hs_pvcy_add_entry(tmp_addr, 0, ble_hs_pvcy_irk); + rc = ble_hs_pvcy_add_entry(tmp_addr, 0, ble_hs_pvcy_irk); + if (rc != 0) { + return rc; + } } + + return 0; } -uint8_t * -ble_hs_pvcy_our_irk(void) +int +ble_hs_pvcy_our_irk(const uint8_t **out_irk) { - if (!ble_hs_pvcy_initialized) { - ble_hs_pvcy_set_our_id_addr(NULL); - } + /* XXX: Return error if privacy not supported. */ - return ble_hs_pvcy_irk; + *out_irk = ble_hs_pvcy_irk; + return 0; } diff --git a/net/nimble/host/src/ble_hs_pvcy_priv.h b/net/nimble/host/src/ble_hs_pvcy_priv.h new file mode 100644 index 00000000..16ded359 --- /dev/null +++ b/net/nimble/host/src/ble_hs_pvcy_priv.h @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_HS_PVCY_PRIV_ +#define H_BLE_HS_PVCY_PRIV_ + +#include <inttypes.h> + +int ble_hs_pvcy_set_our_irk(const uint8_t *irk); +int ble_hs_pvcy_our_irk(const uint8_t **out_irk); +int ble_hs_pvcy_remove_entry(uint8_t addr_type, uint8_t *addr); +int ble_hs_pvcy_add_entry(uint8_t *addr, uint8_t addrtype, uint8_t *irk); +int ble_hs_pvcy_ensure_started(void); + +#endif diff --git a/net/nimble/host/src/ble_hs_startup.c b/net/nimble/host/src/ble_hs_startup.c index 1973cf9a..89cbd700 100644 --- a/net/nimble/host/src/ble_hs_startup.c +++ b/net/nimble/host/src/ble_hs_startup.c @@ -19,7 +19,6 @@ #include <stddef.h> #include <string.h> -#include "host/host_hci.h" #include "host/ble_hs.h" #include "ble_hs_priv.h" @@ -31,8 +30,9 @@ ble_hs_startup_le_read_sup_f_tx(void) uint8_t ack_params_len; int rc; - host_hci_cmd_build_le_read_loc_supp_feat(buf, sizeof buf); - rc = ble_hci_cmd_tx(buf, ack_params, sizeof ack_params, &ack_params_len); + ble_hs_hci_cmd_build_le_read_loc_supp_feat(buf, sizeof buf); + rc = ble_hs_hci_cmd_tx(buf, ack_params, sizeof ack_params, + &ack_params_len); if (rc != 0) { return rc; } @@ -56,8 +56,9 @@ ble_hs_startup_le_read_buf_sz_tx(void) uint8_t max_pkts; int rc; - host_hci_cmd_build_le_read_buffer_size(buf, sizeof buf); - rc = ble_hci_cmd_tx(buf, ack_params, sizeof ack_params, &ack_params_len); + ble_hs_hci_cmd_build_le_read_buffer_size(buf, sizeof buf); + rc = ble_hs_hci_cmd_tx(buf, ack_params, sizeof ack_params, + &ack_params_len); if (rc != 0) { return rc; } @@ -69,7 +70,7 @@ ble_hs_startup_le_read_buf_sz_tx(void) pktlen = le16toh(ack_params + 0); max_pkts = ack_params[2]; - rc = host_hci_set_buf_size(pktlen, max_pkts); + rc = ble_hs_hci_set_buf_sz(pktlen, max_pkts); if (rc != 0) { return rc; } @@ -78,6 +79,29 @@ ble_hs_startup_le_read_buf_sz_tx(void) } static int +ble_hs_startup_read_bd_addr(void) +{ + uint8_t ack_params[BLE_HCI_IP_RD_BD_ADDR_ACK_PARAM_LEN]; + uint8_t buf[BLE_HCI_CMD_HDR_LEN]; + uint8_t ack_params_len; + int rc; + + ble_hs_hci_cmd_build_read_bd_addr(buf, sizeof buf); + rc = ble_hs_hci_cmd_tx(buf, ack_params, sizeof ack_params, + &ack_params_len); + if (rc != 0) { + return rc; + } + + if (ack_params_len != sizeof ack_params) { + return BLE_HS_ECONTROLLER; + } + + ble_hs_id_set_pub(ack_params); + return 0; +} + +static int ble_hs_startup_le_set_evmask_tx(void) { uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_LE_EVENT_MASK_LEN]; @@ -94,8 +118,9 @@ ble_hs_startup_le_set_evmask_tx(void) * 0x0000000000000040 LE Data Length Change Event * 0x0000000000000200 LE Enhanced Connection Complete Event */ - host_hci_cmd_build_le_set_event_mask(0x000000000000027f, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_le_set_event_mask(0x000000000000027f, + buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -151,8 +176,8 @@ ble_hs_startup_set_evmask_tx(void) * 0x0000800000000000 Encryption Key Refresh Complete Event * 0x2000000000000000 LE Meta-Event */ - host_hci_cmd_build_set_event_mask(0x20009fffffffffff, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_set_event_mask(0x20009fffffffffff, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -161,8 +186,8 @@ ble_hs_startup_set_evmask_tx(void) * Enable the following events: * 0x0000000000800000 Authenticated Payload Timeout Event */ - host_hci_cmd_build_set_event_mask2(0x0000000000800000, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_set_event_mask2(0x0000000000800000, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -176,8 +201,8 @@ ble_hs_startup_reset_tx(void) uint8_t buf[BLE_HCI_CMD_HDR_LEN]; int rc; - host_hci_cmd_build_reset(buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_reset(buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -200,19 +225,16 @@ ble_hs_startup_go(void) rc = ble_hs_startup_set_evmask_tx(); if (rc != 0) { - assert(0); return rc; } rc = ble_hs_startup_le_set_evmask_tx(); if (rc != 0) { - assert(0); return rc; } rc = ble_hs_startup_le_read_buf_sz_tx(); if (rc != 0) { - assert(0); return rc; } @@ -220,13 +242,15 @@ ble_hs_startup_go(void) rc = ble_hs_startup_le_read_sup_f_tx(); if (rc != 0) { - assert(0); return rc; } - /* XXX: Read BD_ADDR. */ - ble_hs_pvcy_set_our_id_addr(g_dev_addr); + rc = ble_hs_startup_read_bd_addr(); + if (rc != 0) { + return rc; + } + ble_hs_pvcy_set_our_irk(NULL); - return rc; + return 0; } diff --git a/net/nimble/host/src/ble_ibeacon.c b/net/nimble/host/src/ble_ibeacon.c index db34dfbd..5bdb99d7 100644 --- a/net/nimble/host/src/ble_ibeacon.c +++ b/net/nimble/host/src/ble_ibeacon.c @@ -18,10 +18,24 @@ */ #include <string.h> +#include "host/ble_hs_adv.h" #include "ble_hs_priv.h" #define BLE_IBEACON_MFG_DATA_SIZE 25 +/** + * Configures the device to advertise iBeacons. + * + * @param uuid The 128-bit UUID to advertise. + * @param major The major version number to include in + * iBeacons. + * @param minor The minor version number to include in + * iBeacons. + * + * @return 0 on success; + * BLE_HS_EBUSY if advertising is in progress; + * Other nonzero on failure. + */ int ble_ibeacon_set_adv_data(void *uuid128, uint16_t major, uint16_t minor) { @@ -47,7 +61,7 @@ ble_ibeacon_set_adv_data(void *uuid128, uint16_t major, uint16_t minor) /** Last byte (tx power level) filled in after HCI exchange. */ - rc = ble_hci_util_read_adv_tx_pwr(&tx_pwr); + rc = ble_hs_hci_util_read_adv_tx_pwr(&tx_pwr); if (rc != 0) { return rc; } diff --git a/net/nimble/host/src/ble_l2cap.c b/net/nimble/host/src/ble_l2cap.c index da66bf1b..43ccd6f7 100644 --- a/net/nimble/host/src/ble_l2cap.c +++ b/net/nimble/host/src/ble_l2cap.c @@ -22,7 +22,6 @@ #include "os/os.h" #include "nimble/ble.h" #include "nimble/hci_common.h" -#include "host/host_hci.h" #include "ble_hs_priv.h" _Static_assert(sizeof (struct ble_l2cap_hdr) == BLE_L2CAP_HDR_SZ, @@ -79,7 +78,7 @@ ble_l2cap_chan_free(struct ble_l2cap_chan *chan) } uint16_t -ble_l2cap_chan_mtu(struct ble_l2cap_chan *chan) +ble_l2cap_chan_mtu(const struct ble_l2cap_chan *chan) { uint16_t mtu; @@ -124,7 +123,7 @@ ble_l2cap_prepend_hdr(struct os_mbuf *om, uint16_t cid, uint16_t len) htole16(&hdr.blh_len, len); htole16(&hdr.blh_cid, cid); - om = os_mbuf_prepend(om, sizeof hdr); + om = os_mbuf_prepend_pullup(om, sizeof hdr); if (om == NULL) { return NULL; } @@ -270,33 +269,27 @@ err: * 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. + * @param txom The data to transmit. * * @return 0 on success; nonzero on error. */ int ble_l2cap_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, - struct os_mbuf *om) + struct os_mbuf *txom) { int rc; - om = ble_l2cap_prepend_hdr(om, chan->blc_cid, OS_MBUF_PKTLEN(om)); - if (om == NULL) { - rc = BLE_HS_ENOMEM; - goto err; + txom = ble_l2cap_prepend_hdr(txom, chan->blc_cid, OS_MBUF_PKTLEN(txom)); + if (txom == NULL) { + return BLE_HS_ENOMEM; } - rc = host_hci_data_tx(conn, om); - om = NULL; + rc = ble_hs_hci_acl_tx(conn, txom); if (rc != 0) { - goto err; + return rc; } return 0; - -err: - os_mbuf_free_chain(om); - return rc; } static void diff --git a/net/nimble/host/src/ble_l2cap_priv.h b/net/nimble/host/src/ble_l2cap_priv.h index 9cbf8791..ce19218e 100644 --- a/net/nimble/host/src/ble_l2cap_priv.h +++ b/net/nimble/host/src/ble_l2cap_priv.h @@ -57,8 +57,7 @@ extern struct os_mempool ble_l2cap_chan_pool; typedef uint8_t ble_l2cap_chan_flags; -typedef int ble_l2cap_rx_fn(uint16_t conn_handle, - struct os_mbuf **om); +typedef int ble_l2cap_rx_fn(uint16_t conn_handle, struct os_mbuf **rxom); struct ble_l2cap_chan { SLIST_ENTRY(ble_l2cap_chan) blc_next; @@ -94,7 +93,7 @@ struct os_mbuf *ble_l2cap_prepend_hdr(struct os_mbuf *om, uint16_t cid, struct ble_l2cap_chan *ble_l2cap_chan_alloc(void); void ble_l2cap_chan_free(struct ble_l2cap_chan *chan); -uint16_t ble_l2cap_chan_mtu(struct ble_l2cap_chan *chan); +uint16_t ble_l2cap_chan_mtu(const struct ble_l2cap_chan *chan); int ble_l2cap_rx(struct ble_hs_conn *conn, @@ -103,7 +102,7 @@ int ble_l2cap_rx(struct ble_hs_conn *conn, ble_l2cap_rx_fn **out_rx_cb, struct os_mbuf **out_rx_buf); int ble_l2cap_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, - struct os_mbuf *om); + struct os_mbuf *txom); int ble_l2cap_init(void); diff --git a/net/nimble/host/src/ble_l2cap_sig.c b/net/nimble/host/src/ble_l2cap_sig.c index 93ba2e23..a382b097 100644 --- a/net/nimble/host/src/ble_l2cap_sig.c +++ b/net/nimble/host/src/ble_l2cap_sig.c @@ -300,7 +300,7 @@ ble_l2cap_sig_update_req_rx(uint16_t conn_handle, l2cap_result = 0; /* Silence spurious gcc warning. */ - rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SIG_UPDATE_REQ_SZ); + rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SIG_UPDATE_REQ_SZ); if (rc != 0) { return rc; } @@ -338,18 +338,16 @@ ble_l2cap_sig_update_req_rx(uint16_t conn_handle, /* Send L2CAP response. */ ble_hs_lock(); - rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG, - &conn, &chan); - if (rc == 0) { - if (!sig_err) { - rc = ble_l2cap_sig_update_rsp_tx(conn, chan, hdr->identifier, - l2cap_result); - } else { - ble_l2cap_sig_reject_tx(conn, chan, hdr->identifier, - BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD, - NULL, 0); - rc = BLE_HS_L2C_ERR(BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD); - } + ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG, + &conn, &chan); + if (!sig_err) { + rc = ble_l2cap_sig_update_rsp_tx(conn, chan, hdr->identifier, + l2cap_result); + } else { + ble_l2cap_sig_reject_tx(conn, chan, hdr->identifier, + BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD, + NULL, 0); + rc = BLE_HS_L2C_ERR(BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD); } ble_hs_unlock(); @@ -373,7 +371,7 @@ ble_l2cap_sig_update_rsp_rx(uint16_t conn_handle, return BLE_HS_ENOENT; } - rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SIG_UPDATE_RSP_SZ); + rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SIG_UPDATE_RSP_SZ); if (rc != 0) { cb_status = rc; goto done; @@ -421,11 +419,8 @@ ble_l2cap_sig_update(uint16_t conn_handle, ble_hs_lock(); - rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG, - &conn, &chan); - if (rc != 0) { - goto done; - } + ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG, + &conn, &chan); if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { /* Only the slave can initiate the L2CAP connection update * procedure. @@ -479,10 +474,10 @@ ble_l2cap_sig_rx(uint16_t conn_handle, struct os_mbuf **om) STATS_INC(ble_l2cap_stats, sig_rx); BLE_HS_LOG(DEBUG, "L2CAP - rxed signalling msg: "); - ble_hs_misc_log_mbuf(*om); + ble_hs_log_mbuf(*om); BLE_HS_LOG(DEBUG, "\n"); - rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SIG_HDR_SZ); + rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SIG_HDR_SZ); if (rc != 0) { return rc; } @@ -499,16 +494,12 @@ ble_l2cap_sig_rx(uint16_t conn_handle, struct os_mbuf **om) rx_cb = ble_l2cap_sig_dispatch_get(hdr.op); if (rx_cb == NULL) { ble_hs_lock(); - rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG, - &conn, &chan); - if (rc == 0) { - ble_l2cap_sig_reject_tx(conn, chan, hdr.identifier, - BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD, - NULL, 0); - rc = BLE_HS_L2C_ERR(BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD); - } else { - rc = BLE_HS_ENOTCONN; - } + ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG, + &conn, &chan); + ble_l2cap_sig_reject_tx(conn, chan, hdr.identifier, + BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD, + NULL, 0); + rc = BLE_HS_L2C_ERR(BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD); ble_hs_unlock(); } else { rc = rx_cb(conn_handle, &hdr, om); @@ -582,7 +573,7 @@ ble_l2cap_sig_extract_expired(struct ble_l2cap_sig_proc_list *dst_list) * be called again; currently always * UINT32_MAX. */ -uint32_t +int32_t ble_l2cap_sig_heartbeat(void) { struct ble_l2cap_sig_proc_list temp_list; @@ -596,10 +587,10 @@ ble_l2cap_sig_heartbeat(void) /* Terminate the connection associated with each timed-out procedure. */ STAILQ_FOREACH(proc, &temp_list, next) { STATS_INC(ble_l2cap_stats, proc_timeout); - ble_gap_terminate(proc->conn_handle); + ble_gap_terminate(proc->conn_handle, BLE_ERR_REM_USER_CONN_TERM); } - return UINT32_MAX; + return BLE_HS_FOREVER; } int diff --git a/net/nimble/host/src/ble_l2cap_sig_cmd.c b/net/nimble/host/src/ble_l2cap_sig_cmd.c index a93833c6..d8220322 100644 --- a/net/nimble/host/src/ble_l2cap_sig_cmd.c +++ b/net/nimble/host/src/ble_l2cap_sig_cmd.c @@ -27,18 +27,21 @@ ble_l2cap_sig_init_cmd(uint8_t op, uint8_t id, uint8_t payload_len, struct ble_l2cap_sig_hdr hdr; struct os_mbuf *txom; void *v; + int rc; *out_om = NULL; *out_payload_buf = NULL; - txom = ble_hs_misc_pkthdr(); + txom = ble_hs_mbuf_l2cap_pkt(); if (txom == NULL) { - return BLE_HS_ENOMEM; + rc = BLE_HS_ENOMEM; + goto err; } v = os_mbuf_extend(txom, BLE_L2CAP_SIG_HDR_SZ + payload_len); if (v == NULL) { - return BLE_HS_ENOMEM; + rc = BLE_HS_ENOMEM; + goto err; } hdr.op = op; @@ -51,6 +54,10 @@ ble_l2cap_sig_init_cmd(uint8_t op, uint8_t id, uint8_t payload_len, *out_payload_buf = (uint8_t *)v + BLE_L2CAP_SIG_HDR_SZ; return 0; + +err: + os_mbuf_free(txom); + return rc; } static void @@ -113,6 +120,9 @@ ble_l2cap_sig_reject_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, rc = ble_l2cap_sig_init_cmd(BLE_L2CAP_SIG_OP_REJECT, id, BLE_L2CAP_SIG_REJECT_MIN_SZ + data_len, &txom, &payload_buf); + if (rc != 0) { + return rc; + } cmd.reason = reason; ble_l2cap_sig_reject_write(payload_buf, txom->om_len, &cmd, @@ -120,7 +130,11 @@ ble_l2cap_sig_reject_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, STATS_INC(ble_l2cap_stats, sig_rx); rc = ble_l2cap_tx(conn, chan, txom); - return rc; + if (rc != 0) { + return rc; + } + + return 0; } int diff --git a/net/nimble/host/src/ble_l2cap_sig_priv.h b/net/nimble/host/src/ble_l2cap_sig_priv.h index a561a82a..3477ee13 100644 --- a/net/nimble/host/src/ble_l2cap_sig_priv.h +++ b/net/nimble/host/src/ble_l2cap_sig_priv.h @@ -80,7 +80,7 @@ int ble_l2cap_sig_reject_invalid_cid_tx(struct ble_hs_conn *conn, uint8_t id, uint16_t src_cid, uint16_t dst_cid); -uint32_t ble_l2cap_sig_heartbeat(void); +int32_t ble_l2cap_sig_heartbeat(void); struct ble_l2cap_chan *ble_l2cap_sig_create_chan(void); int ble_l2cap_sig_init(void); diff --git a/net/nimble/host/src/ble_sm.c b/net/nimble/host/src/ble_sm.c index ab411731..8e07cdb0 100644 --- a/net/nimble/host/src/ble_sm.c +++ b/net/nimble/host/src/ble_sm.c @@ -259,7 +259,7 @@ ble_sm_gen_pair_rand(uint8_t *pair_rand) } #endif - rc = ble_hci_util_rand(pair_rand, 16); + rc = ble_hs_hci_util_rand(pair_rand, 16); if (rc != 0) { return rc; } @@ -280,7 +280,7 @@ ble_sm_gen_ediv(uint16_t *ediv) } #endif - rc = ble_hci_util_rand(ediv, sizeof *ediv); + rc = ble_hs_hci_util_rand(ediv, sizeof *ediv); if (rc != 0) { return rc; } @@ -301,7 +301,7 @@ ble_sm_gen_master_id_rand(uint64_t *master_id_rand) } #endif - rc = ble_hci_util_rand(master_id_rand, sizeof *master_id_rand); + rc = ble_hs_hci_util_rand(master_id_rand, sizeof *master_id_rand); if (rc != 0) { return rc; } @@ -323,7 +323,7 @@ ble_sm_gen_ltk(struct ble_sm_proc *proc, uint8_t *ltk) } #endif - rc = ble_hci_util_rand(ltk, 16); + rc = ble_hs_hci_util_rand(ltk, 16); if (rc != 0) { return rc; } @@ -345,7 +345,7 @@ ble_sm_gen_csrk(struct ble_sm_proc *proc, uint8_t *csrk) } #endif - rc = ble_hci_util_rand(csrk, 16); + rc = ble_hs_hci_util_rand(csrk, 16); if (rc != 0) { return rc; } @@ -494,24 +494,7 @@ ble_sm_fill_store_value(uint8_t peer_addr_type, uint8_t *peer_addr, } } -int -ble_sm_peer_addr(struct ble_sm_proc *proc, - uint8_t *out_type, uint8_t **out_addr) -{ - struct ble_hs_conn *conn; - - conn = ble_hs_conn_find(proc->conn_handle); - if (conn == NULL) { - return BLE_HS_ENOTCONN; - } - - *out_type = conn->bhc_addr_type; - *out_addr = conn->bhc_addr; - - return 0; -} - -int +void ble_sm_ia_ra(struct ble_sm_proc *proc, uint8_t *out_iat, uint8_t *out_ia, uint8_t *out_rat, uint8_t *out_ra) @@ -519,10 +502,7 @@ ble_sm_ia_ra(struct ble_sm_proc *proc, struct ble_hs_conn_addrs addrs; struct ble_hs_conn *conn; - conn = ble_hs_conn_find(proc->conn_handle); - if (conn == NULL) { - return BLE_HS_ENOTCONN; - } + conn = ble_hs_conn_find_assert(proc->conn_handle); ble_hs_conn_addrs(conn, &addrs); @@ -539,8 +519,6 @@ ble_sm_ia_ra(struct ble_sm_proc *proc, *out_rat = addrs.our_id_addr_type; memcpy(out_ra, addrs.our_ota_addr, 6); } - - return 0; } static void @@ -562,8 +540,8 @@ ble_sm_persist_keys(struct ble_sm_proc *proc) peer_addr_type = proc->peer_keys.addr_type; memcpy(peer_addr, proc->peer_keys.addr, sizeof peer_addr); } else { - peer_addr_type = ble_hs_misc_addr_type_to_id(conn->bhc_addr_type); - memcpy(peer_addr, conn->bhc_addr, sizeof peer_addr); + peer_addr_type = ble_hs_misc_addr_type_to_id(conn->bhc_peer_addr_type); + memcpy(peer_addr, conn->bhc_peer_addr, sizeof peer_addr); } ble_hs_unlock(); @@ -765,13 +743,16 @@ ble_sm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg) { ble_sm_state_fn *cb; - BLE_HS_DBG_ASSERT(proc->state < BLE_SM_PROC_STATE_CNT); - cb = ble_sm_state_dispatch[proc->state]; - BLE_HS_DBG_ASSERT(cb != NULL); - memset(res, 0, sizeof *res); - cb(proc, res, arg); + if (!ble_hs_conn_exists(proc->conn_handle)) { + res->app_status = BLE_HS_ENOTCONN; + } else { + BLE_HS_DBG_ASSERT(proc->state < BLE_SM_PROC_STATE_CNT); + cb = ble_sm_state_dispatch[proc->state]; + BLE_HS_DBG_ASSERT(cb != NULL); + cb(proc, res, arg); + } } void @@ -824,9 +805,9 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res) } if (res->app_status == 0 && - res->passkey_action.action != BLE_SM_IOACT_NONE) { + res->passkey_params.action != BLE_SM_IOACT_NONE) { - ble_gap_passkey_event(conn_handle, &res->passkey_action); + ble_gap_passkey_event(conn_handle, &res->passkey_params); } /* Persist keys if bonding has successfully completed. */ @@ -875,8 +856,8 @@ ble_sm_start_encrypt_tx(struct hci_start_encrypt *cmd) uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_LE_START_ENCRYPT_LEN]; int rc; - host_hci_cmd_build_le_start_encrypt(cmd, buf, sizeof buf); - rc = ble_hci_cmd_tx_empty_ack(buf); + ble_hs_hci_cmd_build_le_start_encrypt(cmd, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx_empty_ack(buf); if (rc != 0) { return rc; } @@ -1059,9 +1040,9 @@ ble_sm_ltk_req_reply_tx(uint16_t conn_handle, uint8_t *ltk) cmd.conn_handle = conn_handle; memcpy(cmd.long_term_key, ltk, 16); - host_hci_cmd_build_le_lt_key_req_reply(&cmd, buf, sizeof buf); - rc = ble_hci_cmd_tx(buf, &ack_conn_handle, sizeof ack_conn_handle, - &ack_params_len); + ble_hs_hci_cmd_build_le_lt_key_req_reply(&cmd, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx(buf, &ack_conn_handle, sizeof ack_conn_handle, + &ack_params_len); if (rc != 0) { return rc; } @@ -1085,9 +1066,9 @@ ble_sm_ltk_req_neg_reply_tx(uint16_t conn_handle) uint8_t ack_params_len; int rc; - host_hci_cmd_build_le_lt_key_req_neg_reply(conn_handle, buf, sizeof buf); - rc = ble_hci_cmd_tx(buf, &ack_conn_handle, sizeof ack_conn_handle, - &ack_params_len); + ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(conn_handle, buf, sizeof buf); + rc = ble_hs_hci_cmd_tx(buf, &ack_conn_handle, sizeof ack_conn_handle, + &ack_params_len); if (rc != 0) { return rc; } @@ -1208,13 +1189,9 @@ ble_sm_ltk_req_rx(struct hci_le_lt_key_req *evt) } if (restore) { - conn = ble_hs_conn_find(evt->connection_handle); - if (conn == NULL) { - res.app_status = BLE_HS_ENOTCONN; - } else { - ble_hs_conn_addrs(conn, &addrs); - memcpy(peer_id_addr, addrs.peer_id_addr, 6); - } + conn = ble_hs_conn_find_assert(evt->connection_handle); + ble_hs_conn_addrs(conn, &addrs); + memcpy(peer_id_addr, addrs.peer_id_addr, 6); } ble_hs_unlock(); @@ -1285,7 +1262,7 @@ ble_sm_random_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *proc; struct ble_sm_proc *prev; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_RANDOM_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_RANDOM_SZ); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; @@ -1335,7 +1312,7 @@ ble_sm_confirm_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *prev; uint8_t ioact; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CONFIRM_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_CONFIRM_SZ); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; @@ -1466,7 +1443,7 @@ ble_sm_pair_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, ioact = ble_sm_io_action(proc); if (ble_sm_ioact_state(ioact) == proc->state) { - res->passkey_action.action = ioact; + res->passkey_params.action = ioact; } } @@ -1496,7 +1473,7 @@ ble_sm_pair_req_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *prev; struct ble_hs_conn *conn; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CMD_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_CMD_SZ); if (res->app_status != 0) { return; } @@ -1526,11 +1503,8 @@ ble_sm_pair_req_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, proc->pair_req = req; - conn = ble_hs_conn_find(proc->conn_handle); - if (conn == NULL) { - res->sm_err = BLE_SM_ERR_UNSPECIFIED; - res->app_status = BLE_HS_ENOTCONN; - } else if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { + conn = ble_hs_conn_find_assert(proc->conn_handle); + if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); } else if (!ble_sm_pair_cmd_is_valid(&req)) { @@ -1553,7 +1527,7 @@ ble_sm_pair_rsp_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *prev; uint8_t ioact; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CMD_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_CMD_SZ); if (res->app_status != 0) { res->enc_cb = 1; return; @@ -1575,7 +1549,7 @@ ble_sm_pair_rsp_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, proc->state = ble_sm_state_after_pair(proc); ioact = ble_sm_io_action(proc); if (ble_sm_ioact_state(ioact) == proc->state) { - res->passkey_action.action = ioact; + res->passkey_params.action = ioact; } if (ble_sm_proc_can_advance(proc)) { res->execute = 1; @@ -1616,7 +1590,7 @@ ble_sm_sec_req_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_hs_conn *conn; int authreq_mitm; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_SEC_REQ_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_SEC_REQ_SZ); if (res->app_status != 0) { return; } @@ -1630,10 +1604,8 @@ ble_sm_sec_req_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, ble_hs_lock(); - conn = ble_hs_conn_find(conn_handle); - if (conn == NULL) { - res->app_status = BLE_HS_ENOTCONN; - } else if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { + conn = ble_hs_conn_find_assert(conn_handle); + if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; } else { @@ -1703,15 +1675,16 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg) { struct ble_sm_id_addr_info addr_info; + struct ble_hs_conn_addrs addrs; struct ble_sm_sign_info sign_info; struct ble_sm_master_id master_id; struct ble_sm_enc_info enc_info; struct ble_sm_id_info id_info; + struct ble_hs_conn *conn; uint8_t init_key_dist; uint8_t resp_key_dist; uint8_t our_key_dist; - uint8_t *our_id_addr; - uint8_t *irk; + const uint8_t *irk; int rc; ble_sm_key_dist(proc, &init_key_dist, &resp_key_dist); @@ -1754,7 +1727,10 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, if (our_key_dist & BLE_SM_PAIR_KEY_DIST_ID) { /* Send identity information. */ - irk = ble_hs_pvcy_our_irk(); + rc = ble_hs_pvcy_our_irk(&irk); + if (rc != 0) { + goto err; + } memcpy(id_info.irk, irk, 16); @@ -1765,8 +1741,11 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, proc->our_keys.irk_valid = 1; /* Send identity address information. */ - our_id_addr = ble_hs_pvcy_our_id_addr(&addr_info.addr_type); - memcpy(addr_info.bd_addr, our_id_addr, 6); + conn = ble_hs_conn_find_assert(proc->conn_handle); + + ble_hs_conn_addrs(conn, &addrs); + addr_info.addr_type = addrs.our_id_addr_type; + memcpy(addr_info.bd_addr, addrs.our_id_addr, 6); rc = ble_sm_id_addr_info_tx(proc->conn_handle, &addr_info); if (rc != 0) { goto err; @@ -1830,7 +1809,7 @@ ble_sm_enc_info_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *proc; struct ble_sm_proc *prev; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ENC_INFO_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_ENC_INFO_SZ); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; @@ -1866,7 +1845,7 @@ ble_sm_master_id_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *proc; struct ble_sm_proc *prev; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_MASTER_ID_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_MASTER_ID_SZ); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; @@ -1903,7 +1882,7 @@ ble_sm_id_info_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *proc; struct ble_sm_proc *prev; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ID_INFO_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_ID_INFO_SZ); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; @@ -1940,7 +1919,7 @@ ble_sm_id_addr_info_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *proc; struct ble_sm_proc *prev; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ID_ADDR_INFO_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_ID_ADDR_INFO_SZ); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; @@ -1978,7 +1957,7 @@ ble_sm_sign_info_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *proc; struct ble_sm_proc *prev; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_SIGN_INFO_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_SIGN_INFO_SZ); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; @@ -2019,12 +1998,12 @@ ble_sm_fail_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, res->enc_cb = 1; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_FAIL_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_FAIL_SZ); if (res->app_status == 0) { ble_sm_pair_fail_parse((*om)->om_data, (*om)->om_len, &cmd); BLE_SM_LOG_CMD(0, "fail", conn_handle, ble_sm_pair_fail_log, &cmd); - res->app_status = BLE_HS_SM_THEM_ERR(cmd.reason); + res->app_status = BLE_HS_SM_PEER_ERR(cmd.reason); } } @@ -2044,7 +2023,7 @@ ble_sm_fail_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, * be called again; currently always * UINT32_MAX. */ -uint32_t +int32_t ble_sm_heartbeat(void) { struct ble_sm_proc_list exp_list; @@ -2067,7 +2046,7 @@ ble_sm_heartbeat(void) ble_sm_proc_free(proc); } - return UINT32_MAX; + return BLE_HS_FOREVER; } /** @@ -2153,7 +2132,7 @@ ble_sm_slave_initiate(uint16_t conn_handle) * Initiates the encryption procedure for the specified connection. */ int -ble_sm_enc_initiate(uint16_t conn_handle, uint8_t *ltk, uint16_t ediv, +ble_sm_enc_initiate(uint16_t conn_handle, const uint8_t *ltk, uint16_t ediv, uint64_t rand_val, int auth) { struct ble_sm_result res; @@ -2281,17 +2260,12 @@ ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey) switch (pkey->action) { case BLE_SM_IOACT_OOB: - if (pkey->oob == NULL) { - res.app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_OOB); - res.sm_err = BLE_SM_ERR_OOB; - } else { - proc->flags |= BLE_SM_PROC_F_IO_INJECTED; - memcpy(proc->tk, pkey->oob, 16); - if ((proc->flags & BLE_SM_PROC_F_INITIATOR) || - (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) { + proc->flags |= BLE_SM_PROC_F_IO_INJECTED; + memcpy(proc->tk, pkey->oob, 16); + if ((proc->flags & BLE_SM_PROC_F_INITIATOR) || + (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) { - res.execute = 1; - } + res.execute = 1; } break; diff --git a/net/nimble/host/src/ble_sm_alg.c b/net/nimble/host/src/ble_sm_alg.c index 1885d098..66f86dc6 100644 --- a/net/nimble/host/src/ble_sm_alg.c +++ b/net/nimble/host/src/ble_sm_alg.c @@ -40,39 +40,11 @@ static const uint32_t ble_sm_alg_dbg_priv_key[8] = { 0xa3c55f38, 0x3f49f6d4 }; -static const uint8_t ble_sm_alg_dbg_pub_key[64] = { - 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, - 0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef, - 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, - 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20, - 0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74, - 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76, - 0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63, - 0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc -}; - -static const uint8_t ble_sm_alg_dbg_f4[16] = { - 0x2d, 0x87, 0x74, 0xa9, 0xbe, 0xa1, 0xed, 0xf1, - 0x1c, 0xbd, 0xa9, 0x07, 0xf1, 0x16, 0xc9, 0xf2, -}; - -static const uint8_t ble_sm_alg_dbg_f5[32] = { - 0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd, - 0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29, - 0x38, 0x0a, 0x75, 0x94, 0xb5, 0x22, 0x05, 0x98, - 0x23, 0xcd, 0xd7, 0x69, 0x11, 0x79, 0x86, 0x69, -}; - -static const uint8_t ble_sm_alg_dbg_f6[16] = { - 0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2, - 0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3, -}; - static void -ble_sm_alg_log_buf(char *name, uint8_t *buf, int len) +ble_sm_alg_log_buf(const char *name, const uint8_t *buf, int len) { BLE_HS_LOG(DEBUG, " %s=", name); - ble_hs_misc_log_flat_buf(buf, len); + ble_hs_log_flat_buf(buf, len); BLE_HS_LOG(DEBUG, "\n"); } @@ -166,13 +138,13 @@ ble_sm_alg_s1(uint8_t *k, uint8_t *r1, uint8_t *r2, uint8_t *out) } BLE_HS_LOG(DEBUG, "ble_sm_alg_s1()\n k="); - ble_hs_misc_log_flat_buf(k, 16); + ble_hs_log_flat_buf(k, 16); BLE_HS_LOG(DEBUG, "\n r1="); - ble_hs_misc_log_flat_buf(r1, 16); + ble_hs_log_flat_buf(r1, 16); BLE_HS_LOG(DEBUG, "\n r2="); - ble_hs_misc_log_flat_buf(r2, 16); + ble_hs_log_flat_buf(r2, 16); BLE_HS_LOG(DEBUG, "\n out="); - ble_hs_misc_log_flat_buf(out, 16); + ble_hs_log_flat_buf(out, 16); BLE_HS_LOG(DEBUG, "\n"); return 0; @@ -189,18 +161,18 @@ ble_sm_alg_c1(uint8_t *k, uint8_t *r, int rc; BLE_HS_LOG(DEBUG, "ble_sm_alg_c1()\n k="); - ble_hs_misc_log_flat_buf(k, 16); + ble_hs_log_flat_buf(k, 16); BLE_HS_LOG(DEBUG, "\n r="); - ble_hs_misc_log_flat_buf(r, 16); + ble_hs_log_flat_buf(r, 16); BLE_HS_LOG(DEBUG, "\n iat=%d rat=%d", iat, rat); BLE_HS_LOG(DEBUG, "\n ia="); - ble_hs_misc_log_flat_buf(ia, 6); + ble_hs_log_flat_buf(ia, 6); BLE_HS_LOG(DEBUG, "\n ra="); - ble_hs_misc_log_flat_buf(ra, 6); + ble_hs_log_flat_buf(ra, 6); BLE_HS_LOG(DEBUG, "\n preq="); - ble_hs_misc_log_flat_buf(preq, 7); + ble_hs_log_flat_buf(preq, 7); BLE_HS_LOG(DEBUG, "\n pres="); - ble_hs_misc_log_flat_buf(pres, 7); + ble_hs_log_flat_buf(pres, 7); /* pres, preq, rat and iat are concatenated to generate p1 */ p1[0] = iat; @@ -209,7 +181,7 @@ ble_sm_alg_c1(uint8_t *k, uint8_t *r, memcpy(p1 + 9, pres, 7); BLE_HS_LOG(DEBUG, "\n p1="); - ble_hs_misc_log_flat_buf(p1, sizeof p1); + ble_hs_log_flat_buf(p1, sizeof p1); /* c1 = e(k, e(k, r XOR p1) XOR p2) */ @@ -228,7 +200,7 @@ ble_sm_alg_c1(uint8_t *k, uint8_t *r, memset(p2 + 12, 0, 4); BLE_HS_LOG(DEBUG, "\n p2="); - ble_hs_misc_log_flat_buf(p2, sizeof p2); + ble_hs_log_flat_buf(p2, sizeof p2); ble_sm_alg_xor_128(out_enc_data, p2, out_enc_data); @@ -239,7 +211,7 @@ ble_sm_alg_c1(uint8_t *k, uint8_t *r, } BLE_HS_LOG(DEBUG, "\n out_enc_data="); - ble_hs_misc_log_flat_buf(out_enc_data, 16); + ble_hs_log_flat_buf(out_enc_data, 16); rc = 0; @@ -257,11 +229,11 @@ ble_sm_alg_f4(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t z, int rc; BLE_HS_LOG(DEBUG, "ble_sm_alg_f4()\n u="); - ble_hs_misc_log_flat_buf(u, 32); + ble_hs_log_flat_buf(u, 32); BLE_HS_LOG(DEBUG, "\n v="); - ble_hs_misc_log_flat_buf(v, 32); + ble_hs_log_flat_buf(v, 32); BLE_HS_LOG(DEBUG, "\n x="); - ble_hs_misc_log_flat_buf(x, 16); + ble_hs_log_flat_buf(x, 16); BLE_HS_LOG(DEBUG, "\n z=0x%02x\n", z); /* @@ -287,7 +259,7 @@ ble_sm_alg_f4(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t z, swap_in_place(out_enc_data, 16); BLE_HS_LOG(DEBUG, " out_enc_data="); - ble_hs_misc_log_flat_buf(out_enc_data, 16); + ble_hs_log_flat_buf(out_enc_data, 16); BLE_HS_LOG(DEBUG, "\n"); return 0; @@ -362,9 +334,10 @@ ble_sm_alg_f5(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t a1t, } int -ble_sm_alg_f6(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *r, - uint8_t *iocap, uint8_t a1t, uint8_t *a1, - uint8_t a2t, uint8_t *a2, uint8_t *check) +ble_sm_alg_f6(const uint8_t *w, const uint8_t *n1, const uint8_t *n2, + const uint8_t *r, const uint8_t *iocap, uint8_t a1t, + const uint8_t *a1, uint8_t a2t, const uint8_t *a2, + uint8_t *check) { uint8_t ws[16]; uint8_t m[65]; @@ -409,7 +382,8 @@ ble_sm_alg_f6(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *r, } int -ble_sm_alg_g2(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t *y, uint32_t *passkey) +ble_sm_alg_g2(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t *y, + uint32_t *passkey) { uint8_t m[80], xs[16]; int rc; @@ -475,7 +449,7 @@ ble_sm_alg_gen_key_pair(void *pub, uint32_t *priv) int rc; do { - rc = ble_hci_util_rand(random, sizeof random); + rc = ble_hs_hci_util_rand(random, sizeof random); if (rc != 0) { return rc; } diff --git a/net/nimble/host/src/ble_sm_cmd.c b/net/nimble/host/src/ble_sm_cmd.c index 3d506b24..02831374 100644 --- a/net/nimble/host/src/ble_sm_cmd.c +++ b/net/nimble/host/src/ble_sm_cmd.c @@ -38,13 +38,14 @@ ble_sm_tx(uint16_t conn_handle, struct os_mbuf *txom) STATS_INC(ble_l2cap_stats, sm_tx); - rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SM, - &conn, &chan); - if (rc == 0) { - rc = ble_l2cap_tx(conn, chan, txom); + ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SM, + &conn, &chan); + rc = ble_l2cap_tx(conn, chan, txom); + if (rc != 0) { + return rc; } - return rc; + return 0; } static int @@ -53,7 +54,7 @@ ble_sm_init_req(uint16_t initial_sz, struct os_mbuf **out_txom) void *buf; int rc; - *out_txom = ble_hs_misc_pkthdr(); + *out_txom = ble_hs_mbuf_l2cap_pkt(); if (*out_txom == NULL) { rc = BLE_HS_ENOMEM; goto err; @@ -148,8 +149,7 @@ ble_sm_pair_cmd_tx(uint16_t conn_handle, int is_req, rc = ble_sm_init_req(BLE_SM_PAIR_CMD_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } ble_sm_pair_cmd_write(txom->om_data, txom->om_len, is_req, cmd); @@ -158,11 +158,11 @@ ble_sm_pair_cmd_tx(uint16_t conn_handle, int is_req, BLE_HS_DBG_ASSERT(ble_sm_pair_cmd_is_valid(cmd)); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void @@ -204,29 +204,27 @@ ble_sm_pair_confirm_tx(uint16_t conn_handle, struct ble_sm_pair_confirm *cmd) struct os_mbuf *txom; int rc; - rc = ble_sm_init_req(BLE_SM_PAIR_CONFIRM_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } ble_sm_pair_confirm_write(txom->om_data, txom->om_len, cmd); BLE_SM_LOG_CMD(1, "confirm", conn_handle, ble_sm_pair_confirm_log, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void ble_sm_pair_confirm_log(struct ble_sm_pair_confirm *cmd) { BLE_HS_LOG(DEBUG, "value="); - ble_hs_misc_log_flat_buf(cmd->value, sizeof cmd->value); + ble_hs_log_flat_buf(cmd->value, sizeof cmd->value); } void @@ -260,26 +258,25 @@ ble_sm_pair_random_tx(uint16_t conn_handle, struct ble_sm_pair_random *cmd) rc = ble_sm_init_req(BLE_SM_PAIR_RANDOM_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } ble_sm_pair_random_write(txom->om_data, txom->om_len, cmd); BLE_SM_LOG_CMD(1, "random", conn_handle, ble_sm_pair_random_log, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void ble_sm_pair_random_log(struct ble_sm_pair_random *cmd) { BLE_HS_LOG(DEBUG, "value="); - ble_hs_misc_log_flat_buf(cmd->value, sizeof cmd->value); + ble_hs_log_flat_buf(cmd->value, sizeof cmd->value); } void @@ -318,8 +315,7 @@ ble_sm_pair_fail_tx(uint16_t conn_handle, uint8_t reason) rc = ble_sm_init_req(BLE_SM_PAIR_FAIL_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } cmd.reason = reason; @@ -328,11 +324,11 @@ ble_sm_pair_fail_tx(uint16_t conn_handle, uint8_t reason) BLE_SM_LOG_CMD(1, "fail", conn_handle, ble_sm_pair_fail_log, &cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void @@ -368,8 +364,7 @@ ble_sm_enc_info_tx(uint16_t conn_handle, struct ble_sm_enc_info *cmd) rc = ble_sm_init_req(BLE_SM_ENC_INFO_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } ble_sm_enc_info_write(txom->om_data, txom->om_len, cmd); @@ -377,18 +372,18 @@ ble_sm_enc_info_tx(uint16_t conn_handle, struct ble_sm_enc_info *cmd) BLE_SM_LOG_CMD(1, "enc info", conn_handle, ble_sm_enc_info_log, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void ble_sm_enc_info_log(struct ble_sm_enc_info *cmd) { BLE_HS_LOG(DEBUG, "ltk="); - ble_hs_misc_log_flat_buf(cmd->ltk, sizeof cmd->ltk); + ble_hs_log_flat_buf(cmd->ltk, sizeof cmd->ltk); } void @@ -424,8 +419,7 @@ ble_sm_master_id_tx(uint16_t conn_handle, struct ble_sm_master_id *cmd) rc = ble_sm_init_req(BLE_SM_MASTER_ID_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } txom->om_data[0] = BLE_SM_OP_MASTER_ID; @@ -435,11 +429,11 @@ ble_sm_master_id_tx(uint16_t conn_handle, struct ble_sm_master_id *cmd) BLE_SM_LOG_CMD(1, "master id", conn_handle, ble_sm_master_id_log, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void @@ -481,25 +475,24 @@ ble_sm_id_info_tx(uint16_t conn_handle, struct ble_sm_id_info *cmd) rc = ble_sm_init_req(BLE_SM_ID_INFO_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } ble_sm_id_info_write(txom->om_data, txom->om_len, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void ble_sm_id_info_log(struct ble_sm_id_info *cmd) { BLE_HS_LOG(DEBUG, "irk="); - ble_hs_misc_log_flat_buf(cmd->irk, sizeof cmd->irk); + ble_hs_log_flat_buf(cmd->irk, sizeof cmd->irk); } void @@ -537,18 +530,17 @@ ble_sm_id_addr_info_tx(uint16_t conn_handle, struct ble_sm_id_addr_info *cmd) rc = ble_sm_init_req(BLE_SM_ID_ADDR_INFO_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } ble_sm_id_addr_info_write(txom->om_data, txom->om_len, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void @@ -587,25 +579,24 @@ ble_sm_sign_info_tx(uint16_t conn_handle, struct ble_sm_sign_info *cmd) rc = ble_sm_init_req(BLE_SM_SIGN_INFO_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } ble_sm_sign_info_write(txom->om_data, txom->om_len, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void ble_sm_sign_info_log(struct ble_sm_sign_info *cmd) { BLE_HS_LOG(DEBUG, "sig_key="); - ble_hs_misc_log_flat_buf(cmd->sig_key, sizeof cmd->sig_key); + ble_hs_log_flat_buf(cmd->sig_key, sizeof cmd->sig_key); } void @@ -640,8 +631,7 @@ ble_sm_sec_req_tx(uint16_t conn_handle, struct ble_sm_sec_req *cmd) rc = ble_sm_init_req(BLE_SM_SEC_REQ_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } ble_sm_sec_req_write(txom->om_data, txom->om_len, cmd); @@ -649,11 +639,11 @@ ble_sm_sec_req_tx(uint16_t conn_handle, struct ble_sm_sec_req *cmd) BLE_SM_LOG_CMD(1, "sec req", conn_handle, ble_sm_sec_req_log, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void @@ -704,8 +694,7 @@ ble_sm_public_key_tx(uint16_t conn_handle, struct ble_sm_public_key *cmd) rc = ble_sm_init_req(BLE_SM_PUBLIC_KEY_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } rc = ble_sm_public_key_write(txom->om_data, txom->om_len, cmd); @@ -714,20 +703,20 @@ ble_sm_public_key_tx(uint16_t conn_handle, struct ble_sm_public_key *cmd) BLE_SM_LOG_CMD(1, "public key", conn_handle, ble_sm_public_key_log, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void ble_sm_public_key_log(struct ble_sm_public_key *cmd) { BLE_HS_LOG(DEBUG, "x="); - ble_hs_misc_log_flat_buf(cmd->x, sizeof cmd->x); + ble_hs_log_flat_buf(cmd->x, sizeof cmd->x); BLE_HS_LOG(DEBUG, "y="); - ble_hs_misc_log_flat_buf(cmd->y, sizeof cmd->y); + ble_hs_log_flat_buf(cmd->y, sizeof cmd->y); } void @@ -765,8 +754,7 @@ ble_sm_dhkey_check_tx(uint16_t conn_handle, struct ble_sm_dhkey_check *cmd) rc = ble_sm_init_req(BLE_SM_DHKEY_CHECK_SZ, &txom); if (rc != 0) { - rc = BLE_HS_ENOMEM; - goto done; + return BLE_HS_ENOMEM; } rc = ble_sm_dhkey_check_write(txom->om_data, txom->om_len, cmd); @@ -775,18 +763,18 @@ ble_sm_dhkey_check_tx(uint16_t conn_handle, struct ble_sm_dhkey_check *cmd) BLE_SM_LOG_CMD(1, "dhkey check", conn_handle, ble_sm_dhkey_check_log, cmd); rc = ble_sm_tx(conn_handle, txom); - txom = NULL; + if (rc != 0) { + return rc; + } -done: - os_mbuf_free_chain(txom); - return rc; + return 0; } void ble_sm_dhkey_check_log(struct ble_sm_dhkey_check *cmd) { BLE_HS_LOG(DEBUG, "value="); - ble_hs_misc_log_flat_buf(cmd->value, sizeof cmd->value); + ble_hs_log_flat_buf(cmd->value, sizeof cmd->value); } #endif diff --git a/net/nimble/host/src/ble_sm_lgcy.c b/net/nimble/host/src/ble_sm_lgcy.c index d844a6f1..7b1673c7 100644 --- a/net/nimble/host/src/ble_sm_lgcy.c +++ b/net/nimble/host/src/ble_sm_lgcy.c @@ -109,12 +109,7 @@ ble_sm_lgcy_confirm_prepare_args(struct ble_sm_proc *proc, uint8_t *iat, uint8_t *rat, uint8_t *ia, uint8_t *ra) { - int rc; - - rc = ble_sm_ia_ra(proc, iat, ia, rat, ra); - if (rc != 0) { - return rc; - } + ble_sm_ia_ra(proc, iat, ia, rat, ra); memcpy(k, proc->tk, sizeof proc->tk); diff --git a/net/nimble/host/src/ble_sm_priv.h b/net/nimble/host/src/ble_sm_priv.h index 2543514f..d15afbc2 100644 --- a/net/nimble/host/src/ble_sm_priv.h +++ b/net/nimble/host/src/ble_sm_priv.h @@ -276,7 +276,7 @@ struct ble_sm_proc { struct ble_sm_result { int app_status; uint8_t sm_err; - struct ble_gap_passkey_action passkey_action; + struct ble_gap_passkey_params passkey_params; void *state_arg; unsigned execute:1; unsigned enc_cb:1; @@ -386,9 +386,10 @@ int ble_sm_alg_g2(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t *y, int ble_sm_alg_f5(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t a1t, uint8_t *a1, uint8_t a2t, uint8_t *a2, uint8_t *mackey, uint8_t *ltk); -int ble_sm_alg_f6(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *r, - uint8_t *iocap, uint8_t a1t, uint8_t *a1, - uint8_t a2t, uint8_t *a2, uint8_t *check); +int ble_sm_alg_f6(const uint8_t *w, const uint8_t *n1, const uint8_t *n2, + const uint8_t *r, const uint8_t *iocap, uint8_t a1t, + const uint8_t *a1, uint8_t a2t, const uint8_t *a2, + uint8_t *check); int ble_sm_alg_gen_dhkey(uint8_t *peer_pub_key_x, uint8_t *peer_pub_key_y, uint32_t *our_priv_key, void *out_dhkey); int ble_sm_alg_gen_key_pair(void *pub, uint32_t *priv); @@ -416,11 +417,12 @@ void ble_sm_sc_public_key_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg); void ble_sm_sc_public_key_rx(uint16_t conn_handle, uint8_t op, - struct os_mbuf **om, struct ble_sm_result *res); + struct os_mbuf **rxom, struct ble_sm_result *res); void ble_sm_sc_dhkey_check_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg); void ble_sm_sc_dhkey_check_rx(uint16_t conn_handle, uint8_t op, - struct os_mbuf **om, struct ble_sm_result *res); + struct os_mbuf **rxom, + struct ble_sm_result *res); void ble_sm_sc_init(void); #else #define ble_sm_sc_io_action(proc) (BLE_SM_IOACT_NONE) @@ -446,17 +448,15 @@ int ble_sm_ioact_state(uint8_t action); int ble_sm_proc_can_advance(struct ble_sm_proc *proc); void ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res); void ble_sm_confirm_advance(struct ble_sm_proc *proc); -int ble_sm_peer_addr(struct ble_sm_proc *proc, - uint8_t *out_type, uint8_t **out_addr); -int ble_sm_ia_ra(struct ble_sm_proc *proc, - uint8_t *out_iat, uint8_t *out_ia, - uint8_t *out_rat, uint8_t *out_ra); +void ble_sm_ia_ra(struct ble_sm_proc *proc, + uint8_t *out_iat, uint8_t *out_ia, + uint8_t *out_rat, uint8_t *out_ra); -uint32_t ble_sm_heartbeat(void); +int32_t ble_sm_heartbeat(void); void ble_sm_connection_broken(uint16_t conn_handle); int ble_sm_pair_initiate(uint16_t conn_handle); int ble_sm_slave_initiate(uint16_t conn_handle); -int ble_sm_enc_initiate(uint16_t conn_handle, uint8_t *ltk, +int ble_sm_enc_initiate(uint16_t conn_handle, const uint8_t *ltk, uint16_t ediv, uint64_t rand_val, int auth); int ble_sm_init(void); @@ -471,7 +471,7 @@ int ble_sm_init(void); #define ble_sm_ltk_req_rx(evt) ((void)(evt)) #define ble_sm_enc_key_refresh_rx(evt) ((void)(evt)) -#define ble_sm_heartbeat() UINT32_MAX +#define ble_sm_heartbeat() BLE_HS_FOREVER #define ble_sm_connection_broken(conn_handle) #define ble_sm_pair_initiate(conn_handle) BLE_HS_ENOTSUP #define ble_sm_slave_initiate(conn_handle) BLE_HS_ENOTSUP diff --git a/net/nimble/host/src/ble_sm_sc.c b/net/nimble/host/src/ble_sm_sc.c index fc568044..e82ba72f 100644 --- a/net/nimble/host/src/ble_sm_sc.c +++ b/net/nimble/host/src/ble_sm_sc.c @@ -153,10 +153,10 @@ ble_sm_sc_ensure_keys_generated(void) } BLE_HS_LOG(DEBUG, "our pubkey="); - ble_hs_misc_log_flat_buf(&ble_sm_sc_pub_key, 64); + ble_hs_log_flat_buf(&ble_sm_sc_pub_key, 64); BLE_HS_LOG(DEBUG, "\n"); BLE_HS_LOG(DEBUG, "our privkey="); - ble_hs_misc_log_flat_buf(&ble_sm_sc_priv_key, 32); + ble_hs_log_flat_buf(&ble_sm_sc_priv_key, 32); BLE_HS_LOG(DEBUG, "\n"); return 0; @@ -221,7 +221,7 @@ ble_sm_sc_gen_ri(struct ble_sm_proc *proc) return 0; case BLE_SM_PAIR_ALG_OOB: - rc = ble_hci_util_rand(&proc->ri, 1); + rc = ble_hs_hci_util_rand(&proc->ri, 1); return rc; default: @@ -280,7 +280,7 @@ ble_sm_sc_gen_numcmp(struct ble_sm_proc *proc, struct ble_sm_result *res) pkb = ble_sm_sc_pub_key.u8; } res->app_status = ble_sm_alg_g2(pka, pkb, proc->randm, proc->rands, - &res->passkey_action.numcmp); + &res->passkey_params.numcmp); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; @@ -341,7 +341,7 @@ ble_sm_sc_random_exec(struct ble_sm_proc *proc, struct ble_sm_result *res) if (ble_sm_ioact_state(ioact) == proc->state && !(proc->flags & BLE_SM_PROC_F_IO_INJECTED)) { - res->passkey_action.action = ioact; + res->passkey_params.action = ioact; BLE_HS_DBG_ASSERT(ioact == BLE_SM_IOACT_NUMCMP); ble_sm_sc_gen_numcmp(proc, res); } @@ -363,7 +363,7 @@ ble_sm_sc_random_rx(struct ble_sm_proc *proc, struct ble_sm_result *res) ble_sm_sc_responder_verifies_random(proc)) { BLE_HS_LOG(DEBUG, "tk="); - ble_hs_misc_log_flat_buf(proc->tk, 32); + ble_hs_log_flat_buf(proc->tk, 32); BLE_HS_LOG(DEBUG, "\n"); rc = ble_sm_alg_f4(proc->pub_key_peer.x, ble_sm_sc_pub_key.u8, @@ -386,14 +386,7 @@ ble_sm_sc_random_rx(struct ble_sm_proc *proc, struct ble_sm_result *res) } /* Calculate the mac key and ltk. */ - rc = ble_sm_ia_ra(proc, &iat, ia, &rat, ra); - if (rc != 0) { - res->app_status = rc; - res->sm_err = BLE_SM_ERR_UNSPECIFIED; - res->enc_cb = 1; - return; - } - + ble_sm_ia_ra(proc, &iat, ia, &rat, ra); rc = ble_sm_alg_f5(proc->dhkey, proc->randm, proc->rands, iat, ia, rat, ra, proc->mackey, proc->ltk); if (rc != 0) { @@ -423,7 +416,7 @@ ble_sm_sc_random_rx(struct ble_sm_proc *proc, struct ble_sm_result *res) if (ble_sm_ioact_state(ioact) == proc->state && !(proc->flags & BLE_SM_PROC_F_IO_INJECTED)) { - res->passkey_action.action = ioact; + res->passkey_params.action = ioact; BLE_HS_DBG_ASSERT(ioact == BLE_SM_IOACT_NUMCMP); ble_sm_sc_gen_numcmp(proc, res); } else { @@ -457,14 +450,14 @@ ble_sm_sc_public_key_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, return; } - ioact = ble_sm_sc_io_action(proc); - if (ble_sm_ioact_state(ioact) == BLE_SM_PROC_STATE_CONFIRM) { - res->passkey_action.action = ioact; - } - if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) { proc->state = BLE_SM_PROC_STATE_CONFIRM; + ioact = ble_sm_sc_io_action(proc); + if (ble_sm_ioact_state(ioact) == proc->state) { + res->passkey_params.action = ioact; + } + if (ble_sm_proc_can_advance(proc) && !ble_sm_sc_initiator_txes_confirm(proc)) { @@ -480,9 +473,10 @@ ble_sm_sc_public_key_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_public_key cmd; struct ble_sm_proc *proc; struct ble_sm_proc *prev; + uint8_t ioact; int rc; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PUBLIC_KEY_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PUBLIC_KEY_SZ); if (res->app_status != 0) { res->enc_cb = 1; return; @@ -518,6 +512,11 @@ ble_sm_sc_public_key_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, if (proc->flags & BLE_SM_PROC_F_INITIATOR) { proc->state = BLE_SM_PROC_STATE_CONFIRM; + ioact = ble_sm_sc_io_action(proc); + if (ble_sm_ioact_state(ioact) == proc->state) { + res->passkey_params.action = ioact; + } + if (ble_sm_proc_can_advance(proc) && ble_sm_sc_initiator_txes_confirm(proc)) { @@ -531,28 +530,23 @@ ble_sm_sc_public_key_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, ble_hs_unlock(); } -static int +static void ble_sm_sc_dhkey_addrs(struct ble_sm_proc *proc, uint8_t *out_our_id_addr_type, - uint8_t **out_our_ota_addr, + const uint8_t **out_our_ota_addr, uint8_t *out_peer_id_addr_type, - uint8_t **out_peer_ota_addr) + const uint8_t **out_peer_ota_addr) { struct ble_hs_conn_addrs addrs; struct ble_hs_conn *conn; - conn = ble_hs_conn_find(proc->conn_handle); - if (conn == NULL) { - return BLE_HS_ENOTCONN; - } + conn = ble_hs_conn_find_assert(proc->conn_handle); ble_hs_conn_addrs(conn, &addrs); *out_our_id_addr_type = addrs.our_id_addr_type; *out_our_ota_addr = addrs.our_ota_addr; *out_peer_id_addr_type = addrs.peer_id_addr_type; *out_peer_ota_addr = addrs.peer_ota_addr; - - return 0; } static void @@ -569,8 +563,8 @@ ble_sm_sc_dhkey_check_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg) { struct ble_sm_dhkey_check cmd; - uint8_t *our_ota_addr; - uint8_t *peer_ota_addr; + const uint8_t *our_ota_addr; + const uint8_t *peer_ota_addr; uint8_t peer_id_addr_type; uint8_t our_id_addr_type; uint8_t iocap[3]; @@ -582,12 +576,9 @@ ble_sm_sc_dhkey_check_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, ble_sm_sc_dhkey_check_iocap(&proc->pair_rsp, iocap); } - rc = ble_sm_sc_dhkey_addrs(proc, - &our_id_addr_type, &our_ota_addr, - &peer_id_addr_type, &peer_ota_addr); - if (rc != 0) { - goto err; - } + ble_sm_sc_dhkey_addrs(proc, + &our_id_addr_type, &our_ota_addr, + &peer_id_addr_type, &peer_ota_addr); rc = ble_sm_alg_f6(proc->mackey, ble_sm_our_pair_rand(proc), ble_sm_peer_pair_rand(proc), proc->tk, iocap, @@ -621,8 +612,8 @@ ble_sm_dhkey_check_process(struct ble_sm_proc *proc, struct ble_sm_result *res) { uint8_t exp_value[16]; - uint8_t *peer_ota_addr; - uint8_t *our_ota_addr; + const uint8_t *peer_ota_addr; + const uint8_t *our_ota_addr; uint8_t peer_id_addr_type; uint8_t our_id_addr_type; uint8_t iocap[3]; @@ -634,19 +625,13 @@ ble_sm_dhkey_check_process(struct ble_sm_proc *proc, ble_sm_sc_dhkey_check_iocap(&proc->pair_req, iocap); } - res->app_status = ble_sm_sc_dhkey_addrs(proc, - &our_id_addr_type, - &our_ota_addr, - &peer_id_addr_type, - &peer_ota_addr); - if (res->app_status != 0) { - res->sm_err = BLE_SM_ERR_UNSPECIFIED; - res->enc_cb = 1; - return; - } - + ble_sm_sc_dhkey_addrs(proc, + &our_id_addr_type, + &our_ota_addr, + &peer_id_addr_type, + &peer_ota_addr); BLE_HS_LOG(DEBUG, "tk="); - ble_hs_misc_log_flat_buf(proc->tk, 32); + ble_hs_log_flat_buf(proc->tk, 32); BLE_HS_LOG(DEBUG, "\n"); res->app_status = ble_sm_alg_f6(proc->mackey, @@ -693,7 +678,7 @@ ble_sm_sc_dhkey_check_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om, struct ble_sm_proc *proc; struct ble_sm_proc *prev; - res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_DHKEY_CHECK_SZ); + res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_DHKEY_CHECK_SZ); if (res->app_status != 0) { res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; diff --git a/net/nimble/host/src/ble_uuid.c b/net/nimble/host/src/ble_uuid.c index ec015286..805cf497 100644 --- a/net/nimble/host/src/ble_uuid.c +++ b/net/nimble/host/src/ble_uuid.c @@ -34,15 +34,19 @@ static uint8_t ble_uuid_base[16] = { * Attempts to convert the supplied 128-bit UUID into its shortened 16-bit * form. * - * @return Positive 16-bit unsigned integer on + * @param uuid128 The 128-bit UUID to attempt to convert. + * This must point to 16 contiguous bytes. + * + * @return A positive 16-bit unsigned integer on * success; - * 0 if the UUID could not be converted. + * 0 if the UUID cannot be represented in 16 + * bits. */ uint16_t -ble_uuid_128_to_16(void *uuid128) +ble_uuid_128_to_16(const void *uuid128) { + const uint8_t *u8ptr; uint16_t uuid16; - uint8_t *u8ptr; int rc; u8ptr = uuid128; @@ -68,8 +72,19 @@ ble_uuid_128_to_16(void *uuid128) return uuid16; } +/** + * Expands a 16-bit UUID into its 128-bit form. + * + * @param uuid16 The 16-bit UUID to convert. + * @param out_uuid128 On success, the resulting 128-bit UUID gets + * written here. + * + * @return 0 on success; + * BLE_HS_EINVAL if uuid16 is not a valid 16-bit + * UUID. + */ int -ble_uuid_16_to_128(uint16_t uuid16, void *uuid128) +ble_uuid_16_to_128(uint16_t uuid16, void *out_uuid128) { uint8_t *u8ptr; @@ -77,7 +92,7 @@ ble_uuid_16_to_128(uint16_t uuid16, void *uuid128) return BLE_HS_EINVAL; } - u8ptr = uuid128; + u8ptr = out_uuid128; memcpy(u8ptr, ble_uuid_base, 16); htole16(u8ptr + 12, uuid16); @@ -86,7 +101,7 @@ ble_uuid_16_to_128(uint16_t uuid16, void *uuid128) } int -ble_uuid_append(struct os_mbuf *om, void *uuid128) +ble_uuid_append(struct os_mbuf *om, const void *uuid128) { uint16_t uuid16; void *buf; diff --git a/net/nimble/host/src/ble_uuid_priv.h b/net/nimble/host/src/ble_uuid_priv.h new file mode 100644 index 00000000..a1f1bd49 --- /dev/null +++ b/net/nimble/host/src/ble_uuid_priv.h @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_UUID_PRIV_ +#define H_BLE_UUID_PRIV_ + +struct os_mbuf; + +int ble_uuid_append(struct os_mbuf *om, const void *uuid128); +int ble_uuid_extract(struct os_mbuf *om, int off, void *uuid128); + +#endif diff --git a/net/nimble/host/src/test/ble_att_clt_test.c b/net/nimble/host/src/test/ble_att_clt_test.c index dcb402e6..14d66f62 100644 --- a/net/nimble/host/src/test/ble_att_clt_test.c +++ b/net/nimble/host/src/test/ble_att_clt_test.c @@ -63,12 +63,14 @@ ble_att_clt_test_tx_write_req_or_cmd(uint16_t conn_handle, struct ble_att_write_req *req, void *value, int value_len, int is_req) { + struct os_mbuf *om; int rc; + om = ble_hs_test_util_om_from_flat(value, value_len); if (is_req) { - rc = ble_att_clt_tx_write_req(conn_handle, req, value, value_len); + rc = ble_att_clt_tx_write_req(conn_handle, req, om); } else { - rc = ble_att_clt_tx_write_cmd(conn_handle, req, value, value_len); + rc = ble_att_clt_tx_write_cmd(conn_handle, req, om); } TEST_ASSERT(rc == 0); } @@ -212,8 +214,8 @@ ble_att_clt_test_misc_prep_good(uint16_t handle, uint16_t offset, req.bapc_handle = handle; req.bapc_offset = offset; - rc = ble_att_clt_tx_prep_write(conn_handle, &req, attr_data, - attr_data_len); + om = ble_hs_test_util_om_from_flat(attr_data, attr_data_len); + rc = ble_att_clt_tx_prep_write(conn_handle, &req, om); TEST_ASSERT(rc == 0); ble_hs_test_util_tx_all(); @@ -259,18 +261,36 @@ ble_att_clt_test_misc_prep_bad(uint16_t handle, uint16_t offset, int status) { struct ble_att_prep_write_cmd req; + struct os_mbuf *om; uint16_t conn_handle; int rc; conn_handle = ble_att_clt_test_misc_init(); + om = ble_hs_test_util_om_from_flat(attr_data, attr_data_len); + req.bapc_handle = handle; req.bapc_offset = offset; - rc = ble_att_clt_tx_prep_write(conn_handle, &req, attr_data, - attr_data_len); + rc = ble_att_clt_tx_prep_write(conn_handle, &req, om); TEST_ASSERT(rc == status); } +static void +ble_att_clt_test_misc_tx_mtu(uint16_t conn_handle, uint16_t mtu, int status) +{ + struct ble_att_mtu_cmd req; + int rc; + + req.bamc_mtu = mtu; + rc = ble_att_clt_tx_mtu(conn_handle, &req); + TEST_ASSERT(rc == status); + + if (rc == 0) { + ble_hs_test_util_verify_tx_mtu_cmd(1, mtu); + } +} + + TEST_CASE(ble_att_clt_test_tx_write) { ble_att_clt_test_case_tx_write_req_or_cmd(0); @@ -408,7 +428,8 @@ TEST_CASE(ble_att_clt_test_rx_read_mult) htole16(buf + BLE_ATT_READ_MULT_RSP_BASE_SZ + 0, 12); rc = ble_hs_test_util_l2cap_rx_payload_flat( - conn_handle, BLE_L2CAP_CID_ATT, buf, BLE_ATT_READ_MULT_RSP_BASE_SZ + 2); + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_READ_MULT_RSP_BASE_SZ + 2); TEST_ASSERT(rc == 0); /*** Larger response. */ @@ -416,12 +437,14 @@ TEST_CASE(ble_att_clt_test_rx_read_mult) htole16(buf + BLE_ATT_READ_MULT_RSP_BASE_SZ + 2, 43); htole16(buf + BLE_ATT_READ_MULT_RSP_BASE_SZ + 4, 91); rc = ble_hs_test_util_l2cap_rx_payload_flat( - conn_handle, BLE_L2CAP_CID_ATT, buf, BLE_ATT_READ_MULT_RSP_BASE_SZ + 6); + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_READ_MULT_RSP_BASE_SZ + 6); TEST_ASSERT(rc == 0); /*** Zero-length response. */ rc = ble_hs_test_util_l2cap_rx_payload_flat( - conn_handle, BLE_L2CAP_CID_ATT, buf, BLE_ATT_READ_MULT_RSP_BASE_SZ + 0); + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_READ_MULT_RSP_BASE_SZ + 0); TEST_ASSERT(rc == 0); } @@ -502,8 +525,24 @@ TEST_CASE(ble_att_clt_test_tx_exec_write) TEST_ASSERT(rc == BLE_HS_EINVAL); } +TEST_CASE(ble_att_clt_test_tx_mtu) +{ + uint16_t conn_handle; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Success. */ + ble_att_clt_test_misc_tx_mtu(conn_handle, 50, 0); + + /*** Error: repeated sends. */ + ble_att_clt_test_misc_tx_mtu(conn_handle, 50, BLE_HS_EALREADY); + ble_att_clt_test_misc_tx_mtu(conn_handle, 60, BLE_HS_EALREADY); +} + TEST_SUITE(ble_att_clt_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_att_clt_test_tx_find_info(); ble_att_clt_test_rx_find_info(); ble_att_clt_test_tx_read(); @@ -516,6 +555,7 @@ TEST_SUITE(ble_att_clt_suite) ble_att_clt_test_tx_prep_write(); ble_att_clt_test_rx_prep_write(); ble_att_clt_test_tx_exec_write(); + ble_att_clt_test_tx_mtu(); } int diff --git a/net/nimble/host/src/test/ble_att_svr_test.c b/net/nimble/host/src/test/ble_att_svr_test.c index e6f8bdbd..52a56694 100644 --- a/net/nimble/host/src/test/ble_att_svr_test.c +++ b/net/nimble/host/src/test/ble_att_svr_test.c @@ -27,33 +27,32 @@ #include "ble_hs_test_util.h" static uint8_t *ble_att_svr_test_attr_r_1; -static int ble_att_svr_test_attr_r_1_len; +static uint16_t ble_att_svr_test_attr_r_1_len; static uint8_t *ble_att_svr_test_attr_r_2; -static int ble_att_svr_test_attr_r_2_len; +static uint16_t ble_att_svr_test_attr_r_2_len; static uint8_t ble_att_svr_test_attr_w_1[1024]; -static int ble_att_svr_test_attr_w_1_len; +static uint16_t ble_att_svr_test_attr_w_1_len; static uint8_t ble_att_svr_test_attr_w_2[1024]; -static int ble_att_svr_test_attr_w_2_len; +static uint16_t ble_att_svr_test_attr_w_2_len; static uint16_t ble_att_svr_test_n_conn_handle; static uint16_t ble_att_svr_test_n_attr_handle; static uint8_t ble_att_svr_test_attr_n[1024]; -static int ble_att_svr_test_attr_n_len; +static uint16_t ble_att_svr_test_attr_n_len; static int -ble_att_svr_test_misc_gap_cb(int event, - struct ble_gap_conn_ctxt *ctxt, void *arg) +ble_att_svr_test_misc_gap_cb(struct ble_gap_event *event, void *arg) { - switch (event) { - case BLE_GAP_EVENT_NOTIFY: - ble_att_svr_test_n_conn_handle = ctxt->desc->conn_handle; - ble_att_svr_test_n_attr_handle = ctxt->notify.attr_handle; - TEST_ASSERT_FATAL(ctxt->notify.attr_len <= + switch (event->type) { + case BLE_GAP_EVENT_NOTIFY_RX: + ble_att_svr_test_n_conn_handle = event->notify_rx.conn_handle; + ble_att_svr_test_n_attr_handle = event->notify_rx.attr_handle; + TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(event->notify_rx.om) <= sizeof ble_att_svr_test_attr_n); - ble_att_svr_test_attr_n_len = ctxt->notify.attr_len; - memcpy(ble_att_svr_test_attr_n, ctxt->notify.attr_data, - ctxt->notify.attr_len); + ble_att_svr_test_attr_n_len = OS_MBUF_PKTLEN(event->notify_rx.om); + os_mbuf_copydata(event->notify_rx.om, 0, ble_att_svr_test_attr_n_len, + ble_att_svr_test_attr_n); break; default: @@ -100,18 +99,17 @@ ble_att_svr_test_misc_init(uint16_t mtu) static int ble_att_svr_test_misc_attr_fn_r_1(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, - void *arg) + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) { - if (ctxt->offset > ble_att_svr_test_attr_r_1_len) { - return BLE_ATT_ERR_INVALID_OFFSET; - } - switch (op) { case BLE_ATT_ACCESS_OP_READ: - ctxt->attr_data = ble_att_svr_test_attr_r_1 + ctxt->offset; - ctxt->data_len = ble_att_svr_test_attr_r_1_len - ctxt->offset; + if (offset > ble_att_svr_test_attr_r_1_len) { + return BLE_ATT_ERR_INVALID_OFFSET; + } + + os_mbuf_append(*om, ble_att_svr_test_attr_r_1 + offset, + ble_att_svr_test_attr_r_1_len - offset); return 0; default: @@ -121,18 +119,18 @@ ble_att_svr_test_misc_attr_fn_r_1(uint16_t conn_handle, uint16_t attr_handle, static int ble_att_svr_test_misc_attr_fn_r_2(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, - void *arg) + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) { - if (ctxt->offset > ble_att_svr_test_attr_r_2_len) { - return BLE_ATT_ERR_INVALID_OFFSET; - } switch (op) { case BLE_ATT_ACCESS_OP_READ: - ctxt->attr_data = ble_att_svr_test_attr_r_2 + ctxt->offset; - ctxt->data_len = ble_att_svr_test_attr_r_2_len - ctxt->offset; + if (offset > ble_att_svr_test_attr_r_2_len) { + return BLE_ATT_ERR_INVALID_OFFSET; + } + + os_mbuf_append(*om, ble_att_svr_test_attr_r_2 + offset, + ble_att_svr_test_attr_r_2_len - offset); return 0; default: @@ -145,11 +143,15 @@ ble_att_svr_test_misc_attr_fn_r_2(uint16_t conn_handle, uint16_t attr_handle, static int ble_att_svr_test_misc_attr_fn_r_group(uint16_t conn_handle, - uint16_t attr_handle, uint8_t *uuid128, + uint16_t attr_handle, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, + uint16_t offset, + struct os_mbuf **om, void *arg) { + uint8_t *src; + int rc; + /* Service 0x1122 from 1 to 5 */ /* Service 0x2233 from 6 to 10 */ /* Service 010203...0f from 11 to 24 */ @@ -190,11 +192,14 @@ ble_att_svr_test_misc_attr_fn_r_group(uint16_t conn_handle, TEST_ASSERT_FATAL(attr_handle >= 1 && attr_handle <= BLE_ATT_SVR_TEST_LAST_ATTR); - ctxt->attr_data = vals + attr_handle; - if (memcmp(ctxt->attr_data + 2, zeros, 14) == 0) { - ctxt->data_len = 2; + src = &vals[attr_handle][0]; + if (memcmp(src + 2, zeros, 14) == 0) { + rc = os_mbuf_append(*om, src, 2); } else { - ctxt->data_len = 16; + rc = os_mbuf_append(*om, src, 16); + } + if (rc != 0) { + return BLE_ATT_ERR_INSUFFICIENT_RES; } return 0; @@ -282,14 +287,14 @@ ble_att_svr_test_misc_register_group_attrs(void) static int ble_att_svr_test_misc_attr_fn_w_1(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, - void *arg) + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) { switch (op) { case BLE_ATT_ACCESS_OP_WRITE: - memcpy(ble_att_svr_test_attr_w_1, ctxt->attr_data, ctxt->data_len); - ble_att_svr_test_attr_w_1_len = ctxt->data_len; + os_mbuf_copydata(*om, 0, OS_MBUF_PKTLEN(*om), + ble_att_svr_test_attr_w_1); + ble_att_svr_test_attr_w_1_len = OS_MBUF_PKTLEN(*om); return 0; default: @@ -299,14 +304,14 @@ ble_att_svr_test_misc_attr_fn_w_1(uint16_t conn_handle, uint16_t attr_handle, static int ble_att_svr_test_misc_attr_fn_w_2(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, - void *arg) + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) { switch (op) { case BLE_ATT_ACCESS_OP_WRITE: - memcpy(ble_att_svr_test_attr_w_2, ctxt->attr_data, ctxt->data_len); - ble_att_svr_test_attr_w_2_len = ctxt->data_len; + os_mbuf_copydata(*om, 0, OS_MBUF_PKTLEN(*om), + ble_att_svr_test_attr_w_2); + ble_att_svr_test_attr_w_2_len = OS_MBUF_PKTLEN(*om); return 0; default: @@ -314,6 +319,15 @@ ble_att_svr_test_misc_attr_fn_w_2(uint16_t conn_handle, uint16_t attr_handle, } } +static int +ble_att_svr_test_misc_attr_fn_w_fail(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; +} + static void ble_att_svr_test_misc_verify_w_1(void *data, int data_len) { @@ -329,55 +343,6 @@ ble_att_svr_test_misc_verify_w_2(void *data, int data_len) } static void -ble_att_svr_test_misc_verify_tx_err_rsp(uint8_t req_op, uint16_t handle, - uint8_t error_code) -{ - struct ble_att_error_rsp rsp; - struct os_mbuf *om; - uint8_t buf[BLE_ATT_ERROR_RSP_SZ]; - int rc; - - ble_hs_test_util_tx_all(); - - om = ble_hs_test_util_prev_tx_dequeue(); - - rc = os_mbuf_copydata(om, 0, sizeof buf, buf); - TEST_ASSERT(rc == 0); - - ble_att_error_rsp_parse(buf, sizeof buf, &rsp); - - TEST_ASSERT(rsp.baep_req_op == req_op); - TEST_ASSERT(rsp.baep_handle == handle); - TEST_ASSERT(rsp.baep_error_code == error_code); -} - -static void -ble_att_svr_test_misc_verify_tx_read_rsp(uint8_t *attr_data, int attr_len) -{ - struct os_mbuf *om; - uint8_t u8; - int rc; - int i; - - ble_hs_test_util_tx_all(); - - om = ble_hs_test_util_prev_tx_dequeue(); - - rc = os_mbuf_copydata(om, 0, 1, &u8); - TEST_ASSERT(rc == 0); - TEST_ASSERT(u8 == BLE_ATT_OP_READ_RSP); - - for (i = 0; i < attr_len; i++) { - rc = os_mbuf_copydata(om, i + 1, 1, &u8); - TEST_ASSERT(rc == 0); - TEST_ASSERT(u8 == attr_data[i]); - } - - rc = os_mbuf_copydata(om, i + 1, 1, &u8); - TEST_ASSERT(rc != 0); -} - -static void ble_att_svr_test_misc_verify_tx_read_blob_rsp(uint8_t *attr_data, int attr_len) { struct os_mbuf *om; @@ -431,18 +396,17 @@ ble_att_svr_test_misc_rx_read_mult_req(uint16_t conn_handle, } static void -ble_att_svr_test_misc_verify_tx_read_mult_rsp(uint16_t conn_handle, - struct ble_gatt_attr *attrs, - int num_attrs) +ble_att_svr_test_misc_verify_tx_read_mult_rsp( + uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs, + int num_attrs) { struct ble_l2cap_chan *chan; struct os_mbuf *om; + uint16_t attr_len; uint16_t mtu; - uint8_t *attr_value; uint8_t u8; int rc; int off; - int ii; int i; ble_hs_test_util_tx_all(); @@ -464,25 +428,21 @@ ble_att_svr_test_misc_verify_tx_read_mult_rsp(uint16_t conn_handle, off = 1; for (i = 0; i < num_attrs; i++) { - attr_value = attrs[i].value; + attr_len = min(attrs[i].value_len, mtu - off); - for (ii = 0; ii < attrs[i].value_len && off < mtu; ii++) { - rc = os_mbuf_copydata(om, off, 1, &u8); - TEST_ASSERT(rc == 0); - TEST_ASSERT(u8 == attr_value[ii]); + rc = os_mbuf_cmpf(om, off, attrs[i].value, attr_len); + TEST_ASSERT(rc == 0); - off++; - } + off += attr_len; } - rc = os_mbuf_copydata(om, off, 1, &u8); - TEST_ASSERT(rc != 0); + TEST_ASSERT(OS_MBUF_PKTLEN(om) == off); } static void -ble_att_svr_test_misc_verify_all_read_mult(uint16_t conn_handle, - struct ble_gatt_attr *attrs, - int num_attrs) +ble_att_svr_test_misc_verify_all_read_mult( + uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs, + int num_attrs) { uint16_t handles[256]; int i; @@ -498,23 +458,6 @@ ble_att_svr_test_misc_verify_all_read_mult(uint16_t conn_handle, attrs, num_attrs); } - -static void -ble_att_svr_test_misc_verify_tx_write_rsp(void) -{ - struct os_mbuf *om; - uint8_t u8; - int rc; - - ble_hs_test_util_tx_all(); - - om = ble_hs_test_util_prev_tx_dequeue(); - - rc = os_mbuf_copydata(om, 0, 1, &u8); - TEST_ASSERT(rc == 0); - TEST_ASSERT(u8 == BLE_ATT_OP_WRITE_RSP); -} - static void ble_att_svr_test_misc_verify_tx_mtu_rsp(uint16_t conn_handle) { @@ -532,7 +475,7 @@ ble_att_svr_test_misc_verify_tx_mtu_rsp(uint16_t conn_handle) rc = os_mbuf_copydata(om, 0, sizeof buf, buf); TEST_ASSERT(rc == 0); - ble_att_mtu_cmd_parse(buf, sizeof buf, &rsp); + ble_att_mtu_rsp_parse(buf, sizeof buf, &rsp); ble_hs_lock(); rc = ble_hs_misc_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, @@ -836,6 +779,7 @@ ble_att_svr_test_misc_mtu_exchange(uint16_t my_mtu, uint16_t peer_sent, TEST_ASSERT(chan->blc_peer_mtu == peer_actual); TEST_ASSERT(ble_l2cap_chan_mtu(chan) == chan_mtu); ble_hs_unlock(); + } static void @@ -861,7 +805,7 @@ ble_att_svr_test_misc_prep_write(uint16_t conn_handle, uint16_t attr_handle, data, data_len); } else { TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_PREP_WRITE_REQ, + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_PREP_WRITE_REQ, attr_handle, error_code); } } @@ -885,7 +829,7 @@ ble_att_svr_test_misc_exec_write(uint16_t conn_handle, uint8_t flags, ble_att_svr_test_misc_verify_tx_exec_write_rsp(); } else { TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_EXEC_WRITE_REQ, + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_EXEC_WRITE_REQ, error_handle, error_code); } } @@ -1022,12 +966,11 @@ TEST_CASE(ble_att_svr_test_read) { struct ble_att_read_req req; struct ble_hs_conn *conn; + struct os_mbuf *om; uint16_t conn_handle; - uint16_t attr_len; uint8_t buf[BLE_ATT_READ_REQ_SZ]; uint8_t uuid_sec[16] = {1}; uint8_t uuid[16] = {0}; - void *attr_data; int rc; conn_handle = ble_att_svr_test_misc_init(0); @@ -1039,7 +982,7 @@ TEST_CASE(ble_att_svr_test_read) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_REQ, 0, + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); /*** Successful read. */ @@ -1054,7 +997,7 @@ TEST_CASE(ble_att_svr_test_read) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); - ble_att_svr_test_misc_verify_tx_read_rsp( + ble_hs_test_util_verify_tx_read_rsp( ble_att_svr_test_attr_r_1, ble_att_svr_test_attr_r_1_len); /*** Partial read. */ @@ -1068,8 +1011,8 @@ TEST_CASE(ble_att_svr_test_read) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); - ble_att_svr_test_misc_verify_tx_read_rsp(ble_att_svr_test_attr_r_1, - BLE_ATT_MTU_DFLT - 1); + ble_hs_test_util_verify_tx_read_rsp(ble_att_svr_test_attr_r_1, + BLE_ATT_MTU_DFLT - 1); /*** Read requires encryption. */ /* Insufficient authentication. */ @@ -1082,16 +1025,18 @@ TEST_CASE(ble_att_svr_test_read) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); - TEST_ASSERT(rc == BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHENT)); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_REQ, + TEST_ASSERT(rc == BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN)); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_REQ, req.barq_handle, - BLE_ATT_ERR_INSUFFICIENT_AUTHENT); + BLE_ATT_ERR_INSUFFICIENT_AUTHEN); /* Security check bypassed for local reads. */ - rc = ble_att_svr_read_local(req.barq_handle, &attr_data, &attr_len); - TEST_ASSERT(rc == 0); - TEST_ASSERT(attr_len == ble_att_svr_test_attr_r_1_len); - TEST_ASSERT(attr_data == ble_att_svr_test_attr_r_1); + rc = ble_att_svr_read_local(req.barq_handle, &om); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(OS_MBUF_PKTLEN(om) == ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(os_mbuf_cmpf(om, 0, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len) == 0); + os_mbuf_free_chain(om); /* Ensure no response got sent. */ ble_hs_test_util_tx_all(); @@ -1106,8 +1051,9 @@ TEST_CASE(ble_att_svr_test_read) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); - ble_att_svr_test_misc_verify_tx_read_rsp(ble_att_svr_test_attr_r_1, - BLE_ATT_MTU_DFLT - 1); + ble_hs_test_util_verify_tx_read_rsp(ble_att_svr_test_attr_r_1, + BLE_ATT_MTU_DFLT - 1); + } TEST_CASE(ble_att_svr_test_read_blob) @@ -1128,14 +1074,15 @@ TEST_CASE(ble_att_svr_test_read_blob) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_BLOB_REQ, 0, + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_BLOB_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); - /*** Short read failure. */ + + /*** Successful partial read. */ ble_att_svr_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_att_svr_test_attr_r_1_len = BLE_ATT_MTU_DFLT - 3; + ble_att_svr_test_attr_r_1_len = 40; rc = ble_att_svr_register(uuid, HA_FLAG_PERM_RW, &req.babq_handle, ble_att_svr_test_misc_attr_fn_r_1, NULL); TEST_ASSERT(rc == 0); @@ -1144,18 +1091,6 @@ TEST_CASE(ble_att_svr_test_read_blob) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); - TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_BLOB_REQ, - req.babq_handle, - BLE_ATT_ERR_ATTR_NOT_LONG); - - /*** Successful partial read. */ - ble_att_svr_test_attr_r_1_len = 40; - - ble_att_read_blob_req_write(buf, sizeof buf, &req); - - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, - buf, sizeof buf); TEST_ASSERT(rc == 0); ble_att_svr_test_misc_verify_tx_read_blob_rsp(ble_att_svr_test_attr_r_1, BLE_ATT_MTU_DFLT - 1); @@ -1180,73 +1115,84 @@ TEST_CASE(ble_att_svr_test_read_blob) TEST_ASSERT(rc == 0); ble_att_svr_test_misc_verify_tx_read_blob_rsp(ble_att_svr_test_attr_r_1, 0); + } TEST_CASE(ble_att_svr_test_read_mult) { - struct ble_gatt_attr attr1; - struct ble_gatt_attr attr2; uint16_t conn_handle; int rc; conn_handle = ble_att_svr_test_misc_init(0); - attr1.value = (uint8_t[]){ 1, 2, 3, 4 }; - attr1.value_len = 4; - ble_att_svr_test_attr_r_1 = attr1.value; - ble_att_svr_test_attr_r_1_len = attr1.value_len; + struct ble_hs_test_util_flat_attr attrs[2] = { + { + .handle = 0, + .offset = 0, + .value = { 1, 2, 3, 4 }, + .value_len = 4, + }, + { + .handle = 0, + .offset = 0, + .value = { 2, 3, 4, 5, 6 }, + .value_len = 5, + }, + }; + + ble_att_svr_test_attr_r_1 = attrs[0].value; + ble_att_svr_test_attr_r_1_len = attrs[0].value_len; + ble_att_svr_test_attr_r_2 = attrs[1].value; + ble_att_svr_test_attr_r_2_len = attrs[1].value_len; + rc = ble_att_svr_register(BLE_UUID16(0x1111), HA_FLAG_PERM_RW, - &attr1.handle, + &attrs[0].handle, ble_att_svr_test_misc_attr_fn_r_1, NULL); TEST_ASSERT(rc == 0); - attr2.value = (uint8_t[]){ 2, 3, 4, 5, 6 }; - attr2.value_len = 5; - ble_att_svr_test_attr_r_2 = attr2.value; - ble_att_svr_test_attr_r_2_len = attr2.value_len; rc = ble_att_svr_register(BLE_UUID16(0x2222), HA_FLAG_PERM_RW, - &attr2.handle, + &attrs[1].handle, ble_att_svr_test_misc_attr_fn_r_2, NULL); TEST_ASSERT(rc == 0); /*** Single nonexistent attribute. */ ble_att_svr_test_misc_rx_read_mult_req( conn_handle, ((uint16_t[]){ 100 }), 1, 0); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_MULT_REQ, + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_MULT_REQ, 100, BLE_ATT_ERR_INVALID_HANDLE); /*** Single attribute. */ - ble_att_svr_test_misc_verify_all_read_mult(conn_handle, &attr1, 1); + ble_att_svr_test_misc_verify_all_read_mult(conn_handle, &attrs[0], 1); /*** Two attributes. */ - ble_att_svr_test_misc_verify_all_read_mult( - conn_handle, ((struct ble_gatt_attr[]) { attr1, attr2 }), 2); + ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2); /*** Reverse order. */ - ble_att_svr_test_misc_verify_all_read_mult( - conn_handle, ((struct ble_gatt_attr[]) { attr2, attr1 }), 2); + ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2); /*** Second attribute nonexistent; verify only error txed. */ ble_att_svr_test_misc_rx_read_mult_req( - conn_handle, ((uint16_t[]){ attr1.handle, 100 }), 2, 0); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_MULT_REQ, + conn_handle, ((uint16_t[]){ attrs[0].handle, 100 }), 2, 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_MULT_REQ, 100, BLE_ATT_ERR_INVALID_HANDLE); /*** Response too long; verify only MTU bytes sent. */ - attr1.value = - (uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; - attr1.value_len = 20; - ble_att_svr_test_attr_r_1 = attr1.value; - ble_att_svr_test_attr_r_1_len = attr1.value_len; - - attr2.value = - (uint8_t[]){22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39}; - attr2.value_len = 20; - ble_att_svr_test_attr_r_2 = attr2.value; - ble_att_svr_test_attr_r_2_len = attr2.value_len; - - ble_att_svr_test_misc_verify_all_read_mult( - conn_handle, ((struct ble_gatt_attr[]) { attr1, attr2 }), 2); + attrs[0].value_len = 20; + memcpy(attrs[0].value, + ((uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}), + attrs[0].value_len); + ble_att_svr_test_attr_r_1_len = attrs[0].value_len; + + attrs[1].value_len = 20; + memcpy(attrs[1].value, + ((uint8_t[]){ + 22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 + }), + attrs[1].value_len); + ble_att_svr_test_attr_r_2_len = attrs[1].value_len; + + ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2); + } TEST_CASE(ble_att_svr_test_write) @@ -1270,7 +1216,7 @@ TEST_CASE(ble_att_svr_test_write) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_WRITE_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); /*** Write not permitted if non-local. */ @@ -1286,12 +1232,12 @@ TEST_CASE(ble_att_svr_test_write) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == BLE_HS_ENOTSUP); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, req.bawq_handle, BLE_ATT_ERR_WRITE_NOT_PERMITTED); /* Local write (success). */ - rc = ble_att_svr_write_local(req.bawq_handle, buf, sizeof buf); + rc = ble_hs_test_util_write_local_flat(req.bawq_handle, buf, sizeof buf); TEST_ASSERT(rc == 0); /* Ensure no response got sent. */ @@ -1310,7 +1256,7 @@ TEST_CASE(ble_att_svr_test_write) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); - ble_att_svr_test_misc_verify_tx_write_rsp(); + ble_hs_test_util_verify_tx_write_rsp(); /*** Write requires encryption. */ /* Insufficient authentication. */ @@ -1325,13 +1271,13 @@ TEST_CASE(ble_att_svr_test_write) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); - TEST_ASSERT(rc == BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHENT)); - ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, + TEST_ASSERT(rc == BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN)); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, req.bawq_handle, - BLE_ATT_ERR_INSUFFICIENT_AUTHENT); + BLE_ATT_ERR_INSUFFICIENT_AUTHEN); /* Security check bypassed for local writes. */ - rc = ble_att_svr_write_local(req.bawq_handle, buf, sizeof buf); + rc = ble_hs_test_util_write_local_flat(req.bawq_handle, buf, sizeof buf); TEST_ASSERT(rc == 0); /* Ensure no response got sent. */ @@ -1347,7 +1293,7 @@ TEST_CASE(ble_att_svr_test_write) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); - ble_att_svr_test_misc_verify_tx_write_rsp(); + ble_hs_test_util_verify_tx_write_rsp(); } TEST_CASE(ble_att_svr_test_find_info) @@ -1377,7 +1323,7 @@ TEST_CASE(ble_att_svr_test_find_info) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_INFO_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); /*** Start handle > end handle. */ @@ -1389,7 +1335,7 @@ TEST_CASE(ble_att_svr_test_find_info) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_INFO_REQ, 101, BLE_ATT_ERR_INVALID_HANDLE); /*** No attributes. */ @@ -1401,7 +1347,7 @@ TEST_CASE(ble_att_svr_test_find_info) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_INFO_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); /*** Range too late. */ @@ -1417,7 +1363,7 @@ TEST_CASE(ble_att_svr_test_find_info) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_INFO_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); /*** One 128-bit entry. */ @@ -1501,6 +1447,7 @@ TEST_CASE(ble_att_svr_test_find_info) }, { .handle = 0, } })); + } TEST_CASE(ble_att_svr_test_find_type_value) @@ -1543,7 +1490,7 @@ TEST_CASE(ble_att_svr_test_find_type_value) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); @@ -1556,7 +1503,7 @@ TEST_CASE(ble_att_svr_test_find_type_value) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 101, BLE_ATT_ERR_INVALID_HANDLE); @@ -1569,7 +1516,7 @@ TEST_CASE(ble_att_svr_test_find_type_value) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); @@ -1586,7 +1533,7 @@ TEST_CASE(ble_att_svr_test_find_type_value) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); @@ -1701,6 +1648,7 @@ TEST_CASE(ble_att_svr_test_find_type_value) }, { .first = 0, } })); + } static void @@ -1724,7 +1672,7 @@ ble_att_svr_test_misc_read_type(uint16_t mtu) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_TYPE_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); @@ -1739,7 +1687,7 @@ ble_att_svr_test_misc_read_type(uint16_t mtu) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_TYPE_REQ, 101, BLE_ATT_ERR_INVALID_HANDLE); @@ -1754,7 +1702,7 @@ ble_att_svr_test_misc_read_type(uint16_t mtu) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_TYPE_REQ, 1, BLE_ATT_ERR_ATTR_NOT_FOUND); @@ -1770,7 +1718,7 @@ ble_att_svr_test_misc_read_type(uint16_t mtu) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_TYPE_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); @@ -1907,6 +1855,7 @@ ble_att_svr_test_misc_read_type(uint16_t mtu) }, { .handle = 0, } })); + } TEST_CASE(ble_att_svr_test_read_type) @@ -1935,7 +1884,7 @@ TEST_CASE(ble_att_svr_test_read_group_type) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_GROUP_TYPE_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); @@ -1950,7 +1899,7 @@ TEST_CASE(ble_att_svr_test_read_group_type) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_GROUP_TYPE_REQ, 101, BLE_ATT_ERR_INVALID_HANDLE); @@ -1964,7 +1913,7 @@ TEST_CASE(ble_att_svr_test_read_group_type) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_GROUP_TYPE_REQ, 110, BLE_ATT_ERR_UNSUPPORTED_GROUP); @@ -1979,7 +1928,7 @@ TEST_CASE(ble_att_svr_test_read_group_type) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_GROUP_TYPE_REQ, 1, BLE_ATT_ERR_ATTR_NOT_FOUND); @@ -1995,7 +1944,7 @@ TEST_CASE(ble_att_svr_test_read_group_type) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc != 0); - ble_att_svr_test_misc_verify_tx_err_rsp( + ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_READ_GROUP_TYPE_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); @@ -2086,28 +2035,47 @@ TEST_CASE(ble_att_svr_test_read_group_type) }, { .start_handle = 0, } })); + } TEST_CASE(ble_att_svr_test_prep_write) { + struct ble_hs_conn *conn; uint16_t conn_handle; int i; static uint8_t data[1024]; - conn_handle = ble_att_svr_test_misc_init(200); + conn_handle = ble_att_svr_test_misc_init(205); /* Initialize some attribute data. */ for (i = 0; i < sizeof data; i++) { data[i] = i; } - /* Register two attributes. */ + /* Register two writable attributes. */ ble_att_svr_test_misc_register_uuid16(0x1234, HA_FLAG_PERM_RW, 1, ble_att_svr_test_misc_attr_fn_w_1); ble_att_svr_test_misc_register_uuid16(0x8989, HA_FLAG_PERM_RW, 2, ble_att_svr_test_misc_attr_fn_w_2); + /* 3: not writable. */ + ble_att_svr_test_misc_register_uuid16(0xabab, BLE_ATT_F_READ, 3, + ble_att_svr_test_misc_attr_fn_r_1); + /* 4: Encryption required. */ + ble_att_svr_test_misc_register_uuid16( + 0xabac, BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_ENC, 4, + ble_att_svr_test_misc_attr_fn_w_1); + + /* 5: Encryption+authentication required. */ + ble_att_svr_test_misc_register_uuid16( + 0xabad, BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_ENC | BLE_ATT_F_WRITE_AUTHEN, + 5, ble_att_svr_test_misc_attr_fn_w_1); + + /* 6: Write callback always fails. */ + ble_att_svr_test_misc_register_uuid16( + 0xabae, BLE_ATT_F_WRITE, 6, ble_att_svr_test_misc_attr_fn_w_fail); + /*** Empty write succeeds. */ ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_CONFIRM, 0, 0); @@ -2119,6 +2087,28 @@ TEST_CASE(ble_att_svr_test_prep_write) ble_att_svr_test_misc_prep_write(conn_handle, 53525, 0, data, 10, BLE_ATT_ERR_INVALID_HANDLE); + /*** Failure due to write-not-permitted. */ + ble_att_svr_test_misc_prep_write(conn_handle, 3, 0, data, 35, + BLE_ATT_ERR_WRITE_NOT_PERMITTED); + + /*** Failure due to insufficient authentication (encryption required). */ + ble_att_svr_test_misc_prep_write(conn_handle, 4, 0, data, 1, + BLE_ATT_ERR_INSUFFICIENT_AUTHEN); + + /*** Encrypt connection; ensure previous prep write now succeeds. */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.encrypted = 1; + ble_hs_unlock(); + + ble_att_svr_test_misc_prep_write(conn_handle, 4, 0, data, 1, 0); + ble_att_svr_test_misc_exec_write(conn_handle, 0, 0, 0); + + /*** Failure due to insufficient authentication (not authenticated). */ + ble_att_svr_test_misc_prep_write(conn_handle, 5, 0, data, 35, + BLE_ATT_ERR_INSUFFICIENT_AUTHEN); + /*** Failure for write starting at nonzero offset. */ ble_att_svr_test_misc_prep_write(conn_handle, 1, 1, data, 10, 0); ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_CONFIRM, @@ -2195,6 +2185,13 @@ TEST_CASE(ble_att_svr_test_prep_write) 0, 0); ble_att_svr_test_misc_verify_w_1(data, 12); ble_att_svr_test_misc_verify_w_2(data, 61); + + /*** Fail due to attribute callback error. */ + ble_att_svr_test_misc_prep_write(conn_handle, 6, 0, data, 35, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 6, 35, data + 35, 43, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 6, 78, data + 78, 1, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_CONFIRM, + BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN, 6); } TEST_CASE(ble_att_svr_test_notify) @@ -2217,6 +2214,7 @@ TEST_CASE(ble_att_svr_test_notify) /* Attribute handle of 0. */ ble_att_svr_test_misc_verify_notify(conn_handle, 0, (uint8_t[]) { 1, 2, 3 }, 3, 0); + } TEST_CASE(ble_att_svr_test_indicate) @@ -2239,10 +2237,20 @@ TEST_CASE(ble_att_svr_test_indicate) /* Attribute handle of 0. */ ble_att_svr_test_misc_verify_indicate(conn_handle, 0, (uint8_t[]) { 1, 2, 3 }, 3, 0); + } TEST_SUITE(ble_att_svr_suite) { + /* When checking for mbuf leaks, ensure no stale prep entries. */ + static struct ble_hs_test_util_mbuf_params mbuf_params = { + .prev_tx = 1, + .rx_queue = 1, + .prep_list = 0, + }; + + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, &mbuf_params); + ble_att_svr_test_mtu(); ble_att_svr_test_read(); ble_att_svr_test_read_blob(); diff --git a/net/nimble/host/src/test/ble_gap_test.c b/net/nimble/host/src/test/ble_gap_test.c index fcaba400..5dd6532b 100644 --- a/net/nimble/host/src/test/ble_gap_test.c +++ b/net/nimble/host/src/test/ble_gap_test.c @@ -6,7 +6,7 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, @@ -22,18 +22,18 @@ #include "testutil/testutil.h" #include "nimble/ble.h" #include "nimble/hci_common.h" +#include "host/ble_hs_adv.h" #include "host/ble_hs_test.h" #include "ble_hs_test_util.h" -static int ble_gap_test_conn_event; +static struct ble_gap_event ble_gap_test_event; static int ble_gap_test_conn_status; static struct ble_gap_conn_desc ble_gap_test_conn_desc; static void *ble_gap_test_conn_arg; static struct ble_gap_upd_params ble_gap_test_conn_peer_params; static struct ble_gap_upd_params ble_gap_test_conn_self_params; -static int ble_gap_test_disc_event; -static int ble_gap_test_disc_status; +static int ble_gap_test_disc_event_type; static struct ble_gap_disc_desc ble_gap_test_disc_desc; static void *ble_gap_test_disc_arg; @@ -54,13 +54,12 @@ ble_gap_test_util_update_in_progress(uint16_t conn_handle) static void ble_gap_test_util_reset_cb_info(void) { - ble_gap_test_conn_event = -1; + memset(&ble_gap_test_event, 0xff, sizeof ble_gap_test_event); ble_gap_test_conn_status = -1; memset(&ble_gap_test_conn_desc, 0xff, sizeof ble_gap_test_conn_desc); ble_gap_test_conn_arg = (void *)-1; - ble_gap_test_disc_event = -1; - ble_gap_test_disc_status = -1; + ble_gap_test_disc_event_type = -1; memset(&ble_gap_test_disc_desc, 0xff, sizeof ble_gap_test_disc_desc); ble_gap_test_disc_arg = (void *)-1; } @@ -69,47 +68,55 @@ static void ble_gap_test_util_init(void) { ble_hs_test_util_init(); + ble_hs_test_util_set_static_rnd_addr(); ble_gap_test_util_reset_cb_info(); } -static void -ble_gap_test_util_disc_cb(int event, int status, - struct ble_gap_disc_desc *desc, void *arg) +static int +ble_gap_test_util_disc_cb(struct ble_gap_event *event, void *arg) { - ble_gap_test_disc_event = event; - ble_gap_test_disc_status = status; - ble_gap_test_disc_desc = *desc; + ble_gap_test_disc_event_type = event->type; ble_gap_test_disc_arg = arg; + + if (event->type == BLE_GAP_EVENT_DISC) { + ble_gap_test_disc_desc = event->disc; + } + + return 0; } static int -ble_gap_test_util_connect_cb(int event, struct ble_gap_conn_ctxt *ctxt, - void *arg) +ble_gap_test_util_connect_cb(struct ble_gap_event *event, void *arg) { int *fail_reason; - ble_gap_test_conn_event = event; - ble_gap_test_conn_desc = *ctxt->desc; + ble_gap_test_event = *event; ble_gap_test_conn_arg = arg; - switch (event) { + switch (event->type) { case BLE_GAP_EVENT_CONNECT: - ble_gap_test_conn_status = ctxt->connect.status; + ble_gap_test_conn_status = event->connect.status; + ble_gap_conn_find(event->connect.conn_handle, &ble_gap_test_conn_desc); break; case BLE_GAP_EVENT_DISCONNECT: - ble_gap_test_conn_status = ctxt->disconnect.reason; + ble_gap_test_conn_status = event->disconnect.reason; + ble_gap_test_conn_desc = event->disconnect.conn; break; case BLE_GAP_EVENT_CONN_UPDATE: - ble_gap_test_conn_status = ctxt->conn_update.status; + ble_gap_test_conn_status = event->conn_update.status; + ble_gap_conn_find(event->conn_update.conn_handle, + &ble_gap_test_conn_desc); break; case BLE_GAP_EVENT_CONN_CANCEL: break; case BLE_GAP_EVENT_TERM_FAILURE: - ble_gap_test_conn_status = ctxt->term_failure.status; + ble_gap_test_conn_status = event->term_failure.status; + ble_gap_conn_find(event->term_failure.conn_handle, + &ble_gap_test_conn_desc); break; case BLE_GAP_EVENT_ADV_COMPLETE: @@ -117,8 +124,10 @@ ble_gap_test_util_connect_cb(int event, struct ble_gap_conn_ctxt *ctxt, break; case BLE_GAP_EVENT_CONN_UPDATE_REQ: - ble_gap_test_conn_peer_params = *ctxt->conn_update_req.peer_params; - *ctxt->conn_update_req.self_params = ble_gap_test_conn_self_params; + ble_gap_test_conn_peer_params = *event->conn_update_req.peer_params; + *event->conn_update_req.self_params = ble_gap_test_conn_self_params; + ble_gap_conn_find(event->conn_update_req.conn_handle, + &ble_gap_test_conn_desc); fail_reason = arg; if (fail_reason == NULL) { @@ -128,6 +137,9 @@ ble_gap_test_util_connect_cb(int event, struct ble_gap_conn_ctxt *ctxt, } break; + case BLE_GAP_EVENT_MTU: + break; + default: TEST_ASSERT_FATAL(0); break; @@ -165,7 +177,9 @@ ble_gap_test_util_verify_tx_add_wl(struct ble_gap_white_entry *entry) } static void -ble_gap_test_util_verify_tx_set_scan_params(uint16_t itvl, +ble_gap_test_util_verify_tx_set_scan_params(uint8_t own_addr_type, + uint8_t scan_type, + uint16_t itvl, uint16_t scan_window, uint8_t filter_policy) { @@ -176,15 +190,16 @@ ble_gap_test_util_verify_tx_set_scan_params(uint16_t itvl, BLE_HCI_OCF_LE_SET_SCAN_PARAMS, ¶m_len); TEST_ASSERT(param_len == BLE_HCI_SET_SCAN_PARAM_LEN); - TEST_ASSERT(param[0] == BLE_HCI_SCAN_TYPE_ACTIVE); + TEST_ASSERT(param[0] == scan_type); TEST_ASSERT(le16toh(param + 1) == itvl); TEST_ASSERT(le16toh(param + 3) == scan_window); - TEST_ASSERT(param[5] == BLE_HCI_ADV_OWN_ADDR_PUBLIC); + TEST_ASSERT(param[5] == own_addr_type); TEST_ASSERT(param[6] == filter_policy); } static void -ble_gap_test_util_verify_tx_scan_enable(uint8_t enable) +ble_gap_test_util_verify_tx_scan_enable(uint8_t enable, + uint8_t filter_duplicates) { uint8_t param_len; uint8_t *param; @@ -194,26 +209,11 @@ ble_gap_test_util_verify_tx_scan_enable(uint8_t enable) ¶m_len); TEST_ASSERT(param_len == BLE_HCI_SET_SCAN_ENABLE_LEN); TEST_ASSERT(param[0] == enable); + TEST_ASSERT(param[1] == filter_duplicates); } static void -ble_gap_test_util_verify_tx_create_conn(uint8_t filter_policy) -{ - uint8_t param_len; - uint8_t *param; - - param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_CREATE_CONN, - ¶m_len); - TEST_ASSERT(param_len == BLE_HCI_CREATE_CONN_LEN); - - TEST_ASSERT(param[4] == filter_policy); - - /* XXX: Verify other fields. */ -} - -static void -ble_gap_test_util_verify_tx_create_conn_cancel(void) +ble_hs_test_util_verify_tx_create_conn_cancel(void) { uint8_t param_len; @@ -251,17 +251,6 @@ ble_gap_test_util_verify_tx_adv_params(void) } static void -ble_gap_test_util_verify_tx_rd_pwr(void) -{ - uint8_t param_len; - - ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR, - ¶m_len); - TEST_ASSERT(param_len == 0); -} - -static void ble_gap_test_util_verify_tx_adv_data(void) { uint8_t param_len; @@ -384,13 +373,13 @@ ble_gap_test_util_rx_param_req(struct ble_gap_upd_params *params, int pos, evt.itvl_max = params->itvl_max; evt.latency = params->latency; evt.timeout = params->supervision_timeout; - + if (pos) { - opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_REM_CONN_PARAM_RR); + opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_RR); } else { - opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR); + opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR); } if (*cmd_idx == cmd_fail_idx) { hci_status = fail_status; @@ -442,7 +431,7 @@ ble_gap_test_util_wl_set(struct ble_gap_white_entry *white_list, } } -TEST_CASE(ble_gap_test_case_conn_wl_bad_args) +TEST_CASE(ble_gap_test_case_wl_bad_args) { int rc; @@ -461,8 +450,9 @@ TEST_CASE(ble_gap_test_case_conn_wl_bad_args) TEST_ASSERT(rc == BLE_HS_EINVAL); /*** White-list-using connection in progress. */ - rc = ble_hs_test_util_conn_initiate(BLE_GAP_ADDR_TYPE_WL, NULL, NULL, - ble_gap_test_util_connect_cb, NULL, 0); + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_GAP_ADDR_TYPE_WL, NULL, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); TEST_ASSERT(rc == 0); rc = ble_hs_test_util_wl_set( @@ -473,7 +463,7 @@ TEST_CASE(ble_gap_test_case_conn_wl_bad_args) TEST_ASSERT(rc == BLE_HS_EBUSY); } -TEST_CASE(ble_gap_test_case_conn_wl_ctlr_fail) +TEST_CASE(ble_gap_test_case_wl_ctlr_fail) { int i; @@ -491,7 +481,7 @@ TEST_CASE(ble_gap_test_case_conn_wl_ctlr_fail) } } -TEST_CASE(ble_gap_test_case_conn_wl_good) +TEST_CASE(ble_gap_test_case_wl_good) { struct ble_gap_white_entry white_list[] = { { BLE_ADDR_TYPE_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, @@ -504,11 +494,13 @@ TEST_CASE(ble_gap_test_case_conn_wl_good) ble_gap_test_util_wl_set(white_list, white_list_count, 0, 0); } -TEST_SUITE(ble_gap_test_suite_conn_wl) +TEST_SUITE(ble_gap_test_suite_wl) { - ble_gap_test_case_conn_wl_good(); - ble_gap_test_case_conn_wl_bad_args(); - ble_gap_test_case_conn_wl_ctlr_fail(); + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_wl_good(); + ble_gap_test_case_wl_bad_args(); + ble_gap_test_case_wl_ctlr_fail(); } /***************************************************************************** @@ -516,73 +508,85 @@ TEST_SUITE(ble_gap_test_suite_conn_wl) *****************************************************************************/ static int -ble_gap_test_util_disc(uint8_t disc_mode, uint8_t *peer_addr, - struct ble_hs_adv *adv, int cmd_fail_idx, +ble_gap_test_util_disc(uint8_t own_addr_type, + const struct ble_gap_disc_params *disc_params, + struct ble_gap_disc_desc *desc, int cmd_fail_idx, uint8_t fail_status) { int rc; ble_gap_test_util_init(); + TEST_ASSERT(!ble_gap_disc_active()); + /* Begin the discovery procedure. */ - rc = ble_hs_test_util_disc(0, disc_mode, BLE_HCI_SCAN_TYPE_ACTIVE, - BLE_HCI_SCAN_FILT_NO_WL, + rc = ble_hs_test_util_disc(own_addr_type, BLE_HS_FOREVER, disc_params, ble_gap_test_util_disc_cb, NULL, cmd_fail_idx, fail_status); TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); if (rc == 0) { TEST_ASSERT(ble_gap_master_in_progress()); - ble_gap_rx_adv_report(adv); + ble_gap_rx_adv_report(desc); } else { - TEST_ASSERT(ble_gap_test_disc_status == -1); + TEST_ASSERT(ble_gap_test_disc_event_type == -1); } if (cmd_fail_idx > 0) { /* Verify tx of set scan parameters command. */ ble_gap_test_util_verify_tx_set_scan_params( - 30 * 1000 / BLE_HCI_ADV_ITVL, - 30 * 1000 / BLE_HCI_SCAN_ITVL, - BLE_HCI_SCAN_FILT_NO_WL); + own_addr_type, + disc_params->passive ? + BLE_HCI_SCAN_TYPE_PASSIVE : + BLE_HCI_SCAN_TYPE_ACTIVE, + disc_params->itvl, + disc_params->window, + disc_params->filter_policy); } if (cmd_fail_idx > 1) { /* Verify tx of scan enable command. */ - ble_gap_test_util_verify_tx_scan_enable(1); + ble_gap_test_util_verify_tx_scan_enable( + 1, disc_params->filter_duplicates); + } + + if (rc == 0) { + TEST_ASSERT(ble_gap_disc_active()); } return rc; } -TEST_CASE(ble_gap_test_case_conn_disc_bad_args) +TEST_CASE(ble_gap_test_case_disc_bad_args) { + struct ble_gap_disc_params params; int rc; + params.itvl = 0; + params.window = 0; + params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL; + params.limited = 0; + params.passive = 0; + params.filter_duplicates = 0; + ble_gap_test_util_init(); - /*** Invalid discovery mode. */ - rc = ble_gap_disc(0, BLE_GAP_DISC_MODE_NON, BLE_HCI_SCAN_TYPE_ACTIVE, - BLE_HCI_SCAN_FILT_NO_WL, BLE_ADDR_TYPE_PUBLIC, ble_gap_test_util_disc_cb, - NULL); + /*** Invalid filter policy. */ + params.filter_policy = 6; + rc = ble_gap_disc(BLE_ADDR_TYPE_PUBLIC, 0, ¶ms, + ble_gap_test_util_disc_cb, NULL); TEST_ASSERT(rc == BLE_HS_EINVAL); - - /*** Master operation already in progress. */ - rc = ble_hs_test_util_conn_initiate(BLE_GAP_ADDR_TYPE_WL, NULL, NULL, - ble_gap_test_util_connect_cb, NULL, 0); - rc = ble_gap_disc(0, BLE_GAP_DISC_MODE_GEN, BLE_HCI_SCAN_TYPE_ACTIVE, - BLE_HCI_SCAN_FILT_NO_WL, BLE_ADDR_TYPE_PUBLIC, ble_gap_test_util_disc_cb, - NULL); - TEST_ASSERT(rc == BLE_HS_EALREADY); } -TEST_CASE(ble_gap_test_case_conn_disc_good) +TEST_CASE(ble_gap_test_case_disc_good) { uint8_t adv_data[32]; uint8_t flags; + uint8_t own_addr_type; + int passive; + int limited; int rc; - int d; - uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; - struct ble_hs_adv adv = { + struct ble_gap_disc_desc desc = { .event_type = BLE_HCI_ADV_TYPE_ADV_IND, .addr_type = BLE_ADDR_TYPE_PUBLIC, .length_data = 0, @@ -590,56 +594,101 @@ TEST_CASE(ble_gap_test_case_conn_disc_good) .addr = { 1, 2, 3, 4, 5, 6 }, .data = adv_data, }; + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 0, + .passive = 0, + .filter_duplicates = 0, + }; flags = BLE_HS_ADV_F_DISC_LTD; rc = ble_hs_adv_set_flat(BLE_HS_ADV_TYPE_FLAGS, 1, &flags, - adv.data, &adv.length_data, + desc.data, &desc.length_data, sizeof adv_data); TEST_ASSERT_FATAL(rc == 0); - for (d = BLE_GAP_DISC_MODE_LTD; d < BLE_GAP_DISC_MODE_MAX; d++) { - ble_gap_test_util_disc(d, peer_addr, &adv, -1, 0); + for (own_addr_type = 0; + own_addr_type <= BLE_ADDR_TYPE_RPA_RND_DEFAULT; + own_addr_type++) + for (passive = 0; passive <= 1; passive++) + for (limited = 0; limited <= 1; limited++) { + disc_params.passive = passive; + disc_params.limited = limited; + ble_gap_test_util_disc(own_addr_type, &disc_params, &desc, -1, 0); TEST_ASSERT(ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_disc_event == BLE_GAP_EVENT_DISC_SUCCESS); - TEST_ASSERT(ble_gap_test_disc_status == 0); + TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC); TEST_ASSERT(ble_gap_test_disc_desc.event_type == BLE_HCI_ADV_TYPE_ADV_IND); - TEST_ASSERT(ble_gap_test_disc_desc.addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(ble_gap_test_disc_desc.addr_type == + BLE_ADDR_TYPE_PUBLIC); TEST_ASSERT(ble_gap_test_disc_desc.length_data == 3); TEST_ASSERT(ble_gap_test_disc_desc.rssi == 0); - TEST_ASSERT(memcmp(ble_gap_test_disc_desc.addr, adv.addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_disc_desc.addr, desc.addr, 6) == 0); TEST_ASSERT(ble_gap_test_disc_arg == NULL); + } } -TEST_CASE(ble_gap_test_case_conn_disc_bad_flags) +TEST_CASE(ble_gap_test_case_disc_ltd_mismatch) { - uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; - struct ble_hs_adv adv = { + int rc; + struct ble_gap_disc_desc desc = { .event_type = BLE_HCI_ADV_TYPE_ADV_IND, .addr_type = BLE_ADDR_TYPE_PUBLIC, .length_data = 0, .rssi = 0, .addr = { 1, 2, 3, 4, 5, 6 }, - .data = NULL, + .data = (uint8_t[BLE_HCI_MAX_ADV_DATA_LEN]){ + 2, + BLE_HS_ADV_TYPE_FLAGS, + BLE_HS_ADV_F_DISC_GEN, + }, + }; + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 1, + .passive = 0, + .filter_duplicates = 0, }; - ble_gap_test_util_disc(BLE_GAP_DISC_MODE_LTD, peer_addr, &adv, -1, 0); + rc = ble_gap_test_util_disc(BLE_ADDR_TYPE_PUBLIC, &disc_params, &desc, + -1, 0); + TEST_ASSERT(rc == 0); TEST_ASSERT(ble_gap_master_in_progress()); - /* Verify that the report was ignored becuase of a mismatched LTD flag. */ - TEST_ASSERT(ble_gap_test_disc_event == -1); + /* Verify that the report was ignored because of a mismatched LTD flag. */ + TEST_ASSERT(ble_gap_test_disc_event_type == -1); + + /* Stop the scan and swap the flags. */ + rc = ble_hs_test_util_disc_cancel(0); + TEST_ASSERT(rc == 0); + + desc.data[2] = BLE_HS_ADV_F_DISC_LTD; + disc_params.limited = 0; + rc = ble_gap_test_util_disc(BLE_ADDR_TYPE_PUBLIC, &disc_params, &desc, + -1, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + /* This time we should have reported the advertisement; general discovery + * hears everything. + */ + TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC); + } -TEST_CASE(ble_gap_test_case_conn_disc_hci_fail) +TEST_CASE(ble_gap_test_case_disc_hci_fail) { int fail_idx; + int limited; int rc; - int d; - uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; - struct ble_hs_adv adv = { + struct ble_gap_disc_desc desc = { .event_type = BLE_HCI_ADV_TYPE_ADV_IND, .addr_type = BLE_ADDR_TYPE_PUBLIC, .length_data = 0, @@ -647,32 +696,127 @@ TEST_CASE(ble_gap_test_case_conn_disc_hci_fail) .addr = { 1, 2, 3, 4, 5, 6 }, .data = NULL, }; + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 0, + .passive = 0, + .filter_duplicates = 0, + }; + + for (limited = 0; limited <= 1; limited++) { + disc_params.limited = limited; - for (d = BLE_GAP_DISC_MODE_LTD; d < BLE_GAP_DISC_MODE_MAX; d++) { for (fail_idx = 0; fail_idx < 2; fail_idx++) { - rc = ble_gap_test_util_disc(d, peer_addr, &adv, fail_idx, - BLE_ERR_UNSUPPORTED); + rc = ble_gap_test_util_disc(BLE_ADDR_TYPE_PUBLIC, &disc_params, + &desc, fail_idx, BLE_ERR_UNSUPPORTED); TEST_ASSERT(rc == BLE_HS_HCI_ERR(BLE_ERR_UNSUPPORTED)); TEST_ASSERT(!ble_gap_master_in_progress()); } } } -TEST_SUITE(ble_gap_test_suite_conn_disc) +static void +ble_gap_test_util_disc_dflts_once(int limited) +{ + struct ble_gap_disc_params params; + uint16_t exp_window; + uint16_t exp_itvl; + int rc; + + ble_gap_test_util_init(); + + memset(¶ms, 0, sizeof params); + params.limited = limited; + + rc = ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, 0, ¶ms, + ble_gap_test_util_disc_cb, NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + if (limited) { + exp_itvl = BLE_GAP_LIM_DISC_SCAN_INT; + exp_window = BLE_GAP_LIM_DISC_SCAN_WINDOW; + } else { + exp_itvl = BLE_GAP_SCAN_FAST_INTERVAL_MIN; + exp_window = BLE_GAP_SCAN_FAST_WINDOW; + } + ble_gap_test_util_verify_tx_set_scan_params( + BLE_ADDR_TYPE_PUBLIC, + BLE_HCI_SCAN_TYPE_ACTIVE, + exp_itvl, + exp_window, + BLE_HCI_SCAN_FILT_NO_WL); + + ble_gap_test_util_verify_tx_scan_enable(1, 0); +} + +TEST_CASE(ble_gap_test_case_disc_dflts) +{ + ble_gap_test_util_disc_dflts_once(0); + ble_gap_test_util_disc_dflts_once(1); +} + +TEST_CASE(ble_gap_test_case_disc_already) { - ble_gap_test_case_conn_disc_bad_args(); - ble_gap_test_case_conn_disc_good(); - ble_gap_test_case_conn_disc_bad_flags(); - ble_gap_test_case_conn_disc_hci_fail(); + static const struct ble_gap_disc_params disc_params = { 0 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a discovery procedure. */ + rc = ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_gap_test_util_disc_cb, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EALREADY if we try to discover. */ + rc = ble_gap_disc(BLE_ADDR_TYPE_PUBLIC, BLE_HS_FOREVER, &disc_params, + ble_gap_test_util_disc_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EALREADY); +} + +TEST_CASE(ble_gap_test_case_disc_busy) +{ + static const struct ble_gap_disc_params disc_params = { 0 }; + static const uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a connect procedure. */ + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EBUSY if we try to discover. */ + rc = ble_gap_disc(BLE_ADDR_TYPE_PUBLIC, BLE_HS_FOREVER, &disc_params, + ble_gap_test_util_disc_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EBUSY); +} + +TEST_SUITE(ble_gap_test_suite_disc) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_disc_bad_args(); + ble_gap_test_case_disc_good(); + ble_gap_test_case_disc_ltd_mismatch(); + ble_gap_test_case_disc_hci_fail(); + ble_gap_test_case_disc_dflts(); + ble_gap_test_case_disc_already(); + ble_gap_test_case_disc_busy(); } /***************************************************************************** * $direct connect * *****************************************************************************/ -TEST_CASE(ble_gap_test_case_conn_dir_good) +TEST_CASE(ble_gap_test_case_conn_gen_good) { struct hci_le_conn_complete evt; + struct ble_gap_conn_params params; int rc; uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; @@ -680,15 +824,25 @@ TEST_CASE(ble_gap_test_case_conn_dir_good) ble_gap_test_util_init(); TEST_ASSERT(!ble_gap_master_in_progress()); - - rc = ble_hs_test_util_conn_initiate(BLE_ADDR_TYPE_PUBLIC, peer_addr, NULL, - ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(!ble_gap_conn_active()); + + params.scan_itvl = 0x12; + params.scan_window = 0x11; + params.itvl_min = 25; + params.itvl_max = 26; + params.latency = 1; + params.supervision_timeout = 20; + params.min_ce_len = 3; + params.max_ce_len = 4; + + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, peer_addr, 0, ¶ms, + ble_gap_test_util_connect_cb, NULL, 0); TEST_ASSERT(rc == 0); TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_conn_active()); - /* Verify tx of create connection command. */ - ble_gap_test_util_verify_tx_create_conn(BLE_HCI_CONN_FILT_NO_WL); TEST_ASSERT(ble_gap_master_in_progress()); TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); @@ -704,14 +858,15 @@ TEST_CASE(ble_gap_test_case_conn_dir_good) TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); } -TEST_CASE(ble_gap_test_case_conn_dir_bad_args) +TEST_CASE(ble_gap_test_case_conn_gen_bad_args) { int rc; @@ -720,29 +875,92 @@ TEST_CASE(ble_gap_test_case_conn_dir_bad_args) TEST_ASSERT(!ble_gap_master_in_progress()); /*** Invalid address type. */ - rc = ble_gap_conn_initiate(5, ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), NULL, - ble_gap_test_util_connect_cb, NULL); + rc = ble_gap_connect(BLE_ADDR_TYPE_PUBLIC, 5, + ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), 0, NULL, + ble_gap_test_util_connect_cb, NULL); TEST_ASSERT(rc == BLE_HS_EINVAL); TEST_ASSERT(!ble_gap_master_in_progress()); /*** Connection already in progress. */ - rc = ble_hs_test_util_conn_initiate(BLE_ADDR_TYPE_PUBLIC, - ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), - NULL, ble_gap_test_util_connect_cb, - NULL, 0); + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), 0, + NULL, ble_gap_test_util_connect_cb, + NULL, 0); TEST_ASSERT(rc == 0); TEST_ASSERT(ble_gap_master_in_progress()); - rc = ble_gap_conn_initiate(BLE_ADDR_TYPE_PUBLIC, - ((uint8_t[]){ 2, 3, 4, 5, 6, 7 }), NULL, - ble_gap_test_util_connect_cb, NULL); + rc = ble_gap_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), 0, NULL, + ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EALREADY); +} + +TEST_CASE(ble_gap_test_case_conn_gen_dflt_params) +{ + static const uint8_t peer_addr[6] = { 2, 3, 8, 6, 6, 1 }; + int rc; + + ble_gap_test_util_init(); + + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); +} + +TEST_CASE(ble_gap_test_case_conn_gen_already) +{ + static const struct ble_gap_conn_params conn_params = { 0 }; + static const uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a connect procedure. */ + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EALREADY if we try to connect. */ + rc = ble_gap_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, BLE_HS_FOREVER, &conn_params, + ble_gap_test_util_connect_cb, NULL); TEST_ASSERT(rc == BLE_HS_EALREADY); } -TEST_SUITE(ble_gap_test_suite_conn_dir) +TEST_CASE(ble_gap_test_case_conn_gen_busy) { - ble_gap_test_case_conn_dir_good(); - ble_gap_test_case_conn_dir_bad_args(); + static const struct ble_gap_disc_params disc_params = { 0 }; + static const struct ble_gap_conn_params conn_params = { 0 }; + static const uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a discovery procedure. */ + rc = ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_gap_test_util_disc_cb, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EBUSY if we try to connect. */ + rc = ble_gap_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, BLE_HS_FOREVER, &conn_params, + ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EBUSY); +} + +TEST_SUITE(ble_gap_test_suite_conn_gen) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_conn_gen_good(); + ble_gap_test_case_conn_gen_bad_args(); + ble_gap_test_case_conn_gen_dflt_params(); + ble_gap_test_case_conn_gen_already(); + ble_gap_test_case_conn_gen_busy(); } /***************************************************************************** @@ -750,26 +968,17 @@ TEST_SUITE(ble_gap_test_suite_conn_dir) *****************************************************************************/ static void -ble_gap_test_util_conn_cancel(uint8_t *peer_addr, uint8_t hci_status) +ble_gap_test_util_conn_cancel(uint8_t hci_status) { struct hci_le_conn_complete evt; int rc; - ble_gap_test_util_init(); - - /* Begin creating a connection. */ - rc = ble_hs_test_util_conn_initiate(BLE_ADDR_TYPE_PUBLIC, peer_addr, NULL, - ble_gap_test_util_connect_cb, NULL, 0); - TEST_ASSERT(rc == 0); - TEST_ASSERT(ble_gap_master_in_progress()); - ble_gap_test_util_verify_tx_create_conn(BLE_HCI_CONN_FILT_NO_WL); - /* Initiate cancel procedure. */ rc = ble_hs_test_util_conn_cancel(hci_status); TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); /* Verify tx of cancel create connection command. */ - ble_gap_test_util_verify_tx_create_conn_cancel(); + ble_hs_test_util_verify_tx_create_conn_cancel(); if (rc != 0) { return; } @@ -779,12 +988,29 @@ ble_gap_test_util_conn_cancel(uint8_t *peer_addr, uint8_t hci_status) memset(&evt, 0, sizeof evt); evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; evt.status = BLE_ERR_UNK_CONN_ID; - evt.connection_handle = 2; - evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; - memcpy(evt.peer_addr, peer_addr, 6); rc = ble_gap_rx_conn_complete(&evt); TEST_ASSERT(rc == 0); TEST_ASSERT(!ble_gap_master_in_progress()); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_CANCEL); +} + +static void +ble_gap_test_util_conn_and_cancel(uint8_t *peer_addr, uint8_t hci_status) +{ + int rc; + + ble_gap_test_util_init(); + + /* Begin creating a connection. */ + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + /* Initiate cancel procedure. */ + ble_gap_test_util_conn_cancel(hci_status); TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); } @@ -797,16 +1023,16 @@ TEST_CASE(ble_gap_test_case_conn_cancel_bad_args) /* Initiate cancel procedure with no connection in progress. */ TEST_ASSERT(!ble_gap_master_in_progress()); rc = ble_hs_test_util_conn_cancel(0); - TEST_ASSERT(rc == BLE_HS_ENOENT); + TEST_ASSERT(rc == BLE_HS_EALREADY); } TEST_CASE(ble_gap_test_case_conn_cancel_good) { uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; - ble_gap_test_util_conn_cancel(peer_addr, 0); + ble_gap_test_util_conn_and_cancel(peer_addr, 0); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_CANCEL); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_CANCEL); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == BLE_HS_CONN_HANDLE_NONE); } @@ -817,12 +1043,12 @@ TEST_CASE(ble_gap_test_case_conn_cancel_ctlr_fail) uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; - ble_gap_test_util_conn_cancel(peer_addr, BLE_ERR_REPEATED_ATTEMPTS); + ble_gap_test_util_conn_and_cancel(peer_addr, BLE_ERR_REPEATED_ATTEMPTS); /* Make sure the host didn't invoke the application callback. The cancel * failure was indicated via the return code from the gap call. */ - TEST_ASSERT(ble_gap_test_conn_event == -1); + TEST_ASSERT(ble_gap_test_event.type == 0xff); /* Allow connection complete to succeed. */ memset(&evt, 0, sizeof evt); @@ -836,7 +1062,7 @@ TEST_CASE(ble_gap_test_case_conn_cancel_ctlr_fail) TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); @@ -846,6 +1072,8 @@ TEST_CASE(ble_gap_test_case_conn_cancel_ctlr_fail) TEST_SUITE(ble_gap_test_suite_conn_cancel) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gap_test_case_conn_cancel_good(); ble_gap_test_case_conn_cancel_bad_args(); ble_gap_test_case_conn_cancel_ctlr_fail(); @@ -870,7 +1098,7 @@ ble_gap_test_util_terminate(uint8_t *peer_addr, uint8_t hci_status) /* Reset the callback event code; we don't care about the successful * connection in this test. */ - ble_gap_test_conn_event = -1; + ble_gap_test_event.type = -1; /* Terminate the connection. */ rc = ble_hs_test_util_conn_terminate(2, hci_status); @@ -906,12 +1134,14 @@ TEST_CASE(ble_gap_test_case_conn_terminate_good) ble_gap_test_util_terminate(peer_addr, 0); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_DISCONNECT); TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(BLE_ERR_CONN_TERM_LOCAL)); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(ble_gap_test_conn_desc.peer_id_addr_type == BLE_ADDR_TYPE_PUBLIC); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.peer_id_addr_type == + BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_arg == NULL); TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); @@ -945,12 +1175,14 @@ TEST_CASE(ble_gap_test_case_conn_terminate_ctlr_fail) evt.reason = 0; ble_gap_rx_disconn_complete(&evt); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_TERM_FAILURE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_TERM_FAILURE); TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(BLE_ERR_UNSUPPORTED)); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(ble_gap_test_conn_desc.peer_id_addr_type == BLE_ADDR_TYPE_PUBLIC); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.peer_id_addr_type == + BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_arg == NULL); TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); @@ -963,13 +1195,15 @@ TEST_CASE(ble_gap_test_case_conn_terminate_hci_fail) ble_gap_test_util_terminate(peer_addr, BLE_ERR_REPEATED_ATTEMPTS); - TEST_ASSERT(ble_gap_test_conn_event == -1); + TEST_ASSERT(ble_gap_test_event.type == 0xff); TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); TEST_ASSERT(!ble_gap_master_in_progress()); } TEST_SUITE(ble_gap_test_suite_conn_terminate) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gap_test_case_conn_terminate_bad_args(); ble_gap_test_case_conn_terminate_good(); ble_gap_test_case_conn_terminate_ctlr_fail(); @@ -977,38 +1211,170 @@ TEST_SUITE(ble_gap_test_suite_conn_terminate) } /***************************************************************************** + * $conn find * + *****************************************************************************/ + +TEST_CASE(ble_gap_test_case_conn_find) +{ + + struct ble_gap_conn_desc desc; + struct ble_hs_conn *conn; + uint8_t pub_addr[6]; + int rc; + + /*** We are master; public addresses. */ + ble_gap_test_util_init(); + + ble_hs_test_util_create_rpa_conn(8, + BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[6]){0,0,0,0,0,0}), + BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[6]){2,3,4,5,6,7}), + ((uint8_t[6]){0,0,0,0,0,0}), + ble_gap_test_util_connect_cb, + NULL); + + + rc = ble_hs_id_copy_addr(BLE_ADDR_TYPE_PUBLIC, pub_addr, NULL); + TEST_ASSERT_FATAL(rc == 0); + + rc = ble_gap_conn_find(8, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.conn_handle == 8); + TEST_ASSERT(desc.our_id_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(desc.our_ota_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(desc.peer_ota_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_MASTER); + TEST_ASSERT(memcmp(desc.our_ota_addr, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.our_id_addr, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.peer_ota_addr, + ((uint8_t[6]){2,3,4,5,6,7}), 6) == 0); + TEST_ASSERT(memcmp(desc.peer_id_addr, + ((uint8_t[6]){2,3,4,5,6,7}), 6) == 0); + TEST_ASSERT(desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(desc.conn_latency == BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); + TEST_ASSERT(desc.master_clock_accuracy == 0); + TEST_ASSERT(!desc.sec_state.encrypted); + TEST_ASSERT(!desc.sec_state.authenticated); + TEST_ASSERT(!desc.sec_state.bonded); + + /*** Swap roles. */ + ble_hs_lock(); + conn = ble_hs_conn_find(8); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + rc = ble_gap_conn_find(8, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_SLAVE); + + /*** We are master; RPAs. */ + ble_gap_test_util_init(); + + ble_hs_test_util_create_rpa_conn(54, + BLE_ADDR_TYPE_RPA_PUB_DEFAULT, + ((uint8_t[6]){0x40,1,2,3,4,5}), + BLE_ADDR_TYPE_RPA_RND_DEFAULT, + ((uint8_t[6]){3,4,5,6,7,8}), + ((uint8_t[6]){0x50,1,2,3,4,5}), + ble_gap_test_util_connect_cb, + NULL); + + rc = ble_gap_conn_find(54, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.conn_handle == 54); + TEST_ASSERT(desc.our_id_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(desc.our_ota_addr_type == BLE_ADDR_TYPE_RPA_PUB_DEFAULT); + TEST_ASSERT(desc.peer_ota_addr_type == BLE_ADDR_TYPE_RPA_RND_DEFAULT); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_MASTER); + TEST_ASSERT(memcmp(desc.our_ota_addr, + ((uint8_t[6]){0x40,1,2,3,4,5}), 6) == 0); + TEST_ASSERT(memcmp(desc.our_id_addr, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.peer_ota_addr, + ((uint8_t[6]){0x50,1,2,3,4,5}), 6) == 0); + TEST_ASSERT(memcmp(desc.peer_id_addr, + ((uint8_t[6]){3,4,5,6,7,8}), 6) == 0); + TEST_ASSERT(desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(desc.conn_latency == BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); + TEST_ASSERT(desc.master_clock_accuracy == 0); + TEST_ASSERT(!desc.sec_state.encrypted); + TEST_ASSERT(!desc.sec_state.authenticated); + TEST_ASSERT(!desc.sec_state.bonded); + + /*** Swap roles. */ + ble_hs_lock(); + conn = ble_hs_conn_find(54); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + rc = ble_gap_conn_find(54, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_SLAVE); +} + +TEST_SUITE(ble_gap_test_suite_conn_find) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_conn_find(); +} + +/***************************************************************************** * $advertise * *****************************************************************************/ static void -ble_gap_test_util_adv(uint8_t disc_mode, uint8_t conn_mode, - uint8_t *peer_addr, uint8_t peer_addr_type, - int connect_status, +ble_gap_test_util_adv(uint8_t own_addr_type, uint8_t peer_addr_type, + const uint8_t *peer_addr, uint8_t conn_mode, + uint8_t disc_mode, int connect_status, int cmd_fail_idx, uint8_t fail_status) { struct hci_le_conn_complete evt; + struct ble_gap_adv_params adv_params; struct ble_hs_adv_fields adv_fields; + uint8_t hci_status; int cmd_idx; int rc; ble_gap_test_util_init(); - TEST_ASSERT(!ble_gap_slave_in_progress()); + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = conn_mode; + adv_params.disc_mode = disc_mode; + + TEST_ASSERT(!ble_gap_adv_active()); + + cmd_idx = 0; if (conn_mode != BLE_GAP_CONN_MODE_DIR) { memset(&adv_fields, 0, sizeof adv_fields); adv_fields.tx_pwr_lvl_is_present = 1; - rc = ble_gap_adv_set_fields(&adv_fields); - TEST_ASSERT_FATAL(rc == 0); + adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; + + hci_status = ble_hs_test_util_exp_hci_status(cmd_idx, cmd_fail_idx, + fail_status); + rc = ble_hs_test_util_adv_set_fields(&adv_fields, hci_status); + + if (adv_fields.tx_pwr_lvl_is_present && + adv_fields.tx_pwr_lvl == BLE_HS_ADV_TX_PWR_LVL_AUTO) { + + TEST_ASSERT_FATAL(rc == BLE_HS_HCI_ERR(hci_status)); + cmd_idx++; + } } - rc = ble_hs_test_util_adv_start(disc_mode, conn_mode, peer_addr, - peer_addr_type, NULL, - ble_gap_test_util_connect_cb, NULL, - cmd_fail_idx, fail_status); - TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + rc = ble_hs_test_util_adv_start(own_addr_type, peer_addr_type, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, + cmd_fail_idx - cmd_idx, fail_status); - cmd_idx = 0; + TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); + } if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { /* Verify tx of set advertising params command. */ @@ -1018,12 +1384,6 @@ ble_gap_test_util_adv(uint8_t disc_mode, uint8_t conn_mode, if (conn_mode != BLE_GAP_CONN_MODE_DIR) { if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { - /* Verify tx of read tx power command. */ - ble_gap_test_util_verify_tx_rd_pwr(); - } - cmd_idx++; - - if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { /* Verify tx of set advertise data command. */ ble_gap_test_util_verify_tx_adv_data(); } @@ -1042,8 +1402,10 @@ ble_gap_test_util_adv(uint8_t disc_mode, uint8_t conn_mode, } cmd_idx++; - if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { - TEST_ASSERT(ble_gap_slave_in_progress()); + if (connect_status != -1 && + (fail_status == 0 || cmd_fail_idx >= cmd_idx)) { + + TEST_ASSERT(ble_gap_adv_active()); /* Receive a connection complete event. */ if (conn_mode != BLE_GAP_CONN_MODE_NON) { @@ -1059,74 +1421,164 @@ ble_gap_test_util_adv(uint8_t disc_mode, uint8_t conn_mode, if (connect_status == 0 || connect_status == BLE_ERR_DIR_ADV_TMO) { - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); } else { - TEST_ASSERT(ble_gap_slave_in_progress()); + TEST_ASSERT(ble_gap_adv_active()); } } } } -TEST_CASE(ble_gap_test_case_conn_adv_bad_args) +TEST_CASE(ble_gap_test_case_adv_bad_args) { + struct ble_gap_adv_params adv_params; uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; int rc; - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); /*** Invalid discoverable mode. */ - rc = ble_hs_test_util_adv_start(-1, BLE_GAP_CONN_MODE_DIR, peer_addr, - BLE_ADDR_TYPE_PUBLIC, NULL, + adv_params = ble_hs_test_util_adv_params; + adv_params.disc_mode = 43; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, ble_gap_test_util_connect_cb, NULL, 0, 0); TEST_ASSERT(rc == BLE_HS_EINVAL); - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); /*** Invalid connectable mode. */ - rc = ble_hs_test_util_adv_start(BLE_GAP_DISC_MODE_GEN, -1, peer_addr, - BLE_ADDR_TYPE_PUBLIC, NULL, + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = 27; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, ble_gap_test_util_connect_cb, NULL, 0, 0); TEST_ASSERT(rc == BLE_HS_EINVAL); - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); /*** Invalid peer address type with directed advertisable mode. */ - rc = ble_hs_test_util_adv_start(BLE_GAP_DISC_MODE_GEN, - BLE_GAP_CONN_MODE_DIR, peer_addr, -1, - NULL, ble_gap_test_util_connect_cb, NULL, - 0, 0); + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = BLE_GAP_CONN_MODE_DIR; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, 12, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, 0, 0); TEST_ASSERT(rc == BLE_HS_EINVAL); - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); /*** Advertising already in progress. */ - rc = ble_hs_test_util_adv_start(BLE_GAP_DISC_MODE_GEN, - BLE_GAP_CONN_MODE_DIR, - peer_addr, BLE_ADDR_TYPE_PUBLIC, NULL, + adv_params = ble_hs_test_util_adv_params; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, ble_gap_test_util_connect_cb, NULL, 0, 0); TEST_ASSERT(rc == 0); - TEST_ASSERT(ble_gap_slave_in_progress()); + TEST_ASSERT(ble_gap_adv_active()); - rc = ble_hs_test_util_adv_start(BLE_GAP_DISC_MODE_GEN, - BLE_GAP_CONN_MODE_DIR, - peer_addr, BLE_ADDR_TYPE_PUBLIC, NULL, + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, ble_gap_test_util_connect_cb, NULL, 0, 0); TEST_ASSERT(rc == BLE_HS_EALREADY); - TEST_ASSERT(ble_gap_slave_in_progress()); + TEST_ASSERT(ble_gap_adv_active()); +} + +static void +ble_gap_test_util_adv_verify_dflt_params(uint8_t own_addr_type, + uint8_t peer_addr_type, + const uint8_t *peer_addr, + uint8_t conn_mode, + uint8_t disc_mode) +{ + struct ble_gap_adv_params adv_params; + struct hci_adv_params hci_cmd; + uint8_t *hci_buf; + uint8_t hci_param_len; + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_adv_active()); + + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = conn_mode; + adv_params.disc_mode = disc_mode; + + /* Let stack calculate all default parameters. */ + adv_params.itvl_min = 0; + adv_params.itvl_max = 0; + adv_params.channel_map = 0; + adv_params.filter_policy = 0; + adv_params.high_duty_cycle = 0; + + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure default parameters properly filled in. */ + hci_buf = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_PARAMS, + &hci_param_len); + TEST_ASSERT_FATAL(hci_buf != NULL); + TEST_ASSERT_FATAL(hci_param_len == BLE_HCI_SET_ADV_PARAM_LEN); + + hci_cmd.adv_itvl_min = le16toh(hci_buf + 0); + hci_cmd.adv_itvl_max = le16toh(hci_buf + 2); + hci_cmd.adv_type = hci_buf[4]; + hci_cmd.own_addr_type = hci_buf[5]; + hci_cmd.peer_addr_type = hci_buf[6]; + memcpy(hci_cmd.peer_addr, hci_buf + 7, 6); + hci_cmd.adv_channel_map = hci_buf[13]; + hci_cmd.adv_filter_policy = hci_buf[14]; + + if (conn_mode == BLE_GAP_CONN_MODE_NON) { + TEST_ASSERT(hci_cmd.adv_itvl_min == BLE_GAP_ADV_FAST_INTERVAL2_MIN); + TEST_ASSERT(hci_cmd.adv_itvl_max == BLE_GAP_ADV_FAST_INTERVAL2_MAX); + } else { + TEST_ASSERT(hci_cmd.adv_itvl_min == BLE_GAP_ADV_FAST_INTERVAL1_MIN); + TEST_ASSERT(hci_cmd.adv_itvl_max == BLE_GAP_ADV_FAST_INTERVAL1_MAX); + } + + if (conn_mode == BLE_GAP_CONN_MODE_NON) { + if (disc_mode == BLE_GAP_DISC_MODE_NON) { + TEST_ASSERT(hci_cmd.adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND); + } else { + TEST_ASSERT(hci_cmd.adv_type == BLE_HCI_ADV_TYPE_ADV_SCAN_IND); + } + } else if (conn_mode == BLE_GAP_CONN_MODE_UND) { + TEST_ASSERT(hci_cmd.adv_type == BLE_HCI_ADV_TYPE_ADV_IND); + } else { + TEST_ASSERT(hci_cmd.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD); + } } -TEST_CASE(ble_gap_test_case_conn_adv_good) +TEST_CASE(ble_gap_test_case_adv_dflt_params) { uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int d; int c; for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { - ble_gap_test_util_adv(d, c, peer_addr, BLE_ADDR_TYPE_PUBLIC, - BLE_ERR_SUCCESS, -1, 0); + ble_gap_test_util_adv_verify_dflt_params( + BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, peer_addr, c, d); + } + } +} + +TEST_CASE(ble_gap_test_case_adv_good) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_adv(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, c, d, BLE_ERR_SUCCESS, -1, 0); if (c != BLE_GAP_CONN_MODE_NON) { - TEST_ASSERT(!ble_gap_slave_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == - BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == + BLE_GAP_EVENT_CONNECT); TEST_ASSERT(ble_gap_test_conn_status == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, @@ -1137,19 +1589,19 @@ TEST_CASE(ble_gap_test_case_conn_adv_good) } } -TEST_CASE(ble_gap_test_case_conn_adv_ctlr_fail) +TEST_CASE(ble_gap_test_case_adv_ctlr_fail) { uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; int d; int c; - for (c = BLE_GAP_CONN_MODE_DIR; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (c = BLE_GAP_CONN_MODE_NON + 1; c < BLE_GAP_CONN_MODE_MAX; c++) { for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { - ble_gap_test_util_adv(d, c, peer_addr, BLE_ADDR_TYPE_PUBLIC, - BLE_ERR_DIR_ADV_TMO, -1, 0); + ble_gap_test_util_adv(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, c, d, BLE_ERR_DIR_ADV_TMO, -1, 0); - TEST_ASSERT(!ble_gap_slave_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_ADV_COMPLETE); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == BLE_HS_CONN_HANDLE_NONE); @@ -1158,7 +1610,7 @@ TEST_CASE(ble_gap_test_case_conn_adv_ctlr_fail) } } -TEST_CASE(ble_gap_test_case_conn_adv_hci_fail) +TEST_CASE(ble_gap_test_case_adv_hci_fail) { uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; int num_hci_cmds; @@ -1175,21 +1627,26 @@ TEST_CASE(ble_gap_test_case_conn_adv_hci_fail) for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { for (fail_idx = 0; fail_idx < num_hci_cmds; fail_idx++) { - ble_gap_test_util_adv(d, c, peer_addr, BLE_ADDR_TYPE_PUBLIC, - 0, fail_idx, BLE_ERR_UNSUPPORTED); - TEST_ASSERT(!ble_gap_slave_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == -1); + ble_gap_test_util_adv(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, peer_addr, + c, d, 0, fail_idx, BLE_ERR_UNSUPPORTED); + + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == 0xff); } } } } -TEST_SUITE(ble_gap_test_suite_conn_adv) +TEST_SUITE(ble_gap_test_suite_adv) { - ble_gap_test_case_conn_adv_bad_args(); - ble_gap_test_case_conn_adv_good(); - ble_gap_test_case_conn_adv_ctlr_fail(); - ble_gap_test_case_conn_adv_hci_fail(); + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_adv_bad_args(); + ble_gap_test_case_adv_dflt_params(); + ble_gap_test_case_adv_good(); + ble_gap_test_case_adv_ctlr_fail(); + ble_gap_test_case_adv_hci_fail(); } /***************************************************************************** @@ -1197,8 +1654,8 @@ TEST_SUITE(ble_gap_test_suite_conn_adv) *****************************************************************************/ static void -ble_gap_test_util_stop_adv(uint8_t disc_mode, uint8_t conn_mode, - uint8_t *peer_addr, uint8_t peer_addr_type, +ble_gap_test_util_stop_adv(uint8_t peer_addr_type, const uint8_t *peer_addr, + uint8_t conn_mode, uint8_t disc_mode, int cmd_fail_idx, uint8_t fail_status) { uint8_t hci_status; @@ -1207,15 +1664,10 @@ ble_gap_test_util_stop_adv(uint8_t disc_mode, uint8_t conn_mode, ble_gap_test_util_init(); /* Start advertising; don't rx a successful connection event. */ - ble_gap_test_util_adv(disc_mode, conn_mode, peer_addr, - BLE_ADDR_TYPE_PUBLIC, BLE_ERR_UNSUPPORTED, 0, 0); + ble_gap_test_util_adv(BLE_ADDR_TYPE_PUBLIC, peer_addr_type, peer_addr, + conn_mode, disc_mode, -1, -1, 0); - TEST_ASSERT(ble_gap_slave_in_progress()); - - /* Clear the advertising event that the host sent; we only care about what - * happens after advertising is stopped. - */ - ble_gap_test_util_reset_cb_info(); + TEST_ASSERT(ble_gap_adv_active()); /* Stop advertising. */ hci_status = cmd_fail_idx == 0 ? fail_status : 0; @@ -1227,7 +1679,7 @@ ble_gap_test_util_stop_adv(uint8_t disc_mode, uint8_t conn_mode, ble_gap_test_util_verify_tx_adv_enable(0); } -TEST_CASE(ble_gap_test_case_conn_stop_adv_good) +TEST_CASE(ble_gap_test_case_stop_adv_good) { uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; int d; @@ -1235,10 +1687,10 @@ TEST_CASE(ble_gap_test_case_conn_stop_adv_good) for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { - ble_gap_test_util_stop_adv(d, c, peer_addr, BLE_ADDR_TYPE_PUBLIC, + ble_gap_test_util_stop_adv(BLE_ADDR_TYPE_PUBLIC, peer_addr, c, d, -1, 0); - TEST_ASSERT(!ble_gap_slave_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == -1); + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == 0xff); TEST_ASSERT(ble_gap_test_conn_status == -1); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == (uint16_t)-1); TEST_ASSERT(ble_gap_test_conn_arg == (void *)-1); @@ -1246,7 +1698,7 @@ TEST_CASE(ble_gap_test_case_conn_stop_adv_good) } } -TEST_CASE(ble_gap_test_case_conn_stop_adv_hci_fail) +TEST_CASE(ble_gap_test_case_stop_adv_hci_fail) { uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; int d; @@ -1254,10 +1706,10 @@ TEST_CASE(ble_gap_test_case_conn_stop_adv_hci_fail) for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { - ble_gap_test_util_stop_adv(d, c, peer_addr, BLE_ADDR_TYPE_PUBLIC, + ble_gap_test_util_stop_adv(BLE_ADDR_TYPE_PUBLIC, peer_addr, c, d, 0, BLE_ERR_UNSUPPORTED); - TEST_ASSERT(ble_gap_slave_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == -1); + TEST_ASSERT(ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == 0xff); TEST_ASSERT(ble_gap_test_conn_status == -1); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == (uint16_t)-1); TEST_ASSERT(ble_gap_test_conn_arg == (void *)-1); @@ -1265,10 +1717,12 @@ TEST_CASE(ble_gap_test_case_conn_stop_adv_hci_fail) } } -TEST_SUITE(ble_gap_test_suite_conn_stop_adv) +TEST_SUITE(ble_gap_test_suite_stop_adv) { - ble_gap_test_case_conn_stop_adv_good(); - ble_gap_test_case_conn_stop_adv_hci_fail(); + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_stop_adv_good(); + ble_gap_test_case_stop_adv_hci_fail(); } /***************************************************************************** @@ -1316,10 +1770,11 @@ ble_gap_test_util_update(struct ble_gap_upd_params *params, TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); TEST_ASSERT(ble_gap_test_conn_status == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == params->itvl_max); TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == params->latency); TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == @@ -1330,10 +1785,11 @@ ble_gap_test_util_update(struct ble_gap_upd_params *params, return; fail: - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); TEST_ASSERT(ble_gap_test_conn_status == status); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == @@ -1361,7 +1817,7 @@ ble_gap_test_util_update_peer(uint8_t status, TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(status)); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, @@ -1416,10 +1872,11 @@ ble_gap_test_util_update_req_pos(struct ble_gap_upd_params *peer_params, TEST_ASSERT(!ble_gap_master_in_progress()); TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); TEST_ASSERT(ble_gap_test_conn_status == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == self_params->itvl_max); TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == self_params->latency); TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == @@ -1428,10 +1885,11 @@ ble_gap_test_util_update_req_pos(struct ble_gap_upd_params *peer_params, return; hci_fail: - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(hci_status)); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == @@ -1477,10 +1935,11 @@ ble_gap_test_util_update_req_neg(struct ble_gap_upd_params *peer_params, return; hci_fail: - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(hci_status)); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == @@ -1552,10 +2011,11 @@ ble_gap_test_util_update_req_concurrent( TEST_ASSERT(!ble_gap_master_in_progress()); TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); TEST_ASSERT(ble_gap_test_conn_status == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == self_params->itvl_max); TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == self_params->latency); TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == @@ -1564,10 +2024,11 @@ ble_gap_test_util_update_req_concurrent( return; hci_fail: - TEST_ASSERT(ble_gap_test_conn_event == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(fail_status)); TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); - TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, peer_addr, 6) == 0); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == @@ -1831,6 +2292,8 @@ TEST_CASE(ble_gap_test_case_update_concurrent_hci_fail) TEST_SUITE(ble_gap_test_suite_update_conn) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gap_test_case_update_conn_good(); ble_gap_test_case_update_conn_bad(); ble_gap_test_case_update_conn_hci_fail(); @@ -1843,20 +2306,328 @@ TEST_SUITE(ble_gap_test_suite_update_conn) } /***************************************************************************** + * $timeout * + *****************************************************************************/ + +static void +ble_gap_test_util_conn_forever(void) +{ + int32_t ticks_from_now; + + /* Initiate a connect procedure with no timeout. */ + ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), BLE_HS_FOREVER, + NULL, ble_gap_test_util_connect_cb, + NULL, 0); + + /* Ensure no pending GAP event. */ + ticks_from_now = ble_gap_heartbeat(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Advance 100 seconds; ensure no timeout reported. */ + os_time_advance(100 * OS_TICKS_PER_SEC); + ble_gap_heartbeat(); + TEST_ASSERT(ble_gap_test_event.type == 0xff); + TEST_ASSERT(ble_gap_conn_active()); +} + +static void +ble_gap_test_util_conn_timeout(int32_t duration_ms) +{ + struct hci_le_conn_complete evt; + uint32_t duration_ticks; + int32_t ticks_from_now; + int rc; + + TEST_ASSERT_FATAL(duration_ms != BLE_HS_FOREVER); + + /* Initiate a connect procedure with the specified timeout. */ + ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), duration_ms, + NULL, ble_gap_test_util_connect_cb, + NULL, 0); + + /* Ensure next GAP event is at the expected time. */ + rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); + TEST_ASSERT_FATAL(rc == 0); + ticks_from_now = ble_gap_heartbeat(); + TEST_ASSERT(ticks_from_now == duration_ticks); + + /* Advance duration ms; ensure timeout event does not get reported before + * connection complete event rxed. + */ + os_time_advance(duration_ms); + + ble_hs_test_util_set_ack( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN_CANCEL), + 0); + + TEST_ASSERT(ble_gap_test_event.type == 0xff); + + ticks_from_now = ble_gap_heartbeat(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Ensure cancel create connection command was sent. */ + ble_hs_test_util_verify_tx_create_conn_cancel(); + + /* Ensure timer has been stopped. */ + ticks_from_now = ble_gap_heartbeat(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Receive the connection complete event indicating a successful cancel. */ + memset(&evt, 0, sizeof evt); + evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; + evt.status = BLE_ERR_UNK_CONN_ID; + rc = ble_gap_rx_conn_complete(&evt); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure the GAP event was triggered. */ + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_ETIMEOUT); + + /* Clear GAP event for remainder of test. */ + ble_gap_test_util_reset_cb_info(); +} + +static void +ble_gap_test_util_disc_forever(void) +{ + struct ble_gap_disc_params params; + int32_t ticks_from_now; + + memset(¶ms, 0, sizeof params); + + /* Initiate a discovery procedure with no timeout. */ + ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, + BLE_HS_FOREVER, ¶ms, ble_gap_test_util_disc_cb, + NULL, -1, 0); + + /* Ensure no pending GAP event. */ + ticks_from_now = ble_gap_heartbeat(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Advance 100 seconds; ensure no timeout reported. */ + os_time_advance(100 * OS_TICKS_PER_SEC); + TEST_ASSERT(ble_gap_test_disc_event_type == -1); + TEST_ASSERT(ble_gap_disc_active()); +} + +static void +ble_gap_test_util_disc_timeout(int32_t duration_ms) +{ + struct ble_gap_disc_params params; + uint32_t duration_ticks; + int32_t ticks_from_now; + int rc; + + TEST_ASSERT_FATAL(duration_ms != BLE_HS_FOREVER); + + memset(¶ms, 0, sizeof params); + + /* Initiate a discovery procedure with the specified timeout. */ + ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, + duration_ms, ¶ms, ble_gap_test_util_disc_cb, + NULL, -1, 0); + + /* Ensure next GAP event is at the expected time. */ + rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); + TEST_ASSERT_FATAL(rc == 0); + ticks_from_now = ble_gap_heartbeat(); + TEST_ASSERT(ticks_from_now == duration_ticks); + + /* Advance duration ms; ensure timeout event was reported. */ + os_time_advance(duration_ms); + + ble_hs_test_util_set_ack( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + 0); + ticks_from_now = ble_gap_heartbeat(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC_COMPLETE); + + /* Clear GAP event for remainder of test. */ + ble_gap_test_util_reset_cb_info(); +} + +TEST_CASE(ble_gap_test_case_conn_timeout_conn_forever) +{ + ble_gap_test_util_init(); + + /* 3 ms. */ + ble_gap_test_util_conn_timeout(3); + + /* No timeout. */ + ble_gap_test_util_conn_forever(); + +} + +TEST_CASE(ble_gap_test_case_conn_timeout_conn_timeout) +{ + ble_gap_test_util_init(); + + /* 30 ms. */ + ble_gap_test_util_conn_timeout(30); + + /* 5 ms. */ + ble_gap_test_util_conn_timeout(5); + +} + +TEST_CASE(ble_gap_test_case_conn_forever_conn_timeout) +{ + ble_gap_test_util_init(); + + /* No timeout. */ + ble_gap_test_util_conn_forever(); + + /* Cancel connect procedure manually. */ + ble_gap_test_util_conn_cancel(0); + + /* Clear GAP event for remainder of test. */ + ble_gap_test_util_reset_cb_info(); + + /* 3 ms. */ + ble_gap_test_util_conn_timeout(3); +} + +TEST_CASE(ble_gap_test_case_disc_timeout_disc_forever) +{ + ble_gap_test_util_init(); + + /* 3 ms. */ + ble_gap_test_util_disc_timeout(3); + + /* No timeout. */ + ble_gap_test_util_disc_forever(); + +} + +TEST_CASE(ble_gap_test_case_disc_timeout_disc_timeout) +{ + ble_gap_test_util_init(); + + /* 30 ms. */ + ble_gap_test_util_disc_timeout(30); + + /* 5 ms. */ + ble_gap_test_util_disc_timeout(5); + +} + +TEST_CASE(ble_gap_test_case_disc_forever_disc_timeout) +{ + ble_gap_test_util_init(); + + /* No timeout. */ + ble_gap_test_util_disc_forever(); + + /* Cancel discovery procedure manually. */ + ble_hs_test_util_disc_cancel(0); + + /* 3 ms. */ + ble_gap_test_util_disc_timeout(3); +} + +TEST_CASE(ble_gap_test_case_conn_timeout_disc_timeout) +{ + ble_gap_test_util_init(); + + /* 15 seconds. */ + ble_gap_test_util_conn_timeout(15000); + + /* 1285 ms. */ + ble_gap_test_util_disc_timeout(1285); +} + +TEST_SUITE(ble_gap_test_suite_timeout) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_conn_timeout_conn_forever(); + ble_gap_test_case_conn_timeout_conn_timeout(); + ble_gap_test_case_conn_forever_conn_timeout(); + + ble_gap_test_case_disc_timeout_disc_forever(); + ble_gap_test_case_disc_timeout_disc_timeout(); + ble_gap_test_case_disc_forever_disc_timeout(); + + ble_gap_test_case_conn_timeout_disc_timeout(); +} + +TEST_CASE(ble_gap_test_case_mtu_us) +{ + const uint8_t peer_addr[6] = { 1,2,3,4,5,6 }; + int rc; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + ble_att_set_preferred_mtu(200); + + rc = ble_gattc_exchange_mtu(2, NULL, NULL); + TEST_ASSERT_FATAL(rc == 0); + ble_hs_test_util_verify_tx_mtu_cmd(1, 200); + + ble_hs_test_util_rx_att_mtu_cmd(2, 0, 123); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_MTU); + TEST_ASSERT(ble_gap_test_event.mtu.conn_handle == 2); + TEST_ASSERT(ble_gap_test_event.mtu.channel_id == BLE_L2CAP_CID_ATT); + TEST_ASSERT(ble_gap_test_event.mtu.value == 123); +} + +TEST_CASE(ble_gap_test_case_mtu_peer) +{ + const uint8_t peer_addr[6] = { 1,2,3,4,5,6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + ble_att_set_preferred_mtu(200); + + ble_hs_test_util_rx_att_mtu_cmd(2, 1, 123); + ble_hs_test_util_verify_tx_mtu_cmd(0, 200); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_MTU); + TEST_ASSERT(ble_gap_test_event.mtu.conn_handle == 2); + TEST_ASSERT(ble_gap_test_event.mtu.channel_id == BLE_L2CAP_CID_ATT); + TEST_ASSERT(ble_gap_test_event.mtu.value == 123); +} + +TEST_SUITE(ble_gap_test_suite_mtu) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_mtu_us(); + ble_gap_test_case_mtu_peer(); +} + +/***************************************************************************** * $all * *****************************************************************************/ int ble_gap_test_all(void) { - ble_gap_test_suite_conn_wl(); - ble_gap_test_suite_conn_disc(); - ble_gap_test_suite_conn_dir(); + ble_gap_test_suite_wl(); + ble_gap_test_suite_disc(); + ble_gap_test_suite_conn_gen(); ble_gap_test_suite_conn_cancel(); ble_gap_test_suite_conn_terminate(); - ble_gap_test_suite_conn_adv(); - ble_gap_test_suite_conn_stop_adv(); + ble_gap_test_suite_conn_find(); + ble_gap_test_suite_adv(); + ble_gap_test_suite_stop_adv(); ble_gap_test_suite_update_conn(); + ble_gap_test_suite_timeout(); + ble_gap_test_suite_mtu(); return tu_any_failed; } diff --git a/net/nimble/host/src/test/ble_gatt_conn_test.c b/net/nimble/host/src/test/ble_gatt_conn_test.c index 6f3a4a59..be4a46d3 100644 --- a/net/nimble/host/src/test/ble_gatt_conn_test.c +++ b/net/nimble/host/src/test/ble_gatt_conn_test.c @@ -36,16 +36,16 @@ struct ble_gatt_conn_test_cb_arg { static int ble_gatt_conn_test_attr_cb(uint16_t conn_handle, uint16_t attr_handle, - uint8_t *uuid128, uint8_t op, - struct ble_att_svr_access_ctxt *ctxt, + uint8_t op, uint16_t offset, struct os_mbuf **om, void *arg) { - static uint8_t data = 1; + uint8_t *buf; switch (op) { case BLE_ATT_ACCESS_OP_READ: - ctxt->attr_data = &data; - ctxt->data_len = 1; + buf = os_mbuf_extend(*om, 1); + TEST_ASSERT_FATAL(buf != NULL); + *buf = 1; return 0; default: @@ -54,7 +54,8 @@ ble_gatt_conn_test_attr_cb(uint16_t conn_handle, uint16_t attr_handle, } static int -ble_gatt_conn_test_mtu_cb(uint16_t conn_handle, struct ble_gatt_error *error, +ble_gatt_conn_test_mtu_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, uint16_t mtu, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -74,9 +75,9 @@ ble_gatt_conn_test_mtu_cb(uint16_t conn_handle, struct ble_gatt_error *error, static int ble_gatt_conn_test_disc_all_svcs_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_svc *service, - void *arg) + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, + void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -95,8 +96,8 @@ ble_gatt_conn_test_disc_all_svcs_cb(uint16_t conn_handle, static int ble_gatt_conn_test_disc_svc_uuid_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_svc *service, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -116,8 +117,8 @@ ble_gatt_conn_test_disc_svc_uuid_cb(uint16_t conn_handle, static int ble_gatt_conn_test_find_inc_svcs_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_svc *service, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -137,8 +138,8 @@ ble_gatt_conn_test_find_inc_svcs_cb(uint16_t conn_handle, static int ble_gatt_conn_test_disc_all_chrs_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_chr *chr, void *arg) + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -157,8 +158,8 @@ ble_gatt_conn_test_disc_all_chrs_cb(uint16_t conn_handle, static int ble_gatt_conn_test_disc_chr_uuid_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_chr *chr, void *arg) + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -177,9 +178,9 @@ ble_gatt_conn_test_disc_chr_uuid_cb(uint16_t conn_handle, static int ble_gatt_conn_test_disc_all_dscs_cb(uint16_t conn_handle, - struct ble_gatt_error *error, + const struct ble_gatt_error *error, uint16_t chr_def_handle, - struct ble_gatt_dsc *dsc, + const struct ble_gatt_dsc *dsc, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -198,7 +199,8 @@ ble_gatt_conn_test_disc_all_dscs_cb(uint16_t conn_handle, } static int -ble_gatt_conn_test_read_cb(uint16_t conn_handle, struct ble_gatt_error *error, +ble_gatt_conn_test_read_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -218,7 +220,7 @@ ble_gatt_conn_test_read_cb(uint16_t conn_handle, struct ble_gatt_error *error, static int ble_gatt_conn_test_read_uuid_cb(uint16_t conn_handle, - struct ble_gatt_error *error, + const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -238,7 +240,7 @@ ble_gatt_conn_test_read_uuid_cb(uint16_t conn_handle, static int ble_gatt_conn_test_read_long_cb(uint16_t conn_handle, - struct ble_gatt_error *error, + const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -257,7 +259,7 @@ ble_gatt_conn_test_read_long_cb(uint16_t conn_handle, } static int ble_gatt_conn_test_read_mult_cb(uint16_t conn_handle, - struct ble_gatt_error *error, + const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -268,7 +270,7 @@ ble_gatt_conn_test_read_mult_cb(uint16_t conn_handle, TEST_ASSERT(!cb_arg->called); TEST_ASSERT_FATAL(error != NULL); TEST_ASSERT(error->status == BLE_HS_ENOTCONN); - TEST_ASSERT(attr == NULL); + TEST_ASSERT(attr->om == NULL); cb_arg->called++; @@ -276,8 +278,10 @@ ble_gatt_conn_test_read_mult_cb(uint16_t conn_handle, } static int -ble_gatt_conn_test_write_cb(uint16_t conn_handle, struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg) +ble_gatt_conn_test_write_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -297,7 +301,7 @@ ble_gatt_conn_test_write_cb(uint16_t conn_handle, struct ble_gatt_error *error, static int ble_gatt_conn_test_write_long_cb(uint16_t conn_handle, - struct ble_gatt_error *error, + const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -318,8 +322,9 @@ ble_gatt_conn_test_write_long_cb(uint16_t conn_handle, static int ble_gatt_conn_test_write_rel_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_attr *attrs, uint8_t num_attrs, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, void *arg) { struct ble_gatt_conn_test_cb_arg *cb_arg; @@ -337,26 +342,6 @@ ble_gatt_conn_test_write_rel_cb(uint16_t conn_handle, return 0; } -static int -ble_gatt_conn_test_indicate_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg) -{ - struct ble_gatt_conn_test_cb_arg *cb_arg; - - cb_arg = arg; - - TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); - TEST_ASSERT(!cb_arg->called); - TEST_ASSERT_FATAL(error != NULL); - TEST_ASSERT(error->status == BLE_HS_ENOTCONN); - TEST_ASSERT(attr != NULL); - - cb_arg->called++; - - return 0; -} - TEST_CASE(ble_gatt_conn_test_disconnect) { struct ble_gatt_conn_test_cb_arg mtu_arg = { 0 }; @@ -373,7 +358,7 @@ TEST_CASE(ble_gatt_conn_test_disconnect) struct ble_gatt_conn_test_cb_arg write_arg = { 0 }; struct ble_gatt_conn_test_cb_arg write_long_arg = { 0 }; struct ble_gatt_conn_test_cb_arg write_rel_arg = { 0 }; - struct ble_gatt_conn_test_cb_arg indicate_arg = { 0 }; + struct ble_gatt_attr attr; uint16_t attr_handle; int rc; @@ -423,12 +408,12 @@ TEST_CASE(ble_gatt_conn_test_disconnect) /* Connection 2. */ disc_all_dscs_arg.exp_conn_handle = 2; - rc = ble_gattc_disc_all_dscs(2, 1, 0xffff, + rc = ble_gattc_disc_all_dscs(2, 3, 0xffff, ble_gatt_conn_test_disc_all_dscs_cb, &disc_all_dscs_arg); disc_chr_uuid_arg.exp_conn_handle = 2; - rc = ble_gattc_disc_chrs_by_uuid(2, 1, 0xffff, BLE_UUID16(0x2222), + rc = ble_gattc_disc_chrs_by_uuid(2, 2, 0xffff, BLE_UUID16(0x2222), ble_gatt_conn_test_disc_chr_uuid_cb, &disc_chr_uuid_arg); @@ -455,31 +440,25 @@ TEST_CASE(ble_gatt_conn_test_disconnect) TEST_ASSERT_FATAL(rc == 0); write_arg.exp_conn_handle = 3; - rc = ble_gattc_write(3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, - ble_gatt_conn_test_write_value, - sizeof ble_gatt_conn_test_write_value, - ble_gatt_conn_test_write_cb, &write_arg); + rc = ble_hs_test_util_gatt_write_flat( + 3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, + ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value, + ble_gatt_conn_test_write_cb, &write_arg); TEST_ASSERT_FATAL(rc == 0); write_long_arg.exp_conn_handle = 3; - rc = ble_gattc_write_long(3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, - ble_gatt_conn_test_write_value, - sizeof ble_gatt_conn_test_write_value, - ble_gatt_conn_test_write_long_cb, - &write_long_arg); + rc = ble_hs_test_util_gatt_write_long_flat( + 3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, + ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value, + ble_gatt_conn_test_write_long_cb, &write_long_arg); TEST_ASSERT_FATAL(rc == 0); + attr.handle = 8; + attr.offset = 0; + attr.om = os_msys_get_pkthdr(0, 0); write_rel_arg.exp_conn_handle = 3; - rc = ble_gattc_write_reliable(3, - ((struct ble_gatt_attr[]){{8, 0, 0, NULL}}), - 1, ble_gatt_conn_test_write_rel_cb, - &write_rel_arg); - TEST_ASSERT_FATAL(rc == 0); - - indicate_arg.exp_conn_handle = 3; - rc = ble_gattc_indicate(3, attr_handle, - ble_gatt_conn_test_indicate_cb, - &indicate_arg); + rc = ble_gattc_write_reliable( + 3, &attr, 1, ble_gatt_conn_test_write_rel_cb, &write_rel_arg); TEST_ASSERT_FATAL(rc == 0); /*** Start the procedures. */ @@ -502,7 +481,6 @@ TEST_CASE(ble_gatt_conn_test_disconnect) TEST_ASSERT(write_arg.called == 0); TEST_ASSERT(write_long_arg.called == 0); TEST_ASSERT(write_rel_arg.called == 0); - TEST_ASSERT(indicate_arg.called == 0); /* Connection 2. */ ble_gattc_connection_broken(2); @@ -520,7 +498,6 @@ TEST_CASE(ble_gatt_conn_test_disconnect) TEST_ASSERT(write_arg.called == 0); TEST_ASSERT(write_long_arg.called == 0); TEST_ASSERT(write_rel_arg.called == 0); - TEST_ASSERT(indicate_arg.called == 0); /* Connection 3. */ ble_gattc_connection_broken(3); @@ -538,11 +515,12 @@ TEST_CASE(ble_gatt_conn_test_disconnect) TEST_ASSERT(write_arg.called == 1); TEST_ASSERT(write_long_arg.called == 1); TEST_ASSERT(write_rel_arg.called == 1); - TEST_ASSERT(indicate_arg.called == 1); } TEST_SUITE(ble_gatt_break_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatt_conn_test_disconnect(); } diff --git a/net/nimble/host/src/test/ble_gatt_disc_c_test.c b/net/nimble/host/src/test/ble_gatt_disc_c_test.c index 6325926f..a4eb67bf 100644 --- a/net/nimble/host/src/test/ble_gatt_disc_c_test.c +++ b/net/nimble/host/src/test/ble_gatt_disc_c_test.c @@ -169,25 +169,33 @@ ble_gatt_disc_c_test_misc_verify_chars(struct ble_gatt_disc_c_test_char *chars, static int ble_gatt_disc_c_test_misc_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_chr *chr, void *arg) + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg) { struct ble_gatt_chr *dst; int *stop_after; - TEST_ASSERT(error == NULL); + TEST_ASSERT(error != NULL); TEST_ASSERT(!ble_gatt_disc_c_test_rx_complete); stop_after = arg; - if (chr == NULL) { - ble_gatt_disc_c_test_rx_complete = 1; - } else { + switch (error->status) { + case 0: TEST_ASSERT_FATAL(ble_gatt_disc_c_test_num_chars < BLE_GATT_DISC_C_TEST_MAX_CHARS); dst = ble_gatt_disc_c_test_chars + ble_gatt_disc_c_test_num_chars++; *dst = *chr; + break; + + case BLE_HS_EDONE: + ble_gatt_disc_c_test_rx_complete = 1; + break; + + default: + TEST_ASSERT(0); + break; } if (*stop_after > 0) { @@ -524,6 +532,8 @@ TEST_CASE(ble_gatt_disc_c_test_disc_uuid) TEST_SUITE(ble_gatt_disc_c_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatt_disc_c_test_disc_all(); ble_gatt_disc_c_test_disc_uuid(); } diff --git a/net/nimble/host/src/test/ble_gatt_disc_d_test.c b/net/nimble/host/src/test/ble_gatt_disc_d_test.c index 6b0a8077..7e021e2e 100644 --- a/net/nimble/host/src/test/ble_gatt_disc_d_test.c +++ b/net/nimble/host/src/test/ble_gatt_disc_d_test.c @@ -28,7 +28,7 @@ #include "ble_hs_test_util.h" struct ble_gatt_disc_d_test_dsc { - uint16_t chr_def_handle; /* 0 if last entry. */ + uint16_t chr_val_handle; /* 0 if last entry. */ uint16_t dsc_handle; uint8_t dsc_uuid128[16]; }; @@ -74,7 +74,7 @@ ble_gatt_disc_d_test_misc_rx_rsp_once( off = BLE_ATT_FIND_INFO_RSP_BASE_SZ; for (i = 0; ; i++) { - if (dscs[i].chr_def_handle == 0) { + if (dscs[i].chr_val_handle == 0) { /* No more descriptors. */ break; } @@ -113,7 +113,7 @@ ble_gatt_disc_d_test_misc_rx_rsp(uint16_t conn_handle, int idx; idx = 0; - while (dscs[idx].chr_def_handle != 0) { + while (dscs[idx].chr_val_handle != 0) { count = ble_gatt_disc_d_test_misc_rx_rsp_once(conn_handle, dscs + idx); if (count == 0) { break; @@ -140,9 +140,9 @@ ble_gatt_disc_d_test_misc_verify_dscs(struct ble_gatt_disc_d_test_dsc *dscs, stop_after = INT_MAX; } - for (i = 0; i < stop_after && dscs[i].chr_def_handle != 0; i++) { - TEST_ASSERT(dscs[i].chr_def_handle == - ble_gatt_disc_d_test_dscs[i].chr_def_handle); + for (i = 0; i < stop_after && dscs[i].chr_val_handle != 0; i++) { + TEST_ASSERT(dscs[i].chr_val_handle == + ble_gatt_disc_d_test_dscs[i].chr_val_handle); TEST_ASSERT(dscs[i].dsc_handle == ble_gatt_disc_d_test_dscs[i].dsc_handle); TEST_ASSERT(memcmp(dscs[i].dsc_uuid128, @@ -156,28 +156,37 @@ ble_gatt_disc_d_test_misc_verify_dscs(struct ble_gatt_disc_d_test_dsc *dscs, static int ble_gatt_disc_d_test_misc_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - uint16_t chr_def_handle, struct ble_gatt_dsc *dsc, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, void *arg) { struct ble_gatt_disc_d_test_dsc *dst; int *stop_after; - TEST_ASSERT(error == NULL); + TEST_ASSERT(error != NULL); TEST_ASSERT(!ble_gatt_disc_d_test_rx_complete); stop_after = arg; - if (dsc == NULL) { - ble_gatt_disc_d_test_rx_complete = 1; - } else { + switch (error->status) { + case 0: TEST_ASSERT_FATAL(ble_gatt_disc_d_test_num_dscs < BLE_GATT_DISC_D_TEST_MAX_DSCS); dst = ble_gatt_disc_d_test_dscs + ble_gatt_disc_d_test_num_dscs++; - dst->chr_def_handle = chr_def_handle; + dst->chr_val_handle = chr_val_handle; dst->dsc_handle = dsc->handle; memcpy(dst->dsc_uuid128, dsc->uuid128, 16); + break; + + case BLE_HS_EDONE: + ble_gatt_disc_d_test_rx_complete = 1; + break; + + default: + TEST_ASSERT(0); + break; } if (*stop_after > 0) { @@ -192,7 +201,7 @@ ble_gatt_disc_d_test_misc_cb(uint16_t conn_handle, } static void -ble_gatt_disc_d_test_misc_all(uint16_t chr_def_handle, uint16_t end_handle, +ble_gatt_disc_d_test_misc_all(uint16_t chr_val_handle, uint16_t end_handle, int stop_after, struct ble_gatt_disc_d_test_dsc *dscs) { @@ -205,7 +214,7 @@ ble_gatt_disc_d_test_misc_all(uint16_t chr_def_handle, uint16_t end_handle, NULL, NULL); num_left = stop_after; - rc = ble_gattc_disc_all_dscs(2, chr_def_handle, end_handle, + rc = ble_gattc_disc_all_dscs(2, chr_val_handle, end_handle, ble_gatt_disc_d_test_misc_cb, &num_left); TEST_ASSERT(rc == 0); @@ -216,9 +225,9 @@ ble_gatt_disc_d_test_misc_all(uint16_t chr_def_handle, uint16_t end_handle, TEST_CASE(ble_gatt_disc_d_test_1) { /*** One 16-bit descriptor. */ - ble_gatt_disc_d_test_misc_all(4, 10, 0, + ble_gatt_disc_d_test_misc_all(5, 10, 0, ((struct ble_gatt_disc_d_test_dsc[]) { { - .chr_def_handle = 4, + .chr_val_handle = 5, .dsc_handle = 6, .dsc_uuid128 = BLE_UUID16_ARR(0x1234), }, { @@ -227,13 +236,13 @@ TEST_CASE(ble_gatt_disc_d_test_1) ); /*** Two 16-bit descriptors. */ - ble_gatt_disc_d_test_misc_all(49, 100, 0, + ble_gatt_disc_d_test_misc_all(50, 100, 0, ((struct ble_gatt_disc_d_test_dsc[]) { { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 51, .dsc_uuid128 = BLE_UUID16_ARR(0x1111), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 52, .dsc_uuid128 = BLE_UUID16_ARR(0x2222), }, { @@ -242,25 +251,25 @@ TEST_CASE(ble_gatt_disc_d_test_1) ); /*** Five 16-bit descriptors. */ - ble_gatt_disc_d_test_misc_all(49, 100, 0, + ble_gatt_disc_d_test_misc_all(50, 100, 0, ((struct ble_gatt_disc_d_test_dsc[]) { { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 51, .dsc_uuid128 = BLE_UUID16_ARR(0x1111), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 52, .dsc_uuid128 = BLE_UUID16_ARR(0x2222), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 53, .dsc_uuid128 = BLE_UUID16_ARR(0x3333), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 54, .dsc_uuid128 = BLE_UUID16_ARR(0x4444), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 55, .dsc_uuid128 = BLE_UUID16_ARR(0x5555), }, { @@ -269,25 +278,25 @@ TEST_CASE(ble_gatt_disc_d_test_1) ); /*** Interleaved 16-bit and 128-bit descriptors. */ - ble_gatt_disc_d_test_misc_all(49, 100, 0, + ble_gatt_disc_d_test_misc_all(50, 100, 0, ((struct ble_gatt_disc_d_test_dsc[]) { { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 51, .dsc_uuid128 = BLE_UUID16_ARR(0x1111), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 52, .dsc_uuid128 = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }, }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 53, .dsc_uuid128 = BLE_UUID16_ARR(0x3333), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 54, .dsc_uuid128 = { 1,0,4,0,6,9,17,7,8,43,7,4,12,43,19,35 }, }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 55, .dsc_uuid128 = BLE_UUID16_ARR(0x5555), }, { @@ -296,13 +305,13 @@ TEST_CASE(ble_gatt_disc_d_test_1) ); /*** Ends with final handle ID. */ - ble_gatt_disc_d_test_misc_all(49, 52, 0, + ble_gatt_disc_d_test_misc_all(50, 52, 0, ((struct ble_gatt_disc_d_test_dsc[]) { { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 51, .dsc_uuid128 = BLE_UUID16_ARR(0x1111), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 52, .dsc_uuid128 = BLE_UUID16_ARR(0x2222), }, { @@ -311,25 +320,25 @@ TEST_CASE(ble_gatt_disc_d_test_1) ); /*** Stop after two descriptors. */ - ble_gatt_disc_d_test_misc_all(49, 100, 2, + ble_gatt_disc_d_test_misc_all(50, 100, 2, ((struct ble_gatt_disc_d_test_dsc[]) { { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 51, .dsc_uuid128 = BLE_UUID16_ARR(0x1111), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 52, .dsc_uuid128 = BLE_UUID16_ARR(0x2222), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 53, .dsc_uuid128 = BLE_UUID16_ARR(0x3333), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 54, .dsc_uuid128 = BLE_UUID16_ARR(0x4444), }, { - .chr_def_handle = 49, + .chr_val_handle = 50, .dsc_handle = 55, .dsc_uuid128 = BLE_UUID16_ARR(0x5555), }, { @@ -340,6 +349,8 @@ TEST_CASE(ble_gatt_disc_d_test_1) TEST_SUITE(ble_gatt_disc_d_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatt_disc_d_test_1(); } diff --git a/net/nimble/host/src/test/ble_gatt_disc_s_test.c b/net/nimble/host/src/test/ble_gatt_disc_s_test.c index d7572b2c..2e278d6e 100644 --- a/net/nimble/host/src/test/ble_gatt_disc_s_test.c +++ b/net/nimble/host/src/test/ble_gatt_disc_s_test.c @@ -219,18 +219,28 @@ ble_gatt_disc_s_test_misc_verify_services( static int ble_gatt_disc_s_test_misc_disc_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_svc *service, void *arg) + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, + void *arg) { - TEST_ASSERT(error == NULL); + TEST_ASSERT(error != NULL); TEST_ASSERT(!ble_gatt_disc_s_test_rx_complete); - if (service == NULL) { - ble_gatt_disc_s_test_rx_complete = 1; - } else { + switch (error->status) { + case 0: + TEST_ASSERT(service != NULL); TEST_ASSERT_FATAL(ble_gatt_disc_s_test_num_svcs < BLE_GATT_DISC_S_TEST_MAX_SERVICES); ble_gatt_disc_s_test_svcs[ble_gatt_disc_s_test_num_svcs++] = *service; + break; + + case BLE_HS_EDONE: + TEST_ASSERT(service == NULL); + ble_gatt_disc_s_test_rx_complete = 1; + break; + + default: + TEST_ASSERT(0); } return 0; @@ -381,6 +391,8 @@ TEST_CASE(ble_gatt_disc_s_test_disc_service_uuid) TEST_SUITE(ble_gatt_disc_s_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatt_disc_s_test_disc_all(); ble_gatt_disc_s_test_disc_service_uuid(); } diff --git a/net/nimble/host/src/test/ble_gatt_find_s_test.c b/net/nimble/host/src/test/ble_gatt_find_s_test.c index dca1f367..c3ab93df 100644 --- a/net/nimble/host/src/test/ble_gatt_find_s_test.c +++ b/net/nimble/host/src/test/ble_gatt_find_s_test.c @@ -46,17 +46,25 @@ ble_gatt_find_s_test_misc_init(void) static int ble_gatt_find_s_test_misc_cb(uint16_t conn_handle, - struct ble_gatt_error *error, - struct ble_gatt_svc *service, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, void *arg) { TEST_ASSERT(!ble_gatt_find_s_test_proc_complete); - TEST_ASSERT(error == NULL); + TEST_ASSERT(error != NULL); - if (service == NULL) { - ble_gatt_find_s_test_proc_complete = 1; - } else { + switch (error->status) { + case 0: ble_gatt_find_s_test_svcs[ble_gatt_find_s_test_num_svcs++] = *service; + break; + + case BLE_HS_EDONE: + ble_gatt_find_s_test_proc_complete = 1; + break; + + default: + TEST_ASSERT(0); + break; } return 0; @@ -320,6 +328,8 @@ TEST_CASE(ble_gatt_find_s_test_1) TEST_SUITE(ble_gatt_find_s_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatt_find_s_test_1(); } diff --git a/net/nimble/host/src/test/ble_gatt_read_test.c b/net/nimble/host/src/test/ble_gatt_read_test.c index 03df56ec..822de5c7 100644 --- a/net/nimble/host/src/test/ble_gatt_read_test.c +++ b/net/nimble/host/src/test/ble_gatt_read_test.c @@ -57,7 +57,7 @@ ble_gatt_read_test_misc_init(void) } static int -ble_gatt_read_test_cb(uint16_t conn_handle, struct ble_gatt_error *error, +ble_gatt_read_test_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { struct ble_gatt_read_test_attr *dst; @@ -65,7 +65,9 @@ ble_gatt_read_test_cb(uint16_t conn_handle, struct ble_gatt_error *error, stop_after = arg; - if (error != NULL) { + TEST_ASSERT_FATAL(error != NULL); + + if (error->status != 0) { ble_gatt_read_test_bad_conn_handle = conn_handle; ble_gatt_read_test_bad_status = error->status; ble_gatt_read_test_complete = 1; @@ -81,12 +83,12 @@ ble_gatt_read_test_cb(uint16_t conn_handle, struct ble_gatt_error *error, BLE_GATT_READ_TEST_MAX_ATTRS); dst = ble_gatt_read_test_attrs + ble_gatt_read_test_num_attrs++; - TEST_ASSERT_FATAL(attr->value_len <= sizeof dst->value); + TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(attr->om) <= sizeof dst->value); dst->conn_handle = conn_handle; dst->handle = attr->handle; - dst->value_len = attr->value_len; - memcpy(dst->value, attr->value, attr->value_len); + dst->value_len = OS_MBUF_PKTLEN(attr->om); + os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om), dst->value); if (stop_after != NULL && *stop_after > 0) { (*stop_after)--; @@ -102,7 +104,8 @@ ble_gatt_read_test_cb(uint16_t conn_handle, struct ble_gatt_error *error, } static int -ble_gatt_read_test_long_cb(uint16_t conn_handle, struct ble_gatt_error *error, +ble_gatt_read_test_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { struct ble_gatt_read_test_attr *dst; @@ -110,7 +113,9 @@ ble_gatt_read_test_long_cb(uint16_t conn_handle, struct ble_gatt_error *error, reads_left = arg; - if (error != NULL) { + TEST_ASSERT_FATAL(error != NULL); + + if (error->status != 0) { ble_gatt_read_test_bad_conn_handle = conn_handle; ble_gatt_read_test_bad_status = error->status; ble_gatt_read_test_complete = 1; @@ -124,7 +129,8 @@ ble_gatt_read_test_long_cb(uint16_t conn_handle, struct ble_gatt_error *error, dst = ble_gatt_read_test_attrs + 0; - TEST_ASSERT_FATAL(attr->value_len <= dst->value_len + sizeof dst->value); + TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(attr->om) <= + dst->value_len + sizeof dst->value); TEST_ASSERT(attr->offset == dst->value_len); if (attr->offset == 0) { @@ -134,8 +140,9 @@ ble_gatt_read_test_long_cb(uint16_t conn_handle, struct ble_gatt_error *error, TEST_ASSERT(conn_handle == dst->conn_handle); TEST_ASSERT(attr->handle == dst->handle); } - memcpy(dst->value + dst->value_len, attr->value, attr->value_len); - dst->value_len += attr->value_len; + os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om), + dst->value + dst->value_len); + dst->value_len += OS_MBUF_PKTLEN(attr->om); if (reads_left != NULL && *reads_left > 0) { (*reads_left)--; @@ -151,7 +158,7 @@ ble_gatt_read_test_long_cb(uint16_t conn_handle, struct ble_gatt_error *error, static void ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle, uint8_t att_op, - void *data, int data_len) + const void *data, int data_len) { uint8_t buf[1024]; int rc; @@ -171,7 +178,7 @@ ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle, static void ble_gatt_read_test_misc_rx_rsp_good(uint16_t conn_handle, - struct ble_gatt_attr *attr) + struct ble_hs_test_util_flat_attr *attr) { ble_gatt_read_test_misc_rx_rsp_good_raw(conn_handle, BLE_ATT_OP_READ_RSP, attr->value, @@ -190,8 +197,8 @@ ble_gatt_read_test_misc_rx_rsp_bad(uint16_t conn_handle, } static int -ble_gatt_read_test_misc_uuid_rx_rsp_good(uint16_t conn_handle, - struct ble_gatt_attr *attrs) +ble_gatt_read_test_misc_uuid_rx_rsp_good( + uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs) { struct ble_att_read_type_rsp rsp; uint8_t buf[1024]; @@ -233,7 +240,7 @@ ble_gatt_read_test_misc_uuid_rx_rsp_good(uint16_t conn_handle, } static void -ble_gatt_read_test_misc_verify_good(struct ble_gatt_attr *attr) +ble_gatt_read_test_misc_verify_good(struct ble_hs_test_util_flat_attr *attr) { int rc; @@ -256,7 +263,7 @@ ble_gatt_read_test_misc_verify_good(struct ble_gatt_attr *attr) static void ble_gatt_read_test_misc_verify_bad(uint8_t att_status, - struct ble_gatt_attr *attr) + struct ble_hs_test_util_flat_attr *attr) { int rc; @@ -277,10 +284,9 @@ ble_gatt_read_test_misc_verify_bad(uint8_t att_status, } static void -ble_gatt_read_test_misc_uuid_verify_good(uint16_t start_handle, - uint16_t end_handle, void *uuid128, - int stop_after, - struct ble_gatt_attr *attrs) +ble_gatt_read_test_misc_uuid_verify_good( + uint16_t start_handle, uint16_t end_handle, void *uuid128, + int stop_after, struct ble_hs_test_util_flat_attr *attrs) { int num_read; int idx; @@ -324,8 +330,8 @@ ble_gatt_read_test_misc_uuid_verify_good(uint16_t start_handle, } static void -ble_gatt_read_test_misc_long_verify_good(int max_reads, - struct ble_gatt_attr *attr) +ble_gatt_read_test_misc_long_verify_good( + int max_reads, struct ble_hs_test_util_flat_attr *attr) { int reads_left; int chunk_sz; @@ -377,8 +383,8 @@ ble_gatt_read_test_misc_long_verify_good(int max_reads, } static void -ble_gatt_read_test_misc_long_verify_bad(uint8_t att_status, - struct ble_gatt_attr *attr) +ble_gatt_read_test_misc_long_verify_bad( + uint8_t att_status, struct ble_hs_test_util_flat_attr *attr) { int rc; @@ -400,8 +406,8 @@ ble_gatt_read_test_misc_long_verify_bad(uint8_t att_status, } static int -ble_gatt_read_test_misc_extract_handles(struct ble_gatt_attr *attrs, - uint16_t *handles) +ble_gatt_read_test_misc_extract_handles( + struct ble_hs_test_util_flat_attr *attrs, uint16_t *handles) { int i; @@ -412,7 +418,8 @@ ble_gatt_read_test_misc_extract_handles(struct ble_gatt_attr *attrs, } static void -ble_gatt_read_test_misc_mult_verify_good(struct ble_gatt_attr *attrs) +ble_gatt_read_test_misc_mult_verify_good( + struct ble_hs_test_util_flat_attr *attrs) { uint8_t expected_value[512]; uint16_t handles[256]; @@ -458,9 +465,9 @@ ble_gatt_read_test_misc_mult_verify_good(struct ble_gatt_attr *attrs) } static void -ble_gatt_read_test_misc_mult_verify_bad(uint8_t att_status, - uint16_t err_handle, - struct ble_gatt_attr *attrs) +ble_gatt_read_test_misc_mult_verify_bad( + uint8_t att_status, uint16_t err_handle, + struct ble_hs_test_util_flat_attr *attrs) { uint16_t handles[256]; int num_attrs; @@ -488,39 +495,42 @@ ble_gatt_read_test_misc_mult_verify_bad(uint8_t att_status, TEST_CASE(ble_gatt_read_test_by_handle) { /* Read a seven-byte attribute. */ - ble_gatt_read_test_misc_verify_good((struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = (uint8_t[]){ 1,2,3,4,5,6,7 }, + .value = { 1,2,3,4,5,6,7 }, .value_len = 7 } }); /* Read a one-byte attribute. */ - ble_gatt_read_test_misc_verify_good((struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { .handle = 0x5432, - .value = (uint8_t[]){ 0xff }, + .value = { 0xff }, .value_len = 1 } }); /* Read a 200-byte attribute. */ - ble_gatt_read_test_misc_verify_good((struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { .handle = 815, - .value = (uint8_t[200]){ 0 }, + .value = { 0 }, .value_len = 200, } }); /* Fail due to attribute not found. */ ble_gatt_read_test_misc_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND, - (struct ble_gatt_attr[]) { { + (struct ble_hs_test_util_flat_attr[]) { { .handle = 719, - .value = (uint8_t[]){ 1,2,3,4,5,6,7 }, + .value = { 1,2,3,4,5,6,7 }, .value_len = 7 } }); /* Fail due to invalid PDU. */ ble_gatt_read_test_misc_verify_bad(BLE_ATT_ERR_INVALID_PDU, - (struct ble_gatt_attr[]) { { + (struct ble_hs_test_util_flat_attr[]) { { .handle = 65, - .value = (uint8_t[]){ 0xfa, 0x4c }, + .value = { 0xfa, 0x4c }, .value_len = 2 } }); } @@ -529,9 +539,9 @@ TEST_CASE(ble_gatt_read_test_by_uuid) { /* Read a single seven-byte attribute. */ ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16(0x1234), 0, - (struct ble_gatt_attr[]) { { + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = (uint8_t[]){ 1,2,3,4,5,6,7 }, + .value = { 1,2,3,4,5,6,7 }, .value_len = 7 }, { 0, @@ -539,13 +549,13 @@ TEST_CASE(ble_gatt_read_test_by_uuid) /* Read two seven-byte attributes; one response. */ ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16(0x1234), 0, - (struct ble_gatt_attr[]) { { + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = (uint8_t[]){ 1,2,3,4,5,6,7 }, + .value = { 1,2,3,4,5,6,7 }, .value_len = 7 }, { .handle = 44, - .value = (uint8_t[]){ 2,3,4,5,6,7,8 }, + .value = { 2,3,4,5,6,7,8 }, .value_len = 7 }, { 0, @@ -553,13 +563,13 @@ TEST_CASE(ble_gatt_read_test_by_uuid) /* Read two attributes; two responses. */ ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16(0x1234), 0, - (struct ble_gatt_attr[]) { { + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = (uint8_t[]){ 1,2,3,4,5,6,7 }, + .value = { 1,2,3,4,5,6,7 }, .value_len = 7 }, { .handle = 44, - .value = (uint8_t[]){ 2,3,4 }, + .value = { 2,3,4 }, .value_len = 3 }, { 0, @@ -567,25 +577,25 @@ TEST_CASE(ble_gatt_read_test_by_uuid) /* Stop after three reads. */ ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16(0x1234), 3, - (struct ble_gatt_attr[]) { { + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = (uint8_t[]){ 1,2,3,4,5,6,7 }, + .value = { 1,2,3,4,5,6,7 }, .value_len = 7 }, { .handle = 44, - .value = (uint8_t[]){ 2,3,4 }, + .value = { 2,3,4 }, .value_len = 3 }, { .handle = 45, - .value = (uint8_t[]){ 2,3,4 }, + .value = { 2,3,4 }, .value_len = 3 }, { .handle = 46, - .value = (uint8_t[]){ 3,4,5,6 }, + .value = { 3,4,5,6 }, .value_len = 4 }, { .handle = 47, - .value = (uint8_t[]){ 2,3,4 }, + .value = { 2,3,4 }, .value_len = 3 }, { 0, @@ -602,38 +612,52 @@ TEST_CASE(ble_gatt_read_test_long) } /* Read a seven-byte attribute. */ - ble_gatt_read_test_misc_long_verify_good(0, (struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_long_verify_good(0, + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = data512, + .value = { 1,2,3,4,5,6,7 }, .value_len = 7 } }); /* Read a zero-byte attribute. */ - ble_gatt_read_test_misc_long_verify_good(0, (struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_long_verify_good(0, + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = NULL, + .value = { 0 }, .value_len = 0 } }); /* Read a 60-byte attribute; three requests. */ - ble_gatt_read_test_misc_long_verify_good(0, (struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_long_verify_good(0, + (struct ble_hs_test_util_flat_attr[]) { { .handle = 34, - .value = data512, + .value = { + 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 + }, .value_len = 60 } }); /* Stop after two reads. */ - ble_gatt_read_test_misc_long_verify_good(2, (struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_long_verify_good(2, + (struct ble_hs_test_util_flat_attr[]) { { .handle = 34, - .value = data512, + .value = { + 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 + }, .value_len = 60 } }); /* Fail due to attribute not found. */ ble_gatt_read_test_misc_long_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND, - (struct ble_gatt_attr[]) { { + (struct ble_hs_test_util_flat_attr[]) { { .handle = 719, - .value = (uint8_t[]){ 1,2,3,4,5,6,7 }, + .value = { 1, 2, 3, 4, 5, 6, 7 }, .value_len = 7 } }); } @@ -648,60 +672,64 @@ TEST_CASE(ble_gatt_read_test_mult) } /* Read one attribute. */ - ble_gatt_read_test_misc_mult_verify_good((struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_mult_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = data512, + .value = { 0, 1, 2, 3, 4, 5, 6, 7 }, .value_len = 7 }, { 0 } }); /* Read two attributes. */ - ble_gatt_read_test_misc_mult_verify_good((struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_mult_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = data512, + .value = { 0, 1, 2, 3, 4, 5, 6, 7 }, .value_len = 7, }, { .handle = 44, - .value = data512 + 7, + .value = { 8, 9, 10, 11 }, .value_len = 4, }, { 0 } }); /* Read two attributes (swap order). */ - ble_gatt_read_test_misc_mult_verify_good((struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_mult_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { .handle = 44, - .value = data512 + 7, + .value = { 8, 9, 10, 11 }, .value_len = 4, }, { .handle = 43, - .value = data512, + .value = { 0, 1, 2, 3, 4, 5, 6, 7 }, .value_len = 7, }, { 0 } }); /* Read five attributes. */ - ble_gatt_read_test_misc_mult_verify_good((struct ble_gatt_attr[]) { { + ble_gatt_read_test_misc_mult_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { .handle = 43, - .value = data512, + .value = { 0, 1, 2, 3, 4, 5, 6, 7 }, .value_len = 7, }, { .handle = 44, - .value = data512 + 7, + .value = { 8, 9, 10, 11 }, .value_len = 4, }, { .handle = 145, - .value = data512 + 11, + .value = { 12, 13 }, .value_len = 2, }, { .handle = 191, - .value = data512 + 13, + .value = { 14, 15, 16 }, .value_len = 3, }, { .handle = 352, - .value = data512 + 16, + .value = { 17, 18, 19, 20 }, .value_len = 4, }, { 0 @@ -709,21 +737,81 @@ TEST_CASE(ble_gatt_read_test_mult) /* Fail due to attribute not found. */ ble_gatt_read_test_misc_mult_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND, 719, - (struct ble_gatt_attr[]) { { + (struct ble_hs_test_util_flat_attr[]) { { .handle = 719, - .value = (uint8_t[]){ 1,2,3,4,5,6,7 }, + .value = { 1,2,3,4,5,6,7 }, .value_len = 7 }, { 0 } }); } +TEST_CASE(ble_gatt_read_test_concurrent) +{ + int rc; + int i; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /*** + * Perform three concurrent reads. Assert that each response is correctly + * matched up with its corresponding GATT procedure. + */ + + struct ble_hs_test_util_flat_attr attrs[3] = { + { + .handle = 1, + .offset = 0, + .value_len = 3, + .value = { 1, 2, 3 }, + }, + { + .handle = 2, + .offset = 0, + .value_len = 4, + .value = { 2, 3, 4, 5 }, + }, + { + .handle = 3, + .offset = 0, + .value_len = 5, + .value = { 3, 4, 5, 6, 7 }, + }, + }; + + rc = ble_gattc_read(2, attrs[0].handle, ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + rc = ble_gattc_read(2, attrs[1].handle, ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + rc = ble_gattc_read(2, attrs[2].handle, ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 0); + ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 1); + ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 2); + + TEST_ASSERT(ble_gatt_read_test_num_attrs == 3); + + for (i = 0; i < 3; i++) { + TEST_ASSERT(ble_gatt_read_test_attrs[i].handle == attrs[i].handle); + TEST_ASSERT(ble_gatt_read_test_attrs[i].value_len == + attrs[i].value_len); + TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[i].value, attrs[i].value, + attrs[i].value_len) == 0); + } +} + TEST_SUITE(ble_gatt_read_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatt_read_test_by_handle(); ble_gatt_read_test_by_uuid(); ble_gatt_read_test_long(); ble_gatt_read_test_mult(); + ble_gatt_read_test_concurrent(); } int diff --git a/net/nimble/host/src/test/ble_gatt_write_test.c b/net/nimble/host/src/test/ble_gatt_write_test.c index 56e88d36..f5481980 100644 --- a/net/nimble/host/src/test/ble_gatt_write_test.c +++ b/net/nimble/host/src/test/ble_gatt_write_test.c @@ -33,7 +33,7 @@ static int ble_gatt_write_test_cb_called; static uint8_t ble_gatt_write_test_attr_value[BLE_ATT_ATTR_MAX_LEN]; static struct ble_gatt_error ble_gatt_write_test_error; -static struct ble_gatt_attr * +static struct ble_hs_test_util_flat_attr ble_gatt_write_test_attrs[BLE_GATT_WRITE_TEST_MAX_ATTRS]; static int ble_gatt_write_test_num_attrs; @@ -52,20 +52,22 @@ ble_gatt_write_test_init(void) } static int -ble_gatt_write_test_cb_good(uint16_t conn_handle, struct ble_gatt_error *error, +ble_gatt_write_test_cb_good(uint16_t conn_handle, + const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { int *attr_len; attr_len = arg; + TEST_ASSERT(error != NULL); TEST_ASSERT(conn_handle == 2); + + ble_gatt_write_test_error = *error; + if (attr_len != NULL) { - TEST_ASSERT(error == NULL); + TEST_ASSERT(error->status == 0); TEST_ASSERT(attr->handle == 100); - } else { - TEST_ASSERT(error != NULL); - ble_gatt_write_test_error = *error; } ble_gatt_write_test_cb_called = 1; @@ -88,7 +90,7 @@ ble_gatt_write_test_rx_rsp(uint16_t conn_handle) static void ble_gatt_write_test_rx_prep_rsp(uint16_t conn_handle, uint16_t attr_handle, uint16_t offset, - void *attr_data, uint16_t attr_data_len) + const void *attr_data, uint16_t attr_data_len) { struct ble_att_prep_write_cmd rsp; uint8_t buf[512]; @@ -121,6 +123,7 @@ ble_gatt_write_test_rx_exec_rsp(uint16_t conn_handle) static void ble_gatt_write_test_misc_long_good(int attr_len) { + uint16_t mtu; int off; int len; int rc; @@ -130,24 +133,27 @@ ble_gatt_write_test_misc_long_good(int attr_len) ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); - rc = ble_gattc_write_long(2, 100, ble_gatt_write_test_attr_value, - attr_len, ble_gatt_write_test_cb_good, - &attr_len); + mtu = ble_att_mtu(2); + + rc = ble_hs_test_util_gatt_write_long_flat( + 2, 100, ble_gatt_write_test_attr_value, attr_len, + ble_gatt_write_test_cb_good, &attr_len); TEST_ASSERT(rc == 0); off = 0; while (off < attr_len) { - /* Send the pending ATT Prep Write Command. */ - ble_hs_test_util_tx_all(); - - /* Receive Prep Write response. */ - len = BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; if (off + len > attr_len) { len = attr_len - off; } - ble_gatt_write_test_rx_prep_rsp(2, 100, off, - ble_gatt_write_test_attr_value + off, - len); + + /* Send the pending ATT Prep Write Command. */ + ble_hs_test_util_verify_tx_prep_write( + 100, off, ble_gatt_write_test_attr_value + off, len); + + /* Receive Prep Write response. */ + ble_gatt_write_test_rx_prep_rsp( + 2, 100, off, ble_gatt_write_test_attr_value + off, len); /* Verify callback hasn't gotten called. */ TEST_ASSERT(!ble_gatt_write_test_cb_called); @@ -155,6 +161,9 @@ ble_gatt_write_test_misc_long_good(int attr_len) off += len; } + /* Verify execute write request sent. */ + ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_CONFIRM); + /* Receive Exec Write response. */ ble_hs_test_util_tx_all(); ble_gatt_write_test_rx_exec_rsp(2); @@ -170,6 +179,7 @@ static void ble_gatt_write_test_misc_long_bad(int attr_len, ble_gatt_write_test_long_fail_fn *cb) { + uint16_t mtu; int fail_now; int off; int len; @@ -179,17 +189,24 @@ ble_gatt_write_test_misc_long_bad(int attr_len, ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); + mtu = ble_att_mtu(2); - rc = ble_gattc_write_long(2, 100, ble_gatt_write_test_attr_value, - attr_len, ble_gatt_write_test_cb_good, NULL); + rc = ble_hs_test_util_gatt_write_long_flat( + 2, 100, ble_gatt_write_test_attr_value, attr_len, + ble_gatt_write_test_cb_good, NULL); TEST_ASSERT(rc == 0); fail_now = 0; off = 0; while (off < attr_len) { + len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + if (off + len > attr_len) { + len = attr_len - off; + } + /* Send the pending ATT Prep Write Command. */ - ble_hs_test_util_tx_all(); - TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() != NULL); + ble_hs_test_util_verify_tx_prep_write( + 100, off, ble_gatt_write_test_attr_value + off, len); /* Receive Prep Write response. */ len = BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; @@ -255,7 +272,7 @@ ble_gatt_write_test_misc_long_fail_length(uint16_t conn_handle, static int ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle, - struct ble_gatt_error *error, + const struct ble_gatt_error *error, struct ble_gatt_attr *attrs, uint8_t num_attrs, void *arg) { @@ -267,7 +284,8 @@ ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle, ble_gatt_write_test_num_attrs = num_attrs; for (i = 0; i < num_attrs; i++) { - ble_gatt_write_test_attrs[i] = attrs + i; + ble_hs_test_util_attr_to_flat(ble_gatt_write_test_attrs + i, + attrs + i); } ble_gatt_write_test_cb_called = 1; @@ -276,38 +294,66 @@ ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle, } static void -ble_gatt_write_test_misc_reliable_good(struct ble_gatt_attr *attrs) +ble_gatt_write_test_misc_reliable_good( + struct ble_hs_test_util_flat_attr *flat_attrs) { + const struct ble_hs_test_util_flat_attr *attr; + struct ble_gatt_attr attrs[16]; + uint16_t mtu; int num_attrs; int attr_idx; + int len; + int off; int rc; int i; ble_gatt_write_test_init(); - for (num_attrs = 0; attrs[num_attrs].handle != 0; num_attrs++) - ; + for (num_attrs = 0; flat_attrs[num_attrs].handle != 0; num_attrs++) { + TEST_ASSERT_FATAL(num_attrs < sizeof attrs / sizeof attrs[0]); + ble_hs_test_util_attr_from_flat(attrs + num_attrs, + flat_attrs + num_attrs); + } ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); + mtu = ble_att_mtu(2); rc = ble_gattc_write_reliable(2, attrs, num_attrs, ble_gatt_write_test_reliable_cb_good, NULL); TEST_ASSERT(rc == 0); - for (attr_idx = 0; attr_idx < num_attrs; attr_idx++) { + attr_idx = 0; + off = 0; + while (attr_idx < num_attrs) { + attr = flat_attrs + attr_idx; + + len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + if (off + len > attr->value_len) { + len = attr->value_len - off; + } + /* Send the pending ATT Prep Write Command. */ - ble_hs_test_util_tx_all(); + ble_hs_test_util_verify_tx_prep_write(attr->handle, off, + attr->value + off, len); /* Receive Prep Write response. */ - ble_gatt_write_test_rx_prep_rsp(2, attrs[attr_idx].handle, 0, - attrs[attr_idx].value, - attrs[attr_idx].value_len); + ble_gatt_write_test_rx_prep_rsp(2, attr->handle, off, + attr->value + off, len); /* Verify callback hasn't gotten called. */ TEST_ASSERT(!ble_gatt_write_test_cb_called); + + off += len; + if (off >= attr->value_len) { + attr_idx++; + off = 0; + } } + /* Verify execute write request sent. */ + ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_CONFIRM); + /* Receive Exec Write response. */ ble_hs_test_util_tx_all(); ble_gatt_write_test_rx_exec_rsp(2); @@ -316,7 +362,9 @@ ble_gatt_write_test_misc_reliable_good(struct ble_gatt_attr *attrs) TEST_ASSERT(ble_gatt_write_test_cb_called); TEST_ASSERT(ble_gatt_write_test_num_attrs == num_attrs); for (i = 0; i < num_attrs; i++) { - TEST_ASSERT(ble_gatt_write_test_attrs[i] == attrs + i); + rc = ble_hs_test_util_flat_attr_cmp( + ble_gatt_write_test_attrs + i, flat_attrs + i); + TEST_ASSERT(rc == 0); } } @@ -331,8 +379,8 @@ TEST_CASE(ble_gatt_write_test_no_rsp) NULL, NULL); attr_len = 4; - rc = ble_gattc_write_no_rsp(2, 100, ble_gatt_write_test_attr_value, - attr_len); + rc = ble_hs_test_util_gatt_write_no_rsp_flat( + 2, 100, ble_gatt_write_test_attr_value, attr_len); TEST_ASSERT(rc == 0); /* Send the pending ATT Write Command. */ @@ -352,8 +400,9 @@ TEST_CASE(ble_gatt_write_test_rsp) NULL, NULL); attr_len = 4; - ble_gattc_write(2, 100, ble_gatt_write_test_attr_value, attr_len, - ble_gatt_write_test_cb_good, &attr_len); + ble_hs_test_util_gatt_write_flat(2, 100, ble_gatt_write_test_attr_value, + attr_len, ble_gatt_write_test_cb_good, + &attr_len); /* Send the pending ATT Write Command. */ ble_hs_test_util_tx_all(); @@ -458,42 +507,57 @@ TEST_CASE(ble_gatt_write_test_reliable_good) { /*** 1 attribute. */ ble_gatt_write_test_misc_reliable_good( - ((struct ble_gatt_attr[]) { { + ((struct ble_hs_test_util_flat_attr[]) { { .handle = 100, .value_len = 2, - .value = (uint8_t[]){ 1, 2 }, + .value = { 1, 2 }, }, { 0 } })); /*** 2 attributes. */ ble_gatt_write_test_misc_reliable_good( - ((struct ble_gatt_attr[]) { { + ((struct ble_hs_test_util_flat_attr[]) { { .handle = 100, .value_len = 2, - .value = (uint8_t[]){ 1,2 }, + .value = { 1,2 }, }, { .handle = 113, .value_len = 6, - .value = (uint8_t[]){ 5,6,7,8,9,10 }, + .value = { 5,6,7,8,9,10 }, }, { 0 } })); /*** 3 attributes. */ ble_gatt_write_test_misc_reliable_good( - ((struct ble_gatt_attr[]) { { + ((struct ble_hs_test_util_flat_attr[]) { { .handle = 100, .value_len = 2, - .value = (uint8_t[]){ 1,2 }, + .value = { 1,2 }, }, { .handle = 113, .value_len = 6, - .value = (uint8_t[]){ 5,6,7,8,9,10 }, + .value = { 5,6,7,8,9,10 }, }, { .handle = 144, .value_len = 1, - .value = (uint8_t[]){ 0xff }, + .value = { 0xff }, + }, { + 0 + } })); + + /*** Long attributes. */ + ble_gatt_write_test_misc_reliable_good( + ((struct ble_hs_test_util_flat_attr[]) { { + .handle = 100, + .value_len = 20, + .value = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 }, + }, { + .handle = 144, + .value_len = 20, + .value = { 11,12,13,14,15,16,17,18,19,110, + 111,112,113,114,115,116,117,118,119,120 }, }, { 0 } })); @@ -511,8 +575,9 @@ TEST_CASE(ble_gatt_write_test_long_queue_full) ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); - rc = ble_gattc_write_long(2, 100, ble_gatt_write_test_attr_value, - 128, ble_gatt_write_test_cb_good, NULL); + rc = ble_hs_test_util_gatt_write_long_flat( + 2, 100, ble_gatt_write_test_attr_value, 128, + ble_gatt_write_test_cb_good, NULL); TEST_ASSERT(rc == 0); off = 0; @@ -552,6 +617,8 @@ TEST_CASE(ble_gatt_write_test_long_queue_full) TEST_SUITE(ble_gatt_write_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatt_write_test_no_rsp(); ble_gatt_write_test_rsp(); ble_gatt_write_test_long_good(); diff --git a/net/nimble/host/src/test/ble_gatts_notify_test.c b/net/nimble/host/src/test/ble_gatts_notify_test.c index 6a0f2188..4e2d587c 100644 --- a/net/nimble/host/src/test/ble_gatts_notify_test.c +++ b/net/nimble/host/src/test/ble_gatts_notify_test.c @@ -29,16 +29,17 @@ #define BLE_GATTS_NOTIFY_TEST_CHR_1_UUID 0x1111 #define BLE_GATTS_NOTIFY_TEST_CHR_2_UUID 0x2222 -static uint8_t ble_gatts_peer_addr[6] = {2,3,4,5,6,7}; +#define BLE_GATTS_NOTIFY_TEST_MAX_EVENTS 16 + +static uint8_t ble_gatts_notify_test_peer_addr[6] = {2,3,4,5,6,7}; static int ble_gatts_notify_test_misc_access(uint16_t conn_handle, - uint16_t attr_handle, uint8_t op, - union ble_gatt_access_ctxt *ctxt, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); static void -ble_gatts_notify_test_misc_reg_cb(uint8_t op, - union ble_gatt_register_ctxt *ctxt, +ble_gatts_notify_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); static const struct ble_gatt_svc_def ble_gatts_notify_test_svcs[] = { { @@ -69,10 +70,34 @@ static uint16_t ble_gatts_notify_test_chr_2_def_handle; static uint8_t ble_gatts_notify_test_chr_2_val[1024]; static int ble_gatts_notify_test_chr_2_len; +static struct ble_gap_event +ble_gatts_notify_test_events[BLE_GATTS_NOTIFY_TEST_MAX_EVENTS]; + +static int ble_gatts_notify_test_num_events; + typedef int ble_store_write_fn(int obj_type, union ble_store_value *val); typedef int ble_store_delete_fn(int obj_type, union ble_store_key *key); +static int +ble_gatts_notify_test_util_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_NOTIFY_TX: + case BLE_GAP_EVENT_SUBSCRIBE: + TEST_ASSERT_FATAL(ble_gatts_notify_test_num_events < + BLE_GATTS_NOTIFY_TEST_MAX_EVENTS); + + ble_gatts_notify_test_events[ble_gatts_notify_test_num_events++] = + *event; + + default: + break; + } + + return 0; +} + static uint16_t ble_gatts_notify_test_misc_read_notify(uint16_t conn_handle, uint16_t chr_def_handle) @@ -102,9 +127,9 @@ ble_gatts_notify_test_misc_read_notify(uint16_t conn_handle, } static void -ble_gatts_notify_test_misc_enable_notify(uint16_t conn_handle, - uint16_t chr_def_handle, - uint16_t flags) +ble_gatts_notify_test_misc_try_enable_notify(uint16_t conn_handle, + uint16_t chr_def_handle, + uint16_t flags, int fail) { struct ble_att_write_req req; uint8_t buf[BLE_ATT_WRITE_REQ_BASE_SZ + 2]; @@ -116,7 +141,86 @@ ble_gatts_notify_test_misc_enable_notify(uint16_t conn_handle, htole16(buf + BLE_ATT_WRITE_REQ_BASE_SZ, flags); rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); - TEST_ASSERT(rc == 0); + if (fail) { + TEST_ASSERT_FATAL(rc != 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, + req.bawq_handle, + BLE_ATT_ERR_REQ_NOT_SUPPORTED); + } else { + TEST_ASSERT_FATAL(rc == 0); + ble_hs_test_util_verify_tx_write_rsp(); + } +} + +static void +ble_gatts_notify_test_misc_enable_notify(uint16_t conn_handle, + uint16_t chr_def_handle, + uint16_t flags) +{ + ble_gatts_notify_test_misc_try_enable_notify(conn_handle, + chr_def_handle, + flags, 0); +} + +static void +ble_gatts_notify_test_util_next_event(struct ble_gap_event *event) +{ + TEST_ASSERT_FATAL(ble_gatts_notify_test_num_events > 0); + + *event = *ble_gatts_notify_test_events; + + ble_gatts_notify_test_num_events--; + if (ble_gatts_notify_test_num_events > 0) { + memmove(ble_gatts_notify_test_events + 0, + ble_gatts_notify_test_events + 1, + ble_gatts_notify_test_num_events * sizeof *event); + } +} + +static void +ble_gatts_notify_test_util_verify_sub_event(uint16_t conn_handle, + uint8_t attr_handle, + uint8_t reason, + uint8_t prevn, uint8_t curn, + uint8_t previ, uint8_t curi) +{ + struct ble_gap_event event; + + ble_gatts_notify_test_util_next_event(&event); + + TEST_ASSERT(event.type == BLE_GAP_EVENT_SUBSCRIBE); + TEST_ASSERT(event.subscribe.conn_handle == conn_handle); + TEST_ASSERT(event.subscribe.attr_handle == attr_handle); + TEST_ASSERT(event.subscribe.reason == reason); + TEST_ASSERT(event.subscribe.prev_notify == prevn); + TEST_ASSERT(event.subscribe.cur_notify == curn); + TEST_ASSERT(event.subscribe.prev_indicate == previ); + TEST_ASSERT(event.subscribe.cur_indicate == curi); +} + +static void +ble_gatts_notify_test_util_verify_tx_event(uint16_t conn_handle, + uint8_t attr_handle, + int status, + int indication) +{ + struct ble_gap_event event; + + ble_gatts_notify_test_util_next_event(&event); + + TEST_ASSERT(event.type == BLE_GAP_EVENT_NOTIFY_TX); + TEST_ASSERT(event.notify_tx.status == status); + TEST_ASSERT(event.notify_tx.conn_handle == conn_handle); + TEST_ASSERT(event.notify_tx.attr_handle == attr_handle); + TEST_ASSERT(event.notify_tx.indication == indication); +} + +static void +ble_gatts_notify_test_util_verify_ack_event(uint16_t conn_handle, + uint8_t attr_handle) +{ + ble_gatts_notify_test_util_verify_tx_event(conn_handle, attr_handle, + BLE_HS_EDONE, 1); } static void @@ -130,6 +234,8 @@ ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle, int bonding, ble_hs_test_util_init(); + ble_gatts_notify_test_num_events = 0; + ble_hs_test_util_store_init(10, 10, 10); ble_hs_cfg.store_read_cb = ble_hs_test_util_store_read; ble_hs_cfg.store_write_cb = ble_hs_test_util_store_write; @@ -142,7 +248,8 @@ ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle, int bonding, ble_gatts_start(); - ble_hs_test_util_create_conn(2, ble_gatts_peer_addr, NULL, NULL); + ble_hs_test_util_create_conn(2, ble_gatts_notify_test_peer_addr, + ble_gatts_notify_test_util_gap_event, NULL); *out_conn_handle = 2; if (bonding) { @@ -163,16 +270,35 @@ ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle, int bonding, 2, ble_gatts_notify_test_chr_2_def_handle); TEST_ASSERT(flags == 0); - /* Set initial notification / indication state. */ + /* Set initial notification / indication state and verify that subscription + * callback gets executed. + */ if (chr1_flags != 0) { ble_gatts_notify_test_misc_enable_notify( 2, ble_gatts_notify_test_chr_1_def_handle, chr1_flags); + + ble_gatts_notify_test_util_verify_sub_event( + *out_conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_WRITE, + 0, chr1_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, + 0, chr1_flags == BLE_GATTS_CLT_CFG_F_INDICATE); } if (chr2_flags != 0) { ble_gatts_notify_test_misc_enable_notify( 2, ble_gatts_notify_test_chr_2_def_handle, chr2_flags); + + ble_gatts_notify_test_util_verify_sub_event( + *out_conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_WRITE, + 0, chr2_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, + 0, chr2_flags == BLE_GATTS_CLT_CFG_F_INDICATE); } + /* Ensure no extraneous subscription callbacks were executed. */ + TEST_ASSERT(ble_gatts_notify_test_num_events == 0); + /* Toss both write responses. */ ble_hs_test_util_prev_tx_queue_clear(); @@ -185,42 +311,76 @@ ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle, int bonding, TEST_ASSERT(flags == chr2_flags); /* Ensure both CCCDs still persisted. */ - exp_num_cccds = (chr1_flags != 0) + (chr2_flags != 0); + if (bonding) { + exp_num_cccds = (chr1_flags != 0) + (chr2_flags != 0); + } else { + exp_num_cccds = 0; + } TEST_ASSERT(ble_hs_test_util_store_num_cccds == exp_num_cccds); } static void -ble_gatts_restore_bonding(uint16_t conn_handle) +ble_gatts_notify_test_disconnect(uint16_t conn_handle, + uint8_t chr1_flags, + uint8_t chr1_indicate_in_progress, + uint8_t chr2_flags, + uint8_t chr2_indicate_in_progress) { - struct ble_hs_conn *conn; + ble_hs_test_util_conn_disconnect(conn_handle); - ble_hs_lock(); - conn = ble_hs_conn_find(conn_handle); - TEST_ASSERT_FATAL(conn != NULL); - conn->bhc_sec_state.encrypted = 1; - conn->bhc_sec_state.authenticated = 1; - conn->bhc_sec_state.bonded = 1; - ble_hs_unlock(); + if (chr1_indicate_in_progress) { + ble_gatts_notify_test_util_verify_tx_event( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + BLE_HS_ENOTCONN, + 1); + } - ble_gatts_bonding_restored(conn_handle); + /* Verify subscription callback executed for each subscribed + * characteristic. + */ + if (chr1_flags != 0) { + ble_gatts_notify_test_util_verify_sub_event( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_TERM, + chr1_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, 0, + chr1_flags == BLE_GATTS_CLT_CFG_F_INDICATE, 0); + } + + if (chr2_indicate_in_progress) { + ble_gatts_notify_test_util_verify_tx_event( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + BLE_HS_ENOTCONN, + 1); + } + + if (chr2_flags != 0) { + ble_gatts_notify_test_util_verify_sub_event( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_TERM, + chr2_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, 0, + chr2_flags == BLE_GATTS_CLT_CFG_F_INDICATE, 0); + } } static void -ble_gatts_notify_test_misc_reg_cb(uint8_t op, - union ble_gatt_register_ctxt *ctxt, +ble_gatts_notify_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { uint16_t uuid16; - if (op == BLE_GATT_REGISTER_OP_CHR) { - uuid16 = ble_uuid_128_to_16(ctxt->chr_reg.chr->uuid128); + if (ctxt->op == BLE_GATT_REGISTER_OP_CHR) { + uuid16 = ble_uuid_128_to_16(ctxt->chr.chr_def->uuid128); switch (uuid16) { case BLE_GATTS_NOTIFY_TEST_CHR_1_UUID: - ble_gatts_notify_test_chr_1_def_handle = ctxt->chr_reg.def_handle; + ble_gatts_notify_test_chr_1_def_handle = ctxt->chr.def_handle; break; case BLE_GATTS_NOTIFY_TEST_CHR_2_UUID: - ble_gatts_notify_test_chr_2_def_handle = ctxt->chr_reg.def_handle; + ble_gatts_notify_test_chr_2_def_handle = ctxt->chr.def_handle; break; default: @@ -232,32 +392,37 @@ ble_gatts_notify_test_misc_reg_cb(uint8_t op, static int ble_gatts_notify_test_misc_access(uint16_t conn_handle, - uint16_t attr_handle, uint8_t op, - union ble_gatt_access_ctxt *ctxt, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) { - TEST_ASSERT_FATAL(op == BLE_GATT_ACCESS_OP_READ_CHR); + int rc; + + TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); TEST_ASSERT(conn_handle == 0xffff); if (attr_handle == ble_gatts_notify_test_chr_1_def_handle + 1) { - TEST_ASSERT(ctxt->chr_access.chr == + TEST_ASSERT(ctxt->chr == &ble_gatts_notify_test_svcs[0].characteristics[0]); - ctxt->chr_access.data = ble_gatts_notify_test_chr_1_val; - ctxt->chr_access.len = ble_gatts_notify_test_chr_1_len; + rc = os_mbuf_copyinto(ctxt->om, 0, ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); + TEST_ASSERT_FATAL(rc == 0); } else if (attr_handle == ble_gatts_notify_test_chr_2_def_handle + 1) { - TEST_ASSERT(ctxt->chr_access.chr == + TEST_ASSERT(ctxt->chr == &ble_gatts_notify_test_svcs[0].characteristics[1]); - ctxt->chr_access.data = ble_gatts_notify_test_chr_2_val; - ctxt->chr_access.len = ble_gatts_notify_test_chr_2_len; + rc = os_mbuf_copyinto(ctxt->om, 0, ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); + TEST_ASSERT_FATAL(rc == 0); } else { - TEST_ASSERT(0); + TEST_ASSERT_FATAL(0); } return 0; } static void -ble_gatts_notify_test_misc_rx_indicate_rsp(uint16_t conn_handle) +ble_gatts_notify_test_misc_rx_indicate_rsp(uint16_t conn_handle, + uint16_t attr_handle) { uint8_t buf[BLE_ATT_INDICATE_RSP_SZ]; int rc; @@ -267,11 +432,15 @@ ble_gatts_notify_test_misc_rx_indicate_rsp(uint16_t conn_handle) rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); + + ble_gatts_notify_test_util_verify_ack_event(conn_handle, attr_handle); } static void -ble_gatts_notify_test_misc_verify_tx_n(uint8_t *attr_data, int attr_len) +ble_gatts_notify_test_misc_verify_tx_n(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t *attr_data, int attr_len) { struct ble_att_notify_req req; struct os_mbuf *om; @@ -283,15 +452,20 @@ ble_gatts_notify_test_misc_verify_tx_n(uint8_t *attr_data, int attr_len) TEST_ASSERT_FATAL(om != NULL); ble_att_notify_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.banq_handle == attr_handle); for (i = 0; i < attr_len; i++) { TEST_ASSERT(om->om_data[BLE_ATT_NOTIFY_REQ_BASE_SZ + i] == attr_data[i]); } + + ble_gatts_notify_test_util_verify_tx_event(conn_handle, attr_handle, 0, 0); } static void -ble_gatts_notify_test_misc_verify_tx_i(uint8_t *attr_data, int attr_len) +ble_gatts_notify_test_misc_verify_tx_i(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t *attr_data, int attr_len) { struct ble_att_indicate_req req; struct os_mbuf *om; @@ -303,33 +477,117 @@ ble_gatts_notify_test_misc_verify_tx_i(uint8_t *attr_data, int attr_len) TEST_ASSERT_FATAL(om != NULL); ble_att_indicate_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.baiq_handle == attr_handle); for (i = 0; i < attr_len; i++) { TEST_ASSERT(om->om_data[BLE_ATT_INDICATE_REQ_BASE_SZ + i] == attr_data[i]); } + + ble_gatts_notify_test_util_verify_tx_event(conn_handle, attr_handle, 0, 1); } -TEST_CASE(ble_gatts_notify_test_n) +static void +ble_gatts_notify_test_misc_verify_tx_gen(uint16_t conn_handle, int attr_idx, + uint8_t chr_flags) { - uint16_t conn_handle; - uint16_t flags; + uint16_t attr_handle; + uint16_t attr_len; + void *attr_val; + + switch (attr_idx) { + case 1: + attr_handle = ble_gatts_notify_test_chr_1_def_handle + 1; + attr_len = ble_gatts_notify_test_chr_1_len; + attr_val = ble_gatts_notify_test_chr_1_val; + break; + + case 2: + attr_handle = ble_gatts_notify_test_chr_2_def_handle + 1; + attr_len = ble_gatts_notify_test_chr_2_len; + attr_val = ble_gatts_notify_test_chr_2_val; + break; + + default: + TEST_ASSERT_FATAL(0); + break; + } - ble_gatts_notify_test_misc_init(&conn_handle, 0, 0, 0); + switch (chr_flags) { + case 0: + break; - /* Enable notifications on both characteristics. */ - ble_gatts_notify_test_misc_enable_notify( - conn_handle, ble_gatts_notify_test_chr_1_def_handle, - BLE_GATTS_CLT_CFG_F_NOTIFY); - ble_gatts_notify_test_misc_enable_notify( - conn_handle, ble_gatts_notify_test_chr_2_def_handle, - BLE_GATTS_CLT_CFG_F_NOTIFY); + case BLE_GATTS_CLT_CFG_F_NOTIFY: + ble_gatts_notify_test_misc_verify_tx_n(conn_handle, attr_handle, + attr_val, attr_len); + break; - /* Toss both write responses. */ - ble_hs_test_util_prev_tx_queue_clear(); + case BLE_GATTS_CLT_CFG_F_INDICATE: + ble_gatts_notify_test_misc_verify_tx_i(conn_handle, attr_handle, + attr_val, attr_len); + break; + + default: + TEST_ASSERT_FATAL(0); + break; + } +} + +static void +ble_gatts_notify_test_restore_bonding(uint16_t conn_handle, + uint8_t chr1_flags, uint8_t chr1_tx, + uint8_t chr2_flags, uint8_t chr2_tx) +{ + struct ble_hs_conn *conn; + + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.encrypted = 1; + conn->bhc_sec_state.authenticated = 1; + conn->bhc_sec_state.bonded = 1; + ble_hs_unlock(); + + ble_gatts_bonding_restored(conn_handle); + + /* Verify subscription callback executed for each subscribed + * characteristic. + */ + if (chr1_flags != 0) { + ble_gatts_notify_test_util_verify_sub_event( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_RESTORE, + 0, chr1_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, + 0, chr1_flags == BLE_GATTS_CLT_CFG_F_INDICATE); + + } + if (chr1_tx) { + ble_gatts_notify_test_misc_verify_tx_gen(conn_handle, 1, chr1_flags); + } - /* Ensure nothing got persisted since peer is not bonded. */ - TEST_ASSERT(ble_hs_test_util_store_num_cccds == 0); + + if (chr2_flags != 0) { + ble_gatts_notify_test_util_verify_sub_event( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_RESTORE, + 0, chr2_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, + 0, chr2_flags == BLE_GATTS_CLT_CFG_F_INDICATE); + } + if (chr2_tx) { + ble_gatts_notify_test_misc_verify_tx_gen(conn_handle, 2, chr2_flags); + } +} + +TEST_CASE(ble_gatts_notify_test_n) +{ + uint16_t conn_handle; + uint16_t flags; + + ble_gatts_notify_test_misc_init(&conn_handle, 0, + BLE_GATTS_CLT_CFG_F_NOTIFY, + BLE_GATTS_CLT_CFG_F_NOTIFY); /* Ensure notifications read back as enabled. */ flags = ble_gatts_notify_test_misc_read_notify( @@ -345,8 +603,11 @@ TEST_CASE(ble_gatts_notify_test_n) ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); /* Verify notification sent properly. */ - ble_gatts_notify_test_misc_verify_tx_n(ble_gatts_notify_test_chr_1_val, - ble_gatts_notify_test_chr_1_len); + ble_gatts_notify_test_misc_verify_tx_n( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); /* Update characteristic 2's value. */ ble_gatts_notify_test_chr_2_len = 16; @@ -355,15 +616,20 @@ TEST_CASE(ble_gatts_notify_test_n) ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); /* Verify notification sent properly. */ - ble_gatts_notify_test_misc_verify_tx_n(ble_gatts_notify_test_chr_2_val, - ble_gatts_notify_test_chr_2_len); + ble_gatts_notify_test_misc_verify_tx_n( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); /*** * Disconnect, modify characteristic values, and reconnect. Ensure * notifications are not sent and are no longer enabled. */ - ble_hs_test_util_conn_disconnect(conn_handle); + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_NOTIFY, 0, + BLE_GATTS_CLT_CFG_F_NOTIFY, 0); /* Update characteristic 1's value. */ ble_gatts_notify_test_chr_1_len = 1; @@ -377,7 +643,7 @@ TEST_CASE(ble_gatts_notify_test_n) ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), - NULL, NULL); + ble_gatts_notify_test_util_gap_event, NULL); /* Ensure no notifications sent. */ TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); @@ -396,29 +662,9 @@ TEST_CASE(ble_gatts_notify_test_i) uint16_t conn_handle; uint16_t flags; - ble_gatts_notify_test_misc_init(&conn_handle, 0, 0, 0); - - /* Enable indications on both characteristics. */ - ble_gatts_notify_test_misc_enable_notify( - conn_handle, ble_gatts_notify_test_chr_1_def_handle, - BLE_GATTS_CLT_CFG_F_INDICATE); - ble_gatts_notify_test_misc_enable_notify( - conn_handle, ble_gatts_notify_test_chr_2_def_handle, - BLE_GATTS_CLT_CFG_F_INDICATE); - - /* Toss both write responses. */ - ble_hs_test_util_prev_tx_queue_clear(); - - /* Ensure nothing got persisted since peer is not bonded. */ - TEST_ASSERT(ble_hs_test_util_store_num_cccds == 0); - - /* Ensure indications read back as enabled. */ - flags = ble_gatts_notify_test_misc_read_notify( - conn_handle, ble_gatts_notify_test_chr_1_def_handle); - TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE); - flags = ble_gatts_notify_test_misc_read_notify( - conn_handle, ble_gatts_notify_test_chr_2_def_handle); - TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE); + ble_gatts_notify_test_misc_init(&conn_handle, 0, + BLE_GATTS_CLT_CFG_F_INDICATE, + BLE_GATTS_CLT_CFG_F_INDICATE); /* Update characteristic 1's value. */ ble_gatts_notify_test_chr_1_len = 1; @@ -426,8 +672,11 @@ TEST_CASE(ble_gatts_notify_test_i) ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); /* Verify indication sent properly. */ - ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_1_val, - ble_gatts_notify_test_chr_1_len); + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); /* Update characteristic 2's value. */ ble_gatts_notify_test_chr_2_len = 16; @@ -442,15 +691,22 @@ TEST_CASE(ble_gatts_notify_test_i) TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0); /* Receive the confirmation for the first indication. */ - ble_gatts_notify_test_misc_rx_indicate_rsp(conn_handle); + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1); /* Verify indication sent properly. */ ble_hs_test_util_tx_all(); - ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_2_val, - ble_gatts_notify_test_chr_2_len); + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); /* Receive the confirmation for the second indication. */ - ble_gatts_notify_test_misc_rx_indicate_rsp(conn_handle); + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1); /* Verify no pending GATT jobs. */ TEST_ASSERT(!ble_gattc_any_jobs()); @@ -460,7 +716,9 @@ TEST_CASE(ble_gatts_notify_test_i) * indications are not sent and are no longer enabled. */ - ble_hs_test_util_conn_disconnect(conn_handle); + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 0, + BLE_GATTS_CLT_CFG_F_INDICATE, 0); /* Update characteristic 1's value. */ ble_gatts_notify_test_chr_1_len = 1; @@ -474,7 +732,7 @@ TEST_CASE(ble_gatts_notify_test_i) ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), - NULL, NULL); + ble_gatts_notify_test_util_gap_event, NULL); /* Ensure no indications sent. */ TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); @@ -498,7 +756,9 @@ TEST_CASE(ble_gatts_notify_test_bonded_n) BLE_GATTS_CLT_CFG_F_NOTIFY); /* Disconnect. */ - ble_hs_test_util_conn_disconnect(conn_handle); + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_NOTIFY, 0, + BLE_GATTS_CLT_CFG_F_NOTIFY, 0); /* Ensure both CCCDs still persisted. */ TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2); @@ -519,8 +779,9 @@ TEST_CASE(ble_gatts_notify_test_bonded_n) */ ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), - NULL, NULL); + ble_gatts_notify_test_util_gap_event, NULL); + ble_gatts_notify_test_num_events = 0; /* Ensure no notifications sent. */ TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); @@ -533,13 +794,9 @@ TEST_CASE(ble_gatts_notify_test_bonded_n) TEST_ASSERT(flags == 0); /* Simulate a successful encryption procedure (bonding restoration). */ - ble_gatts_restore_bonding(conn_handle); - - /* Verify notifications sent properly. */ - ble_gatts_notify_test_misc_verify_tx_n(ble_gatts_notify_test_chr_1_val, - ble_gatts_notify_test_chr_1_len); - ble_gatts_notify_test_misc_verify_tx_n(ble_gatts_notify_test_chr_2_val, - ble_gatts_notify_test_chr_2_len); + ble_gatts_notify_test_restore_bonding(conn_handle, + BLE_GATTS_CLT_CFG_F_NOTIFY, 1, + BLE_GATTS_CLT_CFG_F_NOTIFY, 1); /* Ensure notifications enabled. */ flags = ble_gatts_notify_test_misc_read_notify( @@ -563,7 +820,9 @@ TEST_CASE(ble_gatts_notify_test_bonded_i) BLE_GATTS_CLT_CFG_F_INDICATE); /* Disconnect. */ - ble_hs_test_util_conn_disconnect(conn_handle); + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 0, + BLE_GATTS_CLT_CFG_F_INDICATE, 0); /* Ensure both CCCDs still persisted. */ TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2); @@ -584,7 +843,7 @@ TEST_CASE(ble_gatts_notify_test_bonded_i) */ ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), - NULL, NULL); + ble_gatts_notify_test_util_gap_event, NULL); /* Ensure no indications sent. */ TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); @@ -598,11 +857,9 @@ TEST_CASE(ble_gatts_notify_test_bonded_i) TEST_ASSERT(flags == 0); /* Simulate a successful encryption procedure (bonding restoration). */ - ble_gatts_restore_bonding(conn_handle); - - /* Verify first indication sent properly. */ - ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_1_val, - ble_gatts_notify_test_chr_1_len); + ble_gatts_notify_test_restore_bonding(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 1, + BLE_GATTS_CLT_CFG_F_INDICATE, 0); /* Verify the second indication doesn't get sent until the first is * confirmed. @@ -611,15 +868,22 @@ TEST_CASE(ble_gatts_notify_test_bonded_i) TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0); /* Receive the confirmation for the first indication. */ - ble_gatts_notify_test_misc_rx_indicate_rsp(conn_handle); + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1); /* Verify indication sent properly. */ ble_hs_test_util_tx_all(); - ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_2_val, - ble_gatts_notify_test_chr_2_len); + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); /* Receive the confirmation for the second indication. */ - ble_gatts_notify_test_misc_rx_indicate_rsp(conn_handle); + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1); /* Verify no pending GATT jobs. */ TEST_ASSERT(!ble_gattc_any_jobs()); @@ -654,8 +918,11 @@ TEST_CASE(ble_gatts_notify_test_bonded_i_no_ack) /* Verify indication sent properly. */ ble_hs_test_util_tx_all(); - ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_1_val, - ble_gatts_notify_test_chr_1_len); + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); /* Verify 'updated' state is still persisted. */ key_cccd.peer_addr_type = BLE_STORE_ADDR_TYPE_NONE; @@ -667,24 +934,25 @@ TEST_CASE(ble_gatts_notify_test_bonded_i_no_ack) TEST_ASSERT(value_cccd.value_changed); /* Disconnect. */ - ble_hs_test_util_conn_disconnect(conn_handle); + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 1, 0, 0); /* Ensure CCCD still persisted. */ TEST_ASSERT(ble_hs_test_util_store_num_cccds == 1); /* Reconnect. */ ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), - NULL, NULL); + ble_gatts_notify_test_util_gap_event, NULL); /* Simulate a successful encryption procedure (bonding restoration). */ - ble_gatts_restore_bonding(conn_handle); - - /* Verify indication sent properly. */ - ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_1_val, - ble_gatts_notify_test_chr_1_len); + ble_gatts_notify_test_restore_bonding(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 1, + 0, 0); /* Receive the confirmation for the indication. */ - ble_gatts_notify_test_misc_rx_indicate_rsp(conn_handle); + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1); /* Verify no pending GATT jobs. */ TEST_ASSERT(!ble_gattc_any_jobs()); @@ -706,8 +974,81 @@ TEST_CASE(ble_gatts_notify_test_bonded_i_no_ack) TEST_ASSERT(!value_cccd.value_changed); } +TEST_CASE(ble_gatts_notify_test_disallowed) +{ + uint16_t chr1_val_handle; + uint16_t chr2_val_handle; + uint16_t chr3_val_handle; + int rc; + + const struct ble_gatt_svc_def svcs[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid128 = BLE_UUID16(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid128 = BLE_UUID16(1), + .access_cb = ble_gatts_notify_test_misc_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, + .val_handle = &chr1_val_handle, + }, { + .uuid128 = BLE_UUID16(2), + .access_cb = ble_gatts_notify_test_misc_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_INDICATE, + .val_handle = &chr2_val_handle, + }, { + .uuid128 = BLE_UUID16(3), + .access_cb = ble_gatts_notify_test_misc_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | + BLE_GATT_CHR_F_INDICATE, + .val_handle = &chr3_val_handle, + }, { + 0 + } }, + }, { + 0 + } }; + + ble_hs_test_util_init(); + + rc = ble_gatts_register_svcs(svcs, NULL, NULL); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(chr1_val_handle != 0); + TEST_ASSERT_FATAL(chr2_val_handle != 0); + TEST_ASSERT_FATAL(chr3_val_handle != 0); + + ble_gatts_start(); + + ble_hs_test_util_create_conn(2, ble_gatts_notify_test_peer_addr, + ble_gatts_notify_test_util_gap_event, NULL); + + /* Attempt to enable notifications on chr1 should succeed. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr1_val_handle - 1, BLE_GATTS_CLT_CFG_F_NOTIFY, 0); + + /* Attempt to enable indications on chr1 should fail. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr1_val_handle - 1, BLE_GATTS_CLT_CFG_F_INDICATE, 1); + + /* Attempt to enable notifications on chr2 should fail. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr2_val_handle - 1, BLE_GATTS_CLT_CFG_F_NOTIFY, 1); + + /* Attempt to enable indications on chr2 should succeed. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr2_val_handle - 1, BLE_GATTS_CLT_CFG_F_INDICATE, 0); + + /* Attempt to enable notifications on chr3 should succeed. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr3_val_handle - 1, BLE_GATTS_CLT_CFG_F_NOTIFY, 0); + + /* Attempt to enable indications on chr3 should succeed. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr3_val_handle - 1, BLE_GATTS_CLT_CFG_F_INDICATE, 0); +} + TEST_SUITE(ble_gatts_notify_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatts_notify_test_n(); ble_gatts_notify_test_i(); @@ -716,6 +1057,8 @@ TEST_SUITE(ble_gatts_notify_suite) ble_gatts_notify_test_bonded_i_no_ack(); + ble_gatts_notify_test_disallowed(); + /* XXX: Test corner cases: * o Bonding after CCCD configuration. * o Disconnect prior to rx of indicate ack. diff --git a/net/nimble/host/src/test/ble_gatts_read_test.c b/net/nimble/host/src/test/ble_gatts_read_test.c new file mode 100644 index 00000000..cef9f927 --- /dev/null +++ b/net/nimble/host/src/test/ble_gatts_read_test.c @@ -0,0 +1,261 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <string.h> +#include <errno.h> +#include "testutil/testutil.h" +#include "host/ble_uuid.h" +#include "host/ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_GATTS_READ_TEST_CHR_1_UUID 0x1111 +#define BLE_GATTS_READ_TEST_CHR_2_UUID 0x2222 + +static uint8_t ble_gatts_read_test_peer_addr[6] = {2,3,4,5,6,7}; + +static int +ble_gatts_read_test_util_access_1(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +ble_gatts_read_test_util_access_2(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); +static void +ble_gatts_read_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, + void *arg); + +static const struct ble_gatt_svc_def ble_gatts_read_test_svcs[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid128 = BLE_UUID16(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid128 = BLE_UUID16(BLE_GATTS_READ_TEST_CHR_1_UUID), + .access_cb = ble_gatts_read_test_util_access_1, + .flags = BLE_GATT_CHR_F_READ + }, { + .uuid128 = BLE_UUID16(BLE_GATTS_READ_TEST_CHR_2_UUID), + .access_cb = ble_gatts_read_test_util_access_2, + .flags = BLE_GATT_CHR_F_READ + }, { + 0 + } }, +}, { + 0 +} }; + + +static uint16_t ble_gatts_read_test_chr_1_def_handle; +static uint16_t ble_gatts_read_test_chr_1_val_handle; +static uint8_t ble_gatts_read_test_chr_1_val[1024]; +static int ble_gatts_read_test_chr_1_len; +static uint16_t ble_gatts_read_test_chr_2_def_handle; +static uint16_t ble_gatts_read_test_chr_2_val_handle; + +static void +ble_gatts_read_test_misc_init(uint16_t *out_conn_handle) +{ + int rc; + + ble_hs_test_util_init(); + + rc = ble_gatts_register_svcs(ble_gatts_read_test_svcs, + ble_gatts_read_test_misc_reg_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_gatts_read_test_chr_1_def_handle != 0); + TEST_ASSERT_FATAL(ble_gatts_read_test_chr_1_val_handle == + ble_gatts_read_test_chr_1_def_handle + 1); + TEST_ASSERT_FATAL(ble_gatts_read_test_chr_2_def_handle != 0); + TEST_ASSERT_FATAL(ble_gatts_read_test_chr_2_val_handle == + ble_gatts_read_test_chr_2_def_handle + 1); + + ble_gatts_start(); + + ble_hs_test_util_create_conn(2, ble_gatts_read_test_peer_addr, NULL, NULL); + + if (out_conn_handle != NULL) { + *out_conn_handle = 2; + } +} + +static void +ble_gatts_read_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + + if (ctxt->op == BLE_GATT_REGISTER_OP_CHR) { + uuid16 = ble_uuid_128_to_16(ctxt->chr.chr_def->uuid128); + switch (uuid16) { + case BLE_GATTS_READ_TEST_CHR_1_UUID: + ble_gatts_read_test_chr_1_def_handle = ctxt->chr.def_handle; + ble_gatts_read_test_chr_1_val_handle = ctxt->chr.val_handle; + break; + + case BLE_GATTS_READ_TEST_CHR_2_UUID: + ble_gatts_read_test_chr_2_def_handle = ctxt->chr.def_handle; + ble_gatts_read_test_chr_2_val_handle = ctxt->chr.val_handle; + break; + + default: + TEST_ASSERT_FATAL(0); + break; + } + } +} + +static int +ble_gatts_read_test_util_access_1(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + int rc; + + TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + TEST_ASSERT_FATAL(attr_handle == ble_gatts_read_test_chr_1_val_handle); + + TEST_ASSERT(ctxt->chr == + &ble_gatts_read_test_svcs[0].characteristics[0]); + + rc = os_mbuf_append(ctxt->om, ble_gatts_read_test_chr_1_val, + ble_gatts_read_test_chr_1_len); + TEST_ASSERT(rc == 0); + + return 0; +} + +static int +ble_gatts_read_test_util_access_2(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint8_t *buf; + + TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + TEST_ASSERT_FATAL(attr_handle == ble_gatts_read_test_chr_2_def_handle + 1); + + TEST_ASSERT(ctxt->chr == + &ble_gatts_read_test_svcs[0].characteristics[1]); + + buf = os_mbuf_extend(ctxt->om, 6); + TEST_ASSERT_FATAL(buf != NULL); + + buf[0] = 0; + buf[1] = 10; + buf[2] = 20; + buf[3] = 30; + buf[4] = 40; + buf[5] = 50; + + return 0; +} + +static void +ble_gatts_read_test_once(uint16_t conn_handle, uint16_t attr_id, + void *expected_value, uint16_t expected_len) +{ + struct ble_att_read_req read_req; + uint8_t buf[BLE_ATT_READ_REQ_SZ]; + int rc; + + read_req.barq_handle = attr_id; + ble_att_read_req_write(buf, sizeof buf, &read_req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_verify_tx_read_rsp(expected_value, expected_len); +} + +TEST_CASE(ble_gatts_read_test_case_basic) +{ + uint16_t conn_handle; + + ble_gatts_read_test_misc_init(&conn_handle); + + /*** Application points attribute at static data. */ + ble_gatts_read_test_chr_1_val[0] = 1; + ble_gatts_read_test_chr_1_val[1] = 2; + ble_gatts_read_test_chr_1_val[2] = 3; + ble_gatts_read_test_chr_1_len = 3; + ble_gatts_read_test_once(conn_handle, + ble_gatts_read_test_chr_1_val_handle, + ble_gatts_read_test_chr_1_val, + ble_gatts_read_test_chr_1_len); + + /*** Application uses stack-provided buffer for dynamic attribute. */ + ble_gatts_read_test_once(conn_handle, + ble_gatts_read_test_chr_2_def_handle + 1, + ((uint8_t[6]){0,10,20,30,40,50}), 6); + +} + +TEST_CASE(ble_gatts_read_test_case_long) +{ + struct ble_att_read_blob_req read_blob_req; + struct ble_att_read_req read_req; + uint8_t buf[max(BLE_ATT_READ_REQ_SZ, BLE_ATT_READ_BLOB_REQ_SZ)]; + uint16_t conn_handle; + int rc; + int i; + + ble_gatts_read_test_misc_init(&conn_handle); + + /*** Prepare characteristic value. */ + ble_gatts_read_test_chr_1_len = 40; + for (i = 0; i < ble_gatts_read_test_chr_1_len; i++) { + ble_gatts_read_test_chr_1_val[i] = i; + } + + /* Receive first read request. */ + read_req.barq_handle = ble_gatts_read_test_chr_1_val_handle; + ble_att_read_req_write(buf, sizeof buf, &read_req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_verify_tx_read_rsp(ble_gatts_read_test_chr_1_val, 22); + + /* Receive follow-up read blob request. */ + read_blob_req.babq_handle = ble_gatts_read_test_chr_1_val_handle; + read_blob_req.babq_offset = 22; + ble_att_read_blob_req_write(buf, sizeof buf, &read_blob_req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + /* Ensure response starts at appropriate offset (22). */ + ble_hs_test_util_verify_tx_read_blob_rsp( + ble_gatts_read_test_chr_1_val + 22, 18); +} + +TEST_SUITE(ble_gatts_read_test_suite) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gatts_read_test_case_basic(); + ble_gatts_read_test_case_long(); +} diff --git a/net/nimble/host/src/test/ble_gatts_reg_test.c b/net/nimble/host/src/test/ble_gatts_reg_test.c index a198d997..ad5f18fa 100644 --- a/net/nimble/host/src/test/ble_gatts_reg_test.c +++ b/net/nimble/host/src/test/ble_gatts_reg_test.c @@ -30,6 +30,12 @@ struct ble_gatts_reg_test_entry { uint8_t op; uint8_t uuid128[16]; + uint16_t handle; + uint16_t val_handle; /* If a characteristic. */ + + const struct ble_gatt_svc_def *svc; + const struct ble_gatt_chr_def *chr; + const struct ble_gatt_dsc_def *dsc; }; static struct ble_gatts_reg_test_entry @@ -45,8 +51,7 @@ ble_gatts_reg_test_init(void) } static void -ble_gatts_reg_test_misc_reg_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, - void *arg) +ble_gatts_reg_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { struct ble_gatts_reg_test_entry *entry; @@ -54,19 +59,65 @@ ble_gatts_reg_test_misc_reg_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, BLE_GATTS_REG_TEST_MAX_ENTRIES); entry = ble_gatts_reg_test_entries + ble_gatts_reg_test_num_entries++; + memset(entry, 0, sizeof *entry); + + entry->op = ctxt->op; + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + memcpy(entry->uuid128, ctxt->svc.svc_def->uuid128, 16); + entry->handle = ctxt->svc.handle; + entry->svc = ctxt->svc.svc_def; + break; + + case BLE_GATT_REGISTER_OP_CHR: + memcpy(entry->uuid128, ctxt->chr.chr_def->uuid128, 16); + entry->handle = ctxt->chr.def_handle; + entry->val_handle = ctxt->chr.val_handle; + entry->svc = ctxt->chr.svc_def; + entry->chr = ctxt->chr.chr_def; + break; + + case BLE_GATT_REGISTER_OP_DSC: + memcpy(entry->uuid128, ctxt->dsc.dsc_def->uuid128, 16); + entry->handle = ctxt->dsc.handle; + entry->svc = ctxt->dsc.svc_def; + entry->chr = ctxt->dsc.chr_def; + entry->dsc = ctxt->dsc.dsc_def; + break; + + default: + TEST_ASSERT(0); + break; + } +} - entry->op = op; - switch (op) { +static void +ble_gatts_reg_test_misc_lookup_good(struct ble_gatts_reg_test_entry *entry) +{ + uint16_t chr_def_handle; + uint16_t chr_val_handle; + uint16_t svc_handle; + uint16_t dsc_handle; + int rc; + + switch (entry->op) { case BLE_GATT_REGISTER_OP_SVC: - memcpy(entry->uuid128, ctxt->svc_reg.svc->uuid128, 16); + rc = ble_gatts_find_svc(entry->uuid128, &svc_handle); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(svc_handle == entry->handle); break; case BLE_GATT_REGISTER_OP_CHR: - memcpy(entry->uuid128, ctxt->chr_reg.chr->uuid128, 16); + rc = ble_gatts_find_chr(entry->svc->uuid128, entry->chr->uuid128, + &chr_def_handle, &chr_val_handle); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(chr_def_handle == entry->handle); + TEST_ASSERT(chr_val_handle == entry->val_handle); break; case BLE_GATT_REGISTER_OP_DSC: - memcpy(entry->uuid128, ctxt->dsc_reg.dsc->uuid128, 16); + rc = ble_gatts_find_dsc(entry->svc->uuid128, entry->chr->uuid128, + entry->dsc->uuid128, &dsc_handle); break; default: @@ -76,7 +127,139 @@ ble_gatts_reg_test_misc_reg_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, } static void -ble_gatts_reg_test_misc_verify_entry(uint8_t op, uint8_t *uuid128) +ble_gatts_reg_test_misc_lookup_bad(struct ble_gatts_reg_test_entry *entry) +{ + struct ble_gatts_reg_test_entry *cur; + uint8_t wrong_uuid[16]; + int rc; + int i; + + switch (entry->op) { + case BLE_GATT_REGISTER_OP_SVC: + /* Wrong service UUID. */ + memcpy(wrong_uuid, entry->svc->uuid128, 16); + wrong_uuid[15]++; + rc = ble_gatts_find_svc(wrong_uuid, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + break; + + case BLE_GATT_REGISTER_OP_CHR: + /* Correct service UUID, wrong characteristic UUID. */ + memcpy(wrong_uuid, entry->chr->uuid128, 16); + wrong_uuid[15]++; + rc = ble_gatts_find_chr(entry->svc->uuid128, wrong_uuid, NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + /* Incorrect service UUID, correct characteristic UUID. */ + memcpy(wrong_uuid, entry->svc->uuid128, 16); + wrong_uuid[15]++; + rc = ble_gatts_find_chr(wrong_uuid, entry->chr->uuid128, NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + /* Existing (but wrong) service, correct characteristic UUID. */ + for (i = 0; i < ble_gatts_reg_test_num_entries; i++) { + cur = ble_gatts_reg_test_entries + i; + switch (cur->op) { + case BLE_GATT_REGISTER_OP_SVC: + if (cur->svc != entry->svc) { + rc = ble_gatts_find_chr(cur->svc->uuid128, + entry->chr->uuid128, + NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + case BLE_GATT_REGISTER_OP_CHR: + /* Characteristic that isn't in this service. */ + if (cur->svc != entry->svc) { + rc = ble_gatts_find_chr(entry->svc->uuid128, + cur->chr->uuid128, + NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + case BLE_GATT_REGISTER_OP_DSC: + /* Use descriptor UUID instead of characteristic UUID. */ + rc = ble_gatts_find_chr(entry->svc->uuid128, + cur->dsc->uuid128, + NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + break; + + default: + TEST_ASSERT(0); + break; + } + } + break; + + case BLE_GATT_REGISTER_OP_DSC: + /* Correct svc/chr UUID, wrong dsc UUID. */ + memcpy(wrong_uuid, entry->dsc->uuid128, 16); + wrong_uuid[15]++; + rc = ble_gatts_find_dsc(entry->svc->uuid128, entry->chr->uuid128, + wrong_uuid, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + /* Incorrect svc UUID, correct chr/dsc UUID. */ + memcpy(wrong_uuid, entry->svc->uuid128, 16); + wrong_uuid[15]++; + rc = ble_gatts_find_dsc(wrong_uuid, entry->chr->uuid128, + entry->dsc->uuid128, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + for (i = 0; i < ble_gatts_reg_test_num_entries; i++) { + cur = ble_gatts_reg_test_entries + i; + switch (cur->op) { + case BLE_GATT_REGISTER_OP_SVC: + /* Existing (but wrong) svc, correct chr/dsc UUID. */ + if (cur->svc != entry->svc) { + rc = ble_gatts_find_dsc(cur->svc->uuid128, + entry->chr->uuid128, + entry->dsc->uuid128, + NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + case BLE_GATT_REGISTER_OP_CHR: + /* Existing (but wrong) svc/chr, correct dsc UUID. */ + if (cur->chr != entry->chr) { + rc = ble_gatts_find_dsc(cur->svc->uuid128, + cur->chr->uuid128, + entry->dsc->uuid128, + NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + case BLE_GATT_REGISTER_OP_DSC: + /* Descriptor that isn't in this characteristic. */ + if (cur->chr != entry->chr) { + rc = ble_gatts_find_dsc(cur->svc->uuid128, + cur->chr->uuid128, + entry->dsc->uuid128, + NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + default: + TEST_ASSERT(0); + break; + } + } + break; + + default: + TEST_ASSERT(0); + break; + } +} + +static void +ble_gatts_reg_test_misc_verify_entry(uint8_t op, const uint8_t *uuid128) { struct ble_gatts_reg_test_entry *entry; int i; @@ -84,17 +267,31 @@ ble_gatts_reg_test_misc_verify_entry(uint8_t op, uint8_t *uuid128) for (i = 0; i < ble_gatts_reg_test_num_entries; i++) { entry = ble_gatts_reg_test_entries + i; if (entry->op == op && memcmp(entry->uuid128, uuid128, 16) == 0) { - return; + break; } } + TEST_ASSERT_FATAL(entry != NULL); - TEST_ASSERT(0); + /* Verify that characteristic value handle was properly assigned at + * registration. + */ + if (op == BLE_GATT_REGISTER_OP_CHR) { + TEST_ASSERT(*entry->chr->val_handle == entry->val_handle); + } + + /* Verify that the entry can be looked up. */ + ble_gatts_reg_test_misc_lookup_good(entry); + + /* Verify that "barely incorrect" UUID information doesn't retrieve any + * handles. + */ + ble_gatts_reg_test_misc_lookup_bad(entry); } static int ble_gatts_reg_test_misc_dummy_access(uint16_t conn_handle, - uint16_t attr_handle, uint8_t op, - union ble_gatt_access_ctxt *ctxt, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) { return 0; @@ -104,9 +301,8 @@ TEST_CASE(ble_gatts_reg_test_svc_return) { int rc; - ble_gatts_reg_test_init(); - /*** Missing UUID. */ + ble_gatts_reg_test_init(); struct ble_gatt_svc_def svcs_no_uuid[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, }, { @@ -117,6 +313,7 @@ TEST_CASE(ble_gatts_reg_test_svc_return) TEST_ASSERT(rc == BLE_HS_EINVAL); /*** Circular dependency. */ + ble_gatts_reg_test_init(); struct ble_gatt_svc_def svcs_circ[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid128 = BLE_UUID16(0x1234), @@ -133,6 +330,7 @@ TEST_CASE(ble_gatts_reg_test_svc_return) TEST_ASSERT(rc == BLE_HS_EINVAL); /*** Success. */ + ble_gatts_reg_test_init(); struct ble_gatt_svc_def svcs_good[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid128 = BLE_UUID16(0x1234), @@ -152,9 +350,8 @@ TEST_CASE(ble_gatts_reg_test_chr_return) { int rc; - ble_gatts_reg_test_init(); - /*** Missing callback. */ + ble_gatts_reg_test_init(); struct ble_gatt_svc_def svcs_no_chr_cb[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid128 = BLE_UUID16(0x1234), @@ -172,6 +369,7 @@ TEST_CASE(ble_gatts_reg_test_chr_return) TEST_ASSERT(rc == BLE_HS_EINVAL); /*** Success. */ + ble_gatts_reg_test_init(); struct ble_gatt_svc_def svcs_good[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid128 = BLE_UUID16(0x1234), @@ -194,9 +392,8 @@ TEST_CASE(ble_gatts_reg_test_dsc_return) { int rc; - ble_gatts_reg_test_init(); - /*** Missing callback. */ + ble_gatts_reg_test_init(); struct ble_gatt_svc_def svcs_no_dsc_cb[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid128 = BLE_UUID16(0x1234), @@ -221,6 +418,7 @@ TEST_CASE(ble_gatts_reg_test_dsc_return) TEST_ASSERT(rc == BLE_HS_EINVAL); /*** Success. */ + ble_gatts_reg_test_init(); struct ble_gatt_svc_def svcs_good[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid128 = BLE_UUID16(0x1234), @@ -249,9 +447,9 @@ TEST_CASE(ble_gatts_reg_test_dsc_return) static void ble_gatts_reg_test_misc_svcs(struct ble_gatt_svc_def *svcs) { - struct ble_gatt_svc_def *svc; - struct ble_gatt_chr_def *chr; - struct ble_gatt_dsc_def *dsc; + const struct ble_gatt_svc_def *svc; + const struct ble_gatt_chr_def *chr; + const struct ble_gatt_dsc_def *dsc; int rc; ble_gatts_reg_test_init(); @@ -337,6 +535,8 @@ TEST_CASE(ble_gatts_reg_test_svc_cb) TEST_CASE(ble_gatts_reg_test_chr_cb) { + uint16_t val_handles[16]; + /*** 1 characteristic. */ ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { .type = BLE_GATT_SVC_TYPE_PRIMARY, @@ -345,6 +545,7 @@ TEST_CASE(ble_gatts_reg_test_chr_cb) .uuid128 = BLE_UUID16(0x1111), .access_cb = ble_gatts_reg_test_misc_dummy_access, .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 0, }, { 0 } }, @@ -360,10 +561,12 @@ TEST_CASE(ble_gatts_reg_test_chr_cb) .uuid128 = BLE_UUID16(0x1111), .access_cb = ble_gatts_reg_test_misc_dummy_access, .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 0, }, { .uuid128 = BLE_UUID16(0x2222), .access_cb = ble_gatts_reg_test_misc_dummy_access, .flags = BLE_GATT_CHR_F_WRITE, + .val_handle = val_handles + 1, }, { 0 } }, @@ -374,6 +577,7 @@ TEST_CASE(ble_gatts_reg_test_chr_cb) .uuid128 = BLE_UUID16(0x3333), .access_cb = ble_gatts_reg_test_misc_dummy_access, .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 2, }, { 0 } }, @@ -384,6 +588,8 @@ TEST_CASE(ble_gatts_reg_test_chr_cb) TEST_CASE(ble_gatts_reg_test_dsc_cb) { + uint16_t val_handles[16]; + /*** 1 descriptor. */ ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { .type = BLE_GATT_SVC_TYPE_PRIMARY, @@ -392,8 +598,9 @@ TEST_CASE(ble_gatts_reg_test_dsc_cb) .uuid128 = BLE_UUID16(0x1111), .access_cb = ble_gatts_reg_test_misc_dummy_access, .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 0, .descriptors = (struct ble_gatt_dsc_def[]) { { - .uuid128 = BLE_UUID16(0xaaaa), + .uuid128 = BLE_UUID16(0x111a), .att_flags = 5, .access_cb = ble_gatts_reg_test_misc_dummy_access, }, { @@ -406,7 +613,7 @@ TEST_CASE(ble_gatts_reg_test_dsc_cb) 0 } }); - /*** 5 descriptors. */ + /*** 5+ descriptors. */ ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid128 = BLE_UUID16(0x1234), @@ -414,8 +621,9 @@ TEST_CASE(ble_gatts_reg_test_dsc_cb) .uuid128 = BLE_UUID16(0x1111), .access_cb = ble_gatts_reg_test_misc_dummy_access, .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 0, .descriptors = (struct ble_gatt_dsc_def[]) { { - .uuid128 = BLE_UUID16(0xaaaa), + .uuid128 = BLE_UUID16(0x111a), .att_flags = 5, .access_cb = ble_gatts_reg_test_misc_dummy_access, }, { @@ -425,6 +633,7 @@ TEST_CASE(ble_gatts_reg_test_dsc_cb) .uuid128 = BLE_UUID16(0x2222), .access_cb = ble_gatts_reg_test_misc_dummy_access, .flags = BLE_GATT_CHR_F_WRITE, + .val_handle = val_handles + 1, }, { 0 } }, @@ -435,20 +644,45 @@ TEST_CASE(ble_gatts_reg_test_dsc_cb) .uuid128 = BLE_UUID16(0x3333), .access_cb = ble_gatts_reg_test_misc_dummy_access, .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 2, .descriptors = (struct ble_gatt_dsc_def[]) { { - .uuid128 = BLE_UUID16(0xaaab), + .uuid128 = BLE_UUID16(0x333a), .att_flags = 5, .access_cb = ble_gatts_reg_test_misc_dummy_access, }, { - .uuid128 = BLE_UUID16(0xaaac), + .uuid128 = BLE_UUID16(0x333b), .att_flags = 5, .access_cb = ble_gatts_reg_test_misc_dummy_access, }, { - .uuid128 = BLE_UUID16(0xaaad), + .uuid128 = BLE_UUID16(0x333c), .att_flags = 5, .access_cb = ble_gatts_reg_test_misc_dummy_access, }, { - .uuid128 = BLE_UUID16(0xaaae), + .uuid128 = BLE_UUID16(0x333e), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + 0 + } }, + }, { + .uuid128 = BLE_UUID16(0x4444), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 3, + .descriptors = (struct ble_gatt_dsc_def[]) { { + .uuid128 = BLE_UUID16(0x444a), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid128 = BLE_UUID16(0x444b), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid128 = BLE_UUID16(0x444c), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid128 = BLE_UUID16(0x444e), .att_flags = 5, .access_cb = ble_gatts_reg_test_misc_dummy_access, }, { @@ -464,6 +698,8 @@ TEST_CASE(ble_gatts_reg_test_dsc_cb) TEST_SUITE(ble_gatts_reg_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_gatts_reg_test_svc_return(); ble_gatts_reg_test_chr_return(); ble_gatts_reg_test_dsc_return(); diff --git a/net/nimble/host/src/test/ble_hs_adv_test.c b/net/nimble/host/src/test/ble_hs_adv_test.c index 9673cc10..e99fd5b4 100644 --- a/net/nimble/host/src/test/ble_hs_adv_test.c +++ b/net/nimble/host/src/test/ble_hs_adv_test.c @@ -22,8 +22,8 @@ #include <string.h> #include "testutil/testutil.h" #include "nimble/hci_common.h" +#include "host/ble_hs_adv.h" #include "host/ble_hs_test.h" -#include "host/host_hci.h" #include "ble_hs_test_util.h" #define BLE_ADV_TEST_DATA_OFF 4 @@ -140,18 +140,36 @@ ble_hs_adv_test_misc_tx_and_verify_data( struct ble_hs_adv_fields *rsp_fields, struct ble_hs_adv_test_field *test_rsp_fields) { + struct ble_gap_adv_params adv_params; int rc; ble_hs_test_util_init(); - rc = ble_gap_adv_set_fields(adv_fields); + adv_params = ble_hs_test_util_adv_params; + adv_params.disc_mode = disc_mode; + + rc = ble_hs_test_util_adv_set_fields(adv_fields, 0); TEST_ASSERT_FATAL(rc == 0); rc = ble_gap_adv_rsp_set_fields(rsp_fields); TEST_ASSERT_FATAL(rc == 0); - rc = ble_hs_test_util_adv_start(disc_mode, BLE_GAP_CONN_MODE_UND, NULL, 0, - NULL, NULL, NULL, 0, 0); + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, 0, NULL, &adv_params, + NULL, NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Discard the adv-enable command. */ + ble_hs_test_util_get_last_hci_tx(); + + ble_hs_adv_test_misc_verify_tx_rsp_data(test_rsp_fields); + ble_hs_adv_test_misc_verify_tx_adv_data(test_adv_fields); + + /* Ensure the same data gets sent on repeated advertise procedures. */ + rc = ble_hs_test_util_adv_stop(0); + TEST_ASSERT_FATAL(rc == 0); + + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, 0, NULL, &adv_params, + NULL, NULL, 0, 0); TEST_ASSERT_FATAL(rc == 0); /* Discard the adv-enable command. */ @@ -170,18 +188,20 @@ TEST_CASE(ble_hs_adv_test_case_flags) memset(&rsp_fields, 0, sizeof rsp_fields); /* Default flags. */ + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -191,15 +211,16 @@ TEST_CASE(ble_hs_adv_test_case_flags) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_LTD, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_FLAGS, .val = (uint8_t[]) { BLE_HS_ADV_F_DISC_LTD | BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, - }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, }, { 0 }, }, &rsp_fields, NULL); @@ -208,15 +229,16 @@ TEST_CASE(ble_hs_adv_test_case_flags) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_GEN, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_FLAGS, .val = (uint8_t[]) { BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, - }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, }, { 0 }, }, &rsp_fields, NULL); @@ -231,7 +253,9 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Complete 16-bit service class UUIDs. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; adv_fields.uuids16 = (uint16_t[]) { 0x0001, 0x1234, 0x54ab }; adv_fields.num_uuids16 = 3; adv_fields.uuids16_is_complete = 1; @@ -244,13 +268,13 @@ TEST_CASE(ble_hs_adv_test_case_user) .val_len = 6, }, { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -258,6 +282,7 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Incomplete 16-bit service class UUIDs. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.uuids16 = (uint16_t[]) { 0x0001, 0x1234, 0x54ab }; adv_fields.num_uuids16 = 3; @@ -271,13 +296,13 @@ TEST_CASE(ble_hs_adv_test_case_user) .val_len = 6, }, { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -285,6 +310,7 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Complete 32-bit service class UUIDs. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.uuids32 = (uint32_t[]) { 0x12345678, 0xabacadae }; adv_fields.num_uuids32 = 2; @@ -298,13 +324,13 @@ TEST_CASE(ble_hs_adv_test_case_user) .val_len = 8, }, { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -312,6 +338,7 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Incomplete 32-bit service class UUIDs. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.uuids32 = (uint32_t[]) { 0x12345678, 0xabacadae }; adv_fields.num_uuids32 = 2; @@ -325,13 +352,13 @@ TEST_CASE(ble_hs_adv_test_case_user) .val_len = 8, }, { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -339,6 +366,7 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Complete 128-bit service class UUIDs. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.uuids128 = (uint8_t[]) { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, @@ -358,13 +386,13 @@ TEST_CASE(ble_hs_adv_test_case_user) .val_len = 16, }, { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -372,6 +400,7 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Incomplete 128-bit service class UUIDs. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.uuids128 = (uint8_t[]) { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, @@ -391,13 +420,13 @@ TEST_CASE(ble_hs_adv_test_case_user) .val_len = 16, }, { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -405,6 +434,7 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Complete name. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.name = (uint8_t *)"myname"; adv_fields.name_len = 6; @@ -418,13 +448,13 @@ TEST_CASE(ble_hs_adv_test_case_user) .val_len = 6, }, { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -432,6 +462,7 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Incomplete name. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.name = (uint8_t *)"myname"; adv_fields.name_len = 6; @@ -445,13 +476,13 @@ TEST_CASE(ble_hs_adv_test_case_user) .val_len = 6, }, { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -459,12 +490,18 @@ TEST_CASE(ble_hs_adv_test_case_user) /*** Class of device. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.device_class = (uint8_t[]){ 1,2,3 }; ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_DEVICE_CLASS, .val = (uint8_t[]) { 1,2,3 }, .val_len = BLE_HS_ADV_DEVICE_CLASS_LEN, @@ -474,22 +511,23 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** Slave interval range. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.slave_itvl_range = (uint8_t[]){ 1,2,3,4 }; ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, .val = (uint8_t[]) { 1,2,3,4 }, .val_len = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN, @@ -499,16 +537,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x16 - Service data - 16-bit UUID. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.svc_data_uuid16 = (uint8_t[]){ 1,2,3,4 }; adv_fields.svc_data_uuid16_len = 4; @@ -516,6 +550,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID16, .val = (uint8_t[]) { 1,2,3,4 }, .val_len = 4, @@ -525,16 +564,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x17 - Public target address. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.public_tgt_addr = (uint8_t[]){ 1,2,3,4,5,6, 6,5,4,3,2,1 }; adv_fields.num_public_tgt_addrs = 2; @@ -542,6 +577,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, .val = (uint8_t[]){ 1,2,3,4,5,6, 6,5,4,3,2,1 }, .val_len = 2 * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN, @@ -551,16 +591,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x19 - Appearance. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.appearance = 0x1234; adv_fields.appearance_is_present = 1; @@ -568,6 +604,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_APPEARANCE, .val = (uint8_t[]){ 0x34, 0x12 }, .val_len = BLE_HS_ADV_APPEARANCE_LEN, @@ -577,16 +618,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x1a - Advertising interval. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.adv_itvl = 0x1234; adv_fields.adv_itvl_is_present = 1; @@ -594,6 +631,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_ADV_ITVL, .val = (uint8_t[]){ 0x34, 0x12 }, .val_len = BLE_HS_ADV_ADV_ITVL_LEN, @@ -603,22 +645,23 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x1b - LE bluetooth device address. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.le_addr = (uint8_t[]){ 1,2,3,4,5,6,7 }; ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_LE_ADDR, .val = (uint8_t[]) { 1,2,3,4,5,6,7 }, .val_len = BLE_HS_ADV_LE_ADDR_LEN, @@ -628,16 +671,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x1c - LE role. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.le_role = BLE_HS_ADV_LE_ROLE_BOTH_PERIPH_PREF; adv_fields.le_role_is_present = 1; @@ -645,6 +684,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_LE_ROLE, .val = (uint8_t[]) { BLE_HS_ADV_LE_ROLE_BOTH_PERIPH_PREF }, .val_len = 1, @@ -654,16 +698,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x20 - Service data - 32-bit UUID. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.svc_data_uuid32 = (uint8_t[]){ 1,2,3,4,5 }; adv_fields.svc_data_uuid32_len = 5; @@ -671,6 +711,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID32, .val = (uint8_t[]) { 1,2,3,4,5 }, .val_len = 5, @@ -680,16 +725,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x21 - Service data - 128-bit UUID. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.svc_data_uuid128 = (uint8_t[]){ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 }; @@ -698,6 +739,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID128, .val = (uint8_t[]){ 1,2,3,4,5,6,7,8,9,10, 11,12,13,14,15,16,17,18 }, @@ -708,16 +754,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0x24 - URI. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.uri = (uint8_t[]){ 1,2,3,4 }; adv_fields.uri_len = 4; @@ -725,6 +767,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_URI, .val = (uint8_t[]) { 1,2,3,4 }, .val_len = 4, @@ -734,16 +781,12 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); /*** 0xff - Manufacturer specific data. */ memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; adv_fields.mfg_data = (uint8_t[]){ 1,2,3,4 }; adv_fields.mfg_data_len = 4; @@ -751,6 +794,11 @@ TEST_CASE(ble_hs_adv_test_case_user) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { .type = BLE_HS_ADV_TYPE_MFG_DATA, .val = (uint8_t[]) { 1,2,3,4 }, .val_len = 4, @@ -760,11 +808,6 @@ TEST_CASE(ble_hs_adv_test_case_user) .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, - { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, - .val_len = 1, - }, { 0 }, }, &rsp_fields, NULL); } @@ -775,6 +818,7 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) struct ble_hs_adv_fields adv_fields; memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags_is_present = 1; adv_fields.tx_pwr_lvl_is_present = 1; /*** Complete 16-bit service class UUIDs. */ @@ -786,13 +830,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -816,13 +860,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -846,13 +890,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -876,13 +920,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -909,13 +953,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -945,13 +989,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -978,13 +1022,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1008,13 +1052,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1036,13 +1080,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1064,13 +1108,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1093,13 +1137,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1122,13 +1166,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1151,13 +1195,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1180,13 +1224,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1208,13 +1252,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1237,13 +1281,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1266,13 +1310,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1296,13 +1340,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1326,13 +1370,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1355,13 +1399,13 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, (struct ble_hs_adv_test_field[]) { { - .type = BLE_HS_ADV_TYPE_FLAGS, - .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, .val_len = 1, }, { - .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, - .val = (uint8_t[]){ 0x00 }, + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, .val_len = 1, }, { 0 }, @@ -1377,11 +1421,59 @@ TEST_CASE(ble_hs_adv_test_case_user_rsp) }); } +TEST_CASE(ble_hs_adv_test_case_user_full_payload) +{ + /* Intentionally allocate an extra byte. */ + static const uint8_t mfg_data[30] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + }; + + struct ble_hs_adv_fields adv_fields; + struct ble_hs_adv_fields rsp_fields; + int rc; + + ble_hs_test_util_init(); + + memset(&rsp_fields, 0, sizeof rsp_fields); + + /*** + * An advertisement should allow 31 bytes of user data. Each field has a + * two-byte header, leaving 29 bytes of payload. + */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.mfg_data = (void *)mfg_data; + adv_fields.mfg_data_len = 29; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_MFG_DATA, + .val = (void *)mfg_data, + .val_len = 29, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Fail with 30 bytes. */ + rc = ble_hs_test_util_adv_stop(0); + TEST_ASSERT_FATAL(rc == 0); + + adv_fields.mfg_data_len = 30; + rc = ble_gap_adv_set_fields(&adv_fields); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); +} + TEST_SUITE(ble_hs_adv_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_hs_adv_test_case_flags(); ble_hs_adv_test_case_user(); ble_hs_adv_test_case_user_rsp(); + ble_hs_adv_test_case_user_full_payload(); } int diff --git a/net/nimble/host/src/test/ble_hs_conn_test.c b/net/nimble/host/src/test/ble_hs_conn_test.c index 5f86ad1b..c9574460 100644 --- a/net/nimble/host/src/test/ble_hs_conn_test.c +++ b/net/nimble/host/src/test/ble_hs_conn_test.c @@ -22,8 +22,8 @@ #include <string.h> #include "testutil/testutil.h" #include "nimble/hci_common.h" +#include "host/ble_hs_adv.h" #include "host/ble_hs_test.h" -#include "host/host_hci.h" #include "ble_hs_test_util.h" static int @@ -53,7 +53,9 @@ TEST_CASE(ble_hs_conn_test_direct_connect_success) TEST_ASSERT(!ble_hs_conn_test_util_any()); /* Initiate connection. */ - rc = ble_hs_test_util_conn_initiate(0, addr, NULL, NULL, NULL, 0); + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, + addr, 0, NULL, NULL, NULL, 0); TEST_ASSERT(rc == 0); TEST_ASSERT(ble_gap_master_in_progress()); @@ -74,7 +76,7 @@ TEST_CASE(ble_hs_conn_test_direct_connect_success) conn = ble_hs_conn_first(); TEST_ASSERT_FATAL(conn != NULL); TEST_ASSERT(conn->bhc_handle == 2); - TEST_ASSERT(memcmp(conn->bhc_addr, addr, 6) == 0); + TEST_ASSERT(memcmp(conn->bhc_peer_addr, addr, 6) == 0); chan = ble_hs_conn_chan_find(conn, BLE_L2CAP_CID_ATT); TEST_ASSERT_FATAL(chan != NULL); @@ -85,28 +87,10 @@ TEST_CASE(ble_hs_conn_test_direct_connect_success) ble_hs_unlock(); } -TEST_CASE(ble_hs_conn_test_direct_connect_hci_errors) -{ - uint8_t addr[6] = { 1, 2, 3, 4, 5, 6 }; - int rc; - - ble_hs_test_util_init(); - - /* Ensure no current or pending connections. */ - TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_hs_conn_test_util_any()); - - /* Initiate connection; receive no HCI ack. */ - rc = ble_gap_conn_initiate(0, addr, NULL, NULL, NULL); - TEST_ASSERT(rc == BLE_HS_ETIMEOUT_HCI); - - TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_hs_conn_test_util_any()); -} - TEST_CASE(ble_hs_conn_test_direct_connectable_success) { struct hci_le_conn_complete evt; + struct ble_gap_adv_params adv_params; struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; uint8_t addr[6] = { 1, 2, 3, 4, 5, 6 }; @@ -116,18 +100,18 @@ TEST_CASE(ble_hs_conn_test_direct_connectable_success) /* Ensure no current or pending connections. */ TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); TEST_ASSERT(!ble_hs_conn_test_util_any()); /* Initiate advertising. */ - rc = ble_hs_test_util_adv_start(BLE_GAP_DISC_MODE_NON, - BLE_GAP_CONN_MODE_DIR, addr, - BLE_HCI_ADV_PEER_ADDR_PUBLIC, NULL, NULL, - NULL, 0, 0); + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = BLE_GAP_CONN_MODE_DIR; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + addr, &adv_params, NULL, NULL, 0, 0); TEST_ASSERT(rc == 0); TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_slave_in_progress()); + TEST_ASSERT(ble_gap_adv_active()); /* Receive successful connection complete event. */ memset(&evt, 0, sizeof evt); @@ -139,14 +123,14 @@ TEST_CASE(ble_hs_conn_test_direct_connectable_success) rc = ble_gap_rx_conn_complete(&evt); TEST_ASSERT(rc == 0); TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); ble_hs_lock(); conn = ble_hs_conn_first(); TEST_ASSERT_FATAL(conn != NULL); TEST_ASSERT(conn->bhc_handle == 2); - TEST_ASSERT(memcmp(conn->bhc_addr, addr, 6) == 0); + TEST_ASSERT(memcmp(conn->bhc_peer_addr, addr, 6) == 0); chan = ble_hs_conn_chan_find(conn, BLE_L2CAP_CID_ATT); TEST_ASSERT_FATAL(chan != NULL); @@ -157,38 +141,11 @@ TEST_CASE(ble_hs_conn_test_direct_connectable_success) ble_hs_unlock(); } -TEST_CASE(ble_hs_conn_test_direct_connectable_hci_errors) -{ - struct hci_le_conn_complete evt; - uint8_t addr[6] = { 1, 2, 3, 4, 5, 6 }; - int rc; - - ble_hs_test_util_init(); - - /* Ensure no current or pending connections. */ - TEST_ASSERT(!ble_gap_slave_in_progress()); - TEST_ASSERT(!ble_hs_conn_test_util_any()); - - /* Initiate connection. */ - rc = ble_hs_test_util_adv_start(BLE_GAP_DISC_MODE_NON, - BLE_GAP_CONN_MODE_DIR, addr, - BLE_HCI_ADV_PEER_ADDR_PUBLIC, NULL, NULL, - NULL, 0, 0); - TEST_ASSERT(rc == 0); - TEST_ASSERT(ble_gap_slave_in_progress()); - - /* Receive failure connection complete event. */ - evt.status = BLE_ERR_UNSPECIFIED; - rc = ble_gap_rx_conn_complete(&evt); - TEST_ASSERT(rc == 0); - TEST_ASSERT(ble_gap_slave_in_progress()); - TEST_ASSERT(!ble_hs_conn_test_util_any()); -} - TEST_CASE(ble_hs_conn_test_undirect_connectable_success) { struct ble_hs_adv_fields adv_fields; struct hci_le_conn_complete evt; + struct ble_gap_adv_params adv_params; struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; uint8_t addr[6] = { 1, 2, 3, 4, 5, 6 }; @@ -198,7 +155,7 @@ TEST_CASE(ble_hs_conn_test_undirect_connectable_success) /* Ensure no current or pending connections. */ TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); TEST_ASSERT(!ble_hs_conn_test_util_any()); /* Initiate advertising. */ @@ -207,13 +164,14 @@ TEST_CASE(ble_hs_conn_test_undirect_connectable_success) rc = ble_gap_adv_set_fields(&adv_fields); TEST_ASSERT_FATAL(rc == 0); - rc = ble_hs_test_util_adv_start(BLE_GAP_DISC_MODE_NON, - BLE_GAP_CONN_MODE_UND, NULL, 0, NULL, - NULL, NULL, 0, 0); + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + addr, &adv_params, NULL, NULL, 0, 0); TEST_ASSERT(rc == 0); TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_slave_in_progress()); + TEST_ASSERT(ble_gap_adv_active()); /* Receive successful connection complete event. */ memset(&evt, 0, sizeof evt); @@ -225,14 +183,14 @@ TEST_CASE(ble_hs_conn_test_undirect_connectable_success) rc = ble_gap_rx_conn_complete(&evt); TEST_ASSERT(rc == 0); TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_slave_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); ble_hs_lock(); conn = ble_hs_conn_first(); TEST_ASSERT_FATAL(conn != NULL); TEST_ASSERT(conn->bhc_handle == 2); - TEST_ASSERT(memcmp(conn->bhc_addr, addr, 6) == 0); + TEST_ASSERT(memcmp(conn->bhc_peer_addr, addr, 6) == 0); chan = ble_hs_conn_chan_find(conn, BLE_L2CAP_CID_ATT); TEST_ASSERT_FATAL(chan != NULL); @@ -245,10 +203,10 @@ TEST_CASE(ble_hs_conn_test_undirect_connectable_success) TEST_SUITE(conn_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_hs_conn_test_direct_connect_success(); - ble_hs_conn_test_direct_connect_hci_errors(); ble_hs_conn_test_direct_connectable_success(); - ble_hs_conn_test_direct_connectable_hci_errors(); ble_hs_conn_test_undirect_connectable_success(); } diff --git a/net/nimble/host/src/test/ble_host_hci_test.c b/net/nimble/host/src/test/ble_hs_hci_test.c index 52837bd3..21184b8a 100644 --- a/net/nimble/host/src/test/ble_host_hci_test.c +++ b/net/nimble/host/src/test/ble_hs_hci_test.c @@ -21,31 +21,34 @@ #include <errno.h> #include <string.h> #include "nimble/hci_common.h" -#include "host/host_hci.h" +#include "nimble/ble_hci_trans.h" #include "host/ble_hs_test.h" #include "testutil/testutil.h" #include "ble_hs_test_util.h" -TEST_CASE(ble_host_hci_test_event_bad) +TEST_CASE(ble_hs_hci_test_event_bad) { - uint8_t buf[2]; + uint8_t *buf; int rc; /*** Invalid event code. */ + buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + TEST_ASSERT_FATAL(buf != NULL); + buf[0] = 0xff; buf[1] = 0; - rc = host_hci_event_rx(buf); + rc = ble_hs_hci_evt_process(buf); TEST_ASSERT(rc == BLE_HS_ENOTSUP); } -TEST_CASE(ble_host_hci_test_rssi) +TEST_CASE(ble_hs_hci_test_rssi) { uint8_t params[BLE_HCI_READ_RSSI_ACK_PARAM_LEN]; uint16_t opcode; int8_t rssi; int rc; - opcode = host_hci_opcode_join(BLE_HCI_OGF_STATUS_PARAMS, + opcode = ble_hs_hci_util_opcode_join(BLE_HCI_OGF_STATUS_PARAMS, BLE_HCI_OCF_RD_RSSI); /*** Success. */ @@ -57,7 +60,7 @@ TEST_CASE(ble_host_hci_test_rssi) ble_hs_test_util_set_ack_params(opcode, 0, params, sizeof params); - rc = ble_hci_util_read_rssi(1, &rssi); + rc = ble_hs_hci_util_read_rssi(1, &rssi); TEST_ASSERT_FATAL(rc == 0); TEST_ASSERT(rssi == -8); @@ -66,29 +69,31 @@ TEST_CASE(ble_host_hci_test_rssi) ble_hs_test_util_set_ack_params(opcode, 0, params, sizeof params); - rc = ble_hci_util_read_rssi(1, &rssi); + rc = ble_hs_hci_util_read_rssi(1, &rssi); TEST_ASSERT(rc == BLE_HS_ECONTROLLER); /*** Failure: params too short. */ ble_hs_test_util_set_ack_params(opcode, 0, params, sizeof params - 1); - rc = ble_hci_util_read_rssi(1, &rssi); + rc = ble_hs_hci_util_read_rssi(1, &rssi); TEST_ASSERT(rc == BLE_HS_ECONTROLLER); /*** Failure: params too long. */ ble_hs_test_util_set_ack_params(opcode, 0, params, sizeof params + 1); - rc = ble_hci_util_read_rssi(1, &rssi); + rc = ble_hs_hci_util_read_rssi(1, &rssi); TEST_ASSERT(rc == BLE_HS_ECONTROLLER); } -TEST_SUITE(ble_host_hci_suite) +TEST_SUITE(ble_hs_hci_suite) { - ble_host_hci_test_event_bad(); - ble_host_hci_test_rssi(); + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_hs_hci_test_event_bad(); + ble_hs_hci_test_rssi(); } int -ble_host_hci_test_all(void) +ble_hs_hci_test_all(void) { - ble_host_hci_suite(); + ble_hs_hci_suite(); return tu_any_failed; } diff --git a/net/nimble/host/src/test/ble_hs_test.c b/net/nimble/host/src/test/ble_hs_test.c index 88a2c0cd..3bc468ec 100644 --- a/net/nimble/host/src/test/ble_hs_test.c +++ b/net/nimble/host/src/test/ble_hs_test.c @@ -23,24 +23,6 @@ #include "testutil/testutil.h" #include "ble_hs_test_util.h" -/* Our global device address. */ -uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; - -void -ble_hs_test_pkt_txed(struct os_mbuf *om) -{ - /* XXX: For now, just strip the HCI ACL data and L2CAP headers. */ - os_mbuf_adj(om, BLE_HCI_DATA_HDR_SZ + BLE_L2CAP_HDR_SZ); - ble_hs_test_util_prev_tx_enqueue(om); -} - -void -ble_hs_test_hci_txed(uint8_t *cmdbuf) -{ - ble_hs_test_util_enqueue_hci_tx(cmdbuf); - os_memblock_put(&g_hci_cmd_pool, cmdbuf); -} - #ifdef MYNEWT_SELFTEST int @@ -62,8 +44,9 @@ main(int argc, char **argv) ble_gatt_read_test_all(); ble_gatt_write_test_all(); ble_gatts_notify_test_all(); + ble_gatts_read_test_suite(); ble_gatts_reg_test_all(); - ble_host_hci_test_all(); + ble_hs_hci_test_all(); ble_hs_adv_test_all(); ble_hs_conn_test_all(); ble_l2cap_test_all(); diff --git a/net/nimble/host/src/test/ble_hs_test_util.c b/net/nimble/host/src/test/ble_hs_test_util.c index 90448da9..e1acb81c 100644 --- a/net/nimble/host/src/test/ble_hs_test_util.c +++ b/net/nimble/host/src/test/ble_hs_test_util.c @@ -23,10 +23,17 @@ #include "testutil/testutil.h" #include "nimble/ble.h" #include "nimble/hci_common.h" -#include "nimble/hci_transport.h" -#include "host/host_hci.h" +#include "nimble/ble_hci_trans.h" +#include "host/ble_hs_adv.h" +#include "host/ble_hs_id.h" +#include "transport/ram/ble_hci_ram.h" #include "ble_hs_test_util.h" +/* Our global device address. */ +uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; + +#define BLE_HS_TEST_UTIL_PUB_ADDR_VAL { 0x0a, 0x54, 0xab, 0x49, 0x7f, 0x06 } + /** Use lots of small mbufs to ensure correct mbuf usage. */ #define BLE_HS_TEST_UTIL_NUM_MBUFS (100) #define BLE_HS_TEST_UTIL_BUF_SIZE OS_ALIGN(100, 4) @@ -36,7 +43,7 @@ OS_MEMPOOL_SIZE(BLE_HS_TEST_UTIL_NUM_MBUFS, BLE_HS_TEST_UTIL_MEMBLOCK_SIZE) #define BLE_HS_TEST_UTIL_LE_OPCODE(ocf) \ - host_hci_opcode_join(BLE_HCI_OGF_LE, (ocf)) + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, (ocf)) struct os_eventq ble_hs_test_util_evq; @@ -54,6 +61,17 @@ int ble_hs_test_util_num_prev_hci_txes; uint8_t ble_hs_test_util_cur_hci_tx[260]; +const struct ble_gap_adv_params ble_hs_test_util_adv_params = { + .conn_mode = BLE_GAP_CONN_MODE_UND, + .disc_mode = BLE_GAP_DISC_MODE_GEN, + + .itvl_min = 0, + .itvl_max = 0, + .channel_map = 0, + .filter_policy = 0, + .high_duty_cycle = 0, +}; + void ble_hs_test_util_prev_tx_enqueue(struct os_mbuf *om) { @@ -69,20 +87,65 @@ ble_hs_test_util_prev_tx_enqueue(struct os_mbuf *om) } } +static struct os_mbuf * +ble_hs_test_util_prev_tx_dequeue_once(struct hci_data_hdr *out_hci_hdr) +{ + struct os_mbuf_pkthdr *omp; + struct os_mbuf *om; + int rc; + + omp = STAILQ_FIRST(&ble_hs_test_util_prev_tx_queue); + if (omp == NULL) { + return NULL; + } + STAILQ_REMOVE_HEAD(&ble_hs_test_util_prev_tx_queue, omp_next); + + om = OS_MBUF_PKTHDR_TO_MBUF(omp); + + rc = ble_hs_hci_util_data_hdr_strip(om, out_hci_hdr); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(out_hci_hdr->hdh_len == OS_MBUF_PKTLEN(om)); + + return om; +} + struct os_mbuf * ble_hs_test_util_prev_tx_dequeue(void) { - struct os_mbuf_pkthdr *omp; + struct ble_l2cap_hdr l2cap_hdr; + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + uint8_t pb; + int rc; os_mbuf_free_chain(ble_hs_test_util_prev_tx_cur); - omp = STAILQ_FIRST(&ble_hs_test_util_prev_tx_queue); - if (omp != NULL) { - STAILQ_REMOVE_HEAD(&ble_hs_test_util_prev_tx_queue, omp_next); - ble_hs_test_util_prev_tx_cur = OS_MBUF_PKTHDR_TO_MBUF(omp); + om = ble_hs_test_util_prev_tx_dequeue_once(&hci_hdr); + if (om != NULL) { + pb = BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc); + TEST_ASSERT_FATAL(pb == BLE_HCI_PB_FIRST_NON_FLUSH); + + rc = ble_l2cap_parse_hdr(om, 0, &l2cap_hdr); + TEST_ASSERT_FATAL(rc == 0); + + os_mbuf_adj(om, BLE_L2CAP_HDR_SZ); + + ble_hs_test_util_prev_tx_cur = om; + while (OS_MBUF_PKTLEN(ble_hs_test_util_prev_tx_cur) < + l2cap_hdr.blh_len) { + + om = ble_hs_test_util_prev_tx_dequeue_once(&hci_hdr); + TEST_ASSERT_FATAL(om != NULL); + + pb = BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc); + TEST_ASSERT_FATAL(pb == BLE_HCI_PB_MIDDLE); + + os_mbuf_concat(ble_hs_test_util_prev_tx_cur, om); + } } else { ble_hs_test_util_prev_tx_cur = NULL; } + return ble_hs_test_util_prev_tx_cur; } @@ -188,13 +251,14 @@ ble_hs_test_util_rx_hci_evt(uint8_t *evt) TEST_ASSERT_FATAL(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN); if (os_started()) { - evbuf = os_memblock_get(&g_hci_cmd_pool); + evbuf = ble_hci_trans_buf_alloc( + BLE_HCI_TRANS_BUF_EVT_LO); TEST_ASSERT_FATAL(evbuf != NULL); memcpy(evbuf, evt, totlen); - rc = ble_hci_transport_ctlr_event_send(evbuf); + rc = ble_hci_trans_ll_evt_tx(evbuf); } else { - rc = host_hci_event_rx(evt); + rc = ble_hs_hci_evt_process(evt); } TEST_ASSERT_FATAL(rc == 0); @@ -284,7 +348,7 @@ ble_hs_test_util_set_ack_params(uint16_t opcode, uint8_t status, void *params, } ble_hs_test_util_num_phony_acks = 1; - ble_hci_set_phony_ack_cb(ble_hs_test_util_phony_ack_cb); + ble_hs_hci_set_phony_ack_cb(ble_hs_test_util_phony_ack_cb); } void @@ -303,22 +367,22 @@ ble_hs_test_util_set_ack_seq(struct ble_hs_test_util_phony_ack *acks) } ble_hs_test_util_num_phony_acks = i; - ble_hci_set_phony_ack_cb(ble_hs_test_util_phony_ack_cb); + ble_hs_hci_set_phony_ack_cb(ble_hs_test_util_phony_ack_cb); } void -ble_hs_test_util_create_rpa_conn(uint16_t handle, uint8_t *our_rpa, - uint8_t peer_addr_type, uint8_t *peer_id_addr, - uint8_t *peer_rpa, +ble_hs_test_util_create_rpa_conn(uint16_t handle, uint8_t own_addr_type, + const uint8_t *our_rpa, + uint8_t peer_addr_type, + const uint8_t *peer_id_addr, + const uint8_t *peer_rpa, ble_gap_event_fn *cb, void *cb_arg) { struct hci_le_conn_complete evt; int rc; - ble_hs_test_util_set_ack( - BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_CREATE_CONN), 0); - rc = ble_gap_conn_initiate(peer_addr_type, peer_id_addr, NULL, cb, cb_arg); - TEST_ASSERT(rc == 0); + ble_hs_test_util_connect(own_addr_type, peer_addr_type, + peer_id_addr, 0, NULL, cb, cb_arg, 0); memset(&evt, 0, sizeof evt); evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; @@ -340,28 +404,116 @@ ble_hs_test_util_create_rpa_conn(uint16_t handle, uint8_t *our_rpa, } void -ble_hs_test_util_create_conn(uint16_t handle, uint8_t *peer_id_addr, +ble_hs_test_util_create_conn(uint16_t handle, const uint8_t *peer_id_addr, ble_gap_event_fn *cb, void *cb_arg) { static uint8_t null_addr[6]; - ble_hs_test_util_create_rpa_conn(handle, null_addr, BLE_ADDR_TYPE_PUBLIC, - peer_id_addr, null_addr, cb, cb_arg); + ble_hs_test_util_create_rpa_conn(handle, BLE_ADDR_TYPE_PUBLIC, null_addr, + BLE_ADDR_TYPE_PUBLIC, peer_id_addr, + null_addr, cb, cb_arg); +} + +static void +ble_hs_test_util_conn_params_dflt(struct ble_gap_conn_params *conn_params) +{ + conn_params->scan_itvl = 0x0010; + conn_params->scan_window = 0x0010; + conn_params->itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN; + conn_params->itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX; + conn_params->latency = BLE_GAP_INITIAL_CONN_LATENCY; + conn_params->supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; + conn_params->min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; + conn_params->max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; +} + +static void +ble_hs_test_util_hcc_from_conn_params( + struct hci_create_conn *hcc, uint8_t own_addr_type, uint8_t peer_addr_type, + const uint8_t *peer_addr, const struct ble_gap_conn_params *conn_params) +{ + hcc->scan_itvl = conn_params->scan_itvl; + hcc->scan_window = conn_params->scan_window; + + if (peer_addr_type == BLE_GAP_ADDR_TYPE_WL) { + hcc->filter_policy = BLE_HCI_CONN_FILT_USE_WL; + hcc->peer_addr_type = 0; + memset(hcc->peer_addr, 0, 6); + } else { + hcc->filter_policy = BLE_HCI_CONN_FILT_NO_WL; + hcc->peer_addr_type = peer_addr_type; + memcpy(hcc->peer_addr, peer_addr, 6); + } + hcc->own_addr_type = own_addr_type; + hcc->conn_itvl_min = conn_params->itvl_min; + hcc->conn_itvl_max = conn_params->itvl_max; + hcc->conn_latency = conn_params->latency; + hcc->supervision_timeout = conn_params->supervision_timeout; + hcc->min_ce_len = conn_params->min_ce_len; + hcc->max_ce_len = conn_params->max_ce_len; +} + +void +ble_hs_test_util_verify_tx_create_conn(const struct hci_create_conn *exp) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CREATE_CONN_LEN); + + TEST_ASSERT(le16toh(param + 0) == exp->scan_itvl); + TEST_ASSERT(le16toh(param + 2) == exp->scan_window); + TEST_ASSERT(param[4] == exp->filter_policy); + TEST_ASSERT(param[5] == exp->peer_addr_type); + TEST_ASSERT(memcmp(param + 6, exp->peer_addr, 6) == 0); + TEST_ASSERT(param[12] == exp->own_addr_type); + TEST_ASSERT(le16toh(param + 13) == exp->conn_itvl_min); + TEST_ASSERT(le16toh(param + 15) == exp->conn_itvl_max); + TEST_ASSERT(le16toh(param + 17) == exp->conn_latency); + TEST_ASSERT(le16toh(param + 19) == exp->supervision_timeout); + TEST_ASSERT(le16toh(param + 21) == exp->min_ce_len); + TEST_ASSERT(le16toh(param + 23) == exp->max_ce_len); } int -ble_hs_test_util_conn_initiate(int addr_type, uint8_t *addr, - struct ble_gap_crt_params *params, - ble_gap_event_fn *cb, void *cb_arg, - uint8_t ack_status) +ble_hs_test_util_connect(uint8_t own_addr_type, uint8_t peer_addr_type, + const uint8_t *peer_addr, int32_t duration_ms, + const struct ble_gap_conn_params *params, + ble_gap_event_fn *cb, void *cb_arg, + uint8_t ack_status) { + struct ble_gap_conn_params dflt_params; + struct hci_create_conn hcc; int rc; + /* This function ensures the most recently sent HCI command is the expected + * create connection command. If the current test case has unverified HCI + * commands, assume we are not interested in them and clear the queue. + */ + ble_hs_test_util_prev_hci_tx_clear(); + ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN), + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN), ack_status); - rc = ble_gap_conn_initiate(addr_type, addr, params, cb, cb_arg); + rc = ble_gap_connect(own_addr_type, peer_addr_type, peer_addr, duration_ms, + params, cb, cb_arg); + + TEST_ASSERT(rc == BLE_HS_HCI_ERR(ack_status)); + + if (params == NULL) { + ble_hs_test_util_conn_params_dflt(&dflt_params); + params = &dflt_params; + } + + ble_hs_test_util_hcc_from_conn_params(&hcc, own_addr_type, + peer_addr_type, peer_addr, params); + ble_hs_test_util_verify_tx_create_conn(&hcc); + return rc; } @@ -371,25 +523,42 @@ ble_hs_test_util_conn_cancel(uint8_t ack_status) int rc; ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_CREATE_CONN_CANCEL), + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN_CANCEL), ack_status); - rc = ble_gap_cancel(); + rc = ble_gap_conn_cancel(); return rc; } +void +ble_hs_test_util_conn_cancel_full(void) +{ + struct hci_le_conn_complete evt; + int rc; + + ble_hs_test_util_conn_cancel(0); + + memset(&evt, 0, sizeof evt); + evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; + evt.status = BLE_ERR_UNK_CONN_ID; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; + + rc = ble_gap_rx_conn_complete(&evt); + TEST_ASSERT_FATAL(rc == 0); +} + int ble_hs_test_util_conn_terminate(uint16_t conn_handle, uint8_t hci_status) { int rc; ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LINK_CTRL, - BLE_HCI_OCF_DISCONNECT_CMD), + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LINK_CTRL, + BLE_HCI_OCF_DISCONNECT_CMD), hci_status); - rc = ble_gap_terminate(conn_handle); + rc = ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); return rc; } @@ -410,9 +579,19 @@ ble_hs_test_util_conn_disconnect(uint16_t conn_handle) } int -ble_hs_test_util_disc(uint32_t duration_ms, uint8_t discovery_mode, - uint8_t scan_type, uint8_t filter_policy, - ble_gap_disc_fn *cb, void *cb_arg, int fail_idx, +ble_hs_test_util_exp_hci_status(int cmd_idx, int fail_idx, uint8_t fail_status) +{ + if (cmd_idx == fail_idx) { + return BLE_HS_HCI_ERR(fail_status); + } else { + return 0; + } +} + +int +ble_hs_test_util_disc(uint8_t own_addr_type, int32_t duration_ms, + const struct ble_gap_disc_params *disc_params, + ble_gap_event_fn *cb, void *cb_arg, int fail_idx, uint8_t fail_status) { int rc; @@ -420,27 +599,77 @@ ble_hs_test_util_disc(uint32_t duration_ms, uint8_t discovery_mode, ble_hs_test_util_set_ack_seq(((struct ble_hs_test_util_phony_ack[]) { { BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_PARAMS), - fail_idx == 0 ? fail_status : 0, + ble_hs_test_util_exp_hci_status(0, fail_idx, fail_status), }, { BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_ENABLE), - fail_idx == 1 ? fail_status : 0, + ble_hs_test_util_exp_hci_status(1, fail_idx, fail_status), }, { 0 } })); - rc = ble_gap_disc(duration_ms, discovery_mode, scan_type, filter_policy, - BLE_ADDR_TYPE_PUBLIC, + rc = ble_gap_disc(own_addr_type, duration_ms, disc_params, cb, cb_arg); return rc; } int -ble_hs_test_util_adv_start(uint8_t discoverable_mode, - uint8_t connectable_mode, - uint8_t *peer_addr, uint8_t peer_addr_type, - struct ble_gap_adv_params *adv_params, +ble_hs_test_util_disc_cancel(uint8_t ack_status) +{ + int rc; + + ble_hs_test_util_set_ack( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + ack_status); + + rc = ble_gap_disc_cancel(); + return rc; +} + +static void +ble_hs_test_util_verify_tx_rd_pwr(void) +{ + uint8_t param_len; + + ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR, + ¶m_len); + TEST_ASSERT(param_len == 0); +} + +int +ble_hs_test_util_adv_set_fields(struct ble_hs_adv_fields *adv_fields, + uint8_t hci_status) +{ + int auto_pwr; + int rc; + + auto_pwr = adv_fields->tx_pwr_lvl_is_present && + adv_fields->tx_pwr_lvl == BLE_HS_ADV_TX_PWR_LVL_AUTO; + + if (auto_pwr) { + ble_hs_test_util_set_ack_params( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR), + hci_status, + ((uint8_t[1]){0}), 1); + } + + rc = ble_gap_adv_set_fields(adv_fields); + if (rc == 0 && auto_pwr) { + /* Verify tx of set advertising params command. */ + ble_hs_test_util_verify_tx_rd_pwr(); + } + + return rc; +} + +int +ble_hs_test_util_adv_start(uint8_t own_addr_type, + uint8_t peer_addr_type, const uint8_t *peer_addr, + const struct ble_gap_adv_params *adv_params, ble_gap_event_fn *cb, void *cb_arg, int fail_idx, uint8_t fail_status) { @@ -456,31 +685,23 @@ ble_hs_test_util_adv_start(uint8_t discoverable_mode, }; i++; - if (connectable_mode != BLE_GAP_CONN_MODE_DIR) { - acks[i] = (struct ble_hs_test_util_phony_ack) { - BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR), - fail_idx == i ? fail_status : 0, - { 0 }, - 1, - }; - i++; - + if (adv_params->conn_mode != BLE_GAP_CONN_MODE_DIR) { acks[i] = (struct ble_hs_test_util_phony_ack) { BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_DATA), - fail_idx == i ? fail_status : 0, + ble_hs_test_util_exp_hci_status(i, fail_idx, fail_status), }; i++; acks[i] = (struct ble_hs_test_util_phony_ack) { BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA), - fail_idx == i ? fail_status : 0, + ble_hs_test_util_exp_hci_status(i, fail_idx, fail_status), }; i++; } acks[i] = (struct ble_hs_test_util_phony_ack) { BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_ENABLE), - fail_idx == i ? fail_status : 0, + ble_hs_test_util_exp_hci_status(i, fail_idx, fail_status), }; i++; @@ -488,9 +709,8 @@ ble_hs_test_util_adv_start(uint8_t discoverable_mode, ble_hs_test_util_set_ack_seq(acks); - rc = ble_gap_adv_start(discoverable_mode, connectable_mode, - peer_addr, peer_addr_type, - adv_params, cb, cb_arg); + rc = ble_gap_adv_start(own_addr_type, peer_addr_type, peer_addr, + BLE_HS_FOREVER, adv_params, cb, cb_arg); return rc; } @@ -523,14 +743,14 @@ ble_hs_test_util_wl_set(struct ble_gap_white_entry *white_list, cmd_idx = 0; acks[cmd_idx] = (struct ble_hs_test_util_phony_ack) { BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_CLEAR_WHITE_LIST), - fail_idx == cmd_idx ? fail_status : 0, + ble_hs_test_util_exp_hci_status(cmd_idx, fail_idx, fail_status), }; cmd_idx++; for (i = 0; i < white_list_count; i++) { acks[cmd_idx] = (struct ble_hs_test_util_phony_ack) { BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_ADD_WHITE_LIST), - fail_idx == cmd_idx ? fail_status : 0, + ble_hs_test_util_exp_hci_status(cmd_idx, fail_idx, fail_status), }; cmd_idx++; @@ -557,6 +777,38 @@ ble_hs_test_util_conn_update(uint16_t conn_handle, } int +ble_hs_test_util_set_our_irk(const uint8_t *irk, int fail_idx, + uint8_t hci_status) +{ + int rc; + + ble_hs_test_util_set_ack_seq(((struct ble_hs_test_util_phony_ack[]) { + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADDR_RES_EN), + ble_hs_test_util_exp_hci_status(0, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_CLR_RESOLV_LIST), + ble_hs_test_util_exp_hci_status(1, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADDR_RES_EN), + ble_hs_test_util_exp_hci_status(2, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_ADD_RESOLV_LIST), + ble_hs_test_util_exp_hci_status(3, fail_idx, hci_status), + }, + { + 0 + } + })); + + rc = ble_hs_pvcy_set_our_irk(irk); + return rc; +} + +int ble_hs_test_util_security_initiate(uint16_t conn_handle, uint8_t hci_status) { int rc; @@ -597,6 +849,8 @@ ble_hs_test_util_l2cap_rx(uint16_t conn_handle, conn = ble_hs_conn_find(conn_handle); if (conn != NULL) { rc = ble_l2cap_rx(conn, hci_hdr, om, &rx_cb, &rx_buf); + } else { + os_mbuf_free_chain(om); } ble_hs_unlock(); @@ -624,15 +878,15 @@ ble_hs_test_util_l2cap_rx_payload_flat(uint16_t conn_handle, uint16_t cid, struct os_mbuf *om; int rc; - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); rc = os_mbuf_append(om, data, len); TEST_ASSERT_FATAL(rc == 0); hci_hdr.hdh_handle_pb_bc = - host_hci_handle_pb_bc_join(conn_handle, - BLE_HCI_PB_FIRST_FLUSH, 0); + ble_hs_hci_util_handle_pb_bc_join(conn_handle, + BLE_HCI_PB_FIRST_FLUSH, 0); hci_hdr.hdh_len = OS_MBUF_PKTHDR(om)->omp_len; rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, cid, &hci_hdr, om); @@ -640,6 +894,26 @@ ble_hs_test_util_l2cap_rx_payload_flat(uint16_t conn_handle, uint16_t cid, } void +ble_hs_test_util_rx_att_mtu_cmd(uint16_t conn_handle, int is_req, uint16_t mtu) +{ + struct ble_att_mtu_cmd cmd; + uint8_t buf[BLE_ATT_MTU_CMD_SZ]; + int rc; + + cmd.bamc_mtu = mtu; + + if (is_req) { + ble_att_mtu_req_write(buf, sizeof buf, &cmd); + } else { + ble_att_mtu_rsp_write(buf, sizeof buf, &cmd); + } + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); +} + +void ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint8_t req_op, uint8_t error_code, uint16_t err_handle) { @@ -666,48 +940,55 @@ ble_hs_test_util_set_startup_acks(void) */ ble_hs_test_util_set_ack_seq(((struct ble_hs_test_util_phony_ack[]) { { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_CTLR_BASEBAND, - BLE_HCI_OCF_CB_RESET), + .opcode = ble_hs_hci_util_opcode_join(BLE_HCI_OGF_CTLR_BASEBAND, + BLE_HCI_OCF_CB_RESET), }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_CTLR_BASEBAND, - BLE_HCI_OCF_CB_SET_EVENT_MASK), + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_SET_EVENT_MASK), }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_CTLR_BASEBAND, - BLE_HCI_OCF_CB_SET_EVENT_MASK2), + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_SET_EVENT_MASK2), }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_SET_EVENT_MASK), + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_EVENT_MASK), }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_RD_BUF_SIZE), - .evt_params = { 0xff, 0xff, 1 }, + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_BUF_SIZE), + /* Use a very low buffer size (16) to test fragmentation. */ + .evt_params = { 0x10, 0x00, 0x20 }, .evt_params_len = 3, }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT), + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT), .evt_params = { 0 }, .evt_params_len = 8, }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_SET_ADDR_RES_EN), + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_BD_ADDR), + .evt_params = BLE_HS_TEST_UTIL_PUB_ADDR_VAL, + .evt_params_len = 6, + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN), }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_CLR_RESOLV_LIST), + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLR_RESOLV_LIST), }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_SET_ADDR_RES_EN), + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN), }, { - .opcode = host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_ADD_RESOLV_LIST), + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST), }, { 0 } })); @@ -790,9 +1071,26 @@ ble_hs_test_util_tx_all(void) } void -ble_hs_test_util_set_public_addr(uint8_t *addr) +ble_hs_test_util_verify_tx_prep_write(uint16_t attr_handle, uint16_t offset, + const void *data, int data_len) { - ble_hs_pvcy_set_our_id_addr(addr); + struct ble_att_prep_write_cmd req; + struct os_mbuf *om; + + ble_hs_test_util_tx_all(); + om = ble_hs_test_util_prev_tx_dequeue(); + TEST_ASSERT_FATAL(om != NULL); + TEST_ASSERT(OS_MBUF_PKTLEN(om) == + BLE_ATT_PREP_WRITE_CMD_BASE_SZ + data_len); + + om = os_mbuf_pullup(om, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + TEST_ASSERT_FATAL(om != NULL); + + ble_att_prep_write_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.bapc_handle == attr_handle); + TEST_ASSERT(req.bapc_offset == offset); + TEST_ASSERT(os_mbuf_cmpf(om, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, + data, data_len) == 0); } void @@ -811,8 +1109,354 @@ ble_hs_test_util_verify_tx_exec_write(uint8_t expected_flags) } void +ble_hs_test_util_verify_tx_read_rsp_gen(uint8_t att_op, + uint8_t *attr_data, int attr_len) +{ + struct os_mbuf *om; + uint8_t u8; + int rc; + int i; + + ble_hs_test_util_tx_all(); + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, 1, &u8); + TEST_ASSERT(rc == 0); + TEST_ASSERT(u8 == att_op); + + for (i = 0; i < attr_len; i++) { + rc = os_mbuf_copydata(om, i + 1, 1, &u8); + TEST_ASSERT(rc == 0); + TEST_ASSERT(u8 == attr_data[i]); + } + + rc = os_mbuf_copydata(om, i + 1, 1, &u8); + TEST_ASSERT(rc != 0); +} + +void +ble_hs_test_util_verify_tx_read_rsp(uint8_t *attr_data, int attr_len) +{ + ble_hs_test_util_verify_tx_read_rsp_gen(BLE_ATT_OP_READ_RSP, + attr_data, attr_len); +} + +void +ble_hs_test_util_verify_tx_read_blob_rsp(uint8_t *attr_data, int attr_len) +{ + ble_hs_test_util_verify_tx_read_rsp_gen(BLE_ATT_OP_READ_BLOB_RSP, + attr_data, attr_len); +} + +void +ble_hs_test_util_verify_tx_write_rsp(void) +{ + struct os_mbuf *om; + uint8_t u8; + int rc; + + ble_hs_test_util_tx_all(); + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, 1, &u8); + TEST_ASSERT(rc == 0); + TEST_ASSERT(u8 == BLE_ATT_OP_WRITE_RSP); +} + +void +ble_hs_test_util_verify_tx_mtu_cmd(int is_req, uint16_t mtu) +{ + struct ble_att_mtu_cmd cmd; + struct os_mbuf *om; + + ble_hs_test_util_tx_all(); + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + + if (is_req) { + ble_att_mtu_req_parse(om->om_data, om->om_len, &cmd); + } else { + ble_att_mtu_rsp_parse(om->om_data, om->om_len, &cmd); + } + + TEST_ASSERT(cmd.bamc_mtu == mtu); +} + +void +ble_hs_test_util_verify_tx_err_rsp(uint8_t req_op, uint16_t handle, + uint8_t error_code) +{ + struct ble_att_error_rsp rsp; + struct os_mbuf *om; + uint8_t buf[BLE_ATT_ERROR_RSP_SZ]; + int rc; + + ble_hs_test_util_tx_all(); + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, sizeof buf, buf); + TEST_ASSERT(rc == 0); + + ble_att_error_rsp_parse(buf, sizeof buf, &rsp); + + TEST_ASSERT(rsp.baep_req_op == req_op); + TEST_ASSERT(rsp.baep_handle == handle); + TEST_ASSERT(rsp.baep_error_code == error_code); +} + +void +ble_hs_test_util_set_static_rnd_addr(void) +{ + uint8_t addr[6] = { 1, 2, 3, 4, 5, 0xc1 }; + int rc; + + ble_hs_test_util_set_ack( + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_RAND_ADDR), 0); + + rc = ble_hs_id_set_rnd(addr); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_get_first_hci_tx(); +} + +struct os_mbuf * +ble_hs_test_util_om_from_flat(const void *buf, uint16_t len) +{ + struct os_mbuf *om; + + om = ble_hs_mbuf_from_flat(buf, len); + TEST_ASSERT_FATAL(om != NULL); + + return om; +} + +int +ble_hs_test_util_flat_attr_cmp(const struct ble_hs_test_util_flat_attr *a, + const struct ble_hs_test_util_flat_attr *b) +{ + if (a->handle != b->handle) { + return -1; + } + if (a->offset != b->offset) { + return -1; + } + if (a->value_len != b->value_len) { + return -1; + } + return memcmp(a->value, b->value, a->value_len); +} + +void +ble_hs_test_util_attr_to_flat(struct ble_hs_test_util_flat_attr *flat, + const struct ble_gatt_attr *attr) +{ + int rc; + + flat->handle = attr->handle; + flat->offset = attr->offset; + rc = ble_hs_mbuf_to_flat(attr->om, flat->value, sizeof flat->value, + &flat->value_len); + TEST_ASSERT_FATAL(rc == 0); +} + +void +ble_hs_test_util_attr_from_flat(struct ble_gatt_attr *attr, + const struct ble_hs_test_util_flat_attr *flat) +{ + attr->handle = flat->handle; + attr->offset = flat->offset; + attr->om = ble_hs_test_util_om_from_flat(flat->value, flat->value_len); +} + +int +ble_hs_test_util_read_local_flat(uint16_t attr_handle, uint16_t max_len, + void *buf, uint16_t *out_len) +{ + struct os_mbuf *om; + int rc; + + rc = ble_att_svr_read_local(attr_handle, &om); + if (rc != 0) { + return rc; + } + + TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(om) <= max_len); + + rc = os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), buf); + TEST_ASSERT_FATAL(rc == 0); + + *out_len = OS_MBUF_PKTLEN(om); + + os_mbuf_free_chain(om); + return 0; +} + +int +ble_hs_test_util_write_local_flat(uint16_t attr_handle, + const void *buf, uint16_t buf_len) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_test_util_om_from_flat(buf, buf_len); + rc = ble_att_svr_write_local(attr_handle, om); + return rc; +} + +int +ble_hs_test_util_gatt_write_flat(uint16_t conn_handle, uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_test_util_om_from_flat(data, data_len); + rc = ble_gattc_write(conn_handle, attr_handle, om, cb, cb_arg); + + return rc; +} + +int +ble_hs_test_util_gatt_write_no_rsp_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, uint16_t data_len) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_test_util_om_from_flat(data, data_len); + rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, om); + + return rc; +} + +int +ble_hs_test_util_gatt_write_long_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_test_util_om_from_flat(data, data_len); + rc = ble_gattc_write_long(conn_handle, attr_handle, om, cb, cb_arg); + + return rc; +} + +static int +ble_hs_test_util_mbuf_chain_len(const struct os_mbuf *om) +{ + int count; + + count = 0; + while (om != NULL) { + count++; + om = SLIST_NEXT(om, om_next); + } + + return count; +} + +int +ble_hs_test_util_mbuf_count(const struct ble_hs_test_util_mbuf_params *params) +{ + const struct ble_att_prep_entry *prep; + const struct os_mbuf_pkthdr *omp; + const struct ble_l2cap_chan *chan; + const struct ble_hs_conn *conn; + const struct os_mbuf *om; + int count; + int i; + + ble_hs_process_tx_data_queue(); + ble_hs_process_rx_data_queue(); + + count = ble_hs_test_util_mbuf_mpool.mp_num_free; + + if (params->prev_tx) { + count += ble_hs_test_util_mbuf_chain_len(ble_hs_test_util_prev_tx_cur); + STAILQ_FOREACH(omp, &ble_hs_test_util_prev_tx_queue, omp_next) { + om = OS_MBUF_PKTHDR_TO_MBUF(omp); + count += ble_hs_test_util_mbuf_chain_len(om); + } + } + + ble_hs_lock(); + for (i = 0; ; i++) { + conn = ble_hs_conn_find_by_idx(i); + if (conn == NULL) { + break; + } + + if (params->rx_queue) { + SLIST_FOREACH(chan, &conn->bhc_channels, blc_next) { + count += ble_hs_test_util_mbuf_chain_len(chan->blc_rx_buf); + } + } + + if (params->prep_list) { + SLIST_FOREACH(prep, &conn->bhc_att_svr.basc_prep_list, bape_next) { + count += ble_hs_test_util_mbuf_chain_len(prep->bape_value); + } + } + } + ble_hs_unlock(); + + return count; +} + +void +ble_hs_test_util_assert_mbufs_freed( + const struct ble_hs_test_util_mbuf_params *params) +{ + static const struct ble_hs_test_util_mbuf_params dflt = { + .prev_tx = 1, + .rx_queue = 1, + .prep_list = 1, + }; + + int count; + + if (params == NULL) { + params = &dflt; + } + + count = ble_hs_test_util_mbuf_count(params); + TEST_ASSERT(count == ble_hs_test_util_mbuf_mpool.mp_num_blocks); +} + +void +ble_hs_test_util_post_test(void *arg) +{ + ble_hs_test_util_assert_mbufs_freed(arg); +} + +static int +ble_hs_test_util_pkt_txed(struct os_mbuf *om, void *arg) +{ + ble_hs_test_util_prev_tx_enqueue(om); + return 0; +} + +static int +ble_hs_test_util_hci_txed(uint8_t *cmdbuf, void *arg) +{ + ble_hs_test_util_enqueue_hci_tx(cmdbuf); + ble_hci_trans_buf_free(cmdbuf); + return 0; +} + +void ble_hs_test_util_init(void) { + struct ble_hci_ram_cfg hci_cfg; struct ble_hs_cfg cfg; int rc; @@ -827,6 +1471,12 @@ ble_hs_test_util_init(void) cfg = ble_hs_cfg_dflt; cfg.max_connections = 8; + cfg.max_l2cap_chans = 3 * cfg.max_connections; + cfg.max_services = 16; + cfg.max_client_configs = 32; + cfg.max_attrs = 64; + cfg.max_gattc_procs = 16; + rc = ble_hs_init(&ble_hs_test_util_evq, &cfg); TEST_ASSERT_FATAL(rc == 0); @@ -846,9 +1496,19 @@ ble_hs_test_util_init(void) rc = os_msys_register(&ble_hs_test_util_mbuf_pool); TEST_ASSERT_FATAL(rc == 0); - ble_hci_set_phony_ack_cb(NULL); + ble_hs_hci_set_phony_ack_cb(NULL); - ble_hs_test_util_prev_hci_tx_clear(); + ble_hci_trans_cfg_ll(ble_hs_test_util_hci_txed, NULL, + ble_hs_test_util_pkt_txed, NULL); - ble_hs_test_util_set_public_addr(g_dev_addr); + hci_cfg = ble_hci_ram_cfg_dflt; + rc = ble_hci_ram_init(&hci_cfg); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_set_startup_acks(); + + rc = ble_hs_start(); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_prev_hci_tx_clear(); } diff --git a/net/nimble/host/src/test/ble_hs_test_util.h b/net/nimble/host/src/test/ble_hs_test_util.h index 92032526..7780d4ee 100644 --- a/net/nimble/host/src/test/ble_hs_test_util.h +++ b/net/nimble/host/src/test/ble_hs_test_util.h @@ -6,7 +6,7 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, @@ -27,14 +27,29 @@ struct ble_hs_conn; struct ble_l2cap_chan; struct hci_disconn_complete; +struct hci_create_conn; -struct os_eventq ble_hs_test_util_evq; +extern struct os_eventq ble_hs_test_util_evq; +extern const struct ble_gap_adv_params ble_hs_test_util_adv_params; struct ble_hs_test_util_num_completed_pkts_entry { uint16_t handle_id; /* 0 for terminating entry in array. */ uint16_t num_pkts; }; +struct ble_hs_test_util_flat_attr { + uint16_t handle; + uint16_t offset; + uint8_t value[BLE_ATT_ATTR_MAX_LEN]; + uint16_t value_len; +}; + +struct ble_hs_test_util_mbuf_params { + unsigned prev_tx:1; + unsigned rx_queue:1; + unsigned prep_list:1; +}; + void ble_hs_test_util_prev_tx_enqueue(struct os_mbuf *om); struct os_mbuf *ble_hs_test_util_prev_tx_dequeue(void); struct os_mbuf *ble_hs_test_util_prev_tx_dequeue_pullup(void); @@ -54,28 +69,40 @@ void ble_hs_test_util_build_cmd_complete(uint8_t *dst, int len, void ble_hs_test_util_build_cmd_status(uint8_t *dst, int len, uint8_t status, uint8_t num_pkts, uint16_t opcode); -void ble_hs_test_util_create_rpa_conn(uint16_t handle, uint8_t *our_rpa, +void ble_hs_test_util_create_rpa_conn(uint16_t handle, uint8_t own_addr_type, + const uint8_t *our_rpa, uint8_t peer_addr_type, - uint8_t *peer_id_addr, - uint8_t *peer_rpa, + const uint8_t *peer_id_addr, + const uint8_t *peer_rpa, ble_gap_event_fn *cb, void *cb_arg); -void ble_hs_test_util_create_conn(uint16_t handle, uint8_t *addr, +void ble_hs_test_util_create_conn(uint16_t handle, const uint8_t *addr, ble_gap_event_fn *cb, void *cb_arg); -int ble_hs_test_util_conn_initiate(int addr_type, uint8_t *addr, - struct ble_gap_crt_params *params, - ble_gap_event_fn *cb, void *cb_arg, +int ble_hs_test_util_connect(uint8_t own_addr_type, + uint8_t peer_addr_type, + const uint8_t *peer_addr, + int32_t duration_ms, + const struct ble_gap_conn_params *params, + ble_gap_event_fn *cb, + void *cb_arg, uint8_t ack_status); int ble_hs_test_util_conn_cancel(uint8_t ack_status); +void ble_hs_test_util_conn_cancel_full(void); int ble_hs_test_util_conn_terminate(uint16_t conn_handle, uint8_t hci_status); void ble_hs_test_util_conn_disconnect(uint16_t conn_handle); -int ble_hs_test_util_disc(uint32_t duration_ms, uint8_t discovery_mode, - uint8_t scan_type, uint8_t filter_policy, - ble_gap_disc_fn *cb, void *cb_arg, int fail_idx, +int ble_hs_test_util_exp_hci_status(int cmd_idx, int fail_idx, + uint8_t fail_status); +int ble_hs_test_util_disc(uint8_t own_addr_type, int32_t duration_ms, + const struct ble_gap_disc_params *disc_params, + ble_gap_event_fn *cb, void *cb_arg, int fail_idx, uint8_t fail_status); -int ble_hs_test_util_adv_start(uint8_t discoverable_mode, - uint8_t connectable_mode, - uint8_t *peer_addr, uint8_t peer_addr_type, - struct ble_gap_adv_params *adv_params, +int ble_hs_test_util_disc_cancel(uint8_t ack_status); +void ble_hs_test_util_verify_tx_create_conn(const struct hci_create_conn *exp); +int ble_hs_test_util_adv_set_fields(struct ble_hs_adv_fields *adv_fields, + uint8_t hci_status); +int ble_hs_test_util_adv_start(uint8_t own_addr_type, + uint8_t peer_addr_type, + const uint8_t *peer_addr, + const struct ble_gap_adv_params *adv_params, ble_gap_event_fn *cb, void *cb_arg, int fail_idx, uint8_t fail_status); int ble_hs_test_util_adv_stop(uint8_t hci_status); @@ -85,6 +112,8 @@ int ble_hs_test_util_wl_set(struct ble_gap_white_entry *white_list, int ble_hs_test_util_conn_update(uint16_t conn_handle, struct ble_gap_upd_params *params, uint8_t hci_status); +int ble_hs_test_util_set_our_irk(const uint8_t *irk, int fail_idx, + uint8_t hci_status); int ble_hs_test_util_security_initiate(uint16_t conn_handle, uint8_t hci_status); int ble_hs_test_util_l2cap_rx_first_frag(uint16_t conn_handle, uint16_t cid, @@ -96,6 +125,8 @@ int ble_hs_test_util_l2cap_rx(uint16_t conn_handle, int ble_hs_test_util_l2cap_rx_payload_flat(uint16_t conn_handle, uint16_t cid, const void *data, int len); void ble_hs_test_util_rx_hci_buf_size_ack(uint16_t buf_size); +void ble_hs_test_util_rx_att_mtu_cmd(uint16_t conn_handle, int is_req, + uint16_t mtu); void ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint8_t req_op, uint8_t error_code, uint16_t err_handle); void ble_hs_test_util_set_startup_acks(void); @@ -106,8 +137,46 @@ void ble_hs_test_util_rx_disconn_complete_event( uint8_t *ble_hs_test_util_verify_tx_hci(uint8_t ogf, uint16_t ocf, uint8_t *out_param_len); void ble_hs_test_util_tx_all(void); -void ble_hs_test_util_set_public_addr(uint8_t *addr); +void ble_hs_test_util_verify_tx_prep_write(uint16_t attr_handle, + uint16_t offset, + const void *data, int data_len); void ble_hs_test_util_verify_tx_exec_write(uint8_t expected_flags); +void ble_hs_test_util_verify_tx_read_rsp(uint8_t *attr_data, int attr_len); +void ble_hs_test_util_verify_tx_read_blob_rsp(uint8_t *attr_data, + int attr_len); +void ble_hs_test_util_verify_tx_write_rsp(void); +void ble_hs_test_util_verify_tx_mtu_cmd(int is_req, uint16_t mtu); +void ble_hs_test_util_verify_tx_err_rsp(uint8_t req_op, uint16_t handle, + uint8_t error_code); +void ble_hs_test_util_set_static_rnd_addr(void); +struct os_mbuf *ble_hs_test_util_om_from_flat(const void *buf, uint16_t len); +int ble_hs_test_util_flat_attr_cmp(const struct ble_hs_test_util_flat_attr *a, + const struct ble_hs_test_util_flat_attr *b); +void ble_hs_test_util_attr_to_flat(struct ble_hs_test_util_flat_attr *flat, + const struct ble_gatt_attr *attr); +void ble_hs_test_util_attr_from_flat( + struct ble_gatt_attr *attr, const struct ble_hs_test_util_flat_attr *flat); +int ble_hs_test_util_read_local_flat(uint16_t attr_handle, uint16_t max_len, + void *buf, uint16_t *out_len); +int ble_hs_test_util_write_local_flat(uint16_t attr_handle, + const void *buf, uint16_t buf_len); +int ble_hs_test_util_gatt_write_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg); +int ble_hs_test_util_gatt_write_no_rsp_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, + uint16_t data_len); +int ble_hs_test_util_gatt_write_long_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg); +int ble_hs_test_util_mbuf_count( + const struct ble_hs_test_util_mbuf_params *params); +void ble_hs_test_util_assert_mbufs_freed( + const struct ble_hs_test_util_mbuf_params *params); +void ble_hs_test_util_post_test(void *arg); void ble_hs_test_util_init(void); #endif diff --git a/net/nimble/host/src/test/ble_l2cap_test.c b/net/nimble/host/src/test/ble_l2cap_test.c index 161bd55c..69db2f87 100644 --- a/net/nimble/host/src/test/ble_l2cap_test.c +++ b/net/nimble/host/src/test/ble_l2cap_test.c @@ -21,7 +21,6 @@ #include <errno.h> #include "testutil/testutil.h" #include "nimble/hci_common.h" -#include "host/host_hci.h" #include "host/ble_hs_test.h" #include "ble_hs_test_util.h" @@ -74,7 +73,8 @@ ble_l2cap_test_util_rx_update_req(uint16_t conn_handle, uint8_t id, ble_l2cap_sig_update_req_write(v, BLE_L2CAP_SIG_UPDATE_REQ_SZ, &req); ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CONN_UPDATE), 0); + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CONN_UPDATE), 0); rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SIG, &hci_hdr, om); TEST_ASSERT_FATAL(rc == 0); @@ -242,7 +242,7 @@ ble_l2cap_test_util_rx_first_frag(uint16_t conn_handle, void *v; int rc; - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); v = os_mbuf_extend(om, l2cap_frag_len); @@ -266,7 +266,7 @@ ble_l2cap_test_util_rx_next_frag(uint16_t conn_handle, uint16_t hci_len) void *v; int rc; - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); v = os_mbuf_extend(om, hci_len); @@ -374,7 +374,7 @@ TEST_CASE(ble_l2cap_test_case_frag_single) /*** HCI header specifies middle fragment without start. */ hci_hdr = BLE_L2CAP_TEST_UTIL_HCI_HDR(2, BLE_HCI_PB_MIDDLE, 10); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); om = ble_l2cap_prepend_hdr(om, 0, 5); @@ -480,12 +480,11 @@ TEST_CASE(ble_l2cap_test_case_sig_unsol_rsp) *****************************************************************************/ static int -ble_l2cap_test_util_conn_cb(int event, struct ble_gap_conn_ctxt *ctxt, - void *arg) +ble_l2cap_test_util_conn_cb(struct ble_gap_event *event, void *arg) { int *accept; - switch (event) { + switch (event->type) { case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: accept = arg; return !*accept; @@ -667,6 +666,8 @@ TEST_CASE(ble_l2cap_test_case_sig_update_init_fail_bad_id) TEST_SUITE(ble_l2cap_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_l2cap_test_case_bad_header(); ble_l2cap_test_case_frag_single(); ble_l2cap_test_case_frag_multiple(); diff --git a/net/nimble/host/src/test/ble_os_test.c b/net/nimble/host/src/test/ble_os_test.c index ee7ffd65..a9c28ea9 100644 --- a/net/nimble/host/src/test/ble_os_test.c +++ b/net/nimble/host/src/test/ble_os_test.c @@ -21,18 +21,13 @@ #include "os/os.h" #include "testutil/testutil.h" #include "nimble/hci_common.h" -#include "nimble/hci_transport.h" +#include "nimble/ble_hci_trans.h" #include "host/ble_hs_test.h" #include "host/ble_gap.h" #include "ble_hs_test_util.h" -#ifdef ARCH_sim -#define BLE_OS_TEST_STACK_SIZE 1024 -#define BLE_OS_TEST_APP_STACK_SIZE 1024 -#else #define BLE_OS_TEST_STACK_SIZE 256 #define BLE_OS_TEST_APP_STACK_SIZE 256 -#endif #define BLE_OS_TEST_APP_PRIO 9 #define BLE_OS_TEST_TASK_PRIO 10 @@ -48,7 +43,7 @@ static uint8_t ble_os_test_peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; static void ble_os_test_app_task_handler(void *arg); -static int ble_os_test_gap_event; +static int ble_os_test_gap_event_type; static void ble_os_test_init_app_task(void) @@ -96,20 +91,23 @@ ble_os_test_misc_conn_exists(uint16_t conn_handle) } static int -ble_gap_direct_connect_test_connect_cb(int event, - struct ble_gap_conn_ctxt *ctxt, - void *arg) +ble_gap_direct_connect_test_connect_cb(struct ble_gap_event *event, void *arg) { + struct ble_gap_conn_desc desc; int *cb_called; + int rc; cb_called = arg; *cb_called = 1; - TEST_ASSERT(event == BLE_GAP_EVENT_CONNECT); - TEST_ASSERT(ctxt->connect.status == 0); - TEST_ASSERT(ctxt->desc->conn_handle == 2); - TEST_ASSERT(ctxt->desc->peer_id_addr_type == BLE_ADDR_TYPE_PUBLIC); - TEST_ASSERT(memcmp(ctxt->desc->peer_id_addr, ble_os_test_peer_addr, 6) == 0); + TEST_ASSERT(event->type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(event->connect.status == 0); + TEST_ASSERT(event->connect.conn_handle == 2); + + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.peer_id_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(memcmp(desc.peer_id_addr, ble_os_test_peer_addr, 6) == 0); return 0; } @@ -133,9 +131,10 @@ ble_gap_direct_connect_test_task_handler(void *arg) TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); /* Initiate a direct connection. */ - ble_hs_test_util_conn_initiate(0, addr, NULL, - ble_gap_direct_connect_test_connect_cb, - &cb_called, 0); + ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + addr, 0, NULL, + ble_gap_direct_connect_test_connect_cb, + &cb_called, 0); TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); TEST_ASSERT(!cb_called); @@ -168,22 +167,23 @@ TEST_CASE(ble_gap_direct_connect_test_case) os_start(); } -static void -ble_gap_gen_disc_test_connect_cb(int event, int status, - struct ble_gap_disc_desc *desc, void *arg) +static int +ble_os_disc_test_cb(struct ble_gap_event *event, void *arg) { int *cb_called; cb_called = arg; *cb_called = 1; - TEST_ASSERT(event == BLE_GAP_EVENT_DISC_COMPLETE); - TEST_ASSERT(status == 0); + TEST_ASSERT(event->type == BLE_GAP_EVENT_DISC_COMPLETE); + + return 0; } static void -ble_gap_gen_disc_test_task_handler(void *arg) +ble_os_disc_test_task_handler(void *arg) { + struct ble_gap_disc_params disc_params; int cb_called; int rc; @@ -203,11 +203,10 @@ ble_gap_gen_disc_test_task_handler(void *arg) TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); TEST_ASSERT(!ble_gap_master_in_progress()); - /* Initiate the general discovery procedure with a 200 ms timeout. */ - rc = ble_hs_test_util_disc(300, BLE_GAP_DISC_MODE_GEN, - BLE_HCI_SCAN_TYPE_ACTIVE, - BLE_HCI_SCAN_FILT_NO_WL, - ble_gap_gen_disc_test_connect_cb, + /* Initiate the general discovery procedure with a 300 ms timeout. */ + memset(&disc_params, 0, sizeof disc_params); + rc = ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, 300, &disc_params, + ble_os_disc_test_cb, &cb_called, 0, 0); TEST_ASSERT(rc == 0); TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); @@ -226,7 +225,8 @@ ble_gap_gen_disc_test_task_handler(void *arg) TEST_ASSERT(!cb_called); ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE), 0); /* Wait 250 more ms; verify scan completed. */ @@ -238,13 +238,13 @@ ble_gap_gen_disc_test_task_handler(void *arg) tu_restart(); } -TEST_CASE(ble_gap_gen_disc_test_case) +TEST_CASE(ble_os_disc_test_case) { ble_os_test_misc_init(); os_task_init(&ble_os_test_task, - "ble_gap_gen_disc_test_task", - ble_gap_gen_disc_test_task_handler, NULL, + "ble_os_disc_test_task", + ble_os_disc_test_task_handler, NULL, BLE_OS_TEST_TASK_PRIO, OS_WAIT_FOREVER, ble_os_test_stack, OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE)); @@ -252,15 +252,15 @@ TEST_CASE(ble_gap_gen_disc_test_case) } static int -ble_gap_terminate_cb(int event, struct ble_gap_conn_ctxt *ctxt, void *arg) +ble_gap_terminate_cb(struct ble_gap_event *event, void *arg) { int *disconn_handle; - ble_os_test_gap_event = event; + ble_os_test_gap_event_type = event->type; - if (event == BLE_GAP_EVENT_DISCONNECT) { + if (event->type == BLE_GAP_EVENT_DISCONNECT) { disconn_handle = arg; - *disconn_handle = ctxt->desc->conn_handle; + *disconn_handle = event->disconnect.conn.conn_handle; } return 0; @@ -294,8 +294,9 @@ ble_gap_terminate_test_task_handler(void *arg) TEST_ASSERT(!ble_gap_master_in_progress()); /* Create two direct connections. */ - ble_hs_test_util_conn_initiate(0, addr1, NULL, ble_gap_terminate_cb, - &disconn_handle, 0); + ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + addr1, 0, NULL, ble_gap_terminate_cb, + &disconn_handle, 0); memset(&conn_evt, 0, sizeof conn_evt); conn_evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; conn_evt.status = BLE_ERR_SUCCESS; @@ -304,8 +305,9 @@ ble_gap_terminate_test_task_handler(void *arg) rc = ble_gap_rx_conn_complete(&conn_evt); TEST_ASSERT(rc == 0); - ble_hs_test_util_conn_initiate(0, addr2, NULL, ble_gap_terminate_cb, - &disconn_handle, 0); + ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + addr2, 0, NULL, ble_gap_terminate_cb, + &disconn_handle, 0); memset(&conn_evt, 0, sizeof conn_evt); conn_evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; conn_evt.status = BLE_ERR_SUCCESS; @@ -324,7 +326,7 @@ ble_gap_terminate_test_task_handler(void *arg) disconn_evt.status = 0; disconn_evt.reason = BLE_ERR_REM_USER_CONN_TERM; ble_hs_test_util_rx_disconn_complete_event(&disconn_evt); - TEST_ASSERT(ble_os_test_gap_event == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(ble_os_test_gap_event_type == BLE_GAP_EVENT_DISCONNECT); TEST_ASSERT(disconn_handle == 1); TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(1)); TEST_ASSERT_FATAL(ble_os_test_misc_conn_exists(2)); @@ -336,7 +338,7 @@ ble_gap_terminate_test_task_handler(void *arg) disconn_evt.status = 0; disconn_evt.reason = BLE_ERR_REM_USER_CONN_TERM; ble_hs_test_util_rx_disconn_complete_event(&disconn_evt); - TEST_ASSERT(ble_os_test_gap_event == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(ble_os_test_gap_event_type == BLE_GAP_EVENT_DISCONNECT); TEST_ASSERT(disconn_handle == 2); TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(1)); TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(2)); @@ -384,7 +386,9 @@ TEST_CASE(ble_gap_terminate_test_case) TEST_SUITE(ble_os_test_suite) { - ble_gap_gen_disc_test_case(); + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_os_disc_test_case(); ble_gap_direct_connect_test_case(); ble_gap_terminate_test_case(); } diff --git a/net/nimble/host/src/test/ble_sm_lgcy_test.c b/net/nimble/host/src/test/ble_sm_lgcy_test.c index 59dceab4..6e451ca9 100644 --- a/net/nimble/host/src/test/ble_sm_lgcy_test.c +++ b/net/nimble/host/src/test/ble_sm_lgcy_test.c @@ -23,7 +23,6 @@ #include "testutil/testutil.h" #include "nimble/hci_common.h" #include "nimble/nimble_opt.h" -#include "host/host_hci.h" #include "host/ble_sm.h" #include "host/ble_hs_test.h" #include "ble_hs_test_util.h" @@ -822,6 +821,8 @@ TEST_CASE(ble_sm_lgcy_peer_pk_iio4_rio4_b1_iat0_rat0_ik7_rk7) TEST_SUITE(ble_sm_lgcy_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + /*** No privacy. */ /* Peer as initiator. */ diff --git a/net/nimble/host/src/test/ble_sm_sc_test.c b/net/nimble/host/src/test/ble_sm_sc_test.c index 4d60f0c5..518720c9 100644 --- a/net/nimble/host/src/test/ble_sm_sc_test.c +++ b/net/nimble/host/src/test/ble_sm_sc_test.c @@ -23,7 +23,6 @@ #include "testutil/testutil.h" #include "nimble/hci_common.h" #include "nimble/nimble_opt.h" -#include "host/host_hci.h" #include "host/ble_sm.h" #include "host/ble_hs_test.h" #include "ble_hs_test_util.h" @@ -4879,6 +4878,8 @@ TEST_CASE(ble_sm_sc_us_pk_iio2_rio0_b1_iat2_rat2_ik7_rk3) TEST_SUITE(ble_sm_sc_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + /*** No privacy. */ /* Peer as initiator. */ diff --git a/net/nimble/host/src/test/ble_sm_test.c b/net/nimble/host/src/test/ble_sm_test.c index d8909965..f139ddb7 100644 --- a/net/nimble/host/src/test/ble_sm_test.c +++ b/net/nimble/host/src/test/ble_sm_test.c @@ -23,7 +23,6 @@ #include "testutil/testutil.h" #include "nimble/hci_common.h" #include "nimble/nimble_opt.h" -#include "host/host_hci.h" #include "host/ble_sm.h" #include "host/ble_hs_test.h" #include "ble_hs_test_util.h" @@ -648,6 +647,8 @@ TEST_CASE(ble_sm_test_case_us_fail_inval) TEST_SUITE(ble_sm_gen_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_sm_test_case_f4(); ble_sm_test_case_f5(); ble_sm_test_case_f6(); diff --git a/net/nimble/host/src/test/ble_sm_test_util.c b/net/nimble/host/src/test/ble_sm_test_util.c index 2225f30e..9edaa04c 100644 --- a/net/nimble/host/src/test/ble_sm_test_util.c +++ b/net/nimble/host/src/test/ble_sm_test_util.c @@ -23,15 +23,16 @@ #include "testutil/testutil.h" #include "nimble/hci_common.h" #include "nimble/nimble_opt.h" -#include "host/host_hci.h" #include "host/ble_sm.h" #include "host/ble_hs_test.h" +#include "host/ble_hs_id.h" #include "ble_hs_test_util.h" #include "ble_sm_test_util.h" -int ble_sm_test_gap_event; +int ble_sm_test_gap_event_type; int ble_sm_test_gap_status; struct ble_gap_sec_state ble_sm_test_sec_state; +static struct ble_gap_passkey_params ble_sm_test_ioact; int ble_sm_test_store_obj_type; union ble_store_key ble_sm_test_store_key; @@ -102,9 +103,10 @@ ble_sm_test_util_init(void) ble_hs_cfg.store_write_cb = ble_sm_test_util_store_write; ble_sm_test_store_obj_type = -1; - ble_sm_test_gap_event = -1; + ble_sm_test_gap_event_type = -1; ble_sm_test_gap_status = -1; + memset(&ble_sm_test_ioact, 0, sizeof ble_sm_test_ioact); memset(&ble_sm_test_sec_state, 0xff, sizeof ble_sm_test_sec_state); } @@ -223,19 +225,19 @@ ble_sm_test_util_init_good(struct ble_sm_test_params *params, ble_hs_cfg.sm_their_key_dist = out_us->pair_cmd->init_key_dist; } - ble_hs_test_util_set_public_addr(out_us->id_addr); + ble_hs_id_set_pub(out_us->id_addr); ble_sm_dbg_set_next_pair_rand(out_us->randoms[0].value); ble_sm_dbg_set_next_ediv(out_us->ediv); ble_sm_dbg_set_next_master_id_rand(out_us->rand_num); ble_sm_dbg_set_next_ltk(out_us->ltk); - ble_hs_pvcy_set_our_irk(out_us->id_info->irk); + ble_hs_test_util_set_our_irk(out_us->id_info->irk, 0, 0); ble_sm_dbg_set_next_csrk(out_us->sign_info->sig_key); if (out_us->public_key != NULL) { ble_sm_dbg_set_sc_keys(out_us->public_key->x, params->our_priv_key); } - ble_hs_test_util_create_rpa_conn(2, out_us->rpa, + ble_hs_test_util_create_rpa_conn(2, out_us->addr_type, out_us->rpa, out_peer->addr_type, out_peer->id_addr, out_peer->rpa, ble_sm_test_util_conn_cb, @@ -260,31 +262,32 @@ ble_sm_test_util_init_good(struct ble_sm_test_params *params, } } -struct ble_gap_passkey_action ble_sm_test_ioact; - int -ble_sm_test_util_conn_cb(int event, struct ble_gap_conn_ctxt *ctxt, void *arg) +ble_sm_test_util_conn_cb(struct ble_gap_event *event, void *arg) { + struct ble_gap_conn_desc desc; int rc; - switch (event) { + switch (event->type) { case BLE_GAP_EVENT_ENC_CHANGE: - ble_sm_test_gap_status = ctxt->enc_change.status; - ble_sm_test_sec_state = ctxt->desc->sec_state; - rc = 0; + ble_sm_test_gap_status = event->enc_change.status; + + rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); + TEST_ASSERT_FATAL(rc == 0); + ble_sm_test_sec_state = desc.sec_state; break; case BLE_GAP_EVENT_PASSKEY_ACTION: - ble_sm_test_ioact = ctxt->passkey_action; + ble_sm_test_ioact = event->passkey.params; break; default: return 0; } - ble_sm_test_gap_event = event; + ble_sm_test_gap_event_type = event->type; - return rc; + return 0; } static void @@ -302,7 +305,7 @@ ble_sm_test_util_rx_pair_cmd(uint16_t conn_handle, uint8_t op, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_PAIR_CMD_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_PAIR_CMD_SZ; @@ -349,7 +352,7 @@ ble_sm_test_util_rx_confirm(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_PAIR_CONFIRM_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_PAIR_CONFIRM_SZ; @@ -379,7 +382,7 @@ ble_sm_test_util_rx_random(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_PAIR_RANDOM_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_PAIR_RANDOM_SZ; @@ -408,7 +411,7 @@ ble_sm_test_util_rx_sec_req(uint16_t conn_handle, struct ble_sm_sec_req *cmd, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_SEC_REQ_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_SEC_REQ_SZ; @@ -437,7 +440,7 @@ ble_sm_test_util_rx_public_key(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_PUBLIC_KEY_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_PUBLIC_KEY_SZ; @@ -467,7 +470,7 @@ ble_sm_test_util_rx_dhkey_check(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_DHKEY_CHECK_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_DHKEY_CHECK_SZ; @@ -497,7 +500,7 @@ ble_sm_test_util_rx_enc_info(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_ENC_INFO_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_ENC_INFO_SZ; @@ -527,7 +530,7 @@ ble_sm_test_util_rx_master_id(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_MASTER_ID_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_MASTER_ID_SZ; @@ -557,7 +560,7 @@ ble_sm_test_util_rx_id_info(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_ID_INFO_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_ID_INFO_SZ; @@ -587,7 +590,7 @@ ble_sm_test_util_rx_id_addr_info(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_ID_ADDR_INFO_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_ID_ADDR_INFO_SZ; @@ -617,7 +620,7 @@ ble_sm_test_util_rx_sign_info(uint16_t conn_handle, 2, BLE_HCI_PB_FIRST_FLUSH, BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_SIGN_INFO_SZ); - om = ble_hs_misc_pkthdr(); + om = ble_hs_mbuf_l2cap_pkt(); TEST_ASSERT_FATAL(om != NULL); payload_len = BLE_SM_HDR_SZ + BLE_SM_SIGN_INFO_SZ; @@ -637,7 +640,7 @@ ble_sm_test_util_verify_tx_hdr(uint8_t sm_op, uint16_t payload_len) { struct os_mbuf *om; - om = ble_hs_test_util_prev_tx_dequeue(); + om = ble_hs_test_util_prev_tx_dequeue_pullup(); TEST_ASSERT_FATAL(om != NULL); TEST_ASSERT(OS_MBUF_PKTLEN(om) == BLE_SM_HDR_SZ + payload_len); @@ -797,10 +800,14 @@ ble_sm_test_util_verify_tx_id_addr_info(struct ble_sm_id_addr_info *exp_cmd) { struct ble_sm_id_addr_info cmd; struct os_mbuf *om; - uint8_t *our_id_addr; - uint8_t our_id_addr_type; + const uint8_t *our_id_addr; + int rc; - our_id_addr = ble_hs_pvcy_our_id_addr(&our_id_addr_type); + ble_hs_lock(); + rc = ble_hs_id_addr(exp_cmd->addr_type, &our_id_addr, NULL); + ble_hs_unlock(); + + TEST_ASSERT_FATAL(rc == 0); ble_hs_test_util_tx_all(); om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_IDENTITY_ADDR_INFO, @@ -809,8 +816,6 @@ ble_sm_test_util_verify_tx_id_addr_info(struct ble_sm_id_addr_info *exp_cmd) TEST_ASSERT(cmd.addr_type == exp_cmd->addr_type); TEST_ASSERT(memcmp(cmd.bd_addr, exp_cmd->bd_addr, 6) == 0); - - TEST_ASSERT(cmd.addr_type == our_id_addr_type); TEST_ASSERT(memcmp(cmd.bd_addr, our_id_addr, 6) == 0); } @@ -902,14 +907,27 @@ ble_sm_test_util_verify_tx_lt_key_req_neg_reply(uint16_t conn_handle) } static void -ble_sm_test_util_set_lt_key_req_reply_ack(uint8_t status, - uint16_t conn_handle) +ble_sm_test_util_set_lt_key_req_neg_reply_ack(uint8_t status, + uint16_t conn_handle) +{ + static uint8_t params[BLE_HCI_LT_KEY_REQ_NEG_REPLY_ACK_PARAM_LEN]; + + htole16(params, conn_handle); + ble_hs_test_util_set_ack_params( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY), + status, params, sizeof params); +} + +static void +ble_sm_test_util_set_lt_key_req_reply_ack(uint8_t status, uint16_t conn_handle) { static uint8_t params[BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN]; htole16(params, conn_handle); ble_hs_test_util_set_ack_params( - host_hci_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY), + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY), status, params, sizeof params); } @@ -975,15 +993,20 @@ ble_sm_test_util_io_inject(struct ble_sm_test_passkey_info *passkey_info, io_sm_state = ble_sm_ioact_state(passkey_info->passkey.action); if (io_sm_state != cur_sm_state) { + TEST_ASSERT(ble_sm_test_ioact.action == BLE_SM_IOACT_NONE); return; } + TEST_ASSERT(ble_sm_test_ioact.action == passkey_info->passkey.action); + if (passkey_info->passkey.action == BLE_SM_IOACT_NUMCMP) { TEST_ASSERT(ble_sm_test_ioact.numcmp == passkey_info->exp_numcmp); } rc = ble_sm_inject_io(2, &passkey_info->passkey); TEST_ASSERT(rc == 0); + + ble_sm_test_ioact.action = BLE_SM_IOACT_NONE; } void @@ -1193,6 +1216,7 @@ ble_sm_test_util_verify_persist(struct ble_sm_test_params *params, static void ble_sm_test_util_peer_bonding_good(int send_enc_req, + uint8_t our_addr_type, uint8_t *our_rpa, uint8_t peer_addr_type, uint8_t *peer_id_addr, @@ -1203,8 +1227,9 @@ ble_sm_test_util_peer_bonding_good(int send_enc_req, struct ble_hs_conn *conn; int rc; - ble_hs_test_util_create_rpa_conn(2, our_rpa, peer_addr_type, peer_id_addr, - peer_rpa, ble_sm_test_util_conn_cb, NULL); + ble_hs_test_util_create_rpa_conn(2, our_addr_type, our_rpa, peer_addr_type, + peer_id_addr, peer_rpa, + ble_sm_test_util_conn_cb, NULL); /* This test inspects and modifies the connection object after unlocking * the host mutex. It is not OK for real code to do this, but this test @@ -1255,7 +1280,7 @@ ble_sm_test_util_peer_bonding_good(int send_enc_req, TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was executed. */ - TEST_ASSERT(ble_sm_test_gap_event == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); TEST_ASSERT(ble_sm_test_gap_status == 0); TEST_ASSERT(ble_sm_test_sec_state.encrypted); TEST_ASSERT(ble_sm_test_sec_state.authenticated == @@ -1294,7 +1319,7 @@ ble_sm_test_util_peer_bonding_bad(uint16_t ediv, uint64_t rand_num) TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Receive a long term key request from the controller. */ - ble_sm_test_util_set_lt_key_req_reply_ack(0, 2); + ble_sm_test_util_set_lt_key_req_neg_reply_ack(0, 2); ble_sm_test_util_rx_lt_key_req(2, rand_num, ediv); TEST_ASSERT(!conn->bhc_sec_state.encrypted); @@ -1323,7 +1348,8 @@ ble_sm_test_util_peer_bonding_bad(uint16_t ediv, uint64_t rand_num) * 0: No security request; we initiate. */ static void -ble_sm_test_util_us_bonding_good(int send_enc_req, uint8_t *our_rpa, +ble_sm_test_util_us_bonding_good(int send_enc_req, uint8_t our_addr_type, + uint8_t *our_rpa, uint8_t peer_addr_type, uint8_t *peer_id_addr, uint8_t *peer_rpa, uint8_t *ltk, int authenticated, @@ -1332,7 +1358,8 @@ ble_sm_test_util_us_bonding_good(int send_enc_req, uint8_t *our_rpa, struct ble_sm_sec_req sec_req; struct ble_hs_conn *conn; - ble_hs_test_util_create_rpa_conn(2, our_rpa, peer_addr_type, peer_id_addr, + ble_hs_test_util_create_rpa_conn(2, our_addr_type, our_rpa, + peer_addr_type, peer_id_addr, peer_rpa, ble_sm_test_util_conn_cb, NULL); /* This test inspects and modifies the connection object after unlocking @@ -1348,7 +1375,8 @@ ble_sm_test_util_us_bonding_good(int send_enc_req, uint8_t *our_rpa, TEST_ASSERT(ble_sm_dbg_num_procs() == 0); ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_START_ENCRYPT), + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_START_ENCRYPT), 0); if (send_enc_req) { @@ -1376,7 +1404,7 @@ ble_sm_test_util_us_bonding_good(int send_enc_req, uint8_t *our_rpa, TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was executed. */ - TEST_ASSERT(ble_sm_test_gap_event == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); TEST_ASSERT(ble_sm_test_gap_status == 0); TEST_ASSERT(ble_sm_test_sec_state.encrypted); TEST_ASSERT(ble_sm_test_sec_state.authenticated == @@ -1401,7 +1429,7 @@ ble_sm_test_util_peer_fail_inval( struct ble_hs_conn *conn; ble_sm_test_util_init(); - ble_hs_test_util_set_public_addr(resp_addr); + ble_hs_id_set_pub(resp_addr); ble_hs_test_util_create_conn(2, init_id_addr, ble_sm_test_util_conn_cb, NULL); @@ -1435,7 +1463,7 @@ ble_sm_test_util_peer_fail_inval( TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was not executed. */ - TEST_ASSERT(ble_sm_test_gap_event == -1); + TEST_ASSERT(ble_sm_test_gap_event_type == -1); TEST_ASSERT(ble_sm_test_gap_status == -1); /* Verify that connection has correct security state. */ @@ -1458,7 +1486,7 @@ ble_sm_test_util_peer_lgcy_fail_confirm( struct ble_hs_conn *conn; ble_sm_test_util_init(); - ble_hs_test_util_set_public_addr(resp_addr); + ble_hs_id_set_pub(resp_addr); ble_sm_dbg_set_next_pair_rand(random_rsp->value); ble_hs_test_util_create_conn(2, init_id_addr, ble_sm_test_util_conn_cb, @@ -1512,7 +1540,7 @@ ble_sm_test_util_peer_lgcy_fail_confirm( TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was executed. */ - TEST_ASSERT(ble_sm_test_gap_event == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); TEST_ASSERT(ble_sm_test_gap_status == BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH)); TEST_ASSERT(!ble_sm_test_sec_state.encrypted); @@ -1548,7 +1576,8 @@ ble_sm_test_util_bonding_all(struct ble_sm_test_params *params, if (sc || peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC) { /* We are master; we initiate procedure. */ - ble_sm_test_util_us_bonding_good(0, our_entity.rpa, + ble_sm_test_util_us_bonding_good(0, our_entity.addr_type, + our_entity.rpa, peer_entity.addr_type, peer_entity.id_addr, peer_entity.rpa, @@ -1558,7 +1587,8 @@ ble_sm_test_util_bonding_all(struct ble_sm_test_params *params, peer_entity.rand_num); /* We are master; peer initiates procedure via security request. */ - ble_sm_test_util_us_bonding_good(1, our_entity.rpa, + ble_sm_test_util_us_bonding_good(1, our_entity.addr_type, + our_entity.rpa, peer_entity.addr_type, peer_entity.id_addr, peer_entity.rpa, @@ -1570,7 +1600,8 @@ ble_sm_test_util_bonding_all(struct ble_sm_test_params *params, if (sc || our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC) { /* Peer is master; peer initiates procedure. */ - ble_sm_test_util_peer_bonding_good(0, our_entity.rpa, + ble_sm_test_util_peer_bonding_good(0, our_entity.addr_type, + our_entity.rpa, peer_entity.addr_type, peer_entity.id_addr, peer_entity.rpa, @@ -1580,7 +1611,8 @@ ble_sm_test_util_bonding_all(struct ble_sm_test_params *params, our_entity.rand_num); /* Peer is master; we initiate procedure via security request. */ - ble_sm_test_util_peer_bonding_good(1, our_entity.rpa, + ble_sm_test_util_peer_bonding_good(1, our_entity.addr_type, + our_entity.rpa, peer_entity.addr_type, peer_entity.id_addr, peer_entity.rpa, @@ -1629,8 +1661,8 @@ ble_sm_test_util_rx_keys(struct ble_sm_test_params *params, } if (peer_key_dist & BLE_SM_PAIR_KEY_DIST_ID) { ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_ADD_RESOLV_LIST), 0); + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_ADD_RESOLV_LIST), 0); ble_sm_test_util_rx_id_info(2, peer_id_info, 0); ble_sm_test_util_rx_id_addr_info(2, peer_id_addr_info, 0); } @@ -1697,7 +1729,8 @@ ble_sm_test_util_us_lgcy_good_once(struct ble_sm_test_params *params) TEST_ASSERT(ble_sm_dbg_num_procs() == 0); ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_START_ENCRYPT), 0); + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_START_ENCRYPT), 0); if (params->sec_req.authreq != 0) { ble_sm_test_util_rx_sec_req(2, ¶ms->sec_req, 0); } else { @@ -1768,7 +1801,7 @@ ble_sm_test_util_us_lgcy_good_once(struct ble_sm_test_params *params) TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was executed. */ - TEST_ASSERT(ble_sm_test_gap_event == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); TEST_ASSERT(ble_sm_test_gap_status == 0); TEST_ASSERT(ble_sm_test_sec_state.encrypted); TEST_ASSERT(ble_sm_test_sec_state.authenticated == params->authenticated); @@ -1894,7 +1927,7 @@ ble_sm_test_util_peer_lgcy_good_once(struct ble_sm_test_params *params) TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was executed. */ - TEST_ASSERT(ble_sm_test_gap_event == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); TEST_ASSERT(ble_sm_test_gap_status == 0); TEST_ASSERT(ble_sm_test_sec_state.encrypted); TEST_ASSERT(ble_sm_test_sec_state.authenticated == @@ -1957,7 +1990,8 @@ ble_sm_test_util_us_sc_good_once(struct ble_sm_test_params *params) TEST_ASSERT(ble_sm_dbg_num_procs() == 0); ble_hs_test_util_set_ack( - host_hci_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_START_ENCRYPT), 0); + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_START_ENCRYPT), 0); if (params->sec_req.authreq != 0) { ble_sm_test_util_rx_sec_req(2, ¶ms->sec_req, 0); } else { @@ -2079,7 +2113,7 @@ ble_sm_test_util_us_sc_good_once(struct ble_sm_test_params *params) TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was executed. */ - TEST_ASSERT(ble_sm_test_gap_event == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); TEST_ASSERT(ble_sm_test_gap_status == 0); TEST_ASSERT(ble_sm_test_sec_state.encrypted); TEST_ASSERT(ble_sm_test_sec_state.authenticated == @@ -2267,7 +2301,7 @@ ble_sm_test_util_peer_sc_good_once(struct ble_sm_test_params *params) TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was executed. */ - TEST_ASSERT(ble_sm_test_gap_event == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); TEST_ASSERT(ble_sm_test_gap_status == 0); TEST_ASSERT(ble_sm_test_sec_state.encrypted); TEST_ASSERT(ble_sm_test_sec_state.authenticated == @@ -2321,7 +2355,7 @@ ble_sm_test_util_us_fail_inval(struct ble_sm_test_params *params) int rc; ble_sm_test_util_init(); - ble_hs_test_util_set_public_addr(params->resp_id_addr); + ble_hs_id_set_pub(params->resp_id_addr); ble_sm_dbg_set_next_pair_rand(((uint8_t[16]){0})); @@ -2365,7 +2399,7 @@ ble_sm_test_util_us_fail_inval(struct ble_sm_test_params *params) TEST_ASSERT(ble_sm_dbg_num_procs() == 0); /* Verify that security callback was not executed. */ - TEST_ASSERT(ble_sm_test_gap_event == -1); + TEST_ASSERT(ble_sm_test_gap_event_type == -1); TEST_ASSERT(ble_sm_test_gap_status == -1); /* Verify that connection has correct security state. */ diff --git a/net/nimble/host/src/test/ble_sm_test_util.h b/net/nimble/host/src/test/ble_sm_test_util.h index 3b0688b3..3323be69 100644 --- a/net/nimble/host/src/test/ble_sm_test_util.h +++ b/net/nimble/host/src/test/ble_sm_test_util.h @@ -78,8 +78,7 @@ extern union ble_store_key ble_sm_test_store_key; extern union ble_store_value ble_sm_test_store_value; void ble_sm_test_util_init(void); -int ble_sm_test_util_conn_cb(int event, struct ble_gap_conn_ctxt *ctxt, - void *arg); +int ble_sm_test_util_conn_cb(struct ble_gap_event *ctxt, void *arg); void ble_sm_test_util_io_inject(struct ble_sm_test_passkey_info *passkey_info, uint8_t cur_sm_state); void ble_sm_test_util_io_inject_bad(uint16_t conn_handle, diff --git a/net/nimble/host/src/test/ble_uuid_test.c b/net/nimble/host/src/test/ble_uuid_test.c index ecb3505f..10113034 100644 --- a/net/nimble/host/src/test/ble_uuid_test.c +++ b/net/nimble/host/src/test/ble_uuid_test.c @@ -19,9 +19,10 @@ #include <stddef.h> #include <string.h> -#include "host/ble_hs_test.h" #include "testutil/testutil.h" +#include "host/ble_hs_test.h" #include "host/ble_uuid.h" +#include "ble_hs_test_util.h" TEST_CASE(ble_uuid_test_128_to_16) { @@ -78,6 +79,8 @@ TEST_CASE(ble_uuid_test_128_to_16) TEST_SUITE(ble_uuid_test_suite) { + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + ble_uuid_test_128_to_16(); } diff --git a/net/nimble/host/store/ram/include/store/ram/ble_store_ram.h b/net/nimble/host/store/ram/include/store/ram/ble_store_ram.h new file mode 100644 index 00000000..b9529c5c --- /dev/null +++ b/net/nimble/host/store/ram/include/store/ram/ble_store_ram.h @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_STORE_RAM_ +#define H_BLE_STORE_RAM_ + +union ble_store_key; +union ble_store_value; + +int ble_store_ram_read(int obj_type, union ble_store_key *key, + union ble_store_value *value); +int ble_store_ram_write(int obj_type, union ble_store_value *val); + +#endif diff --git a/net/nimble/host/store/ram/pkg.yml b/net/nimble/host/store/ram/pkg.yml new file mode 100644 index 00000000..f43e7a55 --- /dev/null +++ b/net/nimble/host/store/ram/pkg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: net/nimble/host/store/ram +pkg.description: RAM-based persistence layer for the NimBLE host. +pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - nimble + - persistence + +pkg.deps: + - net/nimble/host diff --git a/net/nimble/host/store/ram/src/ble_store_ram.c b/net/nimble/host/store/ram/src/ble_store_ram.c new file mode 100644 index 00000000..7528f03a --- /dev/null +++ b/net/nimble/host/store/ram/src/ble_store_ram.c @@ -0,0 +1,373 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * This file implements a simple in-RAM key database for BLE host security + * material and CCCDs. As this database is only ble_store_ramd in RAM, its + * contents are lost when the application terminates. + */ + +#include <inttypes.h> +#include <string.h> + +#include "host/ble_hs.h" +#include "store/ram/ble_store_ram.h" + +/* XXX: This should be configurable. */ +#define STORE_MAX_SLV_LTKS 4 +#define STORE_MAX_MST_LTKS 4 +#define STORE_MAX_CCCDS 16 + +static struct ble_store_value_sec ble_store_ram_our_secs[STORE_MAX_SLV_LTKS]; +static int ble_store_ram_num_our_secs; + +static struct ble_store_value_sec ble_store_ram_peer_secs[STORE_MAX_MST_LTKS]; +static int ble_store_ram_num_peer_secs; + +static struct ble_store_value_cccd ble_store_ram_cccds[STORE_MAX_CCCDS]; +static int ble_store_ram_num_cccds; + +/***************************************************************************** + * $sec * + *****************************************************************************/ + +static void +ble_store_ram_print_value_sec(struct ble_store_value_sec *sec) +{ + if (sec->ltk_present) { + BLE_HS_LOG(DEBUG, "ediv=%u rand=%llu authenticated=%d ltk=", + sec->ediv, sec->rand_num, sec->authenticated); + ble_hs_log_flat_buf(sec->ltk, 16); + BLE_HS_LOG(DEBUG, " "); + } + if (sec->irk_present) { + BLE_HS_LOG(DEBUG, "irk="); + ble_hs_log_flat_buf(sec->irk, 16); + BLE_HS_LOG(DEBUG, " "); + } + if (sec->csrk_present) { + BLE_HS_LOG(DEBUG, "csrk="); + ble_hs_log_flat_buf(sec->csrk, 16); + BLE_HS_LOG(DEBUG, " "); + } + + BLE_HS_LOG(DEBUG, "\n"); +} + +static void +ble_store_ram_print_key_sec(struct ble_store_key_sec *key_sec) +{ + if (key_sec->peer_addr_type != BLE_STORE_ADDR_TYPE_NONE) { + BLE_HS_LOG(DEBUG, "peer_addr_type=%d peer_addr=", + key_sec->peer_addr_type); + ble_hs_log_flat_buf(key_sec->peer_addr, 6); + BLE_HS_LOG(DEBUG, " "); + } + if (key_sec->ediv_rand_present) { + BLE_HS_LOG(DEBUG, "ediv=0x%02x rand=0x%llx ", + key_sec->ediv, key_sec->rand_num); + } +} + +static int +ble_store_ram_find_sec(struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_secs, int num_value_secs) +{ + struct ble_store_value_sec *cur; + int skipped; + int i; + + skipped = 0; + + for (i = 0; i < num_value_secs; i++) { + cur = value_secs + i; + + if (key_sec->peer_addr_type != BLE_STORE_ADDR_TYPE_NONE) { + if (cur->peer_addr_type != key_sec->peer_addr_type) { + continue; + } + + if (memcmp(cur->peer_addr, key_sec->peer_addr, + sizeof cur->peer_addr) != 0) { + continue; + } + } + + if (key_sec->ediv_rand_present) { + if (cur->ediv != key_sec->ediv) { + continue; + } + + if (cur->rand_num != key_sec->rand_num) { + continue; + } + } + + if (key_sec->idx > skipped) { + skipped++; + continue; + } + + return i; + } + + return -1; +} + +static int +ble_store_ram_read_our_sec(struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_sec) +{ + int idx; + + idx = ble_store_ram_find_sec(key_sec, ble_store_ram_our_secs, + ble_store_ram_num_our_secs); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_sec = ble_store_ram_our_secs[idx]; + return 0; +} + +static int +ble_store_ram_write_our_sec(struct ble_store_value_sec *value_sec) +{ + struct ble_store_key_sec key_sec; + int idx; + + BLE_HS_LOG(DEBUG, "persisting our sec; "); + ble_store_ram_print_value_sec(value_sec); + + ble_store_key_from_value_sec(&key_sec, value_sec); + idx = ble_store_ram_find_sec(&key_sec, ble_store_ram_our_secs, + ble_store_ram_num_our_secs); + if (idx == -1) { + if (ble_store_ram_num_our_secs >= STORE_MAX_SLV_LTKS) { + BLE_HS_LOG(DEBUG, "error persisting our sec; too many entries " + "(%d)\n", ble_store_ram_num_our_secs); + return BLE_HS_ENOMEM; + } + + idx = ble_store_ram_num_our_secs; + ble_store_ram_num_our_secs++; + } + + ble_store_ram_our_secs[idx] = *value_sec; + return 0; +} + +static int +ble_store_ram_read_peer_sec(struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_sec) +{ + int idx; + + idx = ble_store_ram_find_sec(key_sec, ble_store_ram_peer_secs, + ble_store_ram_num_peer_secs); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_sec = ble_store_ram_peer_secs[idx]; + return 0; +} + +static int +ble_store_ram_write_peer_sec(struct ble_store_value_sec *value_sec) +{ + struct ble_store_key_sec key_sec; + int idx; + + BLE_HS_LOG(DEBUG, "persisting peer sec; "); + ble_store_ram_print_value_sec(value_sec); + + ble_store_key_from_value_sec(&key_sec, value_sec); + idx = ble_store_ram_find_sec(&key_sec, ble_store_ram_peer_secs, + ble_store_ram_num_peer_secs); + if (idx == -1) { + if (ble_store_ram_num_peer_secs >= STORE_MAX_MST_LTKS) { + BLE_HS_LOG(DEBUG, "error persisting peer sec; too many entries " + "(%d)\n", ble_store_ram_num_peer_secs); + return BLE_HS_ENOMEM; + } + + idx = ble_store_ram_num_peer_secs; + ble_store_ram_num_peer_secs++; + } + + ble_store_ram_peer_secs[idx] = *value_sec; + return 0; +} + +/***************************************************************************** + * $cccd * + *****************************************************************************/ + +static int +ble_store_ram_find_cccd(struct ble_store_key_cccd *key) +{ + struct ble_store_value_cccd *cccd; + int skipped; + int i; + + skipped = 0; + for (i = 0; i < ble_store_ram_num_cccds; i++) { + cccd = ble_store_ram_cccds + i; + + if (key->peer_addr_type != BLE_STORE_ADDR_TYPE_NONE) { + if (cccd->peer_addr_type != key->peer_addr_type) { + continue; + } + + if (memcmp(cccd->peer_addr, key->peer_addr, 6) != 0) { + continue; + } + } + + if (key->chr_val_handle != 0) { + if (cccd->chr_val_handle != key->chr_val_handle) { + continue; + } + } + + if (key->idx > skipped) { + skipped++; + continue; + } + + return i; + } + + return -1; +} + +static int +ble_store_ram_read_cccd(struct ble_store_key_cccd *key_cccd, + struct ble_store_value_cccd *value_cccd) +{ + int idx; + + idx = ble_store_ram_find_cccd(key_cccd); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_cccd = ble_store_ram_cccds[idx]; + return 0; +} + +static int +ble_store_ram_write_cccd(struct ble_store_value_cccd *value_cccd) +{ + struct ble_store_key_cccd key_cccd; + int idx; + + ble_store_key_from_value_cccd(&key_cccd, value_cccd); + idx = ble_store_ram_find_cccd(&key_cccd); + if (idx == -1) { + if (ble_store_ram_num_cccds >= STORE_MAX_SLV_LTKS) { + BLE_HS_LOG(DEBUG, "error persisting cccd; too many entries (%d)\n", + ble_store_ram_num_cccds); + return BLE_HS_ENOMEM; + } + + idx = ble_store_ram_num_cccds; + ble_store_ram_num_cccds++; + } + + ble_store_ram_cccds[idx] = *value_cccd; + return 0; +} + +/***************************************************************************** + * $api * + *****************************************************************************/ + +/** + * Searches the database for an object matching the specified criteria. + * + * @return 0 if a key was found; else BLE_HS_ENOENT. + */ +int +ble_store_ram_read(int obj_type, union ble_store_key *key, + union ble_store_value *value) +{ + int rc; + + switch (obj_type) { + case BLE_STORE_OBJ_TYPE_PEER_SEC: + /* An encryption procedure (bonding) is being attempted. The nimble + * stack is asking us to look in our key database for a long-term key + * corresponding to the specified ediv and random number. + * + * Perform a key lookup and populate the context object with the + * result. The nimble stack will use this key if this function returns + * success. + */ + BLE_HS_LOG(DEBUG, "looking up peer sec; "); + ble_store_ram_print_key_sec(&key->sec); + BLE_HS_LOG(DEBUG, "\n"); + rc = ble_store_ram_read_peer_sec(&key->sec, &value->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_OUR_SEC: + BLE_HS_LOG(DEBUG, "looking up our sec; "); + ble_store_ram_print_key_sec(&key->sec); + BLE_HS_LOG(DEBUG, "\n"); + rc = ble_store_ram_read_our_sec(&key->sec, &value->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_CCCD: + rc = ble_store_ram_read_cccd(&key->cccd, &value->cccd); + return rc; + + default: + return BLE_HS_ENOTSUP; + } +} + +/** + * Adds the specified object to the database. + * + * @return 0 on success; BLE_HS_ENOMEM if the database is + * full. + */ +int +ble_store_ram_write(int obj_type, union ble_store_value *val) +{ + int rc; + + switch (obj_type) { + case BLE_STORE_OBJ_TYPE_PEER_SEC: + rc = ble_store_ram_write_peer_sec(&val->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_OUR_SEC: + rc = ble_store_ram_write_our_sec(&val->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_CCCD: + rc = ble_store_ram_write_cccd(&val->cccd); + return rc; + + default: + return BLE_HS_ENOTSUP; + } +} diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h index 04ea21cb..6c4c90ee 100644 --- a/net/nimble/include/nimble/ble.h +++ b/net/nimble/include/nimble/ble.h @@ -34,10 +34,6 @@ struct ble_encryption_block uint8_t cipher_text[BLE_ENC_BLOCK_SIZE]; }; -/* Shared command pool for transort between host and controller */ -extern struct os_mempool g_hci_cmd_pool; -extern struct os_mempool g_hci_os_event_pool; - /* * BLE MBUF structure: * @@ -140,17 +136,17 @@ extern uint8_t g_random_addr[BLE_DEV_ADDR_LEN]; void htole16(void *buf, uint16_t x); void htole32(void *buf, uint32_t x); void htole64(void *buf, uint64_t x); -uint16_t le16toh(void *buf); -uint32_t le32toh(void *buf); -uint64_t le64toh(void *buf); +uint16_t le16toh(const void *buf); +uint32_t le32toh(const void *buf); +uint64_t le64toh(const void *buf); void htobe16(void *buf, uint16_t x); void htobe32(void *buf, uint32_t x); void htobe64(void *buf, uint64_t x); -uint16_t be16toh(void *buf); -uint32_t be32toh(void *buf); -uint64_t be64toh(void *buf); +uint16_t be16toh(const void *buf); +uint32_t be32toh(const void *buf); +uint64_t be64toh(const void *buf); void swap_in_place(void *buf, int len); -void swap_buf(uint8_t *dst, uint8_t *src, int len); +void swap_buf(uint8_t *dst, const uint8_t *src, int len); /* XXX */ /* BLE Error Codes (Core v4.2 Vol 2 part D) */ @@ -222,7 +218,6 @@ enum ble_error_codes BLE_ERR_CONN_ESTABLISHMENT = 62, BLE_ERR_MAC_CONN_FAIL = 63, BLE_ERR_COARSE_CLK_ADJ = 64, - BLE_ERR_ATTR_NOT_FOUND = 65, BLE_ERR_MAX = 255 }; @@ -232,4 +227,6 @@ enum ble_error_codes #define BLE_ADDR_TYPE_RPA_PUB_DEFAULT (2) #define BLE_ADDR_TYPE_RPA_RND_DEFAULT (3) +int ble_err_from_os(int os_err); + #endif /* H_BLE_ */ diff --git a/net/nimble/include/nimble/ble_hci_trans.h b/net/nimble/include/nimble/ble_hci_trans.h new file mode 100644 index 00000000..3e2ec7a8 --- /dev/null +++ b/net/nimble/include/nimble/ble_hci_trans.h @@ -0,0 +1,169 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_HCI_TRANSPORT_ +#define H_HCI_TRANSPORT_ + +#include <inttypes.h> +struct os_mbuf; + +#define BLE_HCI_TRANS_CMD_SZ 260 + +/*** Type of buffers for holding commands and events. */ +/** + * Controller-to-host event buffers. Events have one of two priorities: + * o Low-priority (BLE_HCI_TRANS_BUF_EVT_LO) + * o High-priority (BLE_HCI_TRANS_BUF_EVT_HI) + * + * Low-priority event buffers are only used for advertising reports. If there + * are no free low-priority event buffers, then an incoming advertising report + * will get dropped. + * + * High-priority event buffers are for everything except advertising reports. + * If there are no free high-priority event buffers, a request to allocate one + * will try to allocate a low-priority buffer instead. + * + * If you want all events to be given equal treatment, then you should allocate + * low-priority events only. + * + * Event priorities solve the problem of critical events getting dropped due to + * a flood of advertising reports. This solution is likely temporary: when + * HCI flow control is added, event priorities may become obsolete. + * + * Not all transports distinguish between low and high priority events. If the + * transport does not have separate settings for low and high buffer counts, + * then it treats all events with equal priority. + */ +#define BLE_HCI_TRANS_BUF_EVT_LO 1 +#define BLE_HCI_TRANS_BUF_EVT_HI 2 + +/* Host-to-controller command. */ +#define BLE_HCI_TRANS_BUF_CMD 3 + +/** Callback function types; executed when HCI packets are received. */ +typedef int ble_hci_trans_rx_cmd_fn(uint8_t *cmd, void *arg); +typedef int ble_hci_trans_rx_acl_fn(struct os_mbuf *om, void *arg); + +/** + * Sends an HCI event from the controller to the host. + * + * @param cmd The HCI event to send. This buffer must be + * allocated via ble_hci_trans_buf_alloc(). + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int ble_hci_trans_ll_evt_tx(uint8_t *hci_ev); + +/** + * Sends ACL data from controller to host. + * + * @param om The ACL data packet to send. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int ble_hci_trans_ll_acl_tx(struct os_mbuf *om); + +/** + * Sends an HCI command from the host to the controller. + * + * @param cmd The HCI command to send. This buffer must be + * allocated via ble_hci_trans_buf_alloc(). + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int ble_hci_trans_hs_cmd_tx(uint8_t *cmd); + +/** + * Sends ACL data from host to controller. + * + * @param om The ACL data packet to send. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int ble_hci_trans_hs_acl_tx(struct os_mbuf *om); + +/** + * Allocates a flat buffer of the specified type. + * + * @param type The type of buffer to allocate; one of the + * BLE_HCI_TRANS_BUF_[...] constants. + * + * @return The allocated buffer on success; + * NULL on buffer exhaustion. + */ +uint8_t *ble_hci_trans_buf_alloc(int type); + +/** + * Frees the specified flat buffer. The buffer must have been allocated via + * ble_hci_trans_buf_alloc(). + * + * @param buf The buffer to free. + */ +void ble_hci_trans_buf_free(uint8_t *buf); + +/** + * Configures the HCI transport to operate with a controller. The transport + * will execute specified callbacks upon receiving HCI packets from the host. + * + * @param cmd_cb The callback to execute upon receiving an HCI + * command. + * @param cmd_arg Optional argument to pass to the command + * callback. + * @param acl_cb The callback to execute upon receiving ACL + * data. + * @param acl_arg Optional argument to pass to the ACL + * callback. + */ +void ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg); + +/** + * Configures the HCI transport to operate with a host. The transport will + * execute specified callbacks upon receiving HCI packets from the controller. + * + * @param cmd_cb The callback to execute upon receiving an HCI + * event. + * @param cmd_arg Optional argument to pass to the command + * callback. + * @param acl_cb The callback to execute upon receiving ACL + * data. + * @param acl_arg Optional argument to pass to the ACL + * callback. + */ +void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg); + +/** + * Resets the HCI module to a clean state. Frees all buffers and reinitializes + * the underlying transport. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int ble_hci_trans_reset(void); + +#endif /* H_HCI_TRANSPORT_ */ diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h index 0292be52..f094cc7d 100644 --- a/net/nimble/include/nimble/hci_common.h +++ b/net/nimble/include/nimble/hci_common.h @@ -131,6 +131,9 @@ /* --- Set event mask (OGF 0x03, OCF 0x0001 --- */ #define BLE_HCI_SET_EVENT_MASK_LEN (8) +/* --- Read BD_ADDR (OGF 0x04, OCF 0x0009 --- */ +#define BLE_HCI_IP_RD_BD_ADDR_ACK_PARAM_LEN (6) + /* --- Read/Write authenticated payload timeout (ocf 0x007B/0x007C) */ #define BLE_HCI_RD_AUTH_PYLD_TMO_LEN (4) #define BLE_HCI_WR_AUTH_PYLD_TMO_LEN (2) @@ -477,6 +480,9 @@ /* Event encryption change (code=0x08) */ #define BLE_HCI_EVENT_ENCRYPT_CHG_LEN (4) +/* Event hardware error (code=0x10) */ +#define BLE_HCI_EVENT_HW_ERROR_LEN (1) + /* Event key refresh complete (code=0x30) */ #define BLE_HCI_EVENT_ENC_KEY_REFRESH_LEN (3) @@ -515,6 +521,9 @@ #define BLE_HCI_LE_ADV_RPT_NUM_RPTS_MIN (1) #define BLE_HCI_LE_ADV_RPT_NUM_RPTS_MAX (0x19) +/* Length of each record in an LE direct advertising report event. */ +#define BLE_HCI_LE_ADV_DIRECT_RPT_SUB_LEN (16) + /* LE connection update complete event (sub event 0x03) */ #define BLE_HCI_LE_CONN_UPD_LEN (10) diff --git a/net/nimble/include/nimble/nimble_opt.h b/net/nimble/include/nimble/nimble_opt.h index f8b08ccb..c82bcb5a 100644 --- a/net/nimble/include/nimble/nimble_opt.h +++ b/net/nimble/include/nimble/nimble_opt.h @@ -64,66 +64,70 @@ #define NIMBLE_OPT_SM_SC 0 #endif -/** HOST: Supported GATT procedures. By default, all are enabled. */ +/** + * HOST: Supported GATT procedures. By default: + * o Notify and indicate are enabled; + * o All other procedures are enabled for centrals. + */ #ifndef NIMBLE_OPT_GATT_DISC_ALL_SVCS -#define NIMBLE_OPT_GATT_DISC_ALL_SVCS 1 +#define NIMBLE_OPT_GATT_DISC_ALL_SVCS NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_DISC_SVC_UUID -#define NIMBLE_OPT_GATT_DISC_SVC_UUID 1 +#define NIMBLE_OPT_GATT_DISC_SVC_UUID NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_FIND_INC_SVCS -#define NIMBLE_OPT_GATT_FIND_INC_SVCS 1 +#define NIMBLE_OPT_GATT_FIND_INC_SVCS NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_DISC_ALL_CHRS -#define NIMBLE_OPT_GATT_DISC_ALL_CHRS 1 +#define NIMBLE_OPT_GATT_DISC_ALL_CHRS NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_DISC_CHR_UUID -#define NIMBLE_OPT_GATT_DISC_CHR_UUID 1 +#define NIMBLE_OPT_GATT_DISC_CHR_UUID NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_DISC_ALL_DSCS -#define NIMBLE_OPT_GATT_DISC_ALL_DSCS 1 +#define NIMBLE_OPT_GATT_DISC_ALL_DSCS NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_READ -#define NIMBLE_OPT_GATT_READ 1 +#define NIMBLE_OPT_GATT_READ NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_READ_UUID -#define NIMBLE_OPT_GATT_READ_UUID 1 +#define NIMBLE_OPT_GATT_READ_UUID NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_READ_LONG -#define NIMBLE_OPT_GATT_READ_LONG 1 +#define NIMBLE_OPT_GATT_READ_LONG NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_READ_MULT -#define NIMBLE_OPT_GATT_READ_MULT 1 +#define NIMBLE_OPT_GATT_READ_MULT NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_WRITE_NO_RSP -#define NIMBLE_OPT_GATT_WRITE_NO_RSP 1 +#define NIMBLE_OPT_GATT_WRITE_NO_RSP NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_SIGNED_WRITE -#define NIMBLE_OPT_GATT_SIGNED_WRITE 1 +#define NIMBLE_OPT_GATT_SIGNED_WRITE NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_WRITE -#define NIMBLE_OPT_GATT_WRITE 1 +#define NIMBLE_OPT_GATT_WRITE NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_WRITE_LONG -#define NIMBLE_OPT_GATT_WRITE_LONG 1 +#define NIMBLE_OPT_GATT_WRITE_LONG NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_WRITE_RELIABLE -#define NIMBLE_OPT_GATT_WRITE_RELIABLE 1 +#define NIMBLE_OPT_GATT_WRITE_RELIABLE NIMBLE_OPT_ROLE_CENTRAL #endif #ifndef NIMBLE_OPT_GATT_NOTIFY @@ -134,6 +138,14 @@ #define NIMBLE_OPT_GATT_INDICATE 1 #endif +/** HOST: GATT options. */ + +/* The maximum number of attributes that can be written with a single GATT + * Reliable Write procedure. + */ +#ifndef NIMBLE_OPT_GATT_WRITE_MAX_ATTRS +#define NIMBLE_OPT_GATT_WRITE_MAX_ATTRS 4 +#endif /** HOST: Supported server ATT commands. */ @@ -343,13 +355,16 @@ #endif /* - * This option allows a controller to send/receive LE pings. Currently, - * this feature is not implemented by the controller so turning it on or off - * has no effect. + * This option allows a controller to send/receive LE pings. */ +#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 0) +#undef BLE_LL_CFG_FEAT_LE_PING +#define BLE_LL_CFG_FEAT_LE_PING (0) +#else #ifndef BLE_LL_CFG_FEAT_LE_PING #define BLE_LL_CFG_FEAT_LE_PING (1) #endif +#endif /* * This option enables/disables the data length update procedure in the diff --git a/net/nimble/src/ble_util.c b/net/nimble/src/ble_util.c new file mode 100644 index 00000000..bfe7083e --- /dev/null +++ b/net/nimble/src/ble_util.c @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/os.h" +#include "nimble/ble.h" + +/** + * Converts an OS error code to its equivalent BLE_ERR code. + * + * @param os_err The OS error code to convert. + * + * @return The equivalent BLE_ERR code. + */ +int +ble_err_from_os(int os_err) +{ + switch (os_err) { + case 0: + return 0; + + case OS_ENOMEM: + return BLE_ERR_MEM_CAPACITY; + + default: + return BLE_ERR_UNSPECIFIED; + } +} diff --git a/net/nimble/src/util.c b/net/nimble/src/util.c index d0056df6..9aef1103 100644 --- a/net/nimble/src/util.c +++ b/net/nimble/src/util.c @@ -58,10 +58,10 @@ htole64(void *buf, uint64_t x) } uint16_t -le16toh(void *buf) +le16toh(const void *buf) { + const uint8_t *u8ptr; uint16_t x; - uint8_t *u8ptr; u8ptr = buf; x = u8ptr[0]; @@ -71,10 +71,10 @@ le16toh(void *buf) } uint32_t -le32toh(void *buf) +le32toh(const void *buf) { + const uint8_t *u8ptr; uint32_t x; - uint8_t *u8ptr; u8ptr = buf; x = u8ptr[0]; @@ -86,10 +86,10 @@ le32toh(void *buf) } uint64_t -le64toh(void *buf) +le64toh(const void *buf) { + const uint8_t *u8ptr; uint64_t x; - uint8_t *u8ptr; u8ptr = buf; x = u8ptr[0]; @@ -143,10 +143,10 @@ htobe64(void *buf, uint64_t x) } uint16_t -be16toh(void *buf) +be16toh(const void *buf) { + const uint8_t *u8ptr; uint16_t x; - uint8_t *u8ptr; u8ptr = buf; x = (uint16_t)u8ptr[0] << 8; @@ -156,10 +156,10 @@ be16toh(void *buf) } uint32_t -be32toh(void *buf) +be32toh(const void *buf) { + const uint8_t *u8ptr; uint32_t x; - uint8_t *u8ptr; u8ptr = buf; x = (uint32_t)u8ptr[0] << 24; @@ -171,10 +171,10 @@ be32toh(void *buf) } uint64_t -be64toh(void *buf) +be64toh(const void *buf) { + const uint8_t *u8ptr; uint64_t x; - uint8_t *u8ptr; u8ptr = buf; x = (uint64_t)u8ptr[0] << 56; @@ -208,7 +208,7 @@ swap_in_place(void *buf, int len) /* swap octets */ void -swap_buf(uint8_t *dst, uint8_t *src, int len) +swap_buf(uint8_t *dst, const uint8_t *src, int len) { int i; diff --git a/net/nimble/transport/ram/include/transport/ram/ble_hci_ram.h b/net/nimble/transport/ram/include/transport/ram/ble_hci_ram.h new file mode 100644 index 00000000..9d2d672b --- /dev/null +++ b/net/nimble/transport/ram/include/transport/ram/ble_hci_ram.h @@ -0,0 +1,30 @@ +#ifndef H_BLE_HCI_RAM_ +#define H_BLE_HCI_RAM_ + +#include "nimble/ble_hci_trans.h" + +struct ble_hci_ram_cfg { + /** Number of high-priority event buffers. */ + uint16_t num_evt_hi_bufs; + + /** Number of low-priority event buffers. */ + uint16_t num_evt_lo_bufs; + + /** Size of each event buffer, in bytes. */ + uint16_t evt_buf_sz; + + /* Note: For information about high-priority vs. low-priority event + * buffers, see net/nimble/include/nimble/ble_hci_trans.h. + */ + + /* Note: host-to-controller command buffers are not configurable. The RAM + * transport only allows one outstanding command, so it uses a single + * statically-allocated buffer. + */ +}; + +extern const struct ble_hci_ram_cfg ble_hci_ram_cfg_dflt; + +int ble_hci_ram_init(const struct ble_hci_ram_cfg *cfg); + +#endif diff --git a/net/nimble/transport/ram/pkg.yml b/net/nimble/transport/ram/pkg.yml new file mode 100644 index 00000000..a3524a19 --- /dev/null +++ b/net/nimble/transport/ram/pkg.yml @@ -0,0 +1,33 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: net/nimble/transport/ram +pkg.description: XXX +pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + +pkg.deps: + - net/nimble + - libs/os + +pkg.apis: + - ble_transport diff --git a/net/nimble/transport/ram/src/ble_hci_ram.c b/net/nimble/transport/ram/src/ble_hci_ram.c new file mode 100644 index 00000000..e3d236ea --- /dev/null +++ b/net/nimble/transport/ram/src/ble_hci_ram.c @@ -0,0 +1,229 @@ +#include <assert.h> +#include <errno.h> +#include <stddef.h> +#include "os/os.h" +#include "util/mem.h" +#include "nimble/ble.h" +#include "nimble/ble_hci_trans.h" +#include "transport/ram/ble_hci_ram.h" + +/** Default configuration. */ +const struct ble_hci_ram_cfg ble_hci_ram_cfg_dflt = { + .num_evt_hi_bufs = 2, + .num_evt_lo_bufs = 8, + + /* The largest event the nimble controller will send is 70 bytes. */ + .evt_buf_sz = 70, +}; + +static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_hs_cb; +static void *ble_hci_ram_rx_cmd_hs_arg; + +static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_ll_cb; +static void *ble_hci_ram_rx_cmd_ll_arg; + +static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_hs_cb; +static void *ble_hci_ram_rx_acl_hs_arg; + +static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_ll_cb; +static void *ble_hci_ram_rx_acl_ll_arg; + +static struct os_mempool ble_hci_ram_evt_hi_pool; +static void *ble_hci_ram_evt_hi_buf; +static struct os_mempool ble_hci_ram_evt_lo_pool; +static void *ble_hci_ram_evt_lo_buf; + +static uint8_t *ble_hci_ram_hs_cmd_buf; +static uint8_t ble_hci_ram_hs_cmd_buf_alloced; + +void +ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg) +{ + ble_hci_ram_rx_cmd_hs_cb = cmd_cb; + ble_hci_ram_rx_cmd_hs_arg = cmd_arg; + ble_hci_ram_rx_acl_hs_cb = acl_cb; + ble_hci_ram_rx_acl_hs_arg = acl_arg; +} + +void +ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg) +{ + ble_hci_ram_rx_cmd_ll_cb = cmd_cb; + ble_hci_ram_rx_cmd_ll_arg = cmd_arg; + ble_hci_ram_rx_acl_ll_cb = acl_cb; + ble_hci_ram_rx_acl_ll_arg = acl_arg; +} + +int +ble_hci_trans_hs_cmd_tx(uint8_t *cmd) +{ + int rc; + + assert(ble_hci_ram_rx_cmd_ll_cb != NULL); + + rc = ble_hci_ram_rx_cmd_ll_cb(cmd, ble_hci_ram_rx_cmd_ll_arg); + return rc; +} + +int +ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) +{ + int rc; + + assert(ble_hci_ram_rx_cmd_hs_cb != NULL); + + rc = ble_hci_ram_rx_cmd_hs_cb(hci_ev, ble_hci_ram_rx_cmd_hs_arg); + return rc; +} + +int +ble_hci_trans_hs_acl_tx(struct os_mbuf *om) +{ + int rc; + + assert(ble_hci_ram_rx_acl_ll_cb != NULL); + + rc = ble_hci_ram_rx_acl_ll_cb(om, ble_hci_ram_rx_acl_ll_arg); + return rc; +} + +int +ble_hci_trans_ll_acl_tx(struct os_mbuf *om) +{ + int rc; + + assert(ble_hci_ram_rx_acl_hs_cb != NULL); + + rc = ble_hci_ram_rx_acl_hs_cb(om, ble_hci_ram_rx_acl_hs_arg); + return rc; +} + +uint8_t * +ble_hci_trans_buf_alloc(int type) +{ + uint8_t *buf; + + switch (type) { + case BLE_HCI_TRANS_BUF_EVT_HI: + buf = os_memblock_get(&ble_hci_ram_evt_hi_pool); + if (buf == NULL) { + /* If no high-priority event buffers remain, try to grab a + * low-priority one. + */ + buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + } + break; + + case BLE_HCI_TRANS_BUF_EVT_LO: + buf = os_memblock_get(&ble_hci_ram_evt_lo_pool); + break; + + case BLE_HCI_TRANS_BUF_CMD: + assert(!ble_hci_ram_hs_cmd_buf_alloced); + ble_hci_ram_hs_cmd_buf_alloced = 1; + buf = ble_hci_ram_hs_cmd_buf; + break; + + default: + assert(0); + buf = NULL; + } + + return buf; +} + +void +ble_hci_trans_buf_free(uint8_t *buf) +{ + int rc; + + if (buf == ble_hci_ram_hs_cmd_buf) { + assert(ble_hci_ram_hs_cmd_buf_alloced); + ble_hci_ram_hs_cmd_buf_alloced = 0; + } else if (os_memblock_from(&ble_hci_ram_evt_hi_pool, buf)) { + rc = os_memblock_put(&ble_hci_ram_evt_hi_pool, buf); + assert(rc == 0); + } else { + assert(os_memblock_from(&ble_hci_ram_evt_lo_pool, buf)); + rc = os_memblock_put(&ble_hci_ram_evt_lo_pool, buf); + assert(rc == 0); + } +} + +static void +ble_hci_ram_free_mem(void) +{ + free(ble_hci_ram_evt_hi_buf); + ble_hci_ram_evt_hi_buf = NULL; + + free(ble_hci_ram_evt_lo_buf); + ble_hci_ram_evt_lo_buf = NULL; + + free(ble_hci_ram_hs_cmd_buf); + ble_hci_ram_hs_cmd_buf = NULL; + ble_hci_ram_hs_cmd_buf_alloced = 0; +} + +int +ble_hci_trans_reset(void) +{ + /* No work to do. All allocated buffers are owned by the host or + * controller, and they will get freed by their owners. + */ + return 0; +} + +/** + * Initializes the RAM HCI transport module. + * + * @param cfg The settings to initialize the HCI RAM + * transport with. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_hci_ram_init(const struct ble_hci_ram_cfg *cfg) +{ + int rc; + + ble_hci_ram_free_mem(); + + rc = mem_malloc_mempool(&ble_hci_ram_evt_hi_pool, + cfg->num_evt_hi_bufs, + cfg->evt_buf_sz, + "ble_hci_ram_evt_hi_pool", + &ble_hci_ram_evt_hi_buf); + if (rc != 0) { + rc = ble_err_from_os(rc); + goto err; + } + + rc = mem_malloc_mempool(&ble_hci_ram_evt_lo_pool, + cfg->num_evt_lo_bufs, + cfg->evt_buf_sz, + "ble_hci_ram_evt_lo_pool", + &ble_hci_ram_evt_lo_buf); + if (rc != 0) { + rc = ble_err_from_os(rc); + goto err; + } + + ble_hci_ram_hs_cmd_buf = malloc(BLE_HCI_TRANS_CMD_SZ); + if (ble_hci_ram_hs_cmd_buf == NULL) { + rc = BLE_ERR_MEM_CAPACITY; + goto err; + } + + return 0; + +err: + ble_hci_ram_free_mem(); + return rc; +} diff --git a/net/nimble/transport/uart/include/transport/uart/ble_hci_uart.h b/net/nimble/transport/uart/include/transport/uart/ble_hci_uart.h new file mode 100644 index 00000000..1fbaa747 --- /dev/null +++ b/net/nimble/transport/uart/include/transport/uart/ble_hci_uart.h @@ -0,0 +1,19 @@ +#ifndef H_BLE_HCI_UART_ +#define H_BLE_HCI_UART_ + +struct ble_hci_uart_cfg { + uint32_t baud; + uint16_t num_evt_bufs; + uint16_t evt_buf_sz; + uint8_t uart_port; + uint8_t flow_ctrl; + uint8_t data_bits; + uint8_t stop_bits; + uint8_t parity; +}; + +extern const struct ble_hci_uart_cfg ble_hci_uart_cfg_dflt; + +int ble_hci_uart_init(const struct ble_hci_uart_cfg *cfg); + +#endif diff --git a/net/nimble/transport/uart/pkg.yml b/net/nimble/transport/uart/pkg.yml new file mode 100644 index 00000000..cce429c9 --- /dev/null +++ b/net/nimble/transport/uart/pkg.yml @@ -0,0 +1,34 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: net/nimble/transport/uart +pkg.description: XXX +pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + +pkg.deps: + - hw/hal + - libs/os + - net/nimble + +pkg.apis: + - ble_transport diff --git a/net/nimble/transport/uart/src/ble_hci_uart.c b/net/nimble/transport/uart/src/ble_hci_uart.c new file mode 100755 index 00000000..0fa982a8 --- /dev/null +++ b/net/nimble/transport/uart/src/ble_hci_uart.c @@ -0,0 +1,743 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include "bsp/bsp.h" +#include "os/os.h" +#include "util/mem.h" +#include "hal/hal_gpio.h" +#include "hal/hal_cputime.h" +#include "hal/hal_uart.h" + +/* BLE */ +#include "nimble/ble.h" +#include "nimble/nimble_opt.h" +#include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" + +#include "transport/uart/ble_hci_uart.h" + +/*** + * NOTE: + * The UART HCI transport doesn't use event buffer priorities. All incoming + * and outgoing events and commands use buffers from the same pool. + */ + +#define BLE_HCI_UART_H4_NONE 0x00 +#define BLE_HCI_UART_H4_CMD 0x01 +#define BLE_HCI_UART_H4_ACL 0x02 +#define BLE_HCI_UART_H4_SCO 0x03 +#define BLE_HCI_UART_H4_EVT 0x04 + +/** Default configuration. */ +const struct ble_hci_uart_cfg ble_hci_uart_cfg_dflt = { + .uart_port = 0, + .baud = 1000000, + .flow_ctrl = HAL_UART_FLOW_CTL_RTS_CTS, + .data_bits = 8, + .stop_bits = 1, + .parity = HAL_UART_PARITY_NONE, + + .num_evt_bufs = 8, + .evt_buf_sz = BLE_HCI_TRANS_CMD_SZ, +}; + +static ble_hci_trans_rx_cmd_fn *ble_hci_uart_rx_cmd_cb; +static void *ble_hci_uart_rx_cmd_arg; + +static ble_hci_trans_rx_acl_fn *ble_hci_uart_rx_acl_cb; +static void *ble_hci_uart_rx_acl_arg; + +static struct os_mempool ble_hci_uart_evt_pool; +static void *ble_hci_uart_evt_buf; + +static struct os_mempool ble_hci_uart_pkt_pool; +static void *ble_hci_uart_pkt_buf; + +/** + * An incoming or outgoing command or event. + */ +struct ble_hci_uart_cmd { + uint8_t *data; /* Pointer to ble_hci_uart_cmd data */ + uint16_t cur; /* Number of bytes read/written */ + uint16_t len; /* Total number of bytes to read/write */ +}; + +/** + * An incoming ACL data packet. + */ +struct ble_hci_uart_acl { + struct os_mbuf *buf; /* Buffer containing the data */ + uint16_t len; /* Target size when buf is considered complete */ +}; + +/** + * A packet to be sent over the UART. This can be a command, an event, or ACL + * data. + */ +struct ble_hci_uart_pkt { + STAILQ_ENTRY(ble_hci_uart_pkt) next; + void *data; + uint8_t type; +}; + +static struct { + /*** State of data received over UART. */ + uint8_t rx_type; /* Pending packet type. 0 means nothing pending */ + union { + struct ble_hci_uart_cmd rx_cmd; + struct ble_hci_uart_acl rx_acl; + }; + + /*** State of data transmitted over UART. */ + uint8_t tx_type; /* Pending packet type. 0 means nothing pending */ + union { + struct ble_hci_uart_cmd tx_cmd; + struct os_mbuf *tx_acl; + }; + STAILQ_HEAD(, ble_hci_uart_pkt) tx_pkts; /* Packet queue to send to UART */ +} ble_hci_uart_state; + +static struct ble_hci_uart_cfg ble_hci_uart_cfg; + +static int +ble_hci_uart_acl_tx(struct os_mbuf *om) +{ + struct ble_hci_uart_pkt *pkt; + os_sr_t sr; + + pkt = os_memblock_get(&ble_hci_uart_pkt_pool); + if (pkt == NULL) { + os_mbuf_free_chain(om); + return BLE_ERR_MEM_CAPACITY; + } + + pkt->type = BLE_HCI_UART_H4_ACL; + pkt->data = om; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&ble_hci_uart_state.tx_pkts, pkt, next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(ble_hci_uart_cfg.uart_port); + + return 0; +} + +static int +ble_hci_uart_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) +{ + struct ble_hci_uart_pkt *pkt; + os_sr_t sr; + + pkt = os_memblock_get(&ble_hci_uart_pkt_pool); + if (pkt == NULL) { + ble_hci_trans_buf_free(hci_ev); + return BLE_ERR_MEM_CAPACITY; + } + + pkt->type = h4_type; + pkt->data = hci_ev; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&ble_hci_uart_state.tx_pkts, pkt, next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(ble_hci_uart_cfg.uart_port); + + return 0; +} + +/** + * @return The packet type to transmit on success; + * -1 if there is nothing to send. + */ +static int +ble_hci_uart_tx_pkt_type(void) +{ + struct ble_hci_uart_pkt *pkt; + os_sr_t sr; + int rc; + + OS_ENTER_CRITICAL(sr); + + pkt = STAILQ_FIRST(&ble_hci_uart_state.tx_pkts); + if (!pkt) { + OS_EXIT_CRITICAL(sr); + return -1; + } + + STAILQ_REMOVE(&ble_hci_uart_state.tx_pkts, pkt, ble_hci_uart_pkt, next); + + OS_EXIT_CRITICAL(sr); + + rc = pkt->type; + switch (pkt->type) { + case BLE_HCI_UART_H4_CMD: + ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_CMD; + ble_hci_uart_state.tx_cmd.data = pkt->data; + ble_hci_uart_state.tx_cmd.cur = 0; + ble_hci_uart_state.tx_cmd.len = ble_hci_uart_state.tx_cmd.data[2] + + BLE_HCI_CMD_HDR_LEN; + break; + + case BLE_HCI_UART_H4_EVT: + ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_EVT; + ble_hci_uart_state.tx_cmd.data = pkt->data; + ble_hci_uart_state.tx_cmd.cur = 0; + ble_hci_uart_state.tx_cmd.len = ble_hci_uart_state.tx_cmd.data[1] + + BLE_HCI_EVENT_HDR_LEN; + break; + + case BLE_HCI_UART_H4_ACL: + ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_ACL; + ble_hci_uart_state.tx_acl = pkt->data; + break; + + default: + rc = -1; + break; + } + + os_memblock_put(&ble_hci_uart_pkt_pool, pkt); + + return rc; +} + +/** + * @return The byte to transmit on success; + * -1 if there is nothing to send. + */ +static int +ble_hci_uart_tx_char(void *arg) +{ + int rc = -1; + + switch (ble_hci_uart_state.tx_type) { + case BLE_HCI_UART_H4_NONE: /* No pending packet, pick one from the queue */ + rc = ble_hci_uart_tx_pkt_type(); + break; + + case BLE_HCI_UART_H4_CMD: + case BLE_HCI_UART_H4_EVT: + rc = ble_hci_uart_state.tx_cmd.data[ble_hci_uart_state.tx_cmd.cur++]; + + if (ble_hci_uart_state.tx_cmd.cur == ble_hci_uart_state.tx_cmd.len) { + ble_hci_trans_buf_free(ble_hci_uart_state.tx_cmd.data); + ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE; + } + break; + + case BLE_HCI_UART_H4_ACL: + rc = *OS_MBUF_DATA(ble_hci_uart_state.tx_acl, uint8_t *); + os_mbuf_adj(ble_hci_uart_state.tx_acl, 1); + if (!OS_MBUF_PKTLEN(ble_hci_uart_state.tx_acl)) { + os_mbuf_free_chain(ble_hci_uart_state.tx_acl); + ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE; + } + break; + } + + return rc; +} + +/** + * @return The type of packet to follow success; + * -1 if there is no valid packet to receive. + */ +static int +ble_hci_uart_rx_pkt_type(uint8_t data) +{ + ble_hci_uart_state.rx_type = data; + + /* XXX: For now we assert that buffer allocation succeeds. The correct + * thing to do is return -1 on allocation failure so that flow control is + * engaged. Then, we will need to tell the UART to start receiving again + * as follows: + * o flat buf: when we free a buffer. + * o mbuf: periodically? (which task executes the callout?) + */ + switch (ble_hci_uart_state.rx_type) { + case BLE_HCI_UART_H4_CMD: + ble_hci_uart_state.rx_cmd.data = + ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + assert(ble_hci_uart_state.rx_cmd.data != NULL); + + ble_hci_uart_state.rx_cmd.len = 0; + ble_hci_uart_state.rx_cmd.cur = 0; + break; + + case BLE_HCI_UART_H4_EVT: + ble_hci_uart_state.rx_cmd.data = + ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + assert(ble_hci_uart_state.rx_cmd.data != NULL); + + ble_hci_uart_state.rx_cmd.len = 0; + ble_hci_uart_state.rx_cmd.cur = 0; + break; + + case BLE_HCI_UART_H4_ACL: + ble_hci_uart_state.rx_acl.buf = + os_msys_get_pkthdr(BLE_HCI_DATA_HDR_SZ, 0); + assert(ble_hci_uart_state.rx_acl.buf != NULL); + + ble_hci_uart_state.rx_acl.len = 0; + break; + + default: + ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; + return -1; + } + + return 0; +} + +static void +ble_hci_uart_rx_cmd(uint8_t data) +{ + int rc; + + ble_hci_uart_state.rx_cmd.data[ble_hci_uart_state.rx_cmd.cur++] = data; + + if (ble_hci_uart_state.rx_cmd.cur < BLE_HCI_CMD_HDR_LEN) { + return; + } + + if (ble_hci_uart_state.rx_cmd.cur == BLE_HCI_CMD_HDR_LEN) { + ble_hci_uart_state.rx_cmd.len = ble_hci_uart_state.rx_cmd.data[2] + + BLE_HCI_CMD_HDR_LEN; + } + + if (ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) { + assert(ble_hci_uart_rx_cmd_cb != NULL); + rc = ble_hci_uart_rx_cmd_cb(ble_hci_uart_state.rx_cmd.data, + ble_hci_uart_rx_cmd_arg); + if (rc != 0) { + ble_hci_trans_buf_free(ble_hci_uart_state.rx_cmd.data); + } + ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; + } +} + +static void +ble_hci_uart_rx_evt(uint8_t data) +{ + int rc; + + ble_hci_uart_state.rx_cmd.data[ble_hci_uart_state.rx_cmd.cur++] = data; + + if (ble_hci_uart_state.rx_cmd.cur < BLE_HCI_EVENT_HDR_LEN) { + return; + } + + if (ble_hci_uart_state.rx_cmd.cur == BLE_HCI_EVENT_HDR_LEN) { + ble_hci_uart_state.rx_cmd.len = ble_hci_uart_state.rx_cmd.data[1] + + BLE_HCI_EVENT_HDR_LEN; + } + + if (ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) { + assert(ble_hci_uart_rx_cmd_cb != NULL); + rc = ble_hci_uart_rx_cmd_cb(ble_hci_uart_state.rx_cmd.data, + ble_hci_uart_rx_cmd_arg); + if (rc != 0) { + ble_hci_trans_buf_free(ble_hci_uart_state.rx_cmd.data); + } + ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; + } +} + +static void +ble_hci_uart_rx_acl(uint8_t data) +{ + uint16_t pktlen; + + os_mbuf_append(ble_hci_uart_state.rx_acl.buf, &data, 1); + + pktlen = OS_MBUF_PKTLEN(ble_hci_uart_state.rx_acl.buf); + + if (pktlen < BLE_HCI_DATA_HDR_SZ) { + return; + } + + if (pktlen == BLE_HCI_DATA_HDR_SZ) { + os_mbuf_copydata(ble_hci_uart_state.rx_acl.buf, 2, + sizeof(ble_hci_uart_state.rx_acl.len), + &ble_hci_uart_state.rx_acl.len); + ble_hci_uart_state.rx_acl.len = + le16toh(&ble_hci_uart_state.rx_acl.len) + BLE_HCI_DATA_HDR_SZ; + } + + if (pktlen == ble_hci_uart_state.rx_acl.len) { + assert(ble_hci_uart_rx_cmd_cb != NULL); + ble_hci_uart_rx_acl_cb(ble_hci_uart_state.rx_acl.buf, + ble_hci_uart_rx_acl_arg); + ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; + } +} + +static int +ble_hci_uart_rx_char(void *arg, uint8_t data) +{ + switch (ble_hci_uart_state.rx_type) { + case BLE_HCI_UART_H4_NONE: + return ble_hci_uart_rx_pkt_type(data); + case BLE_HCI_UART_H4_CMD: + ble_hci_uart_rx_cmd(data); + return 0; + case BLE_HCI_UART_H4_EVT: + ble_hci_uart_rx_evt(data); + return 0; + case BLE_HCI_UART_H4_ACL: + ble_hci_uart_rx_acl(data); + return 0; + default: + return -1; + } +} + +static void +ble_hci_uart_set_rx_cbs(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg) +{ + ble_hci_uart_rx_cmd_cb = cmd_cb; + ble_hci_uart_rx_cmd_arg = cmd_arg; + ble_hci_uart_rx_acl_cb = acl_cb; + ble_hci_uart_rx_acl_arg = acl_arg; +} + +static void +ble_hci_uart_free_pkt(uint8_t type, uint8_t *cmdevt, struct os_mbuf *acl) +{ + switch (type) { + case BLE_HCI_UART_H4_NONE: + break; + + case BLE_HCI_UART_H4_CMD: + case BLE_HCI_UART_H4_EVT: + ble_hci_trans_buf_free(cmdevt); + break; + + case BLE_HCI_UART_H4_ACL: + os_mbuf_free_chain(acl); + break; + + default: + assert(0); + break; + } +} + +static void +ble_hci_uart_free_mem(void) +{ + free(ble_hci_uart_evt_buf); + ble_hci_uart_evt_buf = NULL; + + free(ble_hci_uart_pkt_buf); + ble_hci_uart_pkt_buf = NULL; +} + +static int +ble_hci_uart_config(void) +{ + int rc; + + rc = hal_uart_init_cbs(ble_hci_uart_cfg.uart_port, + ble_hci_uart_tx_char, NULL, + ble_hci_uart_rx_char, NULL); + if (rc != 0) { + return BLE_ERR_UNSPECIFIED; + } + + rc = hal_uart_config(ble_hci_uart_cfg.uart_port, + ble_hci_uart_cfg.baud, + ble_hci_uart_cfg.data_bits, + ble_hci_uart_cfg.stop_bits, + ble_hci_uart_cfg.parity, + ble_hci_uart_cfg.flow_ctrl); + if (rc != 0) { + return BLE_ERR_HW_FAIL; + } + + return 0; +} + +/** + * Sends an HCI event from the controller to the host. + * + * @param cmd The HCI event to send. This buffer must be + * allocated via ble_hci_trans_buf_alloc(). + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_hci_trans_ll_evt_tx(uint8_t *cmd) +{ + int rc; + + rc = ble_hci_uart_cmdevt_tx(cmd, BLE_HCI_UART_H4_EVT); + return rc; +} + +/** + * Sends ACL data from controller to host. + * + * @param om The ACL data packet to send. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_hci_trans_ll_acl_tx(struct os_mbuf *om) +{ + int rc; + + rc = ble_hci_uart_acl_tx(om); + return rc; +} + +/** + * Sends an HCI command from the host to the controller. + * + * @param cmd The HCI command to send. This buffer must be + * allocated via ble_hci_trans_buf_alloc(). + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_hci_trans_hs_cmd_tx(uint8_t *cmd) +{ + int rc; + + rc = ble_hci_uart_cmdevt_tx(cmd, BLE_HCI_UART_H4_CMD); + return rc; +} + +/** + * Sends ACL data from host to controller. + * + * @param om The ACL data packet to send. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_hci_trans_hs_acl_tx(struct os_mbuf *om) +{ + int rc; + + rc = ble_hci_uart_acl_tx(om); + return rc; +} + +/** + * Configures the HCI transport to call the specified callback upon receiving + * HCI packets from the controller. This function should only be called by by + * host. + * + * @param cmd_cb The callback to execute upon receiving an HCI + * event. + * @param cmd_arg Optional argument to pass to the command + * callback. + * @param acl_cb The callback to execute upon receiving ACL + * data. + * @param acl_arg Optional argument to pass to the ACL + * callback. + */ +void +ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg) +{ + ble_hci_uart_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg); +} + +/** + * Configures the HCI transport to operate with a host. The transport will + * execute specified callbacks upon receiving HCI packets from the controller. + * + * @param cmd_cb The callback to execute upon receiving an HCI + * event. + * @param cmd_arg Optional argument to pass to the command + * callback. + * @param acl_cb The callback to execute upon receiving ACL + * data. + * @param acl_arg Optional argument to pass to the ACL + * callback. + */ +void +ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg) +{ + ble_hci_uart_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg); +} + +/** + * Allocates a flat buffer of the specified type. + * + * @param type The type of buffer to allocate; one of the + * BLE_HCI_TRANS_BUF_[...] constants. + * + * @return The allocated buffer on success; + * NULL on buffer exhaustion. + */ +uint8_t * +ble_hci_trans_buf_alloc(int type) +{ + uint8_t *buf; + + switch (type) { + case BLE_HCI_TRANS_BUF_CMD: + case BLE_HCI_TRANS_BUF_EVT_LO: + case BLE_HCI_TRANS_BUF_EVT_HI: + buf = os_memblock_get(&ble_hci_uart_evt_pool); + break; + + default: + assert(0); + buf = NULL; + } + + return buf; +} + +/** + * Frees the specified flat buffer. The buffer must have been allocated via + * ble_hci_trans_buf_alloc(). + * + * @param buf The buffer to free. + */ +void +ble_hci_trans_buf_free(uint8_t *buf) +{ + int rc; + + rc = os_memblock_put(&ble_hci_uart_evt_pool, buf); + assert(rc == 0); +} + +/** + * Resets the HCI UART transport to a clean state. Frees all buffers and + * reconfigures the UART. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_hci_trans_reset(void) +{ + struct ble_hci_uart_pkt *pkt; + int rc; + + /* Close the UART to prevent race conditions as the buffers are freed. */ + rc = hal_uart_close(ble_hci_uart_cfg.uart_port); + if (rc != 0) { + return BLE_ERR_HW_FAIL; + } + + ble_hci_uart_free_pkt(ble_hci_uart_state.rx_type, + ble_hci_uart_state.rx_cmd.data, + ble_hci_uart_state.rx_acl.buf); + ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; + + ble_hci_uart_free_pkt(ble_hci_uart_state.tx_type, + ble_hci_uart_state.tx_cmd.data, + ble_hci_uart_state.tx_acl); + ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE; + + while ((pkt = STAILQ_FIRST(&ble_hci_uart_state.tx_pkts)) != NULL) { + STAILQ_REMOVE(&ble_hci_uart_state.tx_pkts, pkt, ble_hci_uart_pkt, + next); + ble_hci_uart_free_pkt(pkt->type, pkt->data, pkt->data); + os_memblock_put(&ble_hci_uart_pkt_pool, pkt); + } + + /* Reopen the UART. */ + rc = ble_hci_uart_config(); + if (rc != 0) { + return rc; + } + + return 0; +} + +/** + * Initializes the UART HCI transport module. + * + * @param cfg The settings to initialize the HCI UART + * transport with. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_hci_uart_init(const struct ble_hci_uart_cfg *cfg) +{ + int rc; + + ble_hci_uart_free_mem(); + + ble_hci_uart_cfg = *cfg; + + /* Create memory pool of HCI command / event buffers */ + rc = mem_malloc_mempool(&ble_hci_uart_evt_pool, + cfg->num_evt_bufs, + cfg->evt_buf_sz, + "ble_hci_uart_evt_pool", + &ble_hci_uart_evt_buf); + if (rc != 0) { + rc = ble_err_from_os(rc); + goto err; + } + + /* Create memory pool of packet list nodes. */ + rc = mem_malloc_mempool(&ble_hci_uart_pkt_pool, + cfg->num_evt_bufs, + sizeof (struct ble_hci_uart_pkt), + "ble_hci_uart_pkt_pool", + &ble_hci_uart_pkt_buf); + if (rc != 0) { + rc = ble_err_from_os(rc); + goto err; + } + + rc = ble_hci_uart_config(); + if (rc != 0) { + goto err; + } + + memset(&ble_hci_uart_state, 0, sizeof ble_hci_uart_state); + STAILQ_INIT(&ble_hci_uart_state.tx_pkts); + + return 0; + +err: + ble_hci_uart_free_mem(); + return rc; +} |