nimble/l2cap: Add TX_UNSTALLED event to L2CAP CoC

With this patch if L2CAP CoC has been stalled due to lack of credits
BLE_HS_ESTALLED code will be returned.

When NimBLE gets back credits and finish sending SDU,
BLE_L2CAP_EVENT_COC_TX_UNSTALLED will be sent to the application as the
indication that L2CAP CoC is unstalled and ready for sending new data.
This commit is contained in:
Łukasz Rymanowski
2019-04-12 22:35:40 +02:00
parent afaca4f5c5
commit 4d70828f18
5 changed files with 62 additions and 1 deletions
+1
View File
@@ -94,6 +94,7 @@ extern "C" {
#define BLE_HS_ESTORE_FAIL 28
#define BLE_HS_EPREEMPTED 29
#define BLE_HS_EDISABLED 30
#define BLE_HS_ESTALLED 31
/** Error base for ATT errors */
#define BLE_HS_ERR_ATT_BASE 0x100
+23
View File
@@ -75,6 +75,7 @@ struct ble_hs_conn;
#define BLE_L2CAP_EVENT_COC_DISCONNECTED 1
#define BLE_L2CAP_EVENT_COC_ACCEPT 2
#define BLE_L2CAP_EVENT_COC_DATA_RECEIVED 3
#define BLE_L2CAP_EVENT_COC_TX_UNSTALLED 4
typedef void ble_l2cap_sig_update_fn(uint16_t conn_handle, int status,
void *arg);
@@ -173,6 +174,28 @@ struct ble_l2cap_event {
/** The mbuf with received SDU. */
struct os_mbuf *sdu_rx;
} receive;
/**
* Represents tx_unstalled data. Valid for the following event
* types:
* o BLE_L2CAP_EVENT_COC_TX_UNSTALLED
*/
struct {
/** Connection handle of the relevant connection */
uint16_t conn_handle;
/** The L2CAP channel of the relevant L2CAP connection. */
struct ble_l2cap_chan *chan;
/**
* The status of the send attempt which was stalled due to
* lack of credits; This can be non zero only if there
* is an issue with memory allocation for following SDU fragments.
* In such a case last SDU has been partially sent to peer device
* and it is up to application to decide how to handle it.
*/
int status;
} tx_unstalled;
};
};
+31
View File
@@ -316,6 +316,23 @@ ble_l2cap_coc_cleanup_chan(struct ble_l2cap_chan *chan)
os_mbuf_free_chain(chan->coc_tx.sdu);
}
static void
ble_l2cap_event_coc_unstalled(struct ble_l2cap_chan *chan, int status)
{
struct ble_l2cap_event event = { };
if (!chan->cb) {
return;
}
event.type = BLE_L2CAP_EVENT_COC_TX_UNSTALLED;
event.tx_unstalled.conn_handle = chan->conn_handle;
event.tx_unstalled.chan = chan;
event.tx_unstalled.status = status;
chan->cb(&event, chan->cb_arg);
}
static int
ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan)
{
@@ -402,16 +419,30 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan)
os_mbuf_free_chain(tx->sdu);
tx->sdu = 0;
tx->data_offset = 0;
if (tx->flags & BLE_L2CAP_COC_FLAG_STALLED) {
ble_l2cap_event_coc_unstalled(chan, 0);
tx->flags &= ~BLE_L2CAP_COC_FLAG_STALLED;
}
break;
}
}
if (tx->sdu) {
/* Not complete SDU sent, wait for credits */
tx->flags |= BLE_L2CAP_COC_FLAG_STALLED;
return BLE_HS_ESTALLED;
}
return 0;
failed:
os_mbuf_free_chain(tx->sdu);
tx->sdu = NULL;
os_mbuf_free_chain(txom);
if (tx->flags & BLE_L2CAP_COC_FLAG_STALLED) {
ble_l2cap_event_coc_unstalled(chan, rc);
tx->flags &= ~BLE_L2CAP_COC_FLAG_STALLED;
}
return rc;
}
+4 -1
View File
@@ -35,11 +35,14 @@ extern "C" {
struct ble_l2cap_chan;
#define BLE_L2CAP_COC_FLAG_STALLED 0x01
struct ble_l2cap_coc_endpoint {
struct os_mbuf *sdu;
uint16_t mtu;
uint16_t credits;
uint16_t data_offset;
struct os_mbuf *sdu;
uint8_t flags;
};
struct ble_l2cap_coc_srv {
+3
View File
@@ -736,6 +736,9 @@ ble_l2cap_test_event(struct ble_l2cap_event *event, void *arg)
OS_MBUF_PKTLEN(event->receive.sdu_rx));
TEST_ASSERT(memcmp(sdu_rx->om_data, ev->data, ev->data_len) == 0);
return 0;
case BLE_L2CAP_EVENT_COC_TX_UNSTALLED:
/* TODO Add tests for this */
return 0;
default:
return 0;
}