Repository: incubator-mynewt-larva Updated Branches: refs/heads/master 76f96f882 -> d9aa88d23
Separate directed and undirected slave connections Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/d9aa88d2 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/d9aa88d2 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/d9aa88d2 Branch: refs/heads/master Commit: d9aa88d232f1a762ee00ff9c7ba3ac21c126c455 Parents: 76f96f8 Author: Christopher Collins <[email protected]> Authored: Mon Dec 21 11:52:42 2015 -0800 Committer: Christopher Collins <[email protected]> Committed: Mon Dec 21 11:52:42 2015 -0800 ---------------------------------------------------------------------- net/nimble/host/src/ble_gap_conn.c | 164 +++++++++++++++++++---- net/nimble/host/src/host_hci.c | 6 + net/nimble/host/src/test/ble_hs_conn_test.c | 58 +++++++- net/nimble/host/src/test/ble_hs_test_util.c | 16 ++- net/nimble/host/src/test/ble_hs_test_util.h | 3 +- net/nimble/include/nimble/hci_common.h | 4 +- 6 files changed, 217 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d9aa88d2/net/nimble/host/src/ble_gap_conn.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_gap_conn.c b/net/nimble/host/src/ble_gap_conn.c index d42dd49..0b614b6 100644 --- a/net/nimble/host/src/ble_gap_conn.c +++ b/net/nimble/host/src/ble_gap_conn.c @@ -29,22 +29,31 @@ #define BLE_GAP_CONN_STATE_IDLE UINT8_MAX +/** General discovery master states. */ #define BLE_GAP_CONN_M_STATE_GEN_DISC_PENDING 0 #define BLE_GAP_CONN_M_STATE_GEN_DISC_PARAMS 1 #define BLE_GAP_CONN_M_STATE_GEN_DISC_PARAMS_ACKED 2 #define BLE_GAP_CONN_M_STATE_GEN_DISC_ENABLE 3 #define BLE_GAP_CONN_M_STATE_GEN_DISC_ENABLE_ACKED 4 +/** General discovery master states. */ #define BLE_GAP_CONN_M_STATE_DIRECT_PENDING 5 #define BLE_GAP_CONN_M_STATE_DIRECT_UNACKED 6 #define BLE_GAP_CONN_M_STATE_DIRECT_ACKED 7 -#define BLE_GAP_CONN_S_STATE_PARAMS 0 -#define BLE_GAP_CONN_S_STATE_POWER 1 -#define BLE_GAP_CONN_S_STATE_ADV_DATA 2 -#define BLE_GAP_CONN_S_STATE_RSP_DATA 3 -#define BLE_GAP_CONN_S_STATE_ENABLE 4 -#define BLE_GAP_CONN_S_STATE_MAX 5 +/** Undirected slave states. */ +#define BLE_GAP_CONN_S_STATE_UND_PARAMS 0 +#define BLE_GAP_CONN_S_STATE_UND_POWER 1 +#define BLE_GAP_CONN_S_STATE_UND_ADV_DATA 2 +#define BLE_GAP_CONN_S_STATE_UND_RSP_DATA 3 +#define BLE_GAP_CONN_S_STATE_UND_ENABLE 4 + +/** Directed slave states. */ +#define BLE_GAP_CONN_S_STATE_DIR_PARAMS 5 +#define BLE_GAP_CONN_S_STATE_DIR_ENABLE 6 + +/** State machine rests on this state when advertising is in progress. */ +#define BLE_GAP_CONN_S_STATE_MAX 7 /** 30 ms. */ #define BLE_GAP_ADV_FAST_INTERVAL1_MIN (30 * 1000 / BLE_HCI_ADV_ITVL) @@ -91,11 +100,13 @@ static int ble_gap_conn_adv_enable_tx(void *arg); static ble_hci_sched_tx_fn * const ble_gap_conn_slave_dispatch[BLE_GAP_CONN_S_STATE_MAX] = { - [BLE_GAP_CONN_S_STATE_PARAMS] = ble_gap_conn_adv_params_tx, - [BLE_GAP_CONN_S_STATE_POWER] = ble_gap_conn_adv_power_tx, - [BLE_GAP_CONN_S_STATE_ADV_DATA] = ble_gap_conn_adv_data_tx, - [BLE_GAP_CONN_S_STATE_RSP_DATA] = ble_gap_conn_adv_rsp_data_tx, - [BLE_GAP_CONN_S_STATE_ENABLE] = ble_gap_conn_adv_enable_tx, + [BLE_GAP_CONN_S_STATE_UND_PARAMS] = ble_gap_conn_adv_params_tx, + [BLE_GAP_CONN_S_STATE_UND_POWER] = ble_gap_conn_adv_power_tx, + [BLE_GAP_CONN_S_STATE_UND_ADV_DATA] = ble_gap_conn_adv_data_tx, + [BLE_GAP_CONN_S_STATE_UND_RSP_DATA] = ble_gap_conn_adv_rsp_data_tx, + [BLE_GAP_CONN_S_STATE_UND_ENABLE] = ble_gap_conn_adv_enable_tx, + [BLE_GAP_CONN_S_STATE_DIR_PARAMS] = ble_gap_conn_adv_params_tx, + [BLE_GAP_CONN_S_STATE_DIR_ENABLE] = ble_gap_conn_adv_enable_tx, }; static int ble_gap_conn_slave_mode; @@ -286,10 +297,47 @@ ble_gap_conn_slave_in_progress(void) } static int -ble_gap_conn_accept_new_conn(uint8_t *addr) +ble_gap_conn_adv_is_directed(int mode) +{ + switch (mode) { + case BLE_GAP_CONN_S_MODE_NON_DISC: + case BLE_GAP_CONN_S_MODE_LTD_DISC: + case BLE_GAP_CONN_S_MODE_GEN_DISC: + case BLE_GAP_CONN_S_MODE_NON_CONN: + case BLE_GAP_CONN_S_MODE_UND_CONN: + return 0; + + case BLE_GAP_CONN_S_MODE_DIR_CONN: + return 1; + + default: + assert(0); + return 0; + } +} + +/** + * 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 + * valid, the master FSM is reset and success is returned. + * + * @param addr_type The address type of the peer; one of the + * following values: + * o BLE_HCI_ADV_PEER_ADDR_PUBLIC + * o BLE_HCI_ADV_PEER_ADDR_RANDOM + * @param addr The six-byte address of the connection peer. + * + * @return 0 if the connection complete event was + * accepted; + * BLE_HS_ENOENT if the event does not apply. + */ +static int +ble_gap_conn_accept_master_conn(uint8_t addr_type, uint8_t *addr) { switch (ble_gap_conn_master_state) { case BLE_GAP_CONN_M_STATE_DIRECT_ACKED: + /* XXX: Check address type. */ if (memcmp(ble_gap_conn_master_addr, addr, BLE_DEV_ADDR_LEN) == 0) { os_callout_stop(&ble_gap_conn_master_timer.cf_c); ble_gap_conn_master_reset_state(); @@ -297,9 +345,34 @@ ble_gap_conn_accept_new_conn(uint8_t *addr) } } + return BLE_HS_ENOENT; +} + +/** + * Attempts to complete the slave connection process in response to a + * "connection complete" event from the controller. If the slave connection + * FSM is in a state that can accept this event, and the peer device address is + * valid, the master FSM is reset and success is returned. + * + * @param addr_type The address type of the peer; one of the + * following values: + * o BLE_HCI_ADV_PEER_ADDR_PUBLIC + * o BLE_HCI_ADV_PEER_ADDR_RANDOM + * @param addr The six-byte address of the connection peer. + * + * @return 0 if the connection complete event was + * accepted; + * BLE_HS_ENOENT if the event does not apply. + */ +static int +ble_gap_conn_accept_slave_conn(uint8_t addr_type, uint8_t *addr) +{ switch (ble_gap_conn_slave_state) { case BLE_GAP_CONN_S_STATE_MAX: - if (memcmp(ble_gap_conn_slave_addr, addr, BLE_DEV_ADDR_LEN) == 0) { + /* XXX: Check address type. */ + if (!ble_gap_conn_adv_is_directed(ble_gap_conn_slave_mode) || + memcmp(ble_gap_conn_slave_addr, addr, BLE_DEV_ADDR_LEN) == 0) { + os_callout_stop(&ble_gap_conn_master_timer.cf_c); ble_gap_conn_slave_reset_state(); return 0; @@ -353,18 +426,44 @@ ble_gap_conn_rx_conn_complete(struct hci_le_conn_complete *evt) } /* This event refers to a new connection. */ - rc = ble_gap_conn_accept_new_conn(evt->peer_addr); + switch (evt->role) { + case BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER: + rc = ble_gap_conn_accept_master_conn(evt->peer_addr_type, + evt->peer_addr); + break; + + case BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE: + rc = ble_gap_conn_accept_slave_conn(evt->peer_addr_type, + evt->peer_addr); + break; + + default: + assert(0); + rc = -1; + break; + } if (rc != 0) { return BLE_HS_ENOENT; } if (evt->status != BLE_ERR_SUCCESS) { + switch (evt->role) { + case BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER: + ble_gap_conn_master_failed(evt->status); + break; + + case BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE: + ble_gap_conn_slave_failed(evt->status); + break; + + default: + assert(0); + break; + } + return 0; } - /* XXX: Ensure device address is expected. */ - /* XXX: Ensure event fields are acceptable. */ - conn = ble_hs_conn_alloc(); if (conn == NULL) { /* XXX: Ensure this never happens. */ @@ -442,14 +541,23 @@ ble_gap_conn_adv_ack(struct ble_hci_ack *ack, void *arg) } } +static void +ble_gap_conn_adv_ack_enable(struct ble_hci_ack *ack, void *arg) +{ + if (ack->bha_status != BLE_ERR_SUCCESS) { + ble_gap_conn_slave_failed(ack->bha_status); + } else { + /* Advertising should now be active; put the FSM in the final state. */ + ble_gap_conn_slave_state = BLE_GAP_CONN_S_STATE_MAX; + } +} + static int ble_gap_conn_adv_enable_tx(void *arg) { int rc; - assert(ble_gap_conn_slave_state == BLE_GAP_CONN_S_STATE_ENABLE); - - ble_hci_ack_set_callback(ble_gap_conn_adv_ack, NULL); + ble_hci_ack_set_callback(ble_gap_conn_adv_ack_enable, NULL); rc = host_hci_cmd_le_set_adv_enable(1); if (rc != BLE_ERR_SUCCESS) { ble_gap_conn_slave_failed(rc); @@ -465,8 +573,6 @@ ble_gap_conn_adv_rsp_data_tx(void *arg) uint8_t rsp_data[BLE_HCI_MAX_SCAN_RSP_DATA_LEN] = { 0 }; /* XXX */ int rc; - assert(ble_gap_conn_slave_state == BLE_GAP_CONN_S_STATE_RSP_DATA); - ble_hci_ack_set_callback(ble_gap_conn_adv_ack, NULL); rc = host_hci_cmd_le_set_scan_rsp_data(rsp_data, sizeof rsp_data); if (rc != 0) { @@ -483,8 +589,6 @@ ble_gap_conn_adv_data_tx(void *arg) uint8_t adv_data[BLE_HCI_MAX_ADV_DATA_LEN] = { 0 }; /* XXX */ int rc; - assert(ble_gap_conn_slave_state == BLE_GAP_CONN_S_STATE_ADV_DATA); - ble_hci_ack_set_callback(ble_gap_conn_adv_ack, NULL); rc = host_hci_cmd_le_set_adv_data(adv_data, sizeof adv_data); if (rc != 0) { @@ -547,8 +651,6 @@ ble_gap_conn_adv_params_tx(void *arg) struct hci_adv_params hap; int rc; - assert(ble_gap_conn_slave_state == BLE_GAP_CONN_S_STATE_PARAMS); - hap = ble_gap_conn_adv_params[ble_gap_conn_slave_mode]; memcpy(hap.peer_addr, ble_gap_conn_slave_addr, sizeof hap.peer_addr); @@ -569,9 +671,13 @@ ble_gap_conn_adv_initiate(void) assert(!ble_gap_conn_slave_in_progress()); - ble_gap_conn_slave_state = BLE_GAP_CONN_S_STATE_PARAMS; - - rc = ble_hci_sched_enqueue(ble_gap_conn_adv_params_tx, NULL); + if (ble_gap_conn_adv_is_directed(ble_gap_conn_slave_mode)) { + ble_gap_conn_slave_state = BLE_GAP_CONN_S_STATE_DIR_PARAMS; + rc = ble_hci_sched_enqueue(ble_gap_conn_adv_params_tx, NULL); + } else { + ble_gap_conn_slave_state = BLE_GAP_CONN_S_STATE_UND_PARAMS; + rc = ble_hci_sched_enqueue(ble_gap_conn_adv_params_tx, NULL); + } if (rc != 0) { ble_gap_conn_slave_reset_state(); return rc; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d9aa88d2/net/nimble/host/src/host_hci.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/host_hci.c b/net/nimble/host/src/host_hci.c index c901f6d..5ff4726 100644 --- a/net/nimble/host/src/host_hci.c +++ b/net/nimble/host/src/host_hci.c @@ -350,6 +350,12 @@ host_hci_rx_le_conn_complete(uint8_t subevent, uint8_t *data, int len) evt.supervision_timeout = le16toh(data + 16); evt.master_clk_acc = data[18]; + if (evt.role != BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER && + evt.role != BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) { + + return BLE_HS_EBADDATA; + } + rc = ble_gap_conn_rx_conn_complete(&evt); if (rc != 0) { return rc; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d9aa88d2/net/nimble/host/src/test/ble_hs_conn_test.c ---------------------------------------------------------------------- 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 e9083e5..c4e5e8c 100644 --- a/net/nimble/host/src/test/ble_hs_conn_test.c +++ b/net/nimble/host/src/test/ble_hs_conn_test.c @@ -61,6 +61,7 @@ TEST_CASE(ble_hs_conn_test_direct_connect_success) evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; evt.status = BLE_ERR_SUCCESS; evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; memcpy(evt.peer_addr, addr, 6); rc = ble_gap_conn_rx_conn_complete(&evt); TEST_ASSERT(rc == 0); @@ -103,6 +104,7 @@ TEST_CASE(ble_hs_conn_test_direct_connect_hci_errors) evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; evt.status = BLE_ERR_SUCCESS; evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; memcpy(evt.peer_addr, addr, 6); rc = ble_gap_conn_rx_conn_complete(&evt); TEST_ASSERT(rc != 0); @@ -144,13 +146,14 @@ TEST_CASE(ble_hs_conn_test_direct_connectable_success) TEST_ASSERT(!ble_gap_conn_master_in_progress()); TEST_ASSERT(ble_gap_conn_slave_in_progress()); - ble_hs_test_util_rx_adv_acks(); + ble_hs_test_util_rx_dir_adv_acks(); /* Receive successful connection complete event. */ memset(&evt, 0, sizeof evt); evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; evt.status = BLE_ERR_SUCCESS; evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE; memcpy(evt.peer_addr, addr, 6); rc = ble_gap_conn_rx_conn_complete(&evt); TEST_ASSERT(rc == 0); @@ -194,13 +197,14 @@ TEST_CASE(ble_hs_conn_test_direct_connectable_hci_errors) evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; evt.status = BLE_ERR_SUCCESS; evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE; memcpy(evt.peer_addr, addr, 6); rc = ble_gap_conn_rx_conn_complete(&evt); TEST_ASSERT(rc != 0); TEST_ASSERT(ble_gap_conn_slave_in_progress()); /* Receive necessary ack events. */ - ble_hs_test_util_rx_adv_acks(); + ble_hs_test_util_rx_dir_adv_acks(); /* Receive failure connection complete event. */ evt.status = BLE_ERR_UNSPECIFIED; @@ -210,6 +214,55 @@ TEST_CASE(ble_hs_conn_test_direct_connectable_hci_errors) TEST_ASSERT(ble_hs_conn_first() == NULL); } +TEST_CASE(ble_hs_conn_test_undirect_connectable_success) +{ + struct hci_le_conn_complete evt; + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + 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_conn_master_in_progress()); + TEST_ASSERT(!ble_gap_conn_slave_in_progress()); + TEST_ASSERT(ble_hs_conn_first() == NULL); + + /* Initiate advertising. */ + rc = ble_gap_conn_undirect_connectable(); + TEST_ASSERT(rc == 0); + + ble_hci_sched_wakeup(); + + TEST_ASSERT(!ble_gap_conn_master_in_progress()); + TEST_ASSERT(ble_gap_conn_slave_in_progress()); + + ble_hs_test_util_rx_und_adv_acks(); + + /* Receive successful connection complete event. */ + memset(&evt, 0, sizeof evt); + evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE; + memcpy(evt.peer_addr, addr, 6); + rc = ble_gap_conn_rx_conn_complete(&evt); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_gap_conn_master_in_progress()); + TEST_ASSERT(!ble_gap_conn_slave_in_progress()); + + 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); + + chan = ble_hs_conn_chan_find(conn, BLE_L2CAP_CID_ATT); + TEST_ASSERT_FATAL(chan != NULL); + TEST_ASSERT(chan->blc_my_mtu == BLE_ATT_MTU_DFLT); + TEST_ASSERT(chan->blc_peer_mtu == 0); + TEST_ASSERT(chan->blc_default_mtu == BLE_ATT_MTU_DFLT); +} TEST_CASE(ble_hs_conn_test_completed_pkts) { struct ble_hs_conn *conn1; @@ -281,6 +334,7 @@ TEST_SUITE(conn_suite) 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(); ble_hs_conn_test_completed_pkts(); } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d9aa88d2/net/nimble/host/src/test/ble_hs_test_util.c ---------------------------------------------------------------------- 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 d623f76..b496677 100644 --- a/net/nimble/host/src/test/ble_hs_test_util.c +++ b/net/nimble/host/src/test/ble_hs_test_util.c @@ -255,7 +255,7 @@ ble_hs_test_util_rx_num_completed_pkts_event( } void -ble_hs_test_util_rx_adv_acks(void) +ble_hs_test_util_rx_und_adv_acks(void) { /* Receive set-adv-params ack. */ ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_SET_ADV_PARAMS, BLE_ERR_SUCCESS); @@ -289,6 +289,20 @@ ble_hs_test_util_rx_adv_acks(void) } void +ble_hs_test_util_rx_dir_adv_acks(void) +{ + /* Receive set-adv-params ack. */ + ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_SET_ADV_PARAMS, BLE_ERR_SUCCESS); + TEST_ASSERT(ble_gap_conn_slave_in_progress()); + + ble_hci_sched_wakeup(); + + /* Receive set-adv-enable ack. */ + ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_SET_ADV_ENABLE, BLE_ERR_SUCCESS); + TEST_ASSERT(ble_gap_conn_slave_in_progress()); +} + +void ble_hs_test_util_init(void) { int rc; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d9aa88d2/net/nimble/host/src/test/ble_hs_test_util.h ---------------------------------------------------------------------- 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 e8e5999..e61e4eb 100644 --- a/net/nimble/host/src/test/ble_hs_test_util.h +++ b/net/nimble/host/src/test/ble_hs_test_util.h @@ -51,7 +51,8 @@ void ble_hs_test_util_rx_att_err_rsp(struct ble_hs_conn *conn, uint8_t req_op, void ble_hs_test_util_rx_startup_acks(void); void ble_hs_test_util_rx_num_completed_pkts_event( struct ble_hs_test_util_num_completed_pkts_entry *entries); -void ble_hs_test_util_rx_adv_acks(void); +void ble_hs_test_util_rx_und_adv_acks(void); +void ble_hs_test_util_rx_dir_adv_acks(void); void ble_hs_test_util_init(void); #endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d9aa88d2/net/nimble/include/nimble/hci_common.h ---------------------------------------------------------------------- diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h index 7510ade..3a88caa 100644 --- a/net/nimble/include/nimble/hci_common.h +++ b/net/nimble/include/nimble/hci_common.h @@ -378,7 +378,9 @@ #define BLE_HCI_LE_MIN_LEN (1) /* Not including event hdr. */ /* LE connection complete event */ -#define BLE_HCI_LE_CONN_COMPLETE_LEN (19) +#define BLE_HCI_LE_CONN_COMPLETE_LEN (19) +#define BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER (0x00) +#define BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE (0x01) /* LE advertising report event. */ #define BLE_HCI_LE_ADV_RPT_MIN_LEN (12)
