Merge pull request #181 from rymanluk/ll_fix

nimble/ll: Certification fixes - part 2
This commit is contained in:
Łukasz Rymanowski
2018-09-19 12:07:17 +02:00
committed by GitHub
9 changed files with 355 additions and 227 deletions
@@ -253,7 +253,7 @@ uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm,
struct ble_ll_conn_params *req);
int ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm,
uint8_t rej_opcode, uint8_t err);
int ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm, uint8_t opcode);
int ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm);
int ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu);
int ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr *pkthdr);
int ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm);
@@ -92,6 +92,7 @@ struct ble_ll_scan_params
#define BLE_LL_AUX_INCOMPLETE_BIT 0x02
#define BLE_LL_AUX_INCOMPLETE_ERR_BIT 0x04
#define BLE_LL_AUX_HAS_ADDRA 0x08
#define BLE_LL_AUX_IGNORE_BIT 0x10
#define BLE_LL_CHECK_AUX_FLAG(aux_data, flag) (!!((aux_data)->flags & flag))
@@ -102,12 +103,14 @@ struct ble_ll_aux_data {
uint8_t mode;
uint8_t scanning;
uint8_t flags;
uint16_t did;
uint16_t adi;
uint32_t offset;
uint8_t offset_units;
uint8_t addr[6];
uint8_t addr_type;
uint8_t evt_type;
struct ble_ll_sched_item sch;
struct ble_ll_ext_adv_report *evt;
};
struct ble_ll_scan_sm
@@ -234,9 +237,9 @@ int ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc,
struct ble_ll_scan_sm **sm);
/* Called to parse extended advertising*/
struct ble_ll_ext_adv;
struct ble_ll_ext_adv_report;
int ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr,
struct ble_ll_ext_adv *parsed_evt);
struct ble_ll_ext_adv_report *parsed_evt);
void ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_scan);
#endif
+12 -13
View File
@@ -394,9 +394,6 @@ static void
ble_ll_adv_put_aux_ptr(struct ble_ll_adv_sm *advsm, uint32_t offset,
uint8_t *dptr)
{
/* in usecs */
offset = os_cputime_ticks_to_usecs(offset);
dptr[0] = advsm->adv_secondary_chan;
if (offset > 245700) {
@@ -468,7 +465,7 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
/* AuxPtr */
if (AUX_CURRENT(advsm)->sch.enqueued) {
offset = AUX_CURRENT(advsm)->start_time - advsm->adv_pdu_start_time;
offset = os_cputime_ticks_to_usecs(AUX_CURRENT(advsm)->start_time - advsm->adv_pdu_start_time);
} else {
offset = 0;
}
@@ -547,12 +544,10 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
*/
offset = 0;
} else if (advsm->rx_ble_hdr) {
offset = advsm->rx_ble_hdr->rem_usecs +
ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + BLE_LL_IFS + 30;
offset = AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime -
os_cputime_usecs_to_ticks(offset);
offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime);
offset -= (advsm->rx_ble_hdr->rem_usecs + ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + BLE_LL_IFS);
} else {
offset = AUX_NEXT(advsm)->start_time - aux->start_time;
offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - aux->start_time);
}
ble_ll_adv_put_aux_ptr(advsm, offset, dptr);
@@ -1112,14 +1107,18 @@ ble_ll_adv_aux_calculate(struct ble_ll_adv_sm *advsm,
aux->aux_data_offset = aux_data_offset;
aux->aux_data_len = 0;
aux->payload_len = 0;
aux->ext_hdr = 0;
rem_aux_data_len = AUX_DATA_LEN(advsm) - aux_data_offset;
chainable = !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE);
/* Flags and ADI */
aux->ext_hdr = (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT);
hdr_len = BLE_LL_EXT_ADV_HDR_LEN + BLE_LL_EXT_ADV_FLAGS_SIZE +
BLE_LL_EXT_ADV_DATA_INFO_SIZE;
hdr_len = BLE_LL_EXT_ADV_HDR_LEN + BLE_LL_EXT_ADV_FLAGS_SIZE;
if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) {
/* Flags and ADI */
aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT);
hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
}
/* AdvA for 1st PDU in chain (i.e. AUX_ADV_IND or AUX_SCAN_RSP) */
if (aux_data_offset == 0) {
+11 -10
View File
@@ -2130,6 +2130,15 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
/*
* If there is still pending read features request HCI command, send an
* event to complete it.
*/
if (connsm->csmflags.cfbit.pending_hci_rd_features) {
ble_ll_hci_ev_rd_rem_used_feat(connsm, ble_err);
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
/*
* We need to send a disconnection complete event. Connection Complete for
* canceling connection creation is sent from LE Create Connection Cancel
@@ -2143,15 +2152,6 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
ble_ll_disconn_comp_event_send(connsm, ble_err);
}
/*
* If there is still pending read features request HCI command, send an
* event to complete it.
*/
if (connsm->csmflags.cfbit.pending_hci_rd_features) {
ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_UNK_CONN_ID);
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
/* Put connection state machine back on free list */
STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
@@ -3907,7 +3907,8 @@ chk_rx_terminate_ind:
}
/* If we received a terminate IND, we must set some flags */
if (is_ctrl && (opcode == BLE_LL_CTRL_TERMINATE_IND)) {
if (is_ctrl && (opcode == BLE_LL_CTRL_TERMINATE_IND)
&& (rx_pyld_len == BLE_LL_CTRL_TERMINATE_IND_LEN)) {
connsm->csmflags.cfbit.terminate_ind_rxd = 1;
connsm->rxd_disconnect_reason = rxbuf[3];
reply = 1;
+2 -2
View File
@@ -853,7 +853,7 @@ ble_ll_conn_hci_update(uint8_t *cmdbuf)
/* See if this feature is supported on both sides */
if ((connsm->conn_features & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
return BLE_ERR_CMD_DISALLOWED;
return BLE_ERR_UNSUPP_REM_FEATURE;
}
ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE;
} else {
@@ -1362,7 +1362,7 @@ ble_ll_conn_hci_le_ltk_reply(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen)
swap_buf(connsm->enc_data.enc_block.key, cmdbuf + 2, 16);
ble_ll_calc_session_key(connsm);
ble_ll_ctrl_start_enc_send(connsm, BLE_LL_CTRL_START_ENC_REQ);
ble_ll_ctrl_start_enc_send(connsm);
rc = BLE_ERR_SUCCESS;
ltk_key_cmd_complete:
+167 -125
View File
@@ -356,6 +356,91 @@ conn_param_pdu_exit:
return rsp_opcode;
}
/**
* 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,
struct ble_ll_conn_params *cp)
{
uint16_t instant;
uint32_t dt;
uint32_t num_old_ce;
uint32_t new_itvl_usecs;
uint32_t old_itvl_usecs;
struct hci_conn_update *hcu;
struct ble_ll_conn_upd_req *req;
/*
* 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;
if (cp) {
/* XXX: so we need to make the new anchor point some time away
* from txwinoffset by some amount of msecs. Not sure how to do
that here. We dont need to, but we should. */
/* Calculate offset from requested offsets (if any) */
if (cp->offset0 != 0xFFFF) {
new_itvl_usecs = cp->interval_max * BLE_LL_CONN_ITVL_USECS;
old_itvl_usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
if ((int16_t)(cp->ref_conn_event_cnt - instant) >= 0) {
num_old_ce = cp->ref_conn_event_cnt - instant;
dt = old_itvl_usecs * num_old_ce;
dt += (cp->offset0 * BLE_LL_CONN_ITVL_USECS);
dt = dt % new_itvl_usecs;
} else {
num_old_ce = instant - cp->ref_conn_event_cnt;
dt = old_itvl_usecs * num_old_ce;
dt -= (cp->offset0 * BLE_LL_CONN_ITVL_USECS);
dt = dt % new_itvl_usecs;
dt = new_itvl_usecs - dt;
}
req->winoffset = dt / BLE_LL_CONN_TX_WIN_USECS;
} else {
req->winoffset = 0;
}
req->interval = cp->interval_max;
req->timeout = cp->timeout;
req->latency = cp->latency;
req->winsize = 1;
} else {
req->interval = hcu->conn_itvl_max;
req->timeout = hcu->supervision_timeout;
req->latency = hcu->conn_latency;
req->winoffset = 0;
req->winsize = connsm->tx_win_size;
}
req->instant = instant;
/* XXX: make sure this works for the connection parameter request proc. */
pyld[0] = req->winsize;
put_le16(pyld + 1, req->winoffset);
put_le16(pyld + 3, req->interval);
put_le16(pyld + 5, req->latency);
put_le16(pyld + 7, req->timeout);
put_le16(pyld + 9, instant);
/* Set flag in state machine to denote we have scheduled an update */
connsm->csmflags.cfbit.conn_update_sched = 1;
}
/**
* Called to process and UNKNOWN_RSP LL control packet.
*
@@ -363,8 +448,8 @@ conn_param_pdu_exit:
*
* @param dptr
*/
static void
ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
static int
ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t *rspdata)
{
uint8_t ctrl_proc;
uint8_t opcode;
@@ -383,8 +468,14 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
case BLE_LL_CTRL_SLAVE_FEATURE_REQ:
ctrl_proc = BLE_LL_CTRL_PROC_FEATURE_XCHG;
break;
case BLE_LL_CTRL_CONN_PARM_RSP:
case BLE_LL_CTRL_CONN_PARM_REQ:
if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL);
connsm->reject_reason = BLE_ERR_SUCCESS;
return BLE_LL_CTRL_CONN_UPDATE_IND;
}
/* note: fall-through intentional */
case BLE_LL_CTRL_CONN_PARM_RSP:
ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
break;
case BLE_LL_CTRL_PING_REQ:
@@ -418,6 +509,38 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
}
return BLE_ERR_MAX;
}
/**
* 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.
*
* Context: Link Layer
*
* @param arg Pointer to connection state machine.
*/
void
ble_ll_ctrl_proc_rsp_timer_cb(struct ble_npl_event *ev)
{
/* Control procedure has timed out. Kill the connection */
ble_ll_conn_timeout((struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev),
BLE_ERR_LMP_LL_RSP_TMO);
}
static void
ble_ll_ctrl_start_rsp_timer(struct ble_ll_conn_sm *connsm)
{
ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer,
&g_ble_ll_data.ll_evq,
ble_ll_ctrl_proc_rsp_timer_cb,
connsm);
/* Re-start timer. Control procedure timeout is 40 seconds */
ble_npl_callout_reset(&connsm->ctrl_proc_rsp_timer,
ble_npl_time_ms_to_ticks32(BLE_LL_CTRL_PROC_TIMEOUT_MS));
}
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
@@ -700,6 +823,10 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req,
CONN_F_PEER_PHY_UPDATE(connsm) = 1;
ble_ll_ctrl_phy_req_rsp_make(connsm, rsp);
rsp_opcode = BLE_LL_CTRL_PHY_RSP;
/* Start response timer */
connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE;
ble_ll_ctrl_start_rsp_timer(connsm);
}
return rsp_opcode;
}
@@ -992,7 +1119,7 @@ ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu)
}
/**
* Called to create and send a LL_START_ENC_REQ or LL_START_ENC_RSP
* Called to create and send a LL_START_ENC_REQ
*
* @param connsm
* @param err
@@ -1000,7 +1127,7 @@ ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu)
* @return int
*/
int
ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm, uint8_t opcode)
ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm)
{
int rc;
struct os_mbuf *om;
@@ -1008,8 +1135,13 @@ ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm, uint8_t opcode)
om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN,
sizeof(struct ble_mbuf_hdr));
if (om) {
om->om_data[0] = opcode;
om->om_data[0] = BLE_LL_CTRL_START_ENC_REQ;
ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, 1);
/* Wait for LL_START_ENC_RSP */
connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_ENCRYPT;
ble_ll_ctrl_start_rsp_timer(connsm);
rc = 0;
} else {
rc = -1;
@@ -1226,11 +1358,12 @@ ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm *connsm)
return BLE_ERR_MAX;
}
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT);
/* If master, we are done. Stop control procedure and sent event to host */
if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
/* We are encrypted */
connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED;
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT);
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) == 1)
ble_ll_conn_auth_pyld_timer_start(connsm);
#endif
@@ -1336,91 +1469,6 @@ ble_ll_ctrl_chanmap_req_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld)
connsm->csmflags.cfbit.chanmap_update_scheduled = 1;
}
/**
* 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,
struct ble_ll_conn_params *cp)
{
uint16_t instant;
uint32_t dt;
uint32_t num_old_ce;
uint32_t new_itvl_usecs;
uint32_t old_itvl_usecs;
struct hci_conn_update *hcu;
struct ble_ll_conn_upd_req *req;
/*
* 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;
if (cp) {
/* XXX: so we need to make the new anchor point some time away
* from txwinoffset by some amount of msecs. Not sure how to do
that here. We dont need to, but we should. */
/* Calculate offset from requested offsets (if any) */
if (cp->offset0 != 0xFFFF) {
new_itvl_usecs = cp->interval_max * BLE_LL_CONN_ITVL_USECS;
old_itvl_usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
if ((int16_t)(cp->ref_conn_event_cnt - instant) >= 0) {
num_old_ce = cp->ref_conn_event_cnt - instant;
dt = old_itvl_usecs * num_old_ce;
dt += (cp->offset0 * BLE_LL_CONN_ITVL_USECS);
dt = dt % new_itvl_usecs;
} else {
num_old_ce = instant - cp->ref_conn_event_cnt;
dt = old_itvl_usecs * num_old_ce;
dt -= (cp->offset0 * BLE_LL_CONN_ITVL_USECS);
dt = dt % new_itvl_usecs;
dt = new_itvl_usecs - dt;
}
req->winoffset = dt / BLE_LL_CONN_TX_WIN_USECS;
} else {
req->winoffset = 0;
}
req->interval = cp->interval_max;
req->timeout = cp->timeout;
req->latency = cp->latency;
req->winsize = 1;
} else {
req->interval = hcu->conn_itvl_max;
req->timeout = hcu->supervision_timeout;
req->latency = hcu->conn_latency;
req->winoffset = 0;
req->winsize = connsm->tx_win_size;
}
req->instant = instant;
/* XXX: make sure this works for the connection parameter request proc. */
pyld[0] = req->winsize;
put_le16(pyld + 1, req->winoffset);
put_le16(pyld + 3, req->interval);
put_le16(pyld + 5, req->latency);
put_le16(pyld + 7, req->timeout);
put_le16(pyld + 9, instant);
/* Set flag in state machine to denote we have scheduled an update */
connsm->csmflags.cfbit.conn_update_sched = 1;
}
/**
* Called to respond to a LL control PDU connection parameter request or
* response.
@@ -1458,11 +1506,12 @@ ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp,
* @param dptr
* @param opcode
*/
static void
static int
ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
uint8_t opcode)
uint8_t opcode, uint8_t *rspdata)
{
uint8_t ble_error;
uint8_t rsp_opcode = BLE_ERR_MAX;
/* Get error out of received PDU */
if (opcode == BLE_LL_CTRL_REJECT_IND) {
@@ -1476,8 +1525,15 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
switch (connsm->cur_ctrl_proc) {
case BLE_LL_CTRL_PROC_CONN_PARAM_REQ:
if (opcode == BLE_LL_CTRL_REJECT_IND_EXT) {
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
ble_ll_hci_ev_conn_update(connsm, ble_error);
/* As a master we should send connection update indication in this point */
if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND;
ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL);
connsm->reject_reason = BLE_ERR_SUCCESS;
} else {
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
ble_ll_hci_ev_conn_update(connsm, ble_error);
}
}
break;
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
@@ -1503,6 +1559,8 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
default:
break;
}
return rsp_opcode;
}
/**
@@ -1806,23 +1864,6 @@ ble_ll_ctrl_rx_chanmap_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
}
}
/**
* 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.
*
* Context: Link Layer
*
* @param arg Pointer to connection state machine.
*/
void
ble_ll_ctrl_proc_rsp_timer_cb(struct ble_npl_event *ev)
{
/* Control procedure has timed out. Kill the connection */
ble_ll_conn_timeout((struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev),
BLE_ERR_LMP_LL_RSP_TMO);
}
/**
* Initiate LL control procedure.
*
@@ -2020,14 +2061,7 @@ ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc)
/* Initialize the procedure response timeout */
if (ctrl_proc != BLE_LL_CTRL_PROC_CHAN_MAP_UPD) {
ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer,
&g_ble_ll_data.ll_evq,
ble_ll_ctrl_proc_rsp_timer_cb,
connsm);
/* Re-start timer. Control procedure timeout is 40 seconds */
ble_npl_callout_reset(&connsm->ctrl_proc_rsp_timer,
ble_npl_time_ms_to_ticks32(BLE_LL_CTRL_PROC_TIMEOUT_MS));
ble_ll_ctrl_start_rsp_timer(connsm);
}
}
}
@@ -2270,7 +2304,7 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
}
break;
case BLE_LL_CTRL_UNKNOWN_RSP:
ble_ll_ctrl_proc_unk_rsp(connsm, dptr);
rsp_opcode = ble_ll_ctrl_proc_unk_rsp(connsm, dptr, rspdata);
break;
case BLE_LL_CTRL_FEATURE_REQ:
rsp_opcode = ble_ll_ctrl_rx_feature_req(connsm, dptr, rspbuf, opcode);
@@ -2338,7 +2372,8 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
/* Fall-through intentional... */
case BLE_LL_CTRL_REJECT_IND:
case BLE_LL_CTRL_REJECT_IND_EXT:
ble_ll_ctrl_rx_reject_ind(connsm, dptr, opcode);
/* Sometimes reject triggers sending other LL CTRL msg */
rsp_opcode = ble_ll_ctrl_rx_reject_ind(connsm, dptr, opcode, rspdata);
break;
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
case BLE_LL_CTRL_PHY_REQ:
@@ -2453,8 +2488,15 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm)
break;
case BLE_LL_CTRL_REJECT_IND_EXT:
if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
connsm->reject_reason = txpdu->om_data[2];
connsm->csmflags.cfbit.host_expects_upd_event = 1;
/* If rejecting opcode is BLE_LL_CTRL_PROC_CONN_PARAM_REQ and
* reason is LMP collision that means we are master on the link and
* peer wanted to start procedure which we already started.
* Let's wait for response and do not close procedure. */
if (txpdu->om_data[1] == BLE_LL_CTRL_CONN_PARM_REQ &&
txpdu->om_data[2] != BLE_ERR_LMP_COLLISION) {
connsm->reject_reason = txpdu->om_data[2];
connsm->csmflags.cfbit.host_expects_upd_event = 1;
}
}
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) {
+31 -21
View File
@@ -321,16 +321,21 @@ ble_ll_hci_le_read_bufsize(uint8_t *rspbuf, uint8_t *rsplen)
* @param txphy Pointer to output tx phy mask
* @param rxphy Pointer to output rx phy mask
*
* @return int BLE_ERR_SUCCESS or BLE_ERR_INV_HCI_CMD_PARMS
* @return int BLE_ERR_SUCCESS or BLE_ERR_INV_HCI_CMD_PARMS or BLE_ERR_UNSUPPORTED
*/
int
ble_ll_hci_chk_phy_masks(uint8_t *cmdbuf, uint8_t *txphy, uint8_t *rxphy)
{
int rc;
uint8_t all_phys;
uint8_t rx_phys;
uint8_t tx_phys;
/* Check for RFU */
if ((cmdbuf[1] & ~BLE_HCI_LE_PHY_PREF_MASK_ALL) ||
(cmdbuf[2] & ~BLE_HCI_LE_PHY_PREF_MASK_ALL)) {
return BLE_ERR_UNSUPPORTED;
}
/* Check for valid values */
all_phys = cmdbuf[0];
tx_phys = cmdbuf[1] & BLE_HCI_LE_PHY_PREF_MASK_ALL;
@@ -338,29 +343,34 @@ ble_ll_hci_chk_phy_masks(uint8_t *cmdbuf, uint8_t *txphy, uint8_t *rxphy)
if ((!(all_phys & BLE_HCI_LE_PHY_NO_TX_PREF_MASK) && (tx_phys == 0)) ||
(!(all_phys & BLE_HCI_LE_PHY_NO_RX_PREF_MASK) && (rx_phys == 0))) {
rc = BLE_ERR_INV_HCI_CMD_PARMS;
} else {
/* If phy not supported, wipe its bit */
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* If phy not supported, return error */
#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
tx_phys &= ~BLE_HCI_LE_PHY_2M_PREF_MASK;
rx_phys &= ~BLE_HCI_LE_PHY_2M_PREF_MASK;
if((tx_phys & BLE_HCI_LE_PHY_2M_PREF_MASK) ||
(rx_phys & BLE_HCI_LE_PHY_2M_PREF_MASK)) {
return BLE_ERR_UNSUPPORTED;
}
#endif
#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
tx_phys &= ~BLE_HCI_LE_PHY_CODED_PREF_MASK;
rx_phys &= ~BLE_HCI_LE_PHY_CODED_PREF_MASK;
#endif
/* Set the default PHY preferences */
if (all_phys & BLE_HCI_LE_PHY_NO_TX_PREF_MASK) {
tx_phys = BLE_HCI_LE_PHY_PREF_MASK_ALL;
}
*txphy = tx_phys;
if (all_phys & BLE_HCI_LE_PHY_NO_RX_PREF_MASK) {
rx_phys = BLE_HCI_LE_PHY_PREF_MASK_ALL;
}
*rxphy = rx_phys;
rc = BLE_ERR_SUCCESS;
if ((tx_phys & BLE_HCI_LE_PHY_CODED_PREF_MASK) ||
(rx_phys & BLE_HCI_LE_PHY_CODED_PREF_MASK)) {
return BLE_ERR_UNSUPPORTED;
}
return rc;
#endif
/* Set the default PHY preferences */
if (all_phys & BLE_HCI_LE_PHY_NO_TX_PREF_MASK) {
tx_phys = BLE_HCI_LE_PHY_PREF_MASK_ALL;
}
*txphy = tx_phys;
if (all_phys & BLE_HCI_LE_PHY_NO_RX_PREF_MASK) {
rx_phys = BLE_HCI_LE_PHY_PREF_MASK_ALL;
}
*rxphy = rx_phys;
return BLE_ERR_SUCCESS;
}
/**
-4
View File
@@ -485,10 +485,6 @@ ble_ll_resolve_set_priv_mode(uint8_t *cmdbuf)
return BLE_ERR_CMD_DISALLOWED;
}
if (!ble_ll_resolv_enabled()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* cmdbuf = addr_type(0) | addr(6) | priv_mode(1) */
rl = ble_ll_resolv_list_find(&cmdbuf[1], cmdbuf[0]);
if (!rl) {
+125 -48
View File
@@ -95,7 +95,7 @@ struct ble_ll_ext_adv_hdr
uint8_t hdr[0];
};
struct ble_ll_ext_adv {
struct ble_ll_ext_adv_report {
/* We support one report per event for now */
uint8_t event_meta; /* BLE_HCI_EVCODE_LE_META */
uint8_t event_len;
@@ -572,12 +572,12 @@ ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
static struct ble_ll_ext_adv *
ble_ll_scan_init_ext_adv(struct ble_ll_ext_adv *copy_from)
static struct ble_ll_ext_adv_report *
ble_ll_scan_init_ext_adv_report(struct ble_ll_ext_adv_report *copy_from)
{
struct ble_ll_ext_adv *evt;
struct ble_ll_ext_adv_report *evt;
evt = (struct ble_ll_ext_adv *) ble_hci_trans_buf_alloc(
evt = (struct ble_ll_ext_adv_report *) ble_hci_trans_buf_alloc(
BLE_HCI_TRANS_BUF_EVT_LO);
if (!evt) {
return NULL;
@@ -612,7 +612,7 @@ ble_ll_hci_send_legacy_ext_adv_report(uint8_t evtype,
uint8_t adv_data_len, struct os_mbuf *adv_data,
uint8_t *inita)
{
struct ble_ll_ext_adv *evt;
struct ble_ll_ext_adv_report *evt;
if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
return -1;
@@ -624,7 +624,7 @@ ble_ll_hci_send_legacy_ext_adv_report(uint8_t evtype,
return -1;
}
evt = ble_ll_scan_init_ext_adv(NULL);
evt = ble_ll_scan_init_ext_adv_report(NULL);
if (!evt) {
return 0;
}
@@ -1591,7 +1591,7 @@ ble_ll_ext_scan_parse_aux_ptr(struct ble_ll_scan_sm *scansm,
static void
ble_ll_ext_scan_parse_adv_info(struct ble_ll_scan_sm *scansm,
struct ble_ll_ext_adv *evt, uint8_t *buf)
struct ble_ll_ext_adv_report *evt, uint8_t *buf)
{
uint16_t adv_info = get_le16(buf);
@@ -1628,6 +1628,7 @@ ble_ll_scan_get_aux_data(struct ble_ll_scan_sm *scansm,
uint8_t ext_hdr_flags;
uint8_t *ext_hdr;
uint8_t has_addr = 0;
uint8_t has_adi = 0;
int i;
struct ble_ll_aux_data tmp_aux_data = { 0 };
@@ -1639,7 +1640,7 @@ ble_ll_scan_get_aux_data(struct ble_ll_scan_sm *scansm,
tmp_aux_data.mode = rxbuf[2] >> 6;
ext_hdr_len = rxbuf[2] & 0x3F;
if (ext_hdr_len < BLE_LL_EXT_ADV_AUX_PTR_SIZE) {
if (ext_hdr_len < BLE_LL_EXT_ADV_AUX_PTR_SIZE && !scansm->cur_aux_data) {
return -1;
}
@@ -1665,8 +1666,9 @@ ble_ll_scan_get_aux_data(struct ble_ll_scan_sm *scansm,
}
if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) {
tmp_aux_data.did = get_le16(ext_hdr + i);
tmp_aux_data.adi = get_le16(ext_hdr + i);
i += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
has_adi = 1;
}
if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) {
@@ -1682,7 +1684,8 @@ ble_ll_scan_get_aux_data(struct ble_ll_scan_sm *scansm,
*aux_data = scansm->cur_aux_data;
/* TODO Collision; Do smth smart when did does not match */
if (tmp_aux_data.did != (*aux_data)->did) {
if (!((*aux_data)->evt_type & (BLE_HCI_ADV_SCAN_MASK))
&& (tmp_aux_data.adi != (*aux_data)->adi)) {
STATS_INC(ble_ll_stats, aux_chain_err);
(*aux_data)->flags |= BLE_LL_AUX_INCOMPLETE_ERR_BIT;
}
@@ -1703,7 +1706,10 @@ ble_ll_scan_get_aux_data(struct ble_ll_scan_sm *scansm,
scansm->cur_aux_data = NULL;
}
(*aux_data)->did = tmp_aux_data.did;
if (has_adi) {
(*aux_data)->adi = tmp_aux_data.adi;
}
(*aux_data)->chan = tmp_aux_data.chan;
(*aux_data)->offset = tmp_aux_data.offset;
(*aux_data)->mode = tmp_aux_data.mode;
@@ -1736,7 +1742,7 @@ ble_ll_scan_get_aux_data(struct ble_ll_scan_sm *scansm,
*/
int
ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr,
struct ble_ll_ext_adv *out_evt)
struct ble_ll_ext_adv_report *out_evt)
{
uint8_t pdu_len;
uint8_t ext_hdr_len;
@@ -1768,6 +1774,10 @@ ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr,
return -1;
}
if (BLE_MBUF_HDR_SCAN_RSP_RCV(ble_hdr)) {
out_evt->evt_type |= BLE_HCI_ADV_SCAN_RSP_MASK;
}
ext_hdr_len = rxbuf[2] & 0x3F;
os_mbuf_adj(om, 3);
@@ -1781,7 +1791,7 @@ ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr,
ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK);
i += BLE_LL_EXT_ADV_ADVA_SIZE;
} else {
if (aux_data->flags & BLE_LL_AUX_HAS_ADDRA) {
if (aux_data && (aux_data->flags & BLE_LL_AUX_HAS_ADDRA)) {
/* Have address in aux_data */
memcpy(out_evt->addr, aux_data->addr, 6);
out_evt->addr_type = aux_data->addr_type;
@@ -1793,6 +1803,7 @@ ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr,
out_evt->dir_addr_type =
ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK);
i += BLE_LL_EXT_ADV_TARGETA_SIZE;
out_evt->evt_type |= BLE_HCI_ADV_DIRECT_MASK;
}
if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_RFU_BIT)) {
@@ -1803,6 +1814,8 @@ ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr,
if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) {
ble_ll_ext_scan_parse_adv_info(scansm, out_evt, (ext_hdr + i));
i += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
} else if (out_evt->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK) {
out_evt->sid = (aux_data->adi >> 12);
}
/* In this point of time we don't want to care about aux ptr */
@@ -1834,13 +1847,16 @@ ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr,
out_evt->sec_phy = aux_data->aux_phy;
out_evt->prim_phy = aux_data->aux_primary_phy;
if (BLE_MBUF_HDR_SCAN_RSP_RCV(ble_hdr)) {
out_evt->evt_type |= BLE_HCI_ADV_SCAN_RSP_MASK;
}
/* Adjust mbuf to contain advertising data only */
os_mbuf_adj(om, i);
/* Let us first keep update event type in aux data.
* Note that in aux chain and aux scan response packets
* we do miss original event type, which we need for advertising report.
*/
aux_data->evt_type |= out_evt->evt_type;
out_evt->evt_type = aux_data->evt_type;
done:
return pdu_len - i - 1;
}
@@ -2271,83 +2287,123 @@ void
ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_scan)
{
if (aux_scan) {
if (aux_scan->evt) {
ble_hci_trans_buf_free((uint8_t *)aux_scan->evt);
}
os_memblock_put(&ext_adv_pool, aux_scan);
}
}
static void
/*
* Send extended advertising report
*
* @return -1 on error (data truncated or other error)
* 0 on success (data status is "completed")
* 1 on success (data status is not "completed")
*/
static int
ble_ll_hci_send_ext_adv_report(uint8_t ptype, struct os_mbuf *om,
struct ble_mbuf_hdr *hdr)
{
struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data;
struct ble_ll_ext_adv *evt;
struct ble_ll_ext_adv *next_evt;
struct ble_ll_ext_adv_report *evt;
struct ble_ll_ext_adv_report *next_evt;
int offset;
int datalen;
int rc;
bool need_event;
if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
return;
return -1;
}
if (!aux_data) {
BLE_LL_ASSERT(0);
return;
}
evt = ble_ll_scan_init_ext_adv(NULL);
if (!evt) {
return;
/*
* We keep one allocated event in aux_data to be able to truncate chain
* properly in case of error. If there is no event in aux_data it means this
* is the first event for this chain.
*/
if (aux_data && aux_data->evt) {
evt = aux_data->evt;
} else {
evt = ble_ll_scan_init_ext_adv_report(NULL);
if (!evt) {
return -1;
}
}
datalen = ble_ll_scan_parse_ext_hdr(om, hdr, evt);
if (datalen < 0) {
/* XXX what should we do here? send some trimmed event? */
ble_hci_trans_buf_free((uint8_t *)evt);
return;
return -1;
}
offset = 0;
do {
need_event = false;
next_evt = NULL;
evt->adv_data_len = min(BLE_LL_MAX_EVT_LEN - sizeof(*evt),
datalen - offset);
os_mbuf_copydata(om, offset, evt->adv_data_len, evt->adv_data);
evt->event_len = (sizeof(*evt) - BLE_HCI_EVENT_HDR_LEN) +
evt->adv_data_len;
evt->rssi = hdr->rxinfo.rssi;
os_mbuf_copydata(om, offset, evt->adv_data_len, evt->adv_data);
offset += evt->adv_data_len;
if (offset < datalen) {
/* Need another event for next fragment of this PDU */
need_event = true;
} else if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) {
need_event = false;
} else if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_BIT)) {
/* Need another event for next PDU in chain */
need_event = true;
} else {
need_event = false;
}
/* Assume data status is not "completed" */
rc = 1;
if (need_event) {
/*
* We need to fragment this PDU as it does not fit in single HCI
* event. Subsequent event will have exactly the same header data.
* If we cannot allocate another HCI event from pool, just mark
* data as truncated.
* We will need another event so let's try to allocate one now. If
* we cannot do this, need to mark event as truncated.
*/
next_evt = ble_ll_scan_init_ext_adv(evt);
next_evt = ble_ll_scan_init_ext_adv_report(evt);
if (next_evt) {
evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_INCOMPLETE);
} else {
evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_TRUNCATED);
rc = -1;
}
} else if (aux_data) {
if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) {
evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_TRUNCATED);
rc = -1;
} else if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_BIT)) {
evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_INCOMPLETE);
}
} else {
if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_BIT)) {
evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_INCOMPLETE);
} else if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) {
evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_TRUNCATED);
}
rc = 0;
}
evt->event_len = (sizeof(*evt) - BLE_HCI_EVENT_HDR_LEN) +
evt->adv_data_len;
evt->rssi = hdr->rxinfo.rssi;
ble_ll_hci_event_send((uint8_t *)evt);
evt = next_evt;
} while (evt);
} while ((offset < datalen) && evt);
BLE_LL_ASSERT(offset <= datalen);
/* Store any event left for later use */
aux_data->evt = evt;
return rc;
}
#endif
/**
@@ -2380,6 +2436,7 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
int ext_adv_mode = -1;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
struct ble_ll_aux_data *aux_data;
int rc;
#endif
/* Set scan response check flag */
@@ -2484,11 +2541,17 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
aux_data = hdr->rxinfo.user_data;
if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_IGNORE_BIT)) {
goto scan_continue;
}
/* Let's see if that packet contains aux ptr*/
if (BLE_MBUF_HDR_WAIT_AUX(hdr)) {
if (ble_ll_sched_aux_scan(hdr, scansm, hdr->rxinfo.user_data)) {
/* We are here when could not schedule the aux ptr */
hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT;
/* Mark that chain is trimmed */
aux_data->flags |= BLE_LL_AUX_INCOMPLETE_ERR_BIT;
}
if (!BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_CHAIN_BIT)) {
@@ -2503,7 +2566,17 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
STATS_INC(ble_ll_stats, aux_chain_cnt);
}
ble_ll_hci_send_ext_adv_report(ptype, om, hdr);
rc = ble_ll_hci_send_ext_adv_report(ptype, om, hdr);
if (rc < 0) {
/*
* Data were trimmed so no need to scan this chain anymore. Also
* make sure we do not send any more events for this chain, just in
* case we managed to scan something before events were processed.
*/
ble_ll_sched_rmv_elem(&aux_data->sch);
hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT;
aux_data->flags |= BLE_LL_AUX_IGNORE_BIT;
}
ble_ll_scan_switch_phy(scansm);
if (BLE_MBUF_HDR_WAIT_AUX(hdr)) {
@@ -2922,6 +2995,10 @@ ble_ll_scan_set_enable(uint8_t *cmd, uint8_t ext)
if (scansm->cur_phy == PHY_NOT_CONFIGURED) {
scansm->cur_phy = i;
/* Take own_addr_type from the first configured PHY.
* Note: All configured PHYs shall have the same own_addr_type
*/
scansm->own_addr_type = scanphy->own_addr_type;
} else {
scansm->next_phy = i;
}