mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-09-08 18:20:02 +00:00
Merge branch 'nimble/fix_host_flow_ctrl_1.2.0-afr-v4.2' into 'nimble-1.2.0-idf-v4.2-afr'
NimBLE: Fix host flow control related bugs (nimble-1.2.0-idf-v4.2-afr) See merge request espressif/esp-nimble!77
This commit is contained in:
@@ -1458,8 +1458,8 @@ ble_gap_rx_periodic_adv_rpt(struct hci_le_subev_periodic_adv_rpt *evt)
|
||||
{
|
||||
struct ble_hs_periodic_sync *psync;
|
||||
struct ble_gap_event event;
|
||||
ble_gap_event_fn *cb;
|
||||
void *cb_arg;
|
||||
ble_gap_event_fn *cb = NULL;
|
||||
void *cb_arg = NULL;
|
||||
|
||||
ble_hs_lock();
|
||||
psync = ble_hs_periodic_sync_find_by_handle(evt->sync_handle);
|
||||
|
||||
@@ -684,7 +684,7 @@ ble_hs_rx_data(struct os_mbuf *om, void *arg)
|
||||
/* If flow control is enabled, mark this packet with its corresponding
|
||||
* connection handle.
|
||||
*/
|
||||
ble_hs_flow_fill_acl_usrhdr(om);
|
||||
ble_hs_flow_track_data_mbuf(om);
|
||||
|
||||
rc = ble_mqueue_put(&ble_hs_rx_q, ble_hs_evq, om);
|
||||
if (rc != 0) {
|
||||
|
||||
@@ -40,6 +40,23 @@ static ble_npl_event_fn ble_hs_flow_event_cb;
|
||||
|
||||
static struct ble_npl_event ble_hs_flow_ev;
|
||||
|
||||
/* Connection handle associated with each mbuf in ACL pool */
|
||||
static uint16_t ble_hs_flow_mbuf_conn_handle[ MYNEWT_VAL(BLE_ACL_BUF_COUNT) ];
|
||||
|
||||
static inline int
|
||||
ble_hs_flow_mbuf_index(const struct os_mbuf *om)
|
||||
{
|
||||
const struct os_mempool *mp = om->om_omp->omp_pool;
|
||||
uintptr_t addr = (uintptr_t)om;
|
||||
int idx;
|
||||
|
||||
idx = (addr - mp->mp_membuf_addr) / mp->mp_block_size;
|
||||
|
||||
BLE_HS_DBG_ASSERT(mp->mp_membuf_addr + idx * mp->mp_block_size == addr);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int
|
||||
ble_hs_flow_tx_num_comp_pkts(void)
|
||||
{
|
||||
@@ -147,18 +164,13 @@ ble_hs_flow_acl_free(struct os_mempool_ext *mpe, void *data, void *arg)
|
||||
struct ble_hs_conn *conn;
|
||||
const struct os_mbuf *om;
|
||||
uint16_t conn_handle;
|
||||
int idx;
|
||||
int rc;
|
||||
|
||||
om = data;
|
||||
|
||||
/* An ACL data packet must be a single mbuf, and it must contain the
|
||||
* corresponding connection handle in its user header.
|
||||
*/
|
||||
assert(OS_MBUF_IS_PKTHDR(om));
|
||||
assert(OS_MBUF_USRHDR_LEN(om) >= sizeof conn_handle);
|
||||
|
||||
/* Copy the connection handle out of the mbuf. */
|
||||
memcpy(&conn_handle, OS_MBUF_USRHDR(om), sizeof conn_handle);
|
||||
idx = ble_hs_flow_mbuf_index(om);
|
||||
conn_handle = ble_hs_flow_mbuf_conn_handle[idx];
|
||||
|
||||
/* Free the mbuf back to its pool. */
|
||||
rc = os_memblock_put_from_cb(&mpe->mpe_mp, data);
|
||||
@@ -194,23 +206,19 @@ ble_hs_flow_connection_broken(uint16_t conn_handle)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the user header of an incoming data packet. On function return, the
|
||||
* header contains the connection handle associated with the sender.
|
||||
* Associates incoming data packet with a connection handle of the sender.
|
||||
*
|
||||
* If flow control is disabled, this function is a no-op.
|
||||
*/
|
||||
void
|
||||
ble_hs_flow_fill_acl_usrhdr(struct os_mbuf *om)
|
||||
ble_hs_flow_track_data_mbuf(struct os_mbuf *om)
|
||||
{
|
||||
#if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
|
||||
const struct hci_data_hdr *hdr;
|
||||
uint16_t *conn_handle;
|
||||
|
||||
BLE_HS_DBG_ASSERT(OS_MBUF_USRHDR_LEN(om) >= sizeof *conn_handle);
|
||||
conn_handle = OS_MBUF_USRHDR(om);
|
||||
int idx = ble_hs_flow_mbuf_index(om);
|
||||
|
||||
hdr = (void *)om->om_data;
|
||||
*conn_handle = BLE_HCI_DATA_HANDLE(hdr->hdh_handle_pb_bc);
|
||||
ble_hs_flow_mbuf_conn_handle[idx] = BLE_HCI_DATA_HANDLE(hdr->hdh_handle_pb_bc);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
void ble_hs_flow_connection_broken(uint16_t conn_handle);
|
||||
void ble_hs_flow_fill_acl_usrhdr(struct os_mbuf *om);
|
||||
void ble_hs_flow_track_data_mbuf(struct os_mbuf *om);
|
||||
int ble_hs_flow_startup(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -188,17 +188,13 @@ ble_l2cap_remove_rx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan)
|
||||
static void
|
||||
ble_l2cap_append_rx(struct ble_l2cap_chan *chan, struct os_mbuf *frag)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void)rc;
|
||||
|
||||
#if MYNEWT_VAL(BLE_L2CAP_JOIN_RX_FRAGS)
|
||||
struct os_mbuf *m;
|
||||
|
||||
/* Copy the data from the incoming fragment into the packet in progress. */
|
||||
rc = os_mbuf_appendfrom(chan->rx_buf, frag, 0, OS_MBUF_PKTLEN(frag));
|
||||
if (rc == 0) {
|
||||
os_mbuf_free_chain(frag);
|
||||
return;
|
||||
}
|
||||
m = os_mbuf_pack_chains(chan->rx_buf, frag);
|
||||
assert(m);
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* Join disabled or append failed due to mbuf shortage. Just attach the
|
||||
|
||||
@@ -178,7 +178,9 @@ static int
|
||||
get_nvs_db_attribute(int obj_type, bool empty, void *value, int num_value)
|
||||
{
|
||||
union ble_store_value cur = {0};
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
struct ble_hs_dev_records p_dev_rec = {0};
|
||||
#endif
|
||||
esp_err_t err;
|
||||
int i, count = 0, max_limit = 0;
|
||||
char key_string[NIMBLE_NVS_STR_NAME_MAX_LEN];
|
||||
@@ -188,11 +190,15 @@ get_nvs_db_attribute(int obj_type, bool empty, void *value, int num_value)
|
||||
for (i = 1; i <= max_limit; i++) {
|
||||
get_nvs_key_string(obj_type, i, key_string);
|
||||
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
if (obj_type != BLE_STORE_OBJ_TYPE_PEER_DEV_REC) {
|
||||
#endif
|
||||
err = get_nvs_db_value(obj_type, key_string, &cur);
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
} else {
|
||||
err = get_nvs_peer_record(key_string, &p_dev_rec);
|
||||
}
|
||||
#endif
|
||||
/* Check if the user is searching for empty index to write to */
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
if (empty) {
|
||||
@@ -204,10 +210,13 @@ get_nvs_db_attribute(int obj_type, bool empty, void *value, int num_value)
|
||||
/* If user has provided value, then the purpose is to find
|
||||
* non-matching entry from NVS */
|
||||
if (value) {
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
if (obj_type == BLE_STORE_OBJ_TYPE_PEER_DEV_REC) {
|
||||
err = get_nvs_matching_index(&p_dev_rec, value, num_value,
|
||||
sizeof(struct ble_hs_dev_records));
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (obj_type != BLE_STORE_OBJ_TYPE_CCCD) {
|
||||
err = get_nvs_matching_index(&cur.sec, value, num_value,
|
||||
sizeof(struct ble_store_value_sec));
|
||||
@@ -374,7 +383,9 @@ populate_db_from_nvs(int obj_type, void *dst, int *db_num)
|
||||
{
|
||||
uint8_t *db_item = (uint8_t *)dst;
|
||||
union ble_store_value cur = {0};
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
struct ble_hs_dev_records p_dev_rec = {0};
|
||||
#endif
|
||||
|
||||
esp_err_t err;
|
||||
int i;
|
||||
@@ -383,8 +394,9 @@ populate_db_from_nvs(int obj_type, void *dst, int *db_num)
|
||||
for (i = 1; i <= get_nvs_max_obj_value(obj_type); i++) {
|
||||
get_nvs_key_string(obj_type, i, key_string);
|
||||
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
if (obj_type != BLE_STORE_OBJ_TYPE_PEER_DEV_REC) {
|
||||
|
||||
#endif
|
||||
err = get_nvs_db_value(obj_type, key_string, &cur);
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
continue;
|
||||
@@ -392,6 +404,7 @@ populate_db_from_nvs(int obj_type, void *dst, int *db_num)
|
||||
ESP_LOGE(TAG, "NVS read operation failed !!");
|
||||
return -1;
|
||||
}
|
||||
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
} else {
|
||||
err = get_nvs_peer_record(key_string, &p_dev_rec);
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
@@ -408,7 +421,9 @@ populate_db_from_nvs(int obj_type, void *dst, int *db_num)
|
||||
memcpy(db_item, &p_dev_rec, sizeof(struct ble_hs_dev_records));
|
||||
db_item += sizeof(struct ble_hs_dev_records);
|
||||
(*db_num)++;
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (obj_type == BLE_STORE_OBJ_TYPE_CCCD) {
|
||||
ESP_LOGD(TAG, "CCCD in RAM is filled up from NVS index = %d", i);
|
||||
memcpy(db_item, &cur.cccd, sizeof(struct ble_store_value_cccd));
|
||||
|
||||
@@ -295,15 +295,7 @@ done:
|
||||
static struct os_mbuf *
|
||||
ble_hci_trans_acl_buf_alloc(void)
|
||||
{
|
||||
uint8_t usrhdr_len;
|
||||
|
||||
#if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
|
||||
usrhdr_len = BLE_MBUF_HS_HDR_LEN;
|
||||
#else
|
||||
usrhdr_len = 0;
|
||||
#endif
|
||||
|
||||
return os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool, usrhdr_len);
|
||||
return os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -195,8 +195,6 @@ ble_hci_trans_acl_buf_alloc(void)
|
||||
|
||||
#if MYNEWT_VAL(BLE_CONTROLLER)
|
||||
usrhdr_len = sizeof(struct ble_mbuf_hdr);
|
||||
#elif MYNEWT_VAL(BLE_HS_FLOW_CTRL)
|
||||
usrhdr_len = BLE_MBUF_HS_HDR_LEN;
|
||||
#else
|
||||
usrhdr_len = 0;
|
||||
#endif
|
||||
|
||||
@@ -614,6 +614,25 @@ struct os_mbuf *os_mbuf_pullup(struct os_mbuf *om, uint16_t len);
|
||||
*/
|
||||
struct os_mbuf *os_mbuf_trim_front(struct os_mbuf *om);
|
||||
|
||||
/**
|
||||
* Creates a single chained mbuf from m1 and m2 utilizing all
|
||||
* the available buffer space in all mbufs in the resulting
|
||||
* chain. In other words, ensures there is no leading space in
|
||||
* any mbuf in the resulting chain and trailing space only in
|
||||
* the last mbuf in the chain. Mbufs from either chain may be
|
||||
* freed if not needed. No mbufs are allocated. Note that mbufs
|
||||
* from m2 are added to the end of m1. If m1 has a packet
|
||||
* header, it is retained and length updated. If m2 has a packet
|
||||
* header it is discarded. If m1 is NULL, NULL is returned and
|
||||
* m2 is left untouched.
|
||||
*
|
||||
* @param m1 Pointer to first mbuf chain to pack
|
||||
* @param m2 Pointer to second mbuf chain to pack
|
||||
*
|
||||
* @return struct os_mbuf* Pointer to resulting mbuf chain
|
||||
*/
|
||||
struct os_mbuf *os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1037,3 +1037,89 @@ os_mbuf_trim_front(struct os_mbuf *om)
|
||||
return om;
|
||||
}
|
||||
|
||||
struct os_mbuf *
|
||||
os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2)
|
||||
{
|
||||
uint16_t rem_len;
|
||||
uint16_t copylen;
|
||||
uint8_t *dptr;
|
||||
struct os_mbuf *cur;
|
||||
struct os_mbuf *next;
|
||||
|
||||
/* If m1 is NULL, return NULL */
|
||||
if (m1 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenate the two chains to start. This will discard packet header in
|
||||
* m2 and adjust packet length in m1 if m1 has a packet header.
|
||||
*/
|
||||
if (m2 != NULL) {
|
||||
os_mbuf_concat(m1, m2);
|
||||
}
|
||||
|
||||
cur = m1;
|
||||
while (1) {
|
||||
/* If there is leading space in the mbuf, move data up */
|
||||
if (OS_MBUF_LEADINGSPACE(cur)) {
|
||||
dptr = &cur->om_databuf[0];
|
||||
if (OS_MBUF_IS_PKTHDR(cur)) {
|
||||
dptr += cur->om_pkthdr_len;
|
||||
}
|
||||
memmove(dptr, cur->om_data, cur->om_len);
|
||||
cur->om_data = dptr;
|
||||
}
|
||||
|
||||
/* Set pointer to where we will begin copying data in current mbuf */
|
||||
dptr = cur->om_data + cur->om_len;
|
||||
|
||||
/* Get a pointer to the next buf we want to absorb */
|
||||
next = SLIST_NEXT(cur, om_next);
|
||||
|
||||
/*
|
||||
* Is there trailing space in the mbuf? If so, copy data from
|
||||
* following mbufs into the current mbuf
|
||||
*/
|
||||
rem_len = OS_MBUF_TRAILINGSPACE(cur);
|
||||
while (rem_len && next) {
|
||||
copylen = min(rem_len, next->om_len);
|
||||
memcpy(dptr, next->om_data, copylen);
|
||||
cur->om_len += copylen;
|
||||
dptr += copylen;
|
||||
rem_len -= copylen;
|
||||
|
||||
/*
|
||||
* We copied bytes from the next mbuf. Move the data pointer
|
||||
* and subtract from its length
|
||||
*/
|
||||
next->om_data += copylen;
|
||||
next->om_len -= copylen;
|
||||
|
||||
/*
|
||||
* Keep removing and freeing consecutive zero length mbufs,
|
||||
* stopping when we find one with data in it or we have
|
||||
* reached the end. This will prevent any zero length mbufs
|
||||
* from remaining in the chain.
|
||||
*/
|
||||
while (next->om_len == 0) {
|
||||
SLIST_NEXT(cur, om_next) = SLIST_NEXT(next, om_next);
|
||||
os_mbuf_free(next);
|
||||
next = SLIST_NEXT(cur, om_next);
|
||||
if (next == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If no mbufs are left, we are done */
|
||||
if (next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Move cur to next as we filled up current */
|
||||
cur = next;
|
||||
}
|
||||
|
||||
return m1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user