You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2016/01/23 00:20:23 UTC
[1/2] incubator-mynewt-larva git commit: Connection update procedure
implemented. Most of connection parameter request implemented but not final
so connection parameter
Repository: incubator-mynewt-larva
Updated Branches:
refs/heads/master df59850fe -> 7a82be0e5
Connection update procedure implemented. Most of connection parameter request implemented but not final so connection parameter
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/262b1be2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/262b1be2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/262b1be2
Branch: refs/heads/master
Commit: 262b1be2f72c5e42d254dcc92e62598590988332
Parents: df59850
Author: wes3 <wi...@micosa.io>
Authored: Fri Jan 22 15:19:39 2016 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Fri Jan 22 15:19:39 2016 -0800
----------------------------------------------------------------------
hw/bsp/nrf52pdk/include/bsp/bsp.h | 3 +
.../controller/include/controller/ble_ll_conn.h | 46 +-
.../controller/include/controller/ble_ll_ctrl.h | 24 +-
.../controller/include/controller/ble_ll_hci.h | 2 +-
net/nimble/controller/src/ble_ll.c | 14 +-
net/nimble/controller/src/ble_ll_adv.c | 2 +-
net/nimble/controller/src/ble_ll_conn.c | 127 +++-
net/nimble/controller/src/ble_ll_conn_hci.c | 256 ++++++-
net/nimble/controller/src/ble_ll_conn_priv.h | 4 +
net/nimble/controller/src/ble_ll_ctrl.c | 696 ++++++++++++++++---
net/nimble/controller/src/ble_ll_hci.c | 26 +-
net/nimble/controller/src/ble_ll_scan.c | 134 ++--
project/bletest/src/main.c | 59 +-
13 files changed, 1174 insertions(+), 219 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/hw/bsp/nrf52pdk/include/bsp/bsp.h
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf52pdk/include/bsp/bsp.h b/hw/bsp/nrf52pdk/include/bsp/bsp.h
index 2451c31..7ec6b58 100644
--- a/hw/bsp/nrf52pdk/include/bsp/bsp.h
+++ b/hw/bsp/nrf52pdk/include/bsp/bsp.h
@@ -27,6 +27,9 @@ extern "C" {
/* UART info */
#define CONSOLE_UART 0
+/* Declaration of "non-zeroed" bss */
+#define nzbss_t __attribute__((section(".nzbss")))
+
#ifdef __cplusplus
}
#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/include/controller/ble_ll_conn.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h b/net/nimble/controller/include/controller/ble_ll_conn.h
index 444ee72..4df87b7 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -19,7 +19,9 @@
#include "os/os.h"
#include "nimble/ble.h"
+#include "nimble/hci_common.h"
#include "controller/ble_ll_sched.h"
+#include "controller/ble_ll_ctrl.h"
#include "hal/hal_cputime.h"
/* Roles */
@@ -58,7 +60,7 @@ struct ble_ll_conn_sm
{
/* Current connection state and role */
uint8_t conn_state;
- uint8_t conn_role;
+ uint8_t conn_role; /* Can possibly be 1 bit */
/* Connection data length management */
uint8_t max_tx_octets;
@@ -91,37 +93,47 @@ 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 */
- /* connection event timing/mgmt */
+ /* connection event mgmt */
uint8_t pdu_txd; /* note: can be 1 bit */
uint8_t pkt_rxd; /* note: can be 1 bit */
uint8_t terminate_ind_txd; /* note: can be 1 bit */
uint8_t terminate_ind_rxd; /* note: can be 1 bit */
uint8_t allow_slave_latency; /* note: can be 1 bit */
uint8_t slave_set_last_anchor; /* note: can be 1 bit */
+ uint8_t awaiting_host_reply; /* note: can be 1 bit */
+ uint8_t send_conn_upd_event; /* note: can be 1 bit */
+ uint8_t conn_update_scheduled; /* note: can be 1 bit */
+ uint8_t host_expects_upd_event; /* note: can be 1 bit */
+ uint8_t reject_reason;
+ uint8_t host_reply_opcode;
uint8_t master_sca;
uint8_t tx_win_size;
uint8_t cur_ctrl_proc;
uint8_t disconnect_reason;
uint8_t rxd_disconnect_reason;
uint16_t pending_ctrl_procs;
- uint16_t conn_itvl;
- uint16_t slave_latency;
- uint16_t tx_win_off;
- uint16_t min_ce_len;
- uint16_t max_ce_len;
uint16_t event_cntr;
- uint16_t supervision_tmo;
uint16_t conn_handle;
uint16_t completed_pkts;
uint32_t access_addr;
- uint32_t crcinit; /* only low 24 bits used */
- uint32_t anchor_point;
- uint32_t last_anchor_point; /* slave only */
+ uint32_t crcinit; /* only low 24 bits used */
uint32_t ce_end_time; /* cputime at which connection event should end */
uint32_t terminate_timeout;
+ uint32_t last_scheduled;
+
+ /* Connection timing */
+ uint16_t conn_itvl_min;
+ uint16_t conn_itvl_max;
+ uint16_t conn_itvl;
+ uint16_t slave_latency;
+ uint16_t supervision_tmo;
+ uint16_t min_ce_len;
+ uint16_t max_ce_len;
+ uint16_t tx_win_off;
+ uint32_t anchor_point;
+ uint32_t last_anchor_point;
uint32_t slave_cur_tx_win_usecs;
uint32_t slave_cur_window_widening;
- uint32_t last_scheduled;
/* address information */
uint8_t own_addr_type;
@@ -154,6 +166,16 @@ struct ble_ll_conn_sm
/* For scheduling connections */
struct ble_ll_sched_item conn_sch;
+
+ /* XXX: ifdef this by feature? */
+ /*
+ * For connection update procedure. XXX: can make this a pointer and
+ * malloc it if we want to save space.
+ */
+ struct hci_conn_update conn_param_req;
+
+ /* For connection update procedure */
+ struct ble_ll_conn_upd_req conn_update_req;
};
/*
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/include/controller/ble_ll_ctrl.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_ctrl.h b/net/nimble/controller/include/controller/ble_ll_ctrl.h
index 8920f08..1f3de56 100644
--- a/net/nimble/controller/include/controller/ble_ll_ctrl.h
+++ b/net/nimble/controller/include/controller/ble_ll_ctrl.h
@@ -22,7 +22,7 @@
* It is used to determine which LL control procedure is currently running
* in a connection and which ones may be pending.
*/
-#define BLE_LL_CTRL_PROC_CONN_UPD (0)
+#define BLE_LL_CTRL_PROC_CONN_UPDATE (0)
#define BLE_LL_CTRL_PROC_CHAN_MAP_UPD (1)
#define BLE_LL_CTRL_PROC_ENCRYPT (2)
#define BLE_LL_CTRL_PROC_FEATURE_XCHG (3)
@@ -37,6 +37,9 @@
/* Checks if a particular control procedure is running */
#define IS_PENDING_CTRL_PROC_M(sm, proc) (sm->pending_ctrl_procs & (1 << proc))
+/* LL control procedure timeout */
+#define BLE_LL_CTRL_PROC_TIMEOUT (40) /* in secs */
+
/*
* LL CTRL PDU format
* -> Opcode (1 byte)
@@ -65,6 +68,11 @@
#define BLE_LL_CTRL_LENGTH_REQ (20)
#define BLE_LL_CTRL_LENGTH_RSP (21)
+/* Maximum opcode value */
+#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_LENGTH_RSP + 1)
+
+extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES];
+
/* Maximum # of payload bytes in a LL control PDU */
#define BLE_LL_CTRL_MAX_PAYLOAD (26)
@@ -169,7 +177,7 @@ struct ble_ll_conn_params
uint16_t interval_max;
uint16_t latency;
uint16_t timeout;
- uint16_t pref_periodicity;
+ uint8_t pref_periodicity;
uint16_t ref_conn_event_cnt;
uint16_t offset0;
uint16_t offset1;
@@ -215,9 +223,19 @@ struct ble_ll_conn_sm;
void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc);
void ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc);
void ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om);
-void ble_ll_ctrl_datalen_chg_event(struct ble_ll_conn_sm *connsm);
void ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm);
void ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm);
int ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode);
+int ble_ll_ctrl_is_reject_ind_ext(uint8_t hdr, uint8_t opcode);
+uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm,
+ uint8_t *rsp,
+ struct ble_ll_conn_params *req);
+int ble_ll_ctrl_reject_ind_ext_send(struct ble_ll_conn_sm *connsm,
+ uint8_t rej_opcode, uint8_t err);
+
+void ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm);
+void ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm,
+ struct ble_ll_conn_params *cp);
+void ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status);
#endif /* H_BLE_LL_CTRL_ */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/include/controller/ble_ll_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_hci.h b/net/nimble/controller/include/controller/ble_ll_hci.h
index 32a093a..862fbad 100644
--- a/net/nimble/controller/include/controller/ble_ll_hci.h
+++ b/net/nimble/controller/include/controller/ble_ll_hci.h
@@ -41,7 +41,7 @@ void ble_ll_hci_init(void);
void ble_ll_hci_cmd_proc(struct os_event *ev);
/* Used to determine if the LE event is enabled/disabled */
-uint8_t ble_ll_hci_is_le_event_enabled(int bitpos);
+uint8_t ble_ll_hci_is_le_event_enabled(int subev);
/* Used to determine if event is enabled/disabled */
uint8_t ble_ll_hci_is_event_enabled(int bitpos);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll.c b/net/nimble/controller/src/ble_ll.c
index eb44261..4eb4a8e 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -18,6 +18,7 @@
#include <assert.h>
#include <string.h>
#include "os/os.h"
+#include "bsp/bsp.h"
#include "nimble/ble.h"
#include "nimble/hci_common.h"
#include "controller/ble_phy.h"
@@ -49,6 +50,7 @@
/* Configuration for supported features */
#define BLE_LL_CFG_FEAT_DATA_LEN_EXT
+#undef BLE_LL_CFG_FEAT_CONN_PARAM_REQ
#undef BLE_LL_CFG_FEAT_LE_ENCRYPTION
#undef BLE_LL_CFG_FEAT_EXT_REJECT_IND
@@ -78,7 +80,10 @@ struct ble_ll_log
#define BLE_LL_LOG_LEN (256)
-static struct ble_ll_log g_ble_ll_log[BLE_LL_LOG_LEN];
+#if !defined(nzbss_t)
+#define nzbss_t
+#endif
+static nzbss_t struct ble_ll_log g_ble_ll_log[BLE_LL_LOG_LEN];
static uint8_t g_ble_ll_log_index;
void
@@ -939,6 +944,13 @@ ble_ll_init(void)
#ifdef BLE_LL_CFG_FEAT_DATA_LEN_EXT
features |= BLE_LL_FEAT_DATA_LEN_EXT;
#endif
+#ifdef BLE_LL_CFG_FEAT_CONN_PARAM_REQ
+ features |= BLE_LL_FEAT_CONN_PARM_REQ;
+#endif
+#ifdef BLE_LL_CFG_FEAT_EXT_REJECT_IND
+ features |= BLE_LL_FEAT_EXTENDED_REJ;
+#endif
+
lldata->ll_supp_features = features;
/* Initialize the LL task */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_adv.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_adv.c b/net/nimble/controller/src/ble_ll_adv.c
index d74b61a..116da9a 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -1136,7 +1136,7 @@ ble_ll_adv_event_done(void *arg)
os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
/* For debug purposes */
-#ifdef BLETEST
+#ifdef BLETEST_ADV_PKT_NUM
bletest_inc_adv_pkt_num();
#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c
index 373909b..a4b3b44 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -103,9 +103,9 @@ extern int ble_hs_rx_data(struct os_mbuf *om);
#define BLE_LL_CFG_CONN_TX_WIN_SIZE (1)
#define BLE_LL_CFG_CONN_TX_WIN_OFF (0)
#define BLE_LL_CFG_CONN_MASTER_SCA (BLE_MASTER_SCA_251_500_PPM << 5)
-#define BLE_LL_CFG_CONN_MAX_CONNS (8)
+#define BLE_LL_CFG_CONN_MAX_CONNS (32)
#define BLE_LL_CFG_CONN_OUR_SCA (60) /* in ppm */
-#define BLE_LL_CFG_CONN_INIT_SLOTS (8)
+#define BLE_LL_CFG_CONN_INIT_SLOTS (2)
/* We cannot have more than 254 connections given our current implementation */
#if (BLE_LL_CFG_CONN_MAX_CONNS >= 255)
@@ -142,7 +142,10 @@ struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm;
/* Connection state machine array */
-struct ble_ll_conn_sm g_ble_ll_conn_sm[BLE_LL_CFG_CONN_MAX_CONNS];
+#if !defined(nzbss_t)
+#define nzbss_t
+#endif
+nzbss_t struct ble_ll_conn_sm g_ble_ll_conn_sm[BLE_LL_CFG_CONN_MAX_CONNS];
/* List of active connections */
struct ble_ll_conn_active_list g_ble_ll_conn_active_list;
@@ -928,6 +931,8 @@ ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
}
/* XXX: for now, just make connection interval equal to max */
+ connsm->conn_itvl_min = hcc->conn_itvl_min;
+ connsm->conn_itvl_max = hcc->conn_itvl_max;
connsm->conn_itvl = hcc->conn_itvl_max;
/* Check the min/max CE lengths are less than connection interval */
@@ -973,24 +978,35 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
{
struct ble_ll_conn_global_params *conn_params;
- /* Reset event counter and last unmapped channel */
- connsm->last_unmapped_chan = 0;
+ /* Reset following elements */
connsm->event_cntr = 0;
connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
connsm->allow_slave_latency = 0;
connsm->disconnect_reason = 0;
connsm->terminate_ind_txd = 0;
connsm->terminate_ind_rxd = 0;
+ connsm->awaiting_host_reply = 0;
+ connsm->send_conn_upd_event = 0;
+ connsm->conn_update_scheduled = 0;
+ connsm->host_expects_upd_event = 0;
/* Reset current control procedure */
connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
connsm->pending_ctrl_procs = 0;
+ /*
+ * Set handle in connection update procedure to 0. If the handle
+ * is non-zero it means that the host initiated the connection
+ * parameter update request and the rest of the parameters are valid.
+ */
+ connsm->conn_param_req.handle = 0;
+
/* Initialize connection supervision timer */
cputime_timer_init(&connsm->conn_spvn_timer, ble_ll_conn_spvn_timer_cb,
connsm);
/* Calculate the next data channel */
+ connsm->last_unmapped_chan = 0;
connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
/* Initialize event */
@@ -1079,7 +1095,7 @@ ble_ll_conn_datalen_update(struct ble_ll_conn_sm *connsm,
}
if (send_event) {
- ble_ll_ctrl_datalen_chg_event(connsm);
+ ble_ll_hci_ev_datalen_chg(connsm);
}
}
@@ -1151,13 +1167,52 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
ble_ll_log(BLE_LL_LOG_ID_CONN_END,connsm->conn_handle,0,connsm->event_cntr);
}
+/**
+ * Called to move to the next connection event.
+ *
+ * @param connsm
+ *
+ * @return int
+ */
static int
ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
{
+ uint8_t update_status;
uint16_t latency;
uint32_t itvl;
+ uint32_t tmo;
uint32_t cur_ww;
uint32_t max_ww;
+ struct ble_ll_conn_upd_req *upd;
+
+ /*
+ * XXX: we could send the connection update event a bit earlier. The
+ * way this is coded is that we will generally send it when the
+ * connection event corresponding to the instant ends. We can send
+ * it when it begins if we want.
+ */
+
+ /* XXX: deal with connection request procedure here as well */
+
+ /*
+ * There are two cases where this flag gets set:
+ * 1) A connection update procedure was started and the event counter
+ * has passed the instant.
+ * 2) We successfully sent the reject reason.
+ */
+ if (connsm->host_expects_upd_event) {
+ update_status = BLE_ERR_SUCCESS;
+ if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) {
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE);
+ } else {
+ if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
+ update_status = connsm->reject_reason;
+ }
+ }
+ ble_ll_hci_ev_conn_update(connsm, update_status);
+ connsm->host_expects_upd_event = 0;
+ }
/*
* XXX: not quite sure I am interpreting slave latency correctly here.
@@ -1169,7 +1224,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
/* Set event counter to the next connection event that we will tx/rx in */
itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
latency = 1;
- if (connsm->allow_slave_latency) {
+ if (connsm->allow_slave_latency && !connsm->conn_update_scheduled) {
if (connsm->pkt_rxd) {
latency += connsm->slave_latency;
itvl = itvl * latency;
@@ -1180,6 +1235,43 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
/* Set next connection event start time */
connsm->anchor_point += cputime_usecs_to_ticks(itvl);
+ /*
+ * If a connection update has been scheduled and the event counter
+ * is now equal to the instant, we need to adjust the start of the
+ * connection by the the transmit window offset. We also copy in the
+ * update parameters as they now should take effect.
+ */
+ if (connsm->conn_update_scheduled &&
+ (connsm->event_cntr == connsm->conn_update_req.instant)) {
+
+ /* Set flag so we send connection update event */
+ upd = &connsm->conn_update_req;
+ if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) ||
+ (connsm->conn_itvl != upd->interval) ||
+ (connsm->slave_latency != upd->latency) ||
+ (connsm->supervision_tmo != upd->timeout)) {
+ connsm->host_expects_upd_event = 1;
+ }
+
+ connsm->conn_itvl = upd->interval;
+ connsm->supervision_tmo = upd->timeout;
+ connsm->slave_latency = upd->latency;
+ connsm->tx_win_size = upd->winsize;
+ connsm->slave_cur_tx_win_usecs =
+ connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
+ connsm->tx_win_off = upd->winoffset;
+ connsm->anchor_point +=
+ cputime_usecs_to_ticks(upd->winoffset * BLE_LL_CONN_ITVL_USECS);
+
+ /* Reset the connection supervision timeout */
+ cputime_timer_stop(&connsm->conn_spvn_timer);
+ tmo = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000;
+ cputime_timer_start(&connsm->conn_spvn_timer, connsm->anchor_point+tmo);
+
+ /* Reset update scheduled flag */
+ connsm->conn_update_scheduled = 0;
+ }
+
/* Calculate data channel index of next connection event */
connsm->last_unmapped_chan = connsm->unmapped_chan;
while (latency > 0) {
@@ -1370,6 +1462,8 @@ ble_ll_conn_event_end(void *arg)
/* Set initial schedule callback */
connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
+ /* XXX: I think all this fine for when we do connection updates, but
+ we may want to force the first event to be scheduled. Not sure */
/* Schedule the next connection event */
while (ble_ll_sched_conn_reschedule(connsm)) {
if (ble_ll_conn_next_event(connsm)) {
@@ -1514,7 +1608,7 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
if (connsm && BLE_MBUF_HDR_CRC_OK(ble_hdr) &&
(ble_hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_REQ_TXD)) {
/* Set address of advertiser to which we are connecting. */
- if (!ble_ll_scan_whitelist_enabled()) {
+ if (ble_ll_scan_whitelist_enabled()) {
/*
* XXX: need to see if the whitelist tells us exactly what peer
* addr type we should use? Not sure it matters. If whitelisting
@@ -1960,6 +2054,19 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa)
goto conn_rx_pdu_end;
}
+ /*
+ * Did we transmit a REJECT_IND_EXT? If so we need
+ * to make sure we send the connection update event
+ */
+ if (ble_ll_ctrl_is_reject_ind_ext(txhdr->txinfo.hdr_byte,
+ txpdu->om_data[0])) {
+ if (connsm->cur_ctrl_proc ==
+ BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+ connsm->reject_reason = txpdu->om_data[2];
+ connsm->host_expects_upd_event = 1;
+ }
+ }
+
/* Increment offset based on number of bytes sent */
txhdr->txinfo.offset += txhdr->txinfo.pyld_len;
if (txhdr->txinfo.offset >= pkthdr->omp_len) {
@@ -2126,7 +2233,7 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length)
*
* Context: Link Layer
*
- * @param rxbuf Pointer to received PDU
+ * @param rxbuf Pointer to received Connect Request PDU
* @param conn_req_end receive end time of connect request
*
* @return 0: connection not started; 1 connecton started
@@ -2294,6 +2401,8 @@ ble_ll_conn_module_init(void)
*/
connsm = &g_ble_ll_conn_sm[0];
for (i = 0; i < BLE_LL_CFG_CONN_MAX_CONNS; ++i) {
+ memset(connsm, 0, sizeof(struct ble_ll_conn_sm));
+
connsm->conn_handle = i + 1;
STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_conn_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c b/net/nimble/controller/src/ble_ll_conn_hci.c
index a051318..4a26a9d 100644
--- a/net/nimble/controller/src/ble_ll_conn_hci.c
+++ b/net/nimble/controller/src/ble_ll_conn_hci.c
@@ -38,6 +38,47 @@ static uint32_t g_ble_ll_next_num_comp_pkt_evt;
((BLE_LL_CFG_NUM_COMP_PKT_RATE * OS_TICKS_PER_SEC) / 1000)
/**
+ * Called to check that the connection parameters are within range
+ *
+ * @param itvl_min
+ * @param itvl_max
+ * @param latency
+ * @param spvn_tmo
+ *
+ * @return int BLE_ERR_INV_HCI_CMD_PARMS if invalid parameters, 0 otherwise
+ */
+int
+ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
+ uint16_t latency, uint16_t spvn_tmo)
+{
+ uint32_t spvn_tmo_usecs;
+ uint32_t min_spvn_tmo_usecs;
+
+ if ((itvl_min > itvl_max) ||
+ (itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
+ (itvl_min > BLE_HCI_CONN_ITVL_MAX) ||
+ (latency > BLE_HCI_CONN_LATENCY_MAX) ||
+ (spvn_tmo < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
+ (spvn_tmo > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ /*
+ * Supervision timeout (in msecs) must be more than:
+ * (1 + connLatency) * connIntervalMax * 1.25 msecs * 2.
+ */
+ spvn_tmo_usecs = spvn_tmo;
+ spvn_tmo_usecs *= (BLE_HCI_CONN_SPVN_TMO_UNITS * 1000);
+ min_spvn_tmo_usecs = (uint32_t)itvl_max * 2 * BLE_LL_CONN_ITVL_USECS;
+ min_spvn_tmo_usecs *= (1 + latency);
+ if (spvn_tmo_usecs <= min_spvn_tmo_usecs) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ return BLE_ERR_SUCCESS;
+}
+
+/**
* Make a connect request PDU
*
* @param connsm
@@ -102,7 +143,7 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status)
{
uint8_t *evbuf;
- if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_COMPLETE - 1)) {
+ if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_COMPLETE)) {
evbuf = os_memblock_get(&g_hci_cmd_pool);
if (evbuf) {
evbuf[0] = BLE_HCI_EVCODE_LE_META;
@@ -260,8 +301,6 @@ int
ble_ll_conn_create(uint8_t *cmdbuf)
{
int rc;
- uint32_t spvn_tmo_usecs;
- uint32_t min_spvn_tmo_usecs;
struct hci_create_conn ccdata;
struct hci_create_conn *hcc;
struct ble_ll_conn_sm *connsm;
@@ -311,36 +350,17 @@ ble_ll_conn_create(uint8_t *cmdbuf)
return BLE_ERR_INV_HCI_CMD_PARMS;
}
- /* Check connection interval */
+ /* Check connection interval, latency and supervision timeoout */
hcc->conn_itvl_min = le16toh(cmdbuf + 13);
hcc->conn_itvl_max = le16toh(cmdbuf + 15);
hcc->conn_latency = le16toh(cmdbuf + 17);
- if ((hcc->conn_itvl_min > hcc->conn_itvl_max) ||
- (hcc->conn_itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
- (hcc->conn_itvl_min > BLE_HCI_CONN_ITVL_MAX) ||
- (hcc->conn_latency > BLE_HCI_CONN_LATENCY_MAX)) {
- return BLE_ERR_INV_HCI_CMD_PARMS;
- }
-
- /* Check supervision timeout */
hcc->supervision_timeout = le16toh(cmdbuf + 19);
- if ((hcc->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
- (hcc->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX))
- {
- return BLE_ERR_INV_HCI_CMD_PARMS;
- }
-
- /*
- * Supervision timeout (in msecs) must be more than:
- * (1 + connLatency) * connIntervalMax * 1.25 msecs * 2.
- */
- spvn_tmo_usecs = hcc->supervision_timeout;
- spvn_tmo_usecs *= (BLE_HCI_CONN_SPVN_TMO_UNITS * 1000);
- min_spvn_tmo_usecs = (uint32_t)hcc->conn_itvl_max * 2 *
- BLE_LL_CONN_ITVL_USECS;
- min_spvn_tmo_usecs *= (1 + hcc->conn_latency);
- if (spvn_tmo_usecs <= min_spvn_tmo_usecs) {
- return BLE_ERR_INV_HCI_CMD_PARMS;
+ rc = ble_ll_conn_hci_chk_conn_params(hcc->conn_itvl_min,
+ hcc->conn_itvl_max,
+ hcc->conn_latency,
+ hcc->supervision_timeout);
+ if (rc) {
+ return rc;
}
/* Min/max connection event lengths */
@@ -376,6 +396,184 @@ ble_ll_conn_create(uint8_t *cmdbuf)
return rc;
}
+static int
+ble_ll_conn_process_conn_params(uint8_t *cmdbuf, struct ble_ll_conn_sm *connsm)
+{
+ int rc;
+ struct hci_conn_update *hcu;
+
+ /* Retrieve command data */
+ hcu = &connsm->conn_param_req;
+ hcu->handle = connsm->conn_handle;
+ hcu->conn_itvl_min = le16toh(cmdbuf + 2);
+ hcu->conn_itvl_max = le16toh(cmdbuf + 4);
+ hcu->conn_latency = le16toh(cmdbuf + 6);
+ hcu->supervision_timeout = le16toh(cmdbuf + 8);
+ hcu->min_ce_len = le16toh(cmdbuf + 10);
+ hcu->max_ce_len = le16toh(cmdbuf + 12);
+
+ /* Check that parameter values are in range */
+ rc = ble_ll_conn_hci_chk_conn_params(hcu->conn_itvl_min,
+ hcu->conn_itvl_max,
+ hcu->conn_latency,
+ hcu->supervision_timeout);
+
+ /* Check valid min/max ce length */
+ if (rc || (hcu->min_ce_len > hcu->max_ce_len)) {
+ hcu->handle = 0;
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+ return rc;
+}
+
+/**
+ * Called to process a connection update command.
+ *
+ * @param cmdbuf
+ *
+ * @return int
+ */
+int
+ble_ll_conn_update(uint8_t *cmdbuf)
+{
+ int rc;
+ uint8_t ctrl_proc;
+ uint16_t handle;
+ struct ble_ll_conn_sm *connsm;
+ struct hci_conn_update *hcu;
+
+ /* XXX: must deal with slave not supporting this feature and using
+ conn update */
+
+ /* If no connection handle exit with error */
+ handle = le16toh(cmdbuf);
+ connsm = ble_ll_conn_find_active_conn(handle);
+ if (!connsm) {
+ return BLE_ERR_UNK_CONN_ID;
+ }
+
+ /* Better not have this procedure ongoing! */
+ if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) ||
+ IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) {
+ return BLE_ERR_CMD_DISALLOWED;
+ }
+
+ /* See if we support this feature */
+ if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
+ ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE;
+ } else {
+ ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
+ }
+
+ /*
+ * If we are a slave and the master has initiated the procedure already
+ * we should deny the slave request for now. If we are a master and the
+ * slave has initiated the procedure, we need to send a reject to the
+ * slave.
+ */
+ if (connsm->awaiting_host_reply) {
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ return BLE_ERR_LMP_COLLISION;
+ } else {
+ connsm->awaiting_host_reply = 0;
+
+ /* XXX: If this fails no reject ind will be sent! */
+ ble_ll_ctrl_reject_ind_ext_send(connsm,
+ connsm->host_reply_opcode,
+ BLE_ERR_LMP_COLLISION);
+ }
+ }
+
+ /* Retrieve command data */
+ hcu = &connsm->conn_param_req;
+ hcu->handle = handle;
+ hcu->conn_itvl_min = le16toh(cmdbuf + 2);
+ hcu->conn_itvl_max = le16toh(cmdbuf + 4);
+ hcu->conn_latency = le16toh(cmdbuf + 6);
+ hcu->supervision_timeout = le16toh(cmdbuf + 8);
+ hcu->min_ce_len = le16toh(cmdbuf + 10);
+ hcu->max_ce_len = le16toh(cmdbuf + 12);
+ if (hcu->min_ce_len > hcu->max_ce_len) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ /* Check that parameter values are in range */
+ rc = ble_ll_conn_hci_chk_conn_params(hcu->conn_itvl_min,
+ hcu->conn_itvl_max,
+ hcu->conn_latency,
+ hcu->supervision_timeout);
+ if (!rc) {
+ /* Start the control procedure */
+ ble_ll_ctrl_proc_start(connsm, ctrl_proc);
+ }
+
+ return rc;
+}
+
+int
+ble_ll_conn_param_reply(uint8_t *cmdbuf, int positive_reply)
+{
+ int rc;
+ uint8_t ble_err;
+ uint8_t *dptr;
+ uint8_t rsp_opcode;
+ uint8_t len;
+ uint16_t handle;
+ struct os_mbuf *om;
+ struct ble_ll_conn_sm *connsm;
+
+ /* See if we support this feature */
+ if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
+ return BLE_ERR_UNSUPP_FEATURE;
+ }
+
+ /* If no connection handle exit with error */
+ handle = le16toh(cmdbuf);
+
+ /* If we dont have a handle we cant do anything */
+ connsm = ble_ll_conn_find_active_conn(handle);
+ if (!connsm) {
+ return BLE_ERR_UNK_CONN_ID;
+ }
+
+ /* Make sure connection parameters are valid if this is a positive reply */
+ rc = BLE_ERR_SUCCESS;
+ ble_err = cmdbuf[2];
+ if (positive_reply) {
+ rc = ble_ll_conn_process_conn_params(cmdbuf, connsm);
+ if (rc) {
+ ble_err = BLE_ERR_CONN_PARMS;
+ }
+ }
+
+ /* The connection should be awaiting a reply. If not, just discard */
+ if (connsm->awaiting_host_reply) {
+ /* Get a control packet buffer */
+ if (positive_reply && (rc == BLE_ERR_SUCCESS)) {
+ om = os_mbuf_get_pkthdr(&g_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+ if (om) {
+ dptr = om->om_data;
+ rsp_opcode = ble_ll_ctrl_conn_param_reply(connsm, dptr, NULL);
+ dptr[0] = rsp_opcode;
+ len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1;
+ ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
+ }
+ } else {
+ /* XXX: check return code and deal */
+ ble_ll_ctrl_reject_ind_ext_send(connsm,
+ connsm->host_reply_opcode,
+ ble_err);
+ }
+ connsm->awaiting_host_reply = 0;
+
+ /* XXX: if we cant get a buffer, what do we do? We need to remember
+ * reason if it was a negative reply. We also would need to have
+ some state to tell us this happened */
+ }
+
+ return rc;
+}
+
/**
* Called when HCI command to cancel a create connection command has been
* received.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h b/net/nimble/controller/src/ble_ll_conn_priv.h
index 47015a3..5c3a700 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -97,10 +97,14 @@ void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm,
int ble_ll_conn_hci_disconnect_cmd(uint8_t *cmdbuf);
int ble_ll_conn_create(uint8_t *cmdbuf);
+int ble_ll_conn_update(uint8_t *cmdbuf);
+int ble_ll_conn_param_reply(uint8_t *cmdbuf, int negative_reply);
int ble_ll_conn_create_cancel(void);
void ble_ll_conn_num_comp_pkts_event_send(void);
void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status);
void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
+int ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
+ uint16_t latency, uint16_t spvn_tmo);
#endif /* H_BLE_LL_CONN_PRIV_ */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_ctrl.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_ctrl.c b/net/nimble/controller/src/ble_ll_ctrl.c
index 0e5df2d..04b965e 100644
--- a/net/nimble/controller/src/ble_ll_ctrl.c
+++ b/net/nimble/controller/src/ble_ll_ctrl.c
@@ -49,6 +49,38 @@
* sent (actually attempted to tx). Do we count failures? How?
*/
+ /* XXX: NOTE: we are not supposed to send a REJECT_IND_EXT unless we know the
+ slave supports that feature */
+
+/* XXX:
+ * 1) One thing I need to make sure I do: if we initiated this procedure and
+ * we stop it, we have to make sure we send the update complete event! I
+ * am referring to the connection parameter request procedure. The code is
+ * already there to send the event when the connection update procedure
+ * is over.
+ */
+
+/*
+ * XXX: I definitely have an issue with control procedures and connection
+ * param request procedure and connection update procedure. This was
+ * noted when receiving an unknown response. Right now, I am getting confused
+ * with connection parameter request and updates regarding which procedures
+ * are running. So I need to go look through all the code and see where I
+ * used the request procedure and the update procedure and make sure I am doing
+ * the correct thing.
+ */
+
+/*
+ * This array contains the length of the CtrData field in LL control PDU's.
+ * Note that there is a one byte opcode which precedes this field in the LL
+ * control PDU, so total data channel payload length for the control pdu is
+ * one greater.
+ */
+const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] =
+{
+ 11, 7, 1, 22, 12, 0, 0, 1, 8, 8, 0, 0, 5, 1, 8, 23, 23, 2, 0, 0, 8, 8
+};
+
/* XXX: Improvements
* 1) We can inititalize the procedure timer once per connection state machine
*/
@@ -88,10 +120,10 @@ ble_ll_ctrl_len_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
struct ble_ll_len_req ctrl_req;
/* Extract parameters and check if valid */
- ctrl_req.max_rx_bytes = le16toh(dptr + 3);
- ctrl_req.max_rx_time = le16toh(dptr + 5);
- ctrl_req.max_tx_bytes = le16toh(dptr + 7);
- ctrl_req.max_tx_time = le16toh(dptr + 9);
+ ctrl_req.max_rx_bytes = le16toh(dptr);
+ ctrl_req.max_rx_time = le16toh(dptr + 2);
+ ctrl_req.max_tx_bytes = le16toh(dptr + 4);
+ ctrl_req.max_tx_time = le16toh(dptr + 6);
if (!ble_ll_ctrl_chk_supp_bytes(ctrl_req.max_rx_bytes) ||
!ble_ll_ctrl_chk_supp_bytes(ctrl_req.max_tx_bytes) ||
@@ -107,6 +139,122 @@ ble_ll_ctrl_len_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
return rc;
}
+static int
+ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+ uint8_t *rspbuf, uint8_t opcode)
+{
+ int rc;
+ int indicate;
+ uint8_t rsp_opcode;
+ uint8_t ble_err;
+ struct ble_ll_conn_params cp;
+ struct ble_ll_conn_params *req;
+ struct hci_conn_update *hcu;
+
+ /* Extract parameters and check if valid */
+ cp.interval_min = le16toh(dptr);
+ cp.interval_max = le16toh(dptr + 2);
+ cp.latency = le16toh(dptr + 4);
+ cp.timeout = le16toh(dptr + 6);
+ cp.pref_periodicity = dptr[8];
+ cp.ref_conn_event_cnt = le16toh(dptr + 9);
+ cp.offset0 = le16toh(dptr + 11);
+ cp.offset1 = le16toh(dptr + 13);
+ cp.offset2 = le16toh(dptr + 15);
+ cp.offset3 = le16toh(dptr + 17);
+ cp.offset4 = le16toh(dptr + 19);
+ cp.offset5 = le16toh(dptr + 21);
+
+ /* Check if parameters are valid */
+ ble_err = BLE_ERR_SUCCESS;
+ rc = ble_ll_conn_hci_chk_conn_params(cp.interval_min,
+ cp.interval_max,
+ cp.latency,
+ cp.timeout);
+ if (rc) {
+ ble_err = BLE_ERR_INV_LMP_LL_PARM;
+ goto conn_param_pdu_exit;
+ }
+
+ /*
+ * Check if there is a requested change to either the interval, timeout
+ * or latency. If not, this may just be an anchor point change and we do
+ * not have to notify the host.
+ * XXX: what if we dont like the parameters? When do we check that out?
+ */
+ req = NULL;
+ indicate = 1;
+ if ((connsm->conn_itvl >= cp.interval_min) &&
+ (connsm->conn_itvl <= cp.interval_max) &&
+ (connsm->supervision_tmo == cp.timeout) &&
+ (connsm->slave_latency == cp.latency)) {
+ indicate = 0;
+ /* XXX: For now, if we are a master, we wont send a response that
+ * needs to remember the request. That might change with connection
+ update pdu. Not sure. */
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ req = &cp;
+ }
+ goto conn_parm_req_do_indicate;
+ }
+
+ /*
+ * A change has been requested. Is it within the values specified by
+ * the host? Note that for a master we will not be processing a
+ * connect param request from a slave if we are currently trying to
+ * update the connection parameters. This means that the previous
+ * check is all we need for a master (when receiving a request).
+ */
+ if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) ||
+ (opcode == BLE_LL_CTRL_CONN_PARM_RSP)) {
+ /*
+ * Not sure what to do about the slave. It is possible that the
+ * current connection parameters are not the same ones as the local host
+ * has provided? Not sure what to do here. Do we need to remember what
+ * host sent us? For now, I will assume that we need to remember what
+ * the host sent us and check it out.
+ */
+ hcu = &connsm->conn_param_req;
+ if (hcu->handle != 0) {
+ if (!((cp.interval_min < hcu->conn_itvl_min) ||
+ (cp.interval_min > hcu->conn_itvl_max) ||
+ (cp.interval_max < hcu->conn_itvl_min) ||
+ (cp.interval_max > hcu->conn_itvl_max) ||
+ (cp.latency != hcu->conn_latency) ||
+ (cp.timeout != hcu->supervision_timeout))) {
+ indicate = 0;
+ }
+ }
+ }
+
+conn_parm_req_do_indicate:
+ /*
+ * XXX: are the connection update parameters acceptable? If not, we will
+ * need to know before we indicate to the host that they are acceptable.
+ */
+ if (indicate) {
+ /*
+ * Send event to host. At this point we leave and wait to get
+ * an answer.
+ */
+ ble_ll_hci_ev_rem_conn_parm_req(connsm, &cp);
+ connsm->host_reply_opcode = opcode;
+ connsm->awaiting_host_reply = 1;
+ rsp_opcode = 255;
+ } else {
+ /* Create reply to connection request */
+ rsp_opcode = ble_ll_ctrl_conn_param_reply(connsm, rspbuf, req);
+ }
+
+conn_param_pdu_exit:
+ if (ble_err) {
+ rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
+ rspbuf[1] = opcode;
+ rspbuf[2] = ble_err;
+ }
+ return rsp_opcode;
+}
+
/**
* Called to process and UNKNOWN_RSP LL control packet.
*
@@ -121,47 +269,34 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
uint8_t opcode;
/* Get opcode of unknown LL control frame */
- opcode = dptr[3];
+ opcode = dptr[0];
+ /* XXX: add others here */
/* Convert opcode to control procedure id */
switch (opcode) {
case BLE_LL_CTRL_LENGTH_REQ:
ctrl_proc = BLE_LL_CTRL_PROC_DATA_LEN_UPD;
break;
+ case BLE_LL_CTRL_CONN_UPDATE_REQ:
+ ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE;
+ break;
+ case BLE_LL_CTRL_CONN_PARM_RSP:
+ case BLE_LL_CTRL_CONN_PARM_REQ:
+ ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
+ break;
default:
ctrl_proc = BLE_LL_CTRL_PROC_NUM;
break;
}
+ /* XXX: are there any other events that we need to send when we get
+ the unknown response? */
/* If we are running this one currently, stop it */
if (connsm->cur_ctrl_proc == ctrl_proc) {
/* Stop the control procedure */
ble_ll_ctrl_proc_stop(connsm, ctrl_proc);
- }
-}
-
-/**
- * Send a data length change event for a connection to the host.
- *
- * @param connsm Pointer to connection state machine
- */
-void
-ble_ll_ctrl_datalen_chg_event(struct ble_ll_conn_sm *connsm)
-{
- uint8_t *evbuf;
-
- if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DATA_LEN_CHG - 1)) {
- evbuf = os_memblock_get(&g_hci_cmd_pool);
- if (evbuf) {
- evbuf[0] = BLE_HCI_EVCODE_LE_META;
- evbuf[1] = BLE_HCI_LE_DATA_LEN_CHG_LEN;
- evbuf[2] = BLE_HCI_LE_SUBEV_DATA_LEN_CHG;
- htole16(evbuf + 3, connsm->conn_handle);
- htole16(evbuf + 5, connsm->eff_max_tx_octets);
- htole16(evbuf + 7, connsm->eff_max_tx_time);
- htole16(evbuf + 9, connsm->eff_max_rx_octets);
- htole16(evbuf + 11, connsm->eff_max_rx_time);
- ble_ll_hci_event_send(evbuf);
+ if (ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+ ble_ll_hci_ev_conn_update(connsm, BLE_ERR_UNSUPP_FEATURE);
}
}
}
@@ -185,6 +320,285 @@ ble_ll_ctrl_datalen_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
}
/**
+ * Called to make a connection parameter request or response control pdu.
+ *
+ * @param connsm
+ * @param dptr Pointer to start of data. NOTE: the opcode is not part
+ * of the data.
+ */
+static void
+ble_ll_ctrl_conn_param_pdu_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+ struct ble_ll_conn_params *req)
+{
+ uint16_t invalid_offset;
+ struct hci_conn_update *hcu;
+
+ invalid_offset = 0xFFFF;
+ /* If we were passed in a request, we use the parameters from the request */
+ if (req) {
+ htole16(dptr, req->interval_min);
+ htole16(dptr + 2, req->interval_max);
+ htole16(dptr + 4, req->latency);
+ htole16(dptr + 6, req->timeout);
+ } else {
+ hcu = &connsm->conn_param_req;
+ /* The host should have provided the parameters! */
+ assert(hcu->handle != 0);
+ htole16(dptr, hcu->conn_itvl_min);
+ htole16(dptr + 2, hcu->conn_itvl_max);
+ htole16(dptr + 4, hcu->conn_latency);
+ htole16(dptr + 6, hcu->supervision_timeout);
+ }
+
+ /* XXX: NOTE: if interval min and interval max are != to each
+ * other this value should be set to non-zero. I think this
+ * applies only when an offset field is set. See section 5.1.7.1 pg 103
+ * Vol 6 Part B.
+ */
+ /* XXX: for now, set periodicity to 0 */
+ dptr[8] = 0;
+
+ /* XXX: deal with reference event count. what to put here? */
+ htole16(dptr + 9, connsm->event_cntr);
+
+ /* XXX: For now, dont use offsets */
+ htole16(dptr + 11, invalid_offset);
+ htole16(dptr + 13, invalid_offset);
+ htole16(dptr + 15, invalid_offset);
+ htole16(dptr + 17, invalid_offset);
+ htole16(dptr + 19, invalid_offset);
+ htole16(dptr + 21, invalid_offset);
+}
+
+/**
+ * Called to make a connection update request LL control PDU
+ *
+ * Context: Link Layer
+ *
+ * @param connsm
+ * @param rsp
+ */
+static void
+ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld)
+{
+ uint16_t instant;
+ struct hci_conn_update *hcu;
+ struct ble_ll_conn_upd_req *req;
+
+ /* Make sure we have the parameters! */
+ assert(connsm->conn_param_req.handle != 0);
+
+
+ /*
+ * Set instant. We set the instant to the current event counter plus
+ * the amount of slave latency as the slave may not be listening
+ * at every connection interval and we are not sure when the connect
+ * request will actually get sent. We add one more event plus the
+ * minimum as per the spec of 6 connection events.
+ */
+ instant = connsm->event_cntr + connsm->slave_latency + 6 + 1;
+
+ /*
+ * XXX: This should change in the future, but for now we will just
+ * start the new instant at the same anchor using win offset 0.
+ */
+ /* Copy parameters in connection update structure */
+ hcu = &connsm->conn_param_req;
+ req = &connsm->conn_update_req;
+ req->winsize = connsm->tx_win_size;
+ req->winoffset = 0;
+ req->interval = hcu->conn_itvl_max;
+ req->timeout = hcu->supervision_timeout;
+ req->latency = hcu->conn_latency;
+ req->instant = instant;
+
+ /* XXX: make sure this works for the connection parameter request proc. */
+ pyld[0] = req->winsize;
+ htole16(pyld + 1, req->winoffset);
+ htole16(pyld + 3, req->interval);
+ htole16(pyld + 5, req->latency);
+ htole16(pyld + 7, req->timeout);
+ htole16(pyld + 9, instant);
+
+ /* Set flag in state machine to denote we have scheduled an update */
+ connsm->conn_update_scheduled = 1;
+}
+
+/**
+ * Called to respond to a LL control PDU connection parameter request or
+ * response.
+ *
+ * @param connsm
+ * @param rsp
+ * @param req
+ *
+ * @return uint8_t
+ */
+uint8_t
+ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp,
+ struct ble_ll_conn_params *req)
+{
+ uint8_t rsp_opcode;
+
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ /* Create a connection parameter response */
+ ble_ll_ctrl_conn_param_pdu_make(connsm, rsp + 1, req);
+ rsp_opcode = BLE_LL_CTRL_CONN_PARM_RSP;
+ } else {
+ /* Create a connection update pdu */
+ ble_ll_ctrl_conn_upd_make(connsm, rsp + 1);
+ rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_REQ;
+ }
+
+ return rsp_opcode;
+}
+
+/**
+ * Called when we receive a connection update event
+ *
+ * @param connsm
+ * @param dptr
+ * @param rspbuf
+ *
+ * @return int
+ */
+static int
+ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+ uint8_t *rspbuf)
+{
+ uint8_t rsp_opcode;
+ uint16_t conn_events;
+ struct ble_ll_conn_upd_req *reqdata;
+
+ /* Only a slave should receive this */
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+ return BLE_ERR_MAX;
+ }
+
+#if 0
+ /* Deal with receiving this when in this state. I think we are done */
+ if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+ }
+#endif
+
+ /* Retrieve parameters */
+ reqdata = &connsm->conn_update_req;
+ reqdata->winsize = dptr[0];
+ reqdata->winoffset = le16toh(dptr + 1);
+ reqdata->interval = le16toh(dptr + 3);
+ reqdata->latency = le16toh(dptr + 5);
+ reqdata->timeout = le16toh(dptr + 7);
+ reqdata->instant = le16toh(dptr + 9);
+
+ /* XXX: validate them at some point. If they dont check out, we
+ return the unknown response */
+
+ /* If instant is in the past, we have to end the connection */
+ conn_events = (reqdata->instant - connsm->event_cntr) & 0xFFFF;
+ if (conn_events >= 32767) {
+ ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED);
+ rsp_opcode = BLE_ERR_MAX;
+ } else {
+ connsm->conn_update_scheduled = 1;
+ }
+
+ return rsp_opcode;
+}
+
+static int
+ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+ uint8_t *rspbuf)
+{
+ uint8_t rsp_opcode;
+
+ /*
+ * This is not in the specification per se but it simplifies the
+ * implementation. If we get a connection parameter request and we
+ * are awaiting a reply from the host, simply ignore the request. This
+ * might not be a good idea if the parameters are different, but oh
+ * well. This is not expected to happen anyway. A return of BLE_ERR_MAX
+ * means that we will simply discard the connection parameter request
+ */
+ if (connsm->awaiting_host_reply) {
+ return BLE_ERR_MAX;
+ }
+
+ /* XXX: remember to deal with this on the master: if the slave has
+ * initiated a procedure we may have received its connection parameter
+ * update request and have signaled the host with an event. If that
+ * is the case, we will need to drop the host command when we get it
+ and also clear any applicable states. */
+
+ /* XXX: Read 5.3 again. There are multiple control procedures that might
+ * be pending (a connection update) that will cause collisions and the
+ behavior below. */
+ /*
+ * Check for procedure collision (Vol 6 PartB 5.3). If we are a slave
+ * and we receive a request we "consider the slave initiated
+ * procedure as complete". This means send a connection update complete
+ * event (with error).
+ *
+ * If a master, we send reject with a
+ * transaction collision error code.
+ */
+ if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+ ble_ll_ctrl_proc_stop(connsm,
+ BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
+ } else {
+ connsm->pending_ctrl_procs &=
+ ~BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
+ }
+ ble_ll_hci_ev_conn_update(connsm, BLE_ERR_LMP_COLLISION);
+ } else {
+ /* The master sends reject ind ext w/error code 0x23 */
+ rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
+ rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ;
+ rspbuf[2] = BLE_ERR_LMP_COLLISION;
+ return rsp_opcode;
+ }
+ }
+
+ /* Process the received connection parameter request */
+ rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf,
+ BLE_LL_CTRL_CONN_PARM_REQ);
+ return rsp_opcode;
+}
+
+static int
+ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+ uint8_t *rspbuf)
+{
+ uint8_t rsp_opcode;
+
+ /* A slave should never receive this response */
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ return BLE_ERR_MAX;
+ }
+
+ /*
+ * This case should never happen! It means that the slave initiated a
+ * procedure and the master initiated one as well. If we do get in this
+ * state just clear the awaiting reply. The slave will hopefully stop its
+ * procedure when we reply.
+ */
+ if (connsm->awaiting_host_reply) {
+ connsm->awaiting_host_reply = 0;
+ }
+
+ /* If we receive a response and no procedure is pending, just leave */
+ if (!IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+ return BLE_ERR_MAX;
+ }
+
+ /* Process the received connection parameter response */
+ rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf,
+ BLE_LL_CTRL_CONN_PARM_RSP);
+ return rsp_opcode;
+}
+
+/**
* Callback when LL control procedure times out (for a given connection). If
* this is called, it means that we need to end the connection because it
* has not responded to a LL control request.
@@ -224,15 +638,21 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
switch (ctrl_proc) {
case BLE_LL_CTRL_PROC_DATA_LEN_UPD:
- len = BLE_LL_CTRL_LENGTH_REQ_LEN;
opcode = BLE_LL_CTRL_LENGTH_REQ;
ble_ll_ctrl_datalen_upd_make(connsm, dptr);
break;
case BLE_LL_CTRL_PROC_TERMINATE:
- len = BLE_LL_CTRL_TERMINATE_IND_LEN;
opcode = BLE_LL_CTRL_TERMINATE_IND;
dptr[1] = connsm->disconnect_reason;
break;
+ case BLE_LL_CTRL_PROC_CONN_PARAM_REQ:
+ opcode = BLE_LL_CTRL_CONN_PARM_REQ;
+ ble_ll_ctrl_conn_param_pdu_make(connsm, dptr + 1, NULL);
+ break;
+ case BLE_LL_CTRL_PROC_CONN_UPDATE:
+ opcode = BLE_LL_CTRL_CONN_UPDATE_REQ;
+ ble_ll_ctrl_conn_upd_make(connsm, dptr + 1);
+ break;
default:
assert(0);
break;
@@ -240,7 +660,7 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
/* Set llid, length and opcode */
dptr[0] = opcode;
- ++len;
+ len = g_ble_ll_ctrl_pkt_lengths[opcode] + 1;
/* Add packet to transmit queue of connection */
ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
@@ -272,6 +692,29 @@ ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode)
}
/**
+ * Called to determine if the pdu is a TERMINATE_IND
+ *
+ * @param hdr
+ * @param opcode
+ *
+ * @return int
+ */
+int
+ble_ll_ctrl_is_reject_ind_ext(uint8_t hdr, uint8_t opcode)
+{
+ int rc;
+
+ rc = 0;
+ if ((hdr & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) {
+ if (opcode == BLE_LL_CTRL_REJECT_IND_EXT) {
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
+
+/**
* Stops the LL control procedure indicated by 'ctrl_proc'.
*
* Context: Link Layer task
@@ -282,11 +725,11 @@ ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode)
void
ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc)
{
- if (connsm->cur_ctrl_proc == ctrl_proc) {
- os_callout_stop(&connsm->ctrl_proc_rsp_timer.cf_c);
- connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
- connsm->pending_ctrl_procs &= ~(1 << ctrl_proc);
- }
+ assert(connsm->cur_ctrl_proc == ctrl_proc);
+
+ os_callout_stop(&connsm->ctrl_proc_rsp_timer.cf_c);
+ connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
+ connsm->pending_ctrl_procs &= ~(1 << ctrl_proc);
/* If there are others, start them */
ble_ll_ctrl_chk_proc_start(connsm);
@@ -352,7 +795,7 @@ ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc)
/* Re-start the timer. Control procedure timeout is 40 seconds */
os_callout_reset(&connsm->ctrl_proc_rsp_timer.cf_c,
- OS_TICKS_PER_SEC * 40);
+ OS_TICKS_PER_SEC * BLE_LL_CTRL_PROC_TIMEOUT);
}
}
@@ -378,7 +821,7 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm)
/*
* If the terminate procedure is not pending it means we were not
* able to start it right away (no control pdu was available).
- * Start it now
+ * Start it now.
*/
ble_ll_ctrl_terminate_start(connsm);
return;
@@ -413,70 +856,91 @@ void
ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
{
uint8_t features;
+ uint8_t feature;
uint8_t len;
uint8_t opcode;
+ uint8_t rsp_opcode;
uint8_t *dptr;
+ uint8_t *rspbuf;
/* XXX: where do we validate length received and packet header length?
* do this in LL task when received. Someplace!!! What I mean
* is we should validate the over the air length with the mbuf length.
Should the PHY do that???? */
- /* Get length and opcode from PDU */
+ /* Get length and opcode from PDU.*/
dptr = om->om_data;
+ rspbuf = dptr;
len = dptr[1];
opcode = dptr[2];
+ /* Move data pointer to start of control data (2 byte PDU hdr + opcode) */
+ dptr += (BLE_LL_PDU_HDR_LEN + 1);
+
+ /*
+ * Subtract the opcode from the length. Note that if the length was zero,
+ * which would be an error, we will fail the check against the length
+ * of the control packet.
+ */
+ --len;
+
/* opcode must be good */
- if ((opcode > BLE_LL_CTRL_LENGTH_RSP) || (len < 1) ||
- (len > BLE_LL_CTRL_MAX_PAYLOAD)) {
+ if ((opcode >= BLE_LL_CTRL_OPCODES) ||
+ (len != g_ble_ll_ctrl_pkt_lengths[opcode])) {
goto rx_malformed_ctrl;
}
- /* Subtract the opcode from the length */
- --len;
-
+ /* Check if the feature is supported. */
switch (opcode) {
case BLE_LL_CTRL_LENGTH_REQ:
- /* Check length */
- if (len != BLE_LL_CTRL_LENGTH_REQ_LEN) {
- goto rx_malformed_ctrl;
- }
+ feature = BLE_LL_FEAT_DATA_LEN_EXT;
+ break;
+ case BLE_LL_CTRL_CONN_PARM_REQ:
+ case BLE_LL_CTRL_CONN_PARM_RSP:
+ feature = BLE_LL_FEAT_CONN_PARM_REQ;
+ break;
+ default:
+ feature = 0;
+ break;
+ }
- /* Check parameters for validity */
+ if (feature) {
features = ble_ll_read_supp_features();
- if (features & BLE_LL_FEAT_DATA_LEN_EXT) {
- /* Extract parameters and check if valid */
- if (ble_ll_ctrl_len_proc(connsm, dptr)) {
- goto rx_malformed_ctrl;
- }
-
- /*
- * If we have not started this procedure ourselves and it is
- * pending, no need to perform it.
- */
- if ((connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_DATA_LEN_UPD) &&
- IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD)) {
- connsm->pending_ctrl_procs &= ~BLE_LL_CTRL_PROC_DATA_LEN_UPD;
- }
-
- /* Send a response */
- opcode = BLE_LL_CTRL_LENGTH_RSP;
- ble_ll_ctrl_datalen_upd_make(connsm, dptr);
- } else {
- /* XXX: construct unknown pdu */
- opcode = BLE_LL_CTRL_UNKNOWN_RSP;
- len = BLE_LL_CTRL_UNK_RSP_LEN;
- dptr[1] = BLE_LL_CTRL_LENGTH_REQ;
+ if ((features & feature) == 0) {
+ /* Construct unknown rsp pdu */
+ rspbuf[1] = opcode;
+ rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
+ goto ll_ctrl_send_rsp;
}
+ }
+
+ /* Process opcode */
+ rsp_opcode = 255;
+ switch (opcode) {
+ case BLE_LL_CTRL_CONN_UPDATE_REQ:
+ rsp_opcode = ble_ll_ctrl_rx_conn_update(connsm, dptr, rspbuf);
break;
- case BLE_LL_CTRL_LENGTH_RSP:
- /* Check length (response length same as request length) */
- if (len != BLE_LL_CTRL_LENGTH_REQ_LEN) {
+ case BLE_LL_CTRL_LENGTH_REQ:
+ /* Extract parameters and check if valid */
+ if (ble_ll_ctrl_len_proc(connsm, dptr)) {
goto rx_malformed_ctrl;
}
/*
+ * If we have not started this procedure ourselves and it is
+ * pending, no need to perform it.
+ */
+ if ((connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_DATA_LEN_UPD) &&
+ IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD)) {
+ connsm->pending_ctrl_procs &= ~BLE_LL_CTRL_PROC_DATA_LEN_UPD;
+ }
+
+ /* Send a response */
+ rsp_opcode = BLE_LL_CTRL_LENGTH_RSP;
+ ble_ll_ctrl_datalen_upd_make(connsm, rspbuf);
+ break;
+ case BLE_LL_CTRL_LENGTH_RSP:
+ /*
* According to specification, we should only process this if we
* asked for it.
*/
@@ -489,29 +953,49 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
/* Stop the control procedure */
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
}
- opcode = 255;
break;
case BLE_LL_CTRL_UNKNOWN_RSP:
- /* Check length (response length same as request length) */
- if (len != BLE_LL_CTRL_UNK_RSP_LEN) {
- goto rx_malformed_ctrl;
- }
-
ble_ll_ctrl_proc_unk_rsp(connsm, dptr);
- opcode = 255;
+ break;
+
+ /* XXX: remember to check if feature supported */
+ case BLE_LL_CTRL_CHANNEL_MAP_REQ:
+ case BLE_LL_CTRL_ENC_REQ:
+ case BLE_LL_CTRL_START_ENC_REQ:
+ case BLE_LL_CTRL_FEATURE_REQ:
+ case BLE_LL_CTRL_PAUSE_ENC_REQ:
+ case BLE_LL_CTRL_SLAVE_FEATURE_REQ:
+ /* Construct unknown pdu */
+ rspbuf[1] = opcode;
+ rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
+ break;
+ case BLE_LL_CTRL_CONN_PARM_REQ:
+ rsp_opcode = ble_ll_ctrl_rx_conn_param_req(connsm, dptr, rspbuf);
+ break;
+ case BLE_LL_CTRL_CONN_PARM_RSP:
+ rsp_opcode = ble_ll_ctrl_rx_conn_param_rsp(connsm, dptr, rspbuf);
+ break;
+ case BLE_LL_CTRL_REJECT_IND_EXT:
+ /* XXX: not sure what other control procedures to check out, but
+ add them when needed */
+ /* XXX: should I check to make sure that the rejected opcode is sane? */
+ if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
+ ble_ll_hci_ev_conn_update(connsm, dptr[1]);
+ }
break;
default:
- /* XXX: this is an un-implemented control procedure. What to do? */
- opcode = 255;
+ /* We really should never get here */
break;
}
/* Free mbuf or send response */
- if (opcode == 255) {
+ll_ctrl_send_rsp:
+ if (rsp_opcode == 255) {
os_mbuf_free(om);
} else {
- ++len;
- dptr[0] = opcode;
+ rspbuf[0] = rsp_opcode;
+ len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1;
ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
}
return;
@@ -521,3 +1005,37 @@ rx_malformed_ctrl:
++g_ble_ll_stats.rx_malformed_ctrl_pdus;
return;
}
+
+/**
+ * Called to creeate and send a REJECT_IND_EXT control PDU
+ *
+ *
+ * @param connsm
+ * @param rej_opcode
+ * @param err
+ *
+ * @return int
+ */
+int
+ble_ll_ctrl_reject_ind_ext_send(struct ble_ll_conn_sm *connsm,
+ uint8_t rej_opcode, uint8_t err)
+{
+ int rc;
+ uint8_t len;
+ uint8_t *rspbuf;
+ struct os_mbuf *om;
+
+ om = os_mbuf_get_pkthdr(&g_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+ if (om) {
+ rspbuf = om->om_data;
+ rspbuf[0] = BLE_LL_CTRL_REJECT_IND_EXT;
+ rspbuf[1] = rej_opcode;
+ rspbuf[2] = err;
+ len = BLE_LL_CTRL_REJECT_IND_EXT_LEN + 1;
+ ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
+ rc = 0;
+ } else {
+ rc = 1;
+ }
+ return rc;
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_hci.c b/net/nimble/controller/src/ble_ll_hci.c
index 3f6bd95..112e7e8 100644
--- a/net/nimble/controller/src/ble_ll_hci.c
+++ b/net/nimble/controller/src/ble_ll_hci.c
@@ -157,20 +157,22 @@ ble_ll_hci_le_read_local_features(uint8_t *rspbuf, uint8_t *rsplen)
/**
* Checks to see if a LE event has been disabled by the host.
*
- * @param bitpos This is the bit position of the LE event. Note that this can
+ * @param subev Sub-event code of the LE Meta event. Note that this can
* be a value from 0 to 63, inclusive.
*
* @return uint8_t 0: event is not enabled; otherwise event is enabled.
*/
uint8_t
-ble_ll_hci_is_le_event_enabled(int bitpos)
+ble_ll_hci_is_le_event_enabled(int subev)
{
uint8_t enabled;
uint8_t bytenum;
uint8_t bitmask;
+ int bitpos;
/* The LE meta event must be enabled for any LE event to be enabled */
enabled = 0;
+ bitpos = subev - 1;
if (g_ble_ll_hci_event_mask[7] & 0x20) {
bytenum = bitpos / 8;
bitmask = 1 << (bitpos & 0x7);
@@ -332,6 +334,26 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
rc = ble_ll_whitelist_rmv(cmdbuf + 1, cmdbuf[0]);
}
break;
+ case BLE_HCI_OCF_LE_CONN_UPDATE:
+ if (len == BLE_HCI_CONN_UPDATE_LEN) {
+ rc = ble_ll_conn_update(cmdbuf);
+ }
+ /* This is a hack; command status gets sent instead of cmd complete */
+ rc += (BLE_ERR_MAX + 1);
+ break;
+
+ case BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR:
+ if (len == BLE_HCI_CONN_PARAM_NEG_REPLY_LEN) {
+ rc = ble_ll_conn_param_reply(cmdbuf, 0);
+ }
+ break;
+
+ case BLE_HCI_OCF_LE_REM_CONN_PARAM_RR:
+ if (len == BLE_HCI_CONN_PARAM_REPLY_LEN) {
+ rc = ble_ll_conn_param_reply(cmdbuf, 1);
+ }
+ break;
+
default:
rc = BLE_ERR_UNKNOWN_HCI_CMD;
break;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_scan.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_scan.c b/net/nimble/controller/src/ble_ll_scan.c
index 1b2ec0b..93aca0e 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -124,46 +124,6 @@ ble_ll_scan_req_backoff(struct ble_ll_scan_sm *scansm, int success)
}
/**
- * Called to determine if we are inside or outside the scan window. If we
- * are inside the scan window it means that the device should be receiving
- * on the scan channel.
- *
- * Context: Interrupt and Link Layer
- *
- * @param scansm
- *
- * @return int 0: inside scan window 1: outside scan window
- */
-int
-ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm)
-{
- int rc;
- uint32_t now;
- uint32_t itvl;
-
- rc = 0;
- itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
- now = cputime_get32();
- while ((int32_t)(now - scansm->scan_win_start_time) >= itvl) {
- scansm->scan_win_start_time += itvl;
- ++scansm->scan_chan;
- if (scansm->scan_chan == BLE_PHY_NUM_CHANS) {
- scansm->scan_chan = BLE_PHY_ADV_CHAN_START;
- }
- }
-
- if (scansm->scan_window != scansm->scan_itvl) {
- itvl = cputime_usecs_to_ticks(scansm->scan_window *
- BLE_HCI_SCAN_ITVL);
- if ((now - scansm->scan_win_start_time) >= itvl) {
- rc = 1;
- }
- }
-
- return rc;
-}
-
-/**
* ble ll scan req pdu make
*
* Construct a SCAN_REQ PDU.
@@ -431,7 +391,7 @@ ble_ll_hci_send_adv_report(uint8_t pdu_type, uint8_t txadd, uint8_t *rxbuf,
adv_data_len -= BLE_DEV_ADDR_LEN;
}
- if (ble_ll_hci_is_le_event_enabled(subev - 1)) {
+ if (ble_ll_hci_is_le_event_enabled(subev)) {
evbuf = os_memblock_get(&g_hci_cmd_pool);
if (evbuf) {
evbuf[0] = BLE_HCI_EVCODE_LE_META;
@@ -539,12 +499,12 @@ ble_ll_scan_chk_filter_policy(uint8_t pdu_type, uint8_t *rxbuf, uint8_t flags)
* @return int
*/
static int
-ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
+ble_ll_scan_start(struct ble_ll_scan_sm *scansm, uint8_t chan)
{
int rc;
/* Set channel */
- rc = ble_phy_setchan(scansm->scan_chan, 0, 0);
+ rc = ble_phy_setchan(chan, 0, 0);
assert(rc == 0);
/*
@@ -568,7 +528,6 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
/* Set end time to end of scan window */
rc = BLE_LL_SCHED_STATE_RUNNING;
}
- scansm->last_sched_time = cputime_get32();
/* If there is a still a scan response pending, we have failed! */
if (scansm->scan_rsp_pending) {
@@ -578,6 +537,75 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
return rc;
}
+static void
+ble_ll_scan_update_window(struct ble_ll_scan_sm *scansm, uint32_t cputime)
+{
+ uint8_t chan;
+ uint32_t itvl;
+ uint32_t win_start;
+
+ itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
+ chan = scansm->scan_chan;
+ win_start = scansm->scan_win_start_time;
+ while ((int32_t)(cputime - win_start) >= itvl) {
+ win_start += itvl;
+ ++chan;
+ if (chan == BLE_PHY_NUM_CHANS) {
+ chan = BLE_PHY_ADV_CHAN_START;
+ }
+ }
+
+ scansm->scan_chan = chan;
+ scansm->scan_win_start_time = win_start;
+ scansm->last_sched_time = cputime;
+}
+
+/**
+ * Called to determine if we are inside or outside the scan window. If we
+ * are inside the scan window it means that the device should be receiving
+ * on the scan channel.
+ *
+ * Context: Interrupt and Link Layer
+ *
+ * @param scansm
+ *
+ * @return int 0: inside scan window 1: outside scan window
+ */
+static int
+ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime)
+{
+ int rc;
+ uint8_t chan;
+ uint32_t itvl;
+ uint32_t win_start;
+
+ itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
+ chan = scansm->scan_chan;
+ win_start = scansm->scan_win_start_time;
+ while ((int32_t)(cputime - win_start) >= itvl) {
+ win_start += itvl;
+ ++chan;
+ if (chan == BLE_PHY_NUM_CHANS) {
+ chan = BLE_PHY_ADV_CHAN_START;
+ }
+ }
+
+ rc = 0;
+ if (scansm->scan_window != scansm->scan_itvl) {
+ itvl = cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
+ if ((cputime - win_start) >= itvl) {
+ rc = 1;
+ }
+ }
+
+ if (!rc) {
+ /* Turn on the receiver and set state */
+ ble_ll_scan_start(scansm, chan);
+ }
+
+ return rc;
+}
+
/**
* Called when the scanning schedule item executes
*
@@ -591,6 +619,7 @@ int
ble_ll_scan_sched_cb(struct ble_ll_sched_item *sch)
{
int rc;
+ uint32_t now;
struct ble_ll_scan_sm *scansm;
/*
@@ -618,23 +647,22 @@ ble_ll_scan_sched_cb(struct ble_ll_sched_item *sch)
break;
}
+ now = cputime_get32();
scansm = (struct ble_ll_scan_sm *)sch->cb_arg;
if (rc) {
rc = BLE_LL_SCHED_STATE_DONE;
} else {
/* Determine if we should be off or receiving */
- rc = ble_ll_scan_window_chk(scansm);
+ rc = ble_ll_scan_window_chk(scansm, now);
if (!rc) {
- ble_ll_scan_start(scansm);
rc = BLE_LL_SCHED_STATE_RUNNING;
} else {
rc = BLE_LL_SCHED_STATE_DONE;
}
}
- if (rc == BLE_LL_SCHED_STATE_DONE) {
- scansm->last_sched_time = cputime_get32();
- }
+ /* Update scan window start time and channel */
+ ble_ll_scan_update_window(scansm, now);
/* Post scanning scheduled done event */
ble_ll_event_send(&scansm->scan_sched_ev);
@@ -733,6 +761,7 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
/* XXX: align to current or next slot???. */
/* Schedule start time now */
scansm->scan_win_start_time = cputime_get32();
+ scansm->last_sched_time = scansm->scan_win_start_time;
/*
* If we are in standby, start scanning. Otherwise, scanning will resume
@@ -740,7 +769,7 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
*/
OS_ENTER_CRITICAL(sr);
if (ble_ll_state_get() == BLE_LL_STATE_STANDBY) {
- ble_ll_scan_start(scansm);
+ ble_ll_scan_start(scansm, BLE_PHY_ADV_CHAN_START);
}
OS_EXIT_CRITICAL(sr);
@@ -986,10 +1015,7 @@ ble_ll_scan_chk_resume(void)
if (scansm->scan_enabled) {
OS_ENTER_CRITICAL(sr);
if (ble_ll_state_get() == BLE_LL_STATE_STANDBY) {
- if (!ble_ll_scan_window_chk(scansm)) {
- /* Turn on the receiver and set state */
- ble_ll_scan_start(scansm);
- }
+ ble_ll_scan_window_chk(scansm, cputime_get32());
}
OS_EXIT_CRITICAL(sr);
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/project/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c
index a3c1466..67795f5 100755
--- a/project/bletest/src/main.c
+++ b/project/bletest/src/main.c
@@ -25,6 +25,7 @@
/* BLE */
#include "nimble/ble.h"
#include "nimble/hci_transport.h"
+#include "nimble/hci_common.h"
#include "host/host_hci.h"
#include "host/ble_hs.h"
#include "controller/ble_ll.h"
@@ -33,9 +34,6 @@
#include "controller/ble_ll_scan.h"
#include "controller/ble_ll_adv.h"
-/* Init all tasks */
-volatile int tasks_initialized;
-
/* Task 1 */
#define HOST_TASK_PRIO (1)
@@ -53,7 +51,7 @@ uint8_t g_host_adv_data[BLE_HCI_MAX_ADV_DATA_LEN];
uint8_t g_host_adv_len;
/* Create a mbuf pool of BLE mbufs */
-#define MBUF_NUM_MBUFS (20)
+#define MBUF_NUM_MBUFS (40)
#define MBUF_BUF_SIZE \
((BLE_LL_CFG_ACL_DATA_PKT_LEN + sizeof(struct hci_data_hdr) + 3) & 0xFFFC)
#define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + BLE_MBUF_PKT_OVERHEAD)
@@ -77,15 +75,16 @@ os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE];
#define BLETEST_CFG_SCAN_WINDOW (700000 / BLE_HCI_SCAN_ITVL)
#define BLETEST_CFG_SCAN_TYPE (BLE_HCI_SCAN_TYPE_ACTIVE)
#define BLETEST_CFG_SCAN_FILT_POLICY (BLE_HCI_SCAN_FILT_NO_WL)
-#define BLETEST_CFG_CONN_ITVL (1000) /* in 1.25 msec increments */
+#define BLETEST_CFG_CONN_ITVL (64) /* in 1.25 msec increments */
#define BLETEST_CFG_SLAVE_LATENCY (0)
#define BLETEST_CFG_INIT_FILTER_POLICY (BLE_HCI_CONN_FILT_NO_WL)
-#define BLETEST_CFG_CONN_SPVN_TMO (1000) /* 10 seconds */
+#define BLETEST_CFG_CONN_SPVN_TMO (2000) /* 20 seconds */
#define BLETEST_CFG_MIN_CE_LEN (6)
#define BLETEST_CFG_MAX_CE_LEN (BLETEST_CFG_CONN_ITVL)
-#define BLETEST_CFG_CONCURRENT_CONNS (8)
+#define BLETEST_CFG_CONCURRENT_CONNS (1)
/* BLETEST variables */
+#undef BLETEST_ADV_PKT_NUM
#define BLETEST_PKT_SIZE (128)
#define BLETEST_STACK_SIZE (256)
#define BLETEST_TASK_PRIO (HOST_TASK_PRIO + 1)
@@ -94,13 +93,16 @@ int g_bletest_state;
struct os_eventq g_bletest_evq;
struct os_callout_func g_bletest_timer;
struct os_task bletest_task;
-os_stack_t bletest_stack[BLETEST_STACK_SIZE];
+#if !defined(nzbss_t)
+#define nzbss_t
+#endif
+nzbss_t os_stack_t bletest_stack[BLETEST_STACK_SIZE];
uint32_t g_bletest_conn_end;
uint8_t g_bletest_current_conns;
uint8_t g_bletest_cur_peer_addr[BLE_DEV_ADDR_LEN];
uint8_t g_last_handle_used;
-#if 0
+#ifdef BLETEST_ADV_PKT_NUM
void
bletest_inc_adv_pkt_num(void)
{
@@ -128,12 +130,6 @@ bletest_inc_adv_pkt_num(void)
host_hci_outstanding_opcode = 0;
}
}
-#else
-void
-bletest_inc_adv_pkt_num(void)
-{
- return;
-}
#endif
/**
@@ -333,7 +329,9 @@ bletest_init_initiator(void)
void
bletest_execute(void)
{
+ int rc;
uint16_t handle;
+ struct hci_conn_update hcu;
/*
* Determine if there is an active connection for the current handle
@@ -342,6 +340,9 @@ bletest_execute(void)
if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
handle = g_bletest_current_conns + 1;
if (ble_ll_conn_find_active_conn(handle)) {
+ /* Set next os time to start the connection update */
+ g_next_os_time = 0;
+
/* Scanning better be stopped! */
assert(ble_ll_scan_enabled() == 0);
@@ -356,6 +357,30 @@ bletest_execute(void)
bletest_init_initiator();
}
}
+ } else {
+ /* Issue a connection parameter update to connection handle 1 */
+ if (g_next_os_time == 0) {
+ g_next_os_time = os_time_get();
+ g_next_os_time += OS_TICKS_PER_SEC * 5;
+ } else {
+ if (g_next_os_time != 0xffffffff) {
+ if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
+ hcu.conn_latency = 0;
+ hcu.supervision_timeout = 1000;
+ hcu.conn_itvl_min = 1000;
+ hcu.conn_itvl_max = 1000;
+ hcu.handle = 1;
+ hcu.min_ce_len = 4;
+ hcu.max_ce_len = 4;
+
+ rc = host_hci_cmd_le_conn_update(&hcu);
+ assert(rc == 0);
+ host_hci_outstanding_opcode = 0;
+
+ g_next_os_time = 0xffffffff;
+ }
+ }
+ }
}
}
#endif
@@ -488,7 +513,7 @@ bletest_execute(void)
if (g_bletest_current_conns) {
for (i = 0; i < g_bletest_current_conns; ++i) {
if ((g_last_handle_used == 0) ||
- (g_last_handle_used >= g_bletest_current_conns)) {
+ (g_last_handle_used > g_bletest_current_conns)) {
g_last_handle_used = 1;
}
handle = g_last_handle_used;
@@ -653,8 +678,6 @@ init_tasks(void)
BLETEST_TASK_PRIO, OS_WAIT_FOREVER, bletest_stack,
BLETEST_STACK_SIZE);
- tasks_initialized = 1;
-
/* Initialize host HCI */
rc = ble_hs_init(HOST_TASK_PRIO);
assert(rc == 0);
[2/2] incubator-mynewt-larva git commit: Moved some events to new
module since others getting cluttered
Posted by we...@apache.org.
Moved some events to new module since others getting cluttered
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/7a82be0e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/7a82be0e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/7a82be0e
Branch: refs/heads/master
Commit: 7a82be0e594bc706f195aae15b8e711576adcf99
Parents: 262b1be
Author: wes3 <wi...@micosa.io>
Authored: Fri Jan 22 15:20:17 2016 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Fri Jan 22 15:20:17 2016 -0800
----------------------------------------------------------------------
net/nimble/controller/src/ble_ll_hci_ev.c | 106 +++++++++++++++++++++++++
1 file changed, 106 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/7a82be0e/net/nimble/controller/src/ble_ll_hci_ev.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_hci_ev.c b/net/nimble/controller/src/ble_ll_hci_ev.c
new file mode 100644
index 0000000..6fb2157
--- /dev/null
+++ b/net/nimble/controller/src/ble_ll_hci_ev.c
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include "nimble/ble.h"
+#include "nimble/hci_common.h"
+#include "controller/ble_ll.h"
+#include "controller/ble_ll_hci.h"
+#include "controller/ble_ll_ctrl.h"
+#include "ble_ll_conn_priv.h"
+
+/**
+ * Send a data length change event for a connection to the host.
+ *
+ * @param connsm Pointer to connection state machine
+ */
+void
+ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm)
+{
+ uint8_t *evbuf;
+
+ if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DATA_LEN_CHG)) {
+ evbuf = os_memblock_get(&g_hci_cmd_pool);
+ if (evbuf) {
+ evbuf[0] = BLE_HCI_EVCODE_LE_META;
+ evbuf[1] = BLE_HCI_LE_DATA_LEN_CHG_LEN;
+ evbuf[2] = BLE_HCI_LE_SUBEV_DATA_LEN_CHG;
+ htole16(evbuf + 3, connsm->conn_handle);
+ htole16(evbuf + 5, connsm->eff_max_tx_octets);
+ htole16(evbuf + 7, connsm->eff_max_tx_time);
+ htole16(evbuf + 9, connsm->eff_max_rx_octets);
+ htole16(evbuf + 11, connsm->eff_max_rx_time);
+ ble_ll_hci_event_send(evbuf);
+ }
+ }
+}
+
+/**
+ * Send a connection parameter request event for a connection to the host.
+ *
+ * @param connsm Pointer to connection state machine
+ */
+void
+ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm,
+ struct ble_ll_conn_params *cp)
+{
+ uint8_t *evbuf;
+
+ if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ)) {
+ evbuf = os_memblock_get(&g_hci_cmd_pool);
+ if (evbuf) {
+ evbuf[0] = BLE_HCI_EVCODE_LE_META;
+ evbuf[1] = BLE_HCI_LE_REM_CONN_PARM_REQ_LEN;
+ evbuf[2] = BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ;
+ htole16(evbuf + 3, connsm->conn_handle);
+ htole16(evbuf + 5, cp->interval_min);
+ htole16(evbuf + 7, cp->interval_max);
+ htole16(evbuf + 9, cp->latency);
+ htole16(evbuf + 11, cp->timeout);
+ ble_ll_hci_event_send(evbuf);
+ }
+ }
+}
+
+/**
+ * Send a data length change event for a connection to the host.
+ *
+ * @param connsm Pointer to connection state machine
+ * @param status The error code.
+ */
+void
+ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status)
+{
+ uint8_t *evbuf;
+
+ if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE)) {
+ evbuf = os_memblock_get(&g_hci_cmd_pool);
+ if (evbuf) {
+ evbuf[0] = BLE_HCI_EVCODE_LE_META;
+ evbuf[1] = BLE_HCI_LE_CONN_UPD_LEN;
+ evbuf[2] = BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE;
+ evbuf[3] = status;
+ if (status == BLE_ERR_SUCCESS) {
+ htole16(evbuf + 4, connsm->conn_handle);
+ htole16(evbuf + 6, connsm->conn_itvl);
+ htole16(evbuf + 8, connsm->slave_latency);
+ htole16(evbuf + 10, connsm->supervision_tmo);
+ }
+ ble_ll_hci_event_send(evbuf);
+ }
+ }
+}