You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/12/02 00:38:40 UTC
incubator-mynewt-core git commit: MYNEWT-341 BLE Host - Handle
missing ACL fragments
Repository: incubator-mynewt-core
Updated Branches:
refs/heads/develop 5c5a987ef -> 0d402e54a
MYNEWT-341 BLE Host - Handle missing ACL fragments
If a packet is only partially received, and 30 seconds has passed since
the last fragment was received, a timeout occurs. When this happens,
the connection is terminated.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/0d402e54
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/0d402e54
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/0d402e54
Branch: refs/heads/develop
Commit: 0d402e54aa6d0fa24f31eebac15038b1d00b969b
Parents: 5c5a987
Author: Christopher Collins <cc...@apache.org>
Authored: Thu Dec 1 16:35:59 2016 -0800
Committer: Christopher Collins <cc...@apache.org>
Committed: Thu Dec 1 16:35:59 2016 -0800
----------------------------------------------------------------------
net/nimble/host/src/ble_hs.c | 9 ++--
net/nimble/host/src/ble_hs_conn.c | 61 ++++++++++++++++++++++++
net/nimble/host/src/ble_hs_conn_priv.h | 3 ++
net/nimble/host/src/ble_l2cap.c | 2 +
net/nimble/host/src/ble_l2cap_priv.h | 2 +
net/nimble/host/test/src/ble_hs_conn_test.c | 6 ++-
net/nimble/host/test/src/ble_l2cap_test.c | 46 ++++++++++++++++++
7 files changed, 124 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/0d402e54/net/nimble/host/src/ble_hs.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs.c b/net/nimble/host/src/ble_hs.c
index b55dc2c..c5799ee 100644
--- a/net/nimble/host/src/ble_hs.c
+++ b/net/nimble/host/src/ble_hs.c
@@ -314,10 +314,13 @@ ble_hs_timer_exp(struct os_event *ev)
ticks_until_next = ble_sm_timer();
ble_hs_timer_sched(ticks_until_next);
+
+ ticks_until_next = ble_hs_conn_timer();
+ ble_hs_timer_sched(ticks_until_next);
}
static void
-ble_hs_timer_timer_reset(uint32_t ticks)
+ble_hs_timer_reset(uint32_t ticks)
{
int rc;
@@ -341,7 +344,7 @@ ble_hs_timer_sched(int32_t ticks_from_now)
if (!os_callout_queued(&ble_hs_timer_timer) ||
OS_TIME_TICK_LT(abs_time, ble_hs_timer_timer.c_ticks)) {
- ble_hs_timer_timer_reset(ticks_from_now);
+ ble_hs_timer_reset(ticks_from_now);
}
}
@@ -351,7 +354,7 @@ ble_hs_timer_resched(void)
/* Reschedule the timer to run immediately. The timer callback will query
* each module for an up-to-date expiration time.
*/
- ble_hs_timer_timer_reset(0);
+ ble_hs_timer_reset(0);
}
static void
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/0d402e54/net/nimble/host/src/ble_hs_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_conn.c b/net/nimble/host/src/ble_hs_conn.c
index 59c3ae5..9a6517e 100644
--- a/net/nimble/host/src/ble_hs_conn.c
+++ b/net/nimble/host/src/ble_hs_conn.c
@@ -378,6 +378,67 @@ ble_hs_conn_addrs(const struct ble_hs_conn *conn,
}
}
+int32_t
+ble_hs_conn_timer(void)
+{
+ struct ble_hs_conn *conn;
+ os_time_t now;
+ int32_t next_exp_in;
+ int32_t time_diff;
+ uint16_t conn_handle;
+
+ conn_handle = BLE_HS_CONN_HANDLE_NONE;
+ next_exp_in = BLE_HS_FOREVER;
+ now = os_time_get();
+
+ ble_hs_lock();
+
+ /* This loop performs one of two tasks:
+ * 1. Determine if any connections need to be terminated due to timeout.
+ * If so, break out of the loop and terminate the connection. This
+ * function will need to be executed again.
+ * 2. Otherwise, determine when the next timeout will occur.
+ */
+ SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
+ /* Check each connection's rx fragment timer. If too much time passes
+ * after a partial packet is received, the connection is terminated.
+ */
+ if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING) &&
+ conn->bhc_rx_chan != NULL) {
+
+ time_diff = conn->bhc_rx_timeout - now;
+
+ if (time_diff <= 0) {
+ /* ACL reassembly has timed out. Remember the connection
+ * handle so it can be terminated after the mutex is unlocked.
+ */
+ conn_handle = conn->bhc_handle;
+ conn->bhc_flags |= BLE_HS_CONN_F_TERMINATING;
+ break;
+ }
+
+ /* Determine if this connection is the soonest to time out. */
+ if (time_diff < next_exp_in) {
+ next_exp_in = time_diff;
+ }
+ }
+ }
+
+ ble_hs_unlock();
+
+ /* If a connection has timed out, terminate it. We need to recursively
+ * call this function again to determine when the next timeout is. This
+ * is a tail-recursive call, so it should be optimized to execute in the
+ * same stack frame.
+ */
+ if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
+ ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
+ return ble_hs_conn_timer();
+ }
+
+ return next_exp_in;
+}
+
int
ble_hs_conn_init(void)
{
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/0d402e54/net/nimble/host/src/ble_hs_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_conn_priv.h b/net/nimble/host/src/ble_hs_conn_priv.h
index 92e6f37..3dfa5cf 100644
--- a/net/nimble/host/src/ble_hs_conn_priv.h
+++ b/net/nimble/host/src/ble_hs_conn_priv.h
@@ -35,6 +35,7 @@ struct ble_l2cap_chan;
typedef uint8_t ble_hs_conn_flags_t;
#define BLE_HS_CONN_F_MASTER 0x01
+#define BLE_HS_CONN_F_TERMINATING 0x02
struct ble_hs_conn {
SLIST_ENTRY(ble_hs_conn) bhc_next;
@@ -54,6 +55,7 @@ struct ble_hs_conn {
struct ble_l2cap_chan_list bhc_channels;
struct ble_l2cap_chan *bhc_rx_chan; /* Channel rxing current packet. */
+ uint32_t bhc_rx_timeout;
uint16_t bhc_outstanding_pkts;
struct ble_att_svr_conn bhc_att_svr;
@@ -93,6 +95,7 @@ int ble_hs_conn_chan_insert(struct ble_hs_conn *conn,
struct ble_l2cap_chan *chan);
void ble_hs_conn_addrs(const struct ble_hs_conn *conn,
struct ble_hs_conn_addrs *addrs);
+int32_t ble_hs_conn_timer(void);
int ble_hs_conn_init(void);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/0d402e54/net/nimble/host/src/ble_l2cap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap.c b/net/nimble/host/src/ble_l2cap.c
index 66701b1..aa37784 100644
--- a/net/nimble/host/src/ble_l2cap.c
+++ b/net/nimble/host/src/ble_l2cap.c
@@ -180,6 +180,8 @@ ble_l2cap_rx_payload(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
rc = 0;
} else {
/* More fragments remain. */
+ conn->bhc_rx_timeout = os_time_get() + BLE_L2CAP_REASSEM_TIMEOUT;
+ ble_hs_timer_resched();
rc = BLE_HS_EAGAIN;
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/0d402e54/net/nimble/host/src/ble_l2cap_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_priv.h b/net/nimble/host/src/ble_l2cap_priv.h
index 79d58a7..2087e81 100644
--- a/net/nimble/host/src/ble_l2cap_priv.h
+++ b/net/nimble/host/src/ble_l2cap_priv.h
@@ -29,6 +29,8 @@
extern "C" {
#endif
+#define BLE_L2CAP_REASSEM_TIMEOUT (30 * OS_TICKS_PER_SEC)
+
struct ble_hs_conn;
struct hci_data_hdr;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/0d402e54/net/nimble/host/test/src/ble_hs_conn_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/test/src/ble_hs_conn_test.c b/net/nimble/host/test/src/ble_hs_conn_test.c
index 4ba92d2..a5fdba7 100644
--- a/net/nimble/host/test/src/ble_hs_conn_test.c
+++ b/net/nimble/host/test/src/ble_hs_conn_test.c
@@ -167,8 +167,10 @@ TEST_CASE(ble_hs_conn_test_undirect_connectable_success)
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, BLE_HS_FOREVER,
+ rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC,
+ BLE_ADDR_TYPE_PUBLIC,
+ addr, &adv_params,
+ BLE_HS_FOREVER,
NULL, NULL, 0, 0);
TEST_ASSERT(rc == 0);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/0d402e54/net/nimble/host/test/src/ble_l2cap_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/test/src/ble_l2cap_test.c b/net/nimble/host/test/src/ble_l2cap_test.c
index 7be148c..55d6afe 100644
--- a/net/nimble/host/test/src/ble_l2cap_test.c
+++ b/net/nimble/host/test/src/ble_l2cap_test.c
@@ -352,6 +352,51 @@ TEST_CASE(ble_l2cap_test_case_frag_channels)
ble_hs_unlock();
}
+TEST_CASE(ble_l2cap_test_case_frag_timeout)
+{
+ int32_t ticks_from_now;
+ int rc;
+
+ ble_l2cap_test_util_init();
+
+ ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}),
+ NULL, NULL);
+
+ /* Ensure timer is not set. */
+ ticks_from_now = ble_hs_conn_timer();
+ TEST_ASSERT_FATAL(ticks_from_now == BLE_HS_FOREVER);
+
+ /* Receive the first fragment of a multipart ACL data packet. */
+ rc = ble_l2cap_test_util_rx_first_frag(2, 14, BLE_L2CAP_TEST_CID, 30);
+ TEST_ASSERT_FATAL(rc == 0);
+
+ /* Ensure timer will expire in 30 seconds. */
+ ticks_from_now = ble_hs_conn_timer();
+ TEST_ASSERT(ticks_from_now == BLE_L2CAP_REASSEM_TIMEOUT);
+
+ /* Almost let the timer expire. */
+ os_time_advance(BLE_L2CAP_REASSEM_TIMEOUT - 1);
+ ticks_from_now = ble_hs_conn_timer();
+ TEST_ASSERT(ticks_from_now == 1);
+
+ /* Receive a second fragment. */
+ rc = ble_l2cap_test_util_rx_next_frag(2, 14);
+ TEST_ASSERT_FATAL(rc == 0);
+
+ /* Ensure timer got reset. */
+ ticks_from_now = ble_hs_conn_timer();
+ TEST_ASSERT(ticks_from_now == BLE_L2CAP_REASSEM_TIMEOUT);
+
+ /* Allow the timer to expire. */
+ ble_hs_test_util_set_ack_disconnect(0);
+ os_time_advance(BLE_L2CAP_REASSEM_TIMEOUT);
+ ticks_from_now = ble_hs_conn_timer();
+ TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER);
+
+ /* Ensure connection was terminated. */
+ ble_hs_test_util_verify_tx_disconnect(2, BLE_ERR_REM_USER_CONN_TERM);
+}
+
/*****************************************************************************
* $unsolicited response *
*****************************************************************************/
@@ -569,6 +614,7 @@ TEST_SUITE(ble_l2cap_test_suite)
ble_l2cap_test_case_frag_single();
ble_l2cap_test_case_frag_multiple();
ble_l2cap_test_case_frag_channels();
+ ble_l2cap_test_case_frag_timeout();
ble_l2cap_test_case_sig_unsol_rsp();
ble_l2cap_test_case_sig_update_accept();
ble_l2cap_test_case_sig_update_reject();