You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2020/05/18 09:27:21 UTC
[mynewt-nimble] 02/02: nimble/ll: Add controller-to-host flow
control support
This is an automated email from the ASF dual-hosted git repository.
andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 8341bfa7f5844ec1fb379efcd5c5935141e9e0a6
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Mon May 4 15:56:09 2020 +0200
nimble/ll: Add controller-to-host flow control support
---
nimble/controller/include/controller/ble_ll.h | 6 +
nimble/controller/include/controller/ble_ll_conn.h | 4 +
nimble/controller/src/ble_ll_conn.c | 216 ++++++++++++++++++++-
nimble/controller/src/ble_ll_conn_priv.h | 6 +
nimble/controller/src/ble_ll_hci.c | 102 +++++++++-
nimble/controller/src/ble_ll_supp_cmd.c | 17 +-
nimble/controller/syscfg.yml | 7 +
nimble/include/nimble/ble.h | 9 +-
8 files changed, 354 insertions(+), 13 deletions(-)
diff --git a/nimble/controller/include/controller/ble_ll.h b/nimble/controller/include/controller/ble_ll.h
index 47d3ac4..5f9e236 100644
--- a/nimble/controller/include/controller/ble_ll.h
+++ b/nimble/controller/include/controller/ble_ll.h
@@ -396,6 +396,12 @@ struct ble_dev_addr
#define BLE_LL_LLID_DATA_START (2)
#define BLE_LL_LLID_CTRL (3)
+#define BLE_LL_LLID_IS_CTRL(hdr) \
+ (((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL)
+#define BLE_LL_LLID_IS_DATA(hdr) \
+ ((((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_DATA_START) || \
+ (((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_DATA_FRAG))
+
/*
* CONNECT_REQ
* -> InitA (6 bytes)
diff --git a/nimble/controller/include/controller/ble_ll_conn.h b/nimble/controller/include/controller/ble_ll_conn.h
index 94ea42c..8c07462 100644
--- a/nimble/controller/include/controller/ble_ll_conn.h
+++ b/nimble/controller/include/controller/ble_ll_conn.h
@@ -272,6 +272,10 @@ struct ble_ll_conn_sm
uint8_t last_rxd_hdr_byte; /* note: possibly can make 1 bit since we
only use the MD bit now */
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+ uint16_t cth_flow_pending;
+#endif
+
/* connection event mgmt */
uint8_t reject_reason;
uint8_t host_reply_opcode;
diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c
index c5a2a41..8799ff2 100644
--- a/nimble/controller/src/ble_ll_conn.c
+++ b/nimble/controller/src/ble_ll_conn.c
@@ -225,6 +225,166 @@ STATS_NAME_END(ble_ll_conn_stats)
static void ble_ll_conn_event_end(struct ble_npl_event *ev);
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+struct ble_ll_conn_cth_flow {
+ bool enabled;
+ uint16_t max_buffers;
+ uint16_t num_buffers;
+};
+
+static struct ble_ll_conn_cth_flow g_ble_ll_conn_cth_flow;
+
+static struct ble_npl_event g_ble_ll_conn_cth_flow_error_ev;
+
+static bool
+ble_ll_conn_cth_flow_is_enabled(void)
+{
+ return g_ble_ll_conn_cth_flow.enabled;
+}
+
+static bool
+ble_ll_conn_cth_flow_alloc_credit(struct ble_ll_conn_sm *connsm)
+{
+ struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow;
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+
+ if (!cth->num_buffers) {
+ OS_EXIT_CRITICAL(sr);
+ return false;
+ }
+
+ connsm->cth_flow_pending++;
+ cth->num_buffers--;
+
+ OS_EXIT_CRITICAL(sr);
+
+ return true;
+}
+
+static void
+ble_ll_conn_cth_flow_free_credit(struct ble_ll_conn_sm *connsm, uint16_t credits)
+{
+ struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow;
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+
+ /*
+ * It's not quite clear what we should do if host gives back more credits
+ * that we have allocated. For now let's just set invalid values back to
+ * sane values and continue.
+ */
+
+ cth->num_buffers += credits;
+ if (cth->num_buffers > cth->max_buffers) {
+ cth->num_buffers = cth->max_buffers;
+ }
+
+ if (connsm->cth_flow_pending < credits) {
+ connsm->cth_flow_pending = 0;
+ } else {
+ connsm->cth_flow_pending -= credits;
+ }
+
+ OS_EXIT_CRITICAL(sr);
+}
+
+static void
+ble_ll_conn_cth_flow_error_fn(struct ble_npl_event *ev)
+{
+ struct ble_hci_ev *hci_ev;
+ struct ble_hci_ev_command_complete *hci_ev_cp;
+ uint16_t opcode;
+
+ hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+ if (!hci_ev) {
+ /* Not much we can do anyway... */
+ return;
+ }
+
+ /*
+ * We are here in case length of HCI_Host_Number_Of_Completed_Packets was
+ * invalid. We will send an error back to host and we can only hope host is
+ * reasonable and will do some actions to recover, e.g. it should disconnect
+ * all connections to guarantee that all credits are back in pool and we're
+ * back in sync (although spec does not really say what should happen).
+ */
+
+ opcode = BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND,
+ BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS);
+
+ hci_ev->opcode = BLE_HCI_EVCODE_COMMAND_COMPLETE;
+ hci_ev->length = sizeof(*hci_ev_cp);
+
+ hci_ev_cp = (void *)hci_ev->data;
+ hci_ev_cp->num_packets = BLE_LL_CFG_NUM_HCI_CMD_PKTS;
+ hci_ev_cp->opcode = htole16(opcode);
+ hci_ev_cp->status = BLE_ERR_INV_HCI_CMD_PARMS;
+
+ ble_ll_hci_event_send(hci_ev);
+}
+
+void
+ble_ll_conn_cth_flow_set_buffers(uint16_t num_buffers)
+{
+ BLE_LL_ASSERT(num_buffers);
+
+ g_ble_ll_conn_cth_flow.max_buffers = num_buffers;
+ g_ble_ll_conn_cth_flow.num_buffers = num_buffers;
+}
+
+bool
+ble_ll_conn_cth_flow_enable(bool enabled)
+{
+ struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow;
+
+ if (cth->enabled == enabled) {
+ return true;
+ }
+
+ if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) {
+ return false;
+ }
+
+ cth->enabled = enabled;
+
+ return true;
+}
+
+void
+ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf)
+{
+ const struct ble_hci_cmd *cmd;
+ const struct ble_hci_cb_host_num_comp_pkts_cp *cp;
+ struct ble_ll_conn_sm *connsm;
+ int i;
+
+ cmd = (const void *)cmdbuf;
+ cp = (const void *)cmd->data;
+
+ if (cmd->length != sizeof(cp->handles) + cp->handles * sizeof(cp->h[0])) {
+ ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_conn_cth_flow_error_ev);
+ return;
+ }
+
+ for (i = 0; i < cp->handles; i++) {
+ /*
+ * It's probably ok that we do not have active connection with given
+ * handle - this can happen if disconnection already happened in LL but
+ * host sent credits back before processing disconnection event. In such
+ * case we can simply ignore command for that connection since credits
+ * are returned by LL already.
+ */
+ connsm = ble_ll_conn_find_active_conn(cp->h[i].handle);
+ if (connsm) {
+ ble_ll_conn_cth_flow_free_credit(connsm, cp->h[i].count);
+ }
+ }
+}
+#endif
+
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
/**
* Checks to see if we should start a PHY update procedure
@@ -1861,6 +2021,10 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
/* Remove from the active connection list */
SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle);
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_HOST_TO_CTRL_FLOW_CONTROL)
+ ble_ll_conn_cth_flow_free_credit(connsm, connsm->cth_flow_pending);
+#endif
+
/* Free the current transmit pdu if there is one. */
if (connsm->cur_tx_pdu) {
os_mbuf_free_chain(connsm->cur_tx_pdu);
@@ -3577,6 +3741,13 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
/* Free buffer */
conn_rx_data_pdu_end:
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+ /* Need to give credit back if we allocated one for this PDU */
+ if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_CREDIT) {
+ ble_ll_conn_cth_flow_free_credit(connsm, 1);
+ }
+#endif
+
os_mbuf_free_chain(rxpdu);
}
@@ -3597,7 +3768,6 @@ int
ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
{
int rc;
- int is_ctrl;
uint8_t hdr_byte;
uint8_t hdr_sn;
uint8_t hdr_nesn;
@@ -3616,6 +3786,9 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
int rx_phy_mode;
bool alloc_rxpdu = true;
+ rc = -1;
+ connsm = g_ble_ll_conn_cur_sm;
+
/* Retrieve the header and payload length */
hdr_byte = rxbuf[0];
rx_pyld_len = rxbuf[1];
@@ -3628,6 +3801,23 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
alloc_rxpdu = false;
}
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+ /*
+ * If flow control is enabled, we need to have credit available for each
+ * non-empty data packet that LL may send to host. If there are no credits
+ * available, we don't need to allocate buffer for this packet so LL will
+ * nak it.
+ */
+ if (ble_ll_conn_cth_flow_is_enabled() &&
+ BLE_LL_LLID_IS_DATA(hdr_byte) && (rx_pyld_len > 0)) {
+ if (ble_ll_conn_cth_flow_alloc_credit(connsm)) {
+ rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT;
+ } else {
+ alloc_rxpdu = false;
+ }
+ }
+#endif
+
/*
* 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
@@ -3643,8 +3833,6 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
* We should have a current connection state machine. If we dont, we just
* hand the packet to the higher layer to count it.
*/
- rc = -1;
- connsm = g_ble_ll_conn_cur_sm;
if (!connsm) {
STATS_INC(ble_ll_conn_stats, rx_data_pdu_no_conn);
goto conn_exit;
@@ -3706,9 +3894,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
/* Set last received header byte */
connsm->last_rxd_hdr_byte = hdr_byte;
- is_ctrl = 0;
- if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) {
- is_ctrl = 1;
+ if (BLE_LL_LLID_IS_CTRL(hdr_byte)) {
opcode = rxbuf[2];
}
@@ -3797,7 +3983,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
/* Adjust payload for max TX time and octets */
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
- if (is_ctrl &&
+ if (BLE_LL_LLID_IS_CTRL(hdr_byte) &&
(connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) &&
(opcode == BLE_LL_CTRL_PHY_UPDATE_IND)) {
connsm->phy_tx_transition =
@@ -3816,8 +4002,9 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
/* If this is a TERMINATE_IND, we have to reply */
chk_rx_terminate_ind:
/* If we received a terminate IND, we must set some flags */
- if (is_ctrl && (opcode == BLE_LL_CTRL_TERMINATE_IND)
- && (rx_pyld_len == (1 + BLE_LL_CTRL_TERMINATE_IND_LEN))) {
+ if (BLE_LL_LLID_IS_CTRL(hdr_byte) &&
+ (opcode == BLE_LL_CTRL_TERMINATE_IND) &&
+ (rx_pyld_len == (1 + BLE_LL_CTRL_TERMINATE_IND_LEN))) {
connsm->csmflags.cfbit.terminate_ind_rxd = 1;
connsm->rxd_disconnect_reason = rxbuf[3];
}
@@ -4239,6 +4426,12 @@ ble_ll_conn_module_reset(void)
g_ble_ll_conn_sync_transfer_params.mode = 0;
g_ble_ll_conn_sync_transfer_params.sync_timeout_us = 0;
#endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+ g_ble_ll_conn_cth_flow.enabled = false;
+ g_ble_ll_conn_cth_flow.max_buffers = 1;
+ g_ble_ll_conn_cth_flow.num_buffers = 1;
+#endif
}
/* Initialize the connection module */
@@ -4278,6 +4471,11 @@ ble_ll_conn_module_init(void)
"ble_ll_conn");
BLE_LL_ASSERT(rc == 0);
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+ ble_npl_event_init(&g_ble_ll_conn_cth_flow_error_ev,
+ ble_ll_conn_cth_flow_error_fn, NULL);
+#endif
+
/* Call reset to finish reset of initialization */
ble_ll_conn_module_reset();
}
diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h
index 9891bfa..53358c4 100644
--- a/nimble/controller/src/ble_ll_conn_priv.h
+++ b/nimble/controller/src/ble_ll_conn_priv.h
@@ -207,6 +207,12 @@ void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm);
#define ble_ll_conn_auth_pyld_timer_start(x)
#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+void ble_ll_conn_cth_flow_set_buffers(uint16_t num_buffers);
+bool ble_ll_conn_cth_flow_enable(bool enabled);
+void ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf);
+#endif
+
int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg);
int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg);
diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c
index c42e24d..a3da98d 100644
--- a/nimble/controller/src/ble_ll_hci.c
+++ b/nimble/controller/src/ble_ll_hci.c
@@ -1343,6 +1343,64 @@ ble_ll_hci_cb_set_event_mask(const uint8_t *cmdbuf, uint8_t len)
return BLE_ERR_SUCCESS;
}
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+static int
+ble_ll_hci_cb_set_ctrlr_to_host_fc(const uint8_t *cmdbuf, uint8_t len)
+{
+ const struct ble_hci_cb_ctlr_to_host_fc_cp *cmd = (const void *) cmdbuf;
+
+ if (len != sizeof (*cmd)) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ /* We only allow to either disable flow control or enable for ACL only */
+ if (cmd->enable > 1) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ if (!ble_ll_conn_cth_flow_enable(cmd->enable)) {
+ return BLE_ERR_CMD_DISALLOWED;
+ }
+
+ return BLE_ERR_SUCCESS;
+}
+
+static int
+ble_ll_hci_cb_host_buf_size(const uint8_t *cmdbuf, uint8_t len)
+{
+ const struct ble_hci_cb_host_buf_size_cp *cmd = (const void *) cmdbuf;
+ uint16_t acl_num;
+ uint16_t acl_data_len;
+
+ if (len != sizeof (*cmd)) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ /* We do not support SCO so those parameters should be set to 0 */
+ if (cmd->sco_num || cmd->sco_data_len) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ /*
+ * Core 5.2 Vol 4 Part E section 7.3.39 states that "Both the Host and the
+ * Controller shall support command and event packets, where the data portion
+ * (excluding header) contained in the packets is 255 octets in size.".
+ * This means we can basically accept any allowed value since LL does not
+ * reassemble incoming data thus will not send more than 255 octets in single
+ * data packet.
+ */
+ acl_num = le16toh(cmd->acl_num);
+ acl_data_len = le16toh(cmd->acl_data_len);
+ if (acl_data_len < 255) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ ble_ll_conn_cth_flow_set_buffers(acl_num);
+
+ return BLE_ERR_SUCCESS;
+}
+#endif
+
static int
ble_ll_hci_cb_set_event_mask2(const uint8_t *cmdbuf, uint8_t len)
{
@@ -1375,6 +1433,22 @@ ble_ll_hci_ctlr_bb_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf,
rc = ble_ll_reset();
}
break;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+ case BLE_HCI_OCF_CB_SET_CTLR_TO_HOST_FC:
+ rc = ble_ll_hci_cb_set_ctrlr_to_host_fc(cmdbuf, len);
+ break;
+ case BLE_HCI_OCF_CB_HOST_BUF_SIZE:
+ rc = ble_ll_hci_cb_host_buf_size(cmdbuf, len);
+ break;
+ case BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS:
+ /*
+ * HCI_Host_Number_Of_Completed_Packets is handled immediately when
+ * received from transport so we should never receive it here.
+ */
+ BLE_LL_ASSERT(0);
+ rc = BLE_ERR_UNKNOWN_HCI_CMD;
+ break;
+#endif
case BLE_HCI_OCF_CB_SET_EVENT_MASK2:
rc = ble_ll_hci_cb_set_event_mask2(cmdbuf, len);
break;
@@ -1570,9 +1644,33 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev)
* BLE_ERR_MEM_CAPACITY on HCI buffer exhaustion.
*/
int
-ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg)
+ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg)
{
struct ble_npl_event *ev;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+ const struct ble_hci_cmd *cmd;
+ uint16_t opcode;
+ uint16_t ocf;
+ uint16_t ogf;
+
+ cmd = (const void *)cmdbuf;
+ opcode = le16toh(cmd->opcode);
+ ogf = BLE_HCI_OGF(opcode);
+ ocf = BLE_HCI_OCF(opcode);
+
+ /*
+ * HCI_Host_Number_Of_Completed_Packets is processed outside standard flow
+ * thus it can be sent at any time, even if another command is already
+ * pending. This means we should better process it here and send an event to
+ * LL in case of error.
+ */
+ if ((ogf == BLE_HCI_OGF_CTLR_BASEBAND) &&
+ (ocf == BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS)) {
+ ble_ll_conn_cth_flow_process_cmd(cmdbuf);
+ ble_hci_trans_buf_free(cmdbuf);
+ return 0;
+ }
+#endif
/* Get an event structure off the queue */
ev = &g_ble_ll_hci_cmd_ev;
@@ -1581,7 +1679,7 @@ ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg)
}
/* Fill out the event and post to Link Layer */
- ble_npl_event_set_arg(ev, cmd);
+ ble_npl_event_set_arg(ev, cmdbuf);
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, ev);
return 0;
diff --git a/nimble/controller/src/ble_ll_supp_cmd.c b/nimble/controller/src/ble_ll_supp_cmd.c
index 863e698..cae9eb7 100644
--- a/nimble/controller/src/ble_ll_supp_cmd.c
+++ b/nimble/controller/src/ble_ll_supp_cmd.c
@@ -36,7 +36,22 @@
/* Octet 10 */
#define BLE_SUPP_CMD_RD_TX_PWR (0 << 2)
-#define BLE_LL_SUPP_CMD_OCTET_10 (BLE_SUPP_CMD_RD_TX_PWR)
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
+#define BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW (1 << 5)
+#define BLE_SUPP_CMD_HOST_BUFFER_SIZE (1 << 6)
+#define BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS (1 << 7)
+#else
+#define BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW (0 << 5)
+#define BLE_SUPP_CMD_HOST_BUFFER_SIZE (0 << 6)
+#define BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS (0 << 7)
+#endif
+#define BLE_LL_SUPP_CMD_OCTET_10 \
+( \
+ BLE_SUPP_CMD_RD_TX_PWR | \
+ BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW | \
+ BLE_SUPP_CMD_HOST_BUFFER_SIZE | \
+ BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS \
+)
/* Octet 14 */
#define BLE_SUPP_CMD_RD_LOC_VER (1 << 3)
diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml
index ea04388..2c7c2cb 100644
--- a/nimble/controller/syscfg.yml
+++ b/nimble/controller/syscfg.yml
@@ -260,6 +260,13 @@ syscfg.defs:
Advertising Sync Transfer Feature.
value: MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+ BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL:
+ description: >
+ Enable controller-to-host flow control support. This allows host to
+ limit number of ACL packets sent at once from controller to avoid
+ congestion on HCI transport if feature is also supported by host.
+ value: 0
+
BLE_LL_CFG_FEAT_LL_SCA_UPDATE:
description: >
This option is used to enable/disable support for SCA update procedure
diff --git a/nimble/include/nimble/ble.h b/nimble/include/nimble/ble.h
index 3fc2902..248e8ae 100644
--- a/nimble/include/nimble/ble.h
+++ b/nimble/include/nimble/ble.h
@@ -81,7 +81,14 @@ struct ble_mbuf_hdr_rxinfo
#endif
};
-/* Flag definitions for rxinfo */
+/*
+ * Flag definitions for rxinfo
+ *
+ * Note: it's ok to have symbols with the same values as long as they cannot be
+ * set for the same PDU (e.g. one use by scanner, other one used by
+ * connection)
+ */
+#define BLE_MBUF_HDR_F_CONN_CREDIT (0x8000)
#define BLE_MBUF_HDR_F_IGNORED (0x8000)
#define BLE_MBUF_HDR_F_SCAN_REQ_TXD (0x4000)
#define BLE_MBUF_HDR_F_INITA_RESOLVED (0x2000)