/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 #include #include #include #include "os/os.h" #include "nimble/hci_common.h" #include "nimble/ble_hci_trans.h" #include "host/ble_gap.h" #include "host/ble_monitor.h" #include "ble_hs_priv.h" #include "ble_hs_dbg_priv.h" _Static_assert(sizeof (struct hci_data_hdr) == BLE_HCI_DATA_HDR_SZ, "struct hci_data_hdr must be 4 bytes"); typedef int ble_hs_hci_evt_fn(uint8_t event_code, uint8_t *data, int len); static ble_hs_hci_evt_fn ble_hs_hci_evt_disconn_complete; static ble_hs_hci_evt_fn ble_hs_hci_evt_encrypt_change; static ble_hs_hci_evt_fn ble_hs_hci_evt_hw_error; static ble_hs_hci_evt_fn ble_hs_hci_evt_num_completed_pkts; static ble_hs_hci_evt_fn ble_hs_hci_evt_enc_key_refresh; static ble_hs_hci_evt_fn ble_hs_hci_evt_le_meta; typedef int ble_hs_hci_evt_le_fn(uint8_t subevent, uint8_t *data, int len); static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_complete; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_adv_rpt; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_upd_complete; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_lt_key_req; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_parm_req; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_dir_adv_rpt; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_phy_update_complete; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_ext_adv_rpt; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_rd_rem_used_feat_complete; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_scan_timeout; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_adv_set_terminated; /* Statistics */ struct host_hci_stats { uint32_t events_rxd; uint32_t good_acks_rxd; uint32_t bad_acks_rxd; uint32_t unknown_events_rxd; }; #define BLE_HS_HCI_EVT_TIMEOUT 50 /* Milliseconds. */ /** Dispatch table for incoming HCI events. Sorted by event code field. */ struct ble_hs_hci_evt_dispatch_entry { uint8_t event_code; ble_hs_hci_evt_fn *cb; }; static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = { { BLE_HCI_EVCODE_DISCONN_CMP, ble_hs_hci_evt_disconn_complete }, { BLE_HCI_EVCODE_ENCRYPT_CHG, ble_hs_hci_evt_encrypt_change }, { BLE_HCI_EVCODE_HW_ERROR, ble_hs_hci_evt_hw_error }, { BLE_HCI_EVCODE_NUM_COMP_PKTS, ble_hs_hci_evt_num_completed_pkts }, { BLE_HCI_EVCODE_ENC_KEY_REFRESH, ble_hs_hci_evt_enc_key_refresh }, { BLE_HCI_EVCODE_LE_META, ble_hs_hci_evt_le_meta }, }; #define BLE_HS_HCI_EVT_DISPATCH_SZ \ (sizeof ble_hs_hci_evt_dispatch / sizeof ble_hs_hci_evt_dispatch[0]) /** Dispatch table for incoming LE meta events. Sorted by subevent field. */ struct ble_hs_hci_evt_le_dispatch_entry { uint8_t subevent; ble_hs_hci_evt_le_fn *cb; }; static const struct ble_hs_hci_evt_le_dispatch_entry ble_hs_hci_evt_le_dispatch[] = { { BLE_HCI_LE_SUBEV_CONN_COMPLETE, ble_hs_hci_evt_le_conn_complete }, { BLE_HCI_LE_SUBEV_ADV_RPT, ble_hs_hci_evt_le_adv_rpt }, { BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE, ble_hs_hci_evt_le_conn_upd_complete }, { BLE_HCI_LE_SUBEV_LT_KEY_REQ, ble_hs_hci_evt_le_lt_key_req }, { BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ, ble_hs_hci_evt_le_conn_parm_req }, { BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE, ble_hs_hci_evt_le_conn_complete }, { BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT, ble_hs_hci_evt_le_dir_adv_rpt }, { BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE, ble_hs_hci_evt_le_phy_update_complete }, { BLE_HCI_LE_SUBEV_EXT_ADV_RPT, ble_hs_hci_evt_le_ext_adv_rpt }, { BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT, ble_hs_hci_evt_le_rd_rem_used_feat_complete }, { BLE_HCI_LE_SUBEV_SCAN_TIMEOUT, ble_hs_hci_evt_le_scan_timeout }, { BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED, ble_hs_hci_evt_le_adv_set_terminated }, }; #define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \ (sizeof ble_hs_hci_evt_le_dispatch / sizeof ble_hs_hci_evt_le_dispatch[0]) static const struct ble_hs_hci_evt_dispatch_entry * ble_hs_hci_evt_dispatch_find(uint8_t event_code) { const struct ble_hs_hci_evt_dispatch_entry *entry; int i; for (i = 0; i < BLE_HS_HCI_EVT_DISPATCH_SZ; i++) { entry = ble_hs_hci_evt_dispatch + i; if (entry->event_code == event_code) { return entry; } } return NULL; } static const struct ble_hs_hci_evt_le_dispatch_entry * ble_hs_hci_evt_le_dispatch_find(uint8_t event_code) { const struct ble_hs_hci_evt_le_dispatch_entry *entry; int i; for (i = 0; i < BLE_HS_HCI_EVT_LE_DISPATCH_SZ; i++) { entry = ble_hs_hci_evt_le_dispatch + i; if (entry->subevent == event_code) { return entry; } } return NULL; } static int ble_hs_hci_evt_disconn_complete(uint8_t event_code, uint8_t *data, int len) { struct hci_disconn_complete evt; const struct ble_hs_conn *conn; if (len < BLE_HCI_EVENT_DISCONN_COMPLETE_LEN) { return BLE_HS_ECONTROLLER; } evt.status = data[2]; evt.connection_handle = get_le16(data + 3); evt.reason = data[5]; ble_hs_lock(); conn = ble_hs_conn_find(evt.connection_handle); if (conn != NULL) { ble_hs_hci_add_avail_pkts(conn->bhc_outstanding_pkts); } ble_hs_unlock(); ble_gap_rx_disconn_complete(&evt); return 0; } static int ble_hs_hci_evt_encrypt_change(uint8_t event_code, uint8_t *data, int len) { struct hci_encrypt_change evt; if (len < BLE_HCI_EVENT_ENCRYPT_CHG_LEN) { return BLE_HS_ECONTROLLER; } evt.status = data[2]; evt.connection_handle = get_le16(data + 3); evt.encryption_enabled = data[5]; ble_sm_enc_change_rx(&evt); return 0; } static int ble_hs_hci_evt_hw_error(uint8_t event_code, uint8_t *data, int len) { uint8_t hw_code; if (len < BLE_HCI_EVENT_HW_ERROR_LEN) { return BLE_HS_ECONTROLLER; } hw_code = data[0]; ble_hs_hw_error(hw_code); return 0; } static int ble_hs_hci_evt_enc_key_refresh(uint8_t event_code, uint8_t *data, int len) { struct hci_encrypt_key_refresh evt; if (len < BLE_HCI_EVENT_ENC_KEY_REFRESH_LEN) { return BLE_HS_ECONTROLLER; } evt.status = data[2]; evt.connection_handle = get_le16(data + 3); ble_sm_enc_key_refresh_rx(&evt); return 0; } static int ble_hs_hci_evt_num_completed_pkts(uint8_t event_code, uint8_t *data, int len) { struct ble_hs_conn *conn; uint16_t num_pkts; uint16_t handle; uint8_t num_handles; int tx_outstanding; int off; int i; if (len < BLE_HCI_EVENT_HDR_LEN + BLE_HCI_EVENT_NUM_COMP_PKTS_HDR_LEN) { return BLE_HS_ECONTROLLER; } off = BLE_HCI_EVENT_HDR_LEN; num_handles = data[off]; if (len < BLE_HCI_EVENT_NUM_COMP_PKTS_HDR_LEN + num_handles * BLE_HCI_EVENT_NUM_COMP_PKTS_ENT_LEN) { return BLE_HS_ECONTROLLER; } off++; /* If we were previously blocked due to controller buffer exhaustion, and * this event indicates that some buffers have been freed, then the host * needs to resume transmitting. `tx_outstanding` keeps track of whether * this is the case. */ tx_outstanding = 0; for (i = 0; i < num_handles; i++) { handle = get_le16(data + off); num_pkts = get_le16(data + off + 2); off += (2 * sizeof(uint16_t)); if (num_pkts > 0) { ble_hs_lock(); conn = ble_hs_conn_find(handle); if (conn != NULL) { if (conn->bhc_outstanding_pkts < num_pkts) { ble_hs_sched_reset(BLE_HS_ECONTROLLER); } else { conn->bhc_outstanding_pkts -= num_pkts; } if (ble_hs_hci_avail_pkts == 0) { tx_outstanding = 1; } ble_hs_hci_add_avail_pkts(num_pkts); } ble_hs_unlock(); } } if (tx_outstanding) { ble_hs_wakeup_tx(); } return 0; } static int ble_hs_hci_evt_le_meta(uint8_t event_code, uint8_t *data, int len) { const struct ble_hs_hci_evt_le_dispatch_entry *entry; uint8_t subevent; int rc; if (len < BLE_HCI_EVENT_HDR_LEN + BLE_HCI_LE_MIN_LEN) { return BLE_HS_ECONTROLLER; } subevent = data[2]; entry = ble_hs_hci_evt_le_dispatch_find(subevent); if (entry != NULL) { rc = entry->cb(subevent, data + BLE_HCI_EVENT_HDR_LEN, len - BLE_HCI_EVENT_HDR_LEN); if (rc != 0) { return rc; } } return 0; } #if MYNEWT_VAL(BLE_EXT_ADV) static struct hci_le_conn_complete pend_conn_complete; #endif static int ble_hs_hci_evt_le_conn_complete(uint8_t subevent, uint8_t *data, int len) { struct hci_le_conn_complete evt; int extended_offset = 0; if (len < BLE_HCI_LE_CONN_COMPLETE_LEN) { return BLE_HS_ECONTROLLER; } /* this code processes two different events that are really similar */ if ((subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE) && ( len < BLE_HCI_LE_ENH_CONN_COMPLETE_LEN)) { return BLE_HS_ECONTROLLER; } memset(&evt, 0, sizeof(evt)); evt.subevent_code = data[0]; evt.status = data[1]; if (evt.status == BLE_ERR_SUCCESS) { evt.connection_handle = get_le16(data + 2); evt.role = data[4]; evt.peer_addr_type = data[5]; memcpy(evt.peer_addr, data + 6, BLE_DEV_ADDR_LEN); /* enhanced connection event has the same information with these * extra fields stuffed into the middle */ if (subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE) { memcpy(evt.local_rpa, data + 12, BLE_DEV_ADDR_LEN); memcpy(evt.peer_rpa, data + 18, BLE_DEV_ADDR_LEN); extended_offset = 12; } else { memset(evt.local_rpa, 0, BLE_DEV_ADDR_LEN); memset(evt.peer_rpa, 0, BLE_DEV_ADDR_LEN); } evt.conn_itvl = get_le16(data + 12 + extended_offset); evt.conn_latency = get_le16(data + 14 + extended_offset); evt.supervision_timeout = get_le16(data + 16 + extended_offset); evt.master_clk_acc = data[18 + extended_offset]; } else { #if MYNEWT_VAL(BLE_HS_DEBUG) evt.connection_handle = BLE_HS_CONN_HANDLE_NONE; #endif } #if MYNEWT_VAL(BLE_EXT_ADV) if (evt.status == BLE_ERR_DIR_ADV_TMO || evt.role == BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) { /* store this until we get set terminated event with adv handle */ memcpy(&pend_conn_complete, &evt, sizeof(evt)); return 0; } #endif return ble_gap_rx_conn_complete(&evt, 0); } static int ble_hs_hci_evt_le_adv_rpt_first_pass(uint8_t *data, int len) { uint8_t num_reports; int off; int i; if (len < BLE_HCI_LE_ADV_RPT_MIN_LEN) { return BLE_HS_ECONTROLLER; } num_reports = data[1]; if (num_reports < BLE_HCI_LE_ADV_RPT_NUM_RPTS_MIN || num_reports > BLE_HCI_LE_ADV_RPT_NUM_RPTS_MAX) { return BLE_HS_EBADDATA; } off = 2; /* Subevent code and num reports. */ for (i = 0; i < num_reports; i++) { /* Move past event type (1), address type (1) and address (6) */ off += 8; /* Add advertising data length (N), length (1) and rssi (1) */ off += data[off]; off += 2; /* Make sure we are not past length */ if (off > len) { return BLE_HS_ECONTROLLER; } } /* Make sure length was correct */ if (off != len) { return BLE_HS_ECONTROLLER; } return 0; } static int ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, uint8_t *data, int len) { struct ble_gap_disc_desc desc = {0}; uint8_t num_reports; int off; int rc; int i; /* Validate the event is formatted correctly */ rc = ble_hs_hci_evt_le_adv_rpt_first_pass(data, len); if (rc != 0) { return rc; } desc.direct_addr = *BLE_ADDR_ANY; off = 2; /* skip sub-event and num reports */ num_reports = data[1]; for (i = 0; i < num_reports; i++) { desc.event_type = data[off]; ++off; desc.addr.type = data[off]; ++off; memcpy(desc.addr.val, data + off, 6); off += 6; desc.length_data = data[off]; ++off; desc.data = data + off; off += desc.length_data; desc.rssi = data[off]; ++off; ble_gap_rx_adv_report(&desc); } return 0; } static int ble_hs_hci_evt_le_dir_adv_rpt(uint8_t subevent, uint8_t *data, int len) { struct ble_gap_disc_desc desc = {0}; uint8_t num_reports; int suboff; int off; int i; if (len < BLE_HCI_LE_ADV_DIRECT_RPT_LEN) { return BLE_HS_ECONTROLLER; } num_reports = data[1]; if (len != 2 + num_reports * BLE_HCI_LE_ADV_DIRECT_RPT_SUB_LEN) { return BLE_HS_ECONTROLLER; } /* Data fields not present in a direct advertising report. */ desc.data = NULL; desc.length_data = 0; for (i = 0; i < num_reports; i++) { suboff = 0; off = 2 + suboff * num_reports + i; desc.event_type = data[off]; suboff++; off = 2 + suboff * num_reports + i; desc.addr.type = data[off]; suboff++; off = 2 + suboff * num_reports + i * 6; memcpy(desc.addr.val, data + off, 6); suboff += 6; off = 2 + suboff * num_reports + i; desc.direct_addr.type = data[off]; suboff++; off = 2 + suboff * num_reports + i * 6; memcpy(desc.direct_addr.val, data + off, 6); suboff += 6; off = 2 + suboff * num_reports + i; desc.rssi = data[off]; suboff++; ble_gap_rx_adv_report(&desc); } return 0; } static int ble_hs_hci_evt_le_rd_rem_used_feat_complete(uint8_t subevent, uint8_t *data, int len) { struct hci_le_rd_rem_supp_feat_complete evt; if (len < BLE_HCI_LE_RD_REM_USED_FEAT_LEN) { return BLE_HS_ECONTROLLER; } evt.subevent_code = data[0]; evt.status = data[1]; evt.connection_handle = get_le16(data + 2); memcpy(evt.features, data + 4, 8); ble_gap_rx_rd_rem_sup_feat_complete(&evt); return 0; } #if MYNEWT_VAL(BLE_EXT_ADV) static int ble_hs_hci_decode_legacy_type(uint16_t evt_type) { switch (evt_type) { case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_IND: return BLE_HCI_ADV_RPT_EVTYPE_ADV_IND; case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_DIRECT_IND: return BLE_HCI_ADV_RPT_EVTYPE_DIR_IND; case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_SCAN_IND: return BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND; case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_NONCON_IND: return BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND; case BLE_HCI_LEGACY_ADV_EVTYPE_SCAN_RSP_ADV_IND: return BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP; default: return -1; } } #endif static int ble_hs_hci_evt_le_ext_adv_rpt(uint8_t subevent, uint8_t *data, int len) { #if MYNEWT_VAL(BLE_EXT_ADV) struct ble_gap_ext_disc_desc desc; struct hci_ext_adv_report *ext_adv; struct hci_ext_adv_report_param *params; int num_reports; int i; int legacy_event_type; if (len < sizeof(*ext_adv)) { return BLE_HS_EBADDATA; } ext_adv = (struct hci_ext_adv_report *) data; num_reports = ext_adv->num_reports; if (num_reports < BLE_HCI_LE_ADV_RPT_NUM_RPTS_MIN || num_reports > BLE_HCI_LE_ADV_RPT_NUM_RPTS_MAX) { return BLE_HS_EBADDATA; } if (len < (sizeof(*ext_adv) + ext_adv->num_reports * sizeof(*params))) { return BLE_HS_ECONTROLLER; } params = &ext_adv->params[0]; for (i = 0; i < num_reports; i++) { memset(&desc, 0, sizeof(desc)); desc.props = (params->evt_type) & 0x1F; if (desc.props & BLE_HCI_ADV_LEGACY_MASK) { legacy_event_type = ble_hs_hci_decode_legacy_type(params->evt_type); if (legacy_event_type < 0) { params += 1; continue; } desc.legacy_event_type = legacy_event_type; desc.data_status = BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE; } else { switch(params->evt_type & BLE_HCI_ADV_DATA_STATUS_MASK) { case BLE_HCI_ADV_DATA_STATUS_COMPLETE: desc.data_status = BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE; break; case BLE_HCI_ADV_DATA_STATUS_INCOMPLETE: desc.data_status = BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE; break; case BLE_HCI_ADV_DATA_STATUS_TRUNCATED: desc.data_status = BLE_GAP_EXT_ADV_DATA_STATUS_TRUNCATED; break; default: assert(false); } } desc.addr.type = params->addr_type; memcpy(desc.addr.val, params->addr, 6); desc.length_data = params->adv_data_len; desc.data = params->adv_data; desc.rssi = params->rssi; desc.tx_power = params->tx_power; memcpy(desc.direct_addr.val, params->dir_addr, 6); desc.direct_addr.type = params->dir_addr_type; desc.sid = params->sid; desc.prim_phy = params->prim_phy; desc.sec_phy = params->sec_phy; ble_gap_rx_ext_adv_report(&desc); params += 1; } #endif return 0; } static int ble_hs_hci_evt_le_scan_timeout(uint8_t subevent, uint8_t *data, int len) { #if MYNEWT_VAL(BLE_EXT_ADV) && NIMBLE_BLE_SCAN ble_gap_rx_le_scan_timeout(); #endif return 0; } static int ble_hs_hci_evt_le_adv_set_terminated(uint8_t subevent, uint8_t *data, int len) { #if MYNEWT_VAL(BLE_EXT_ADV) struct hci_le_adv_set_terminated evt; if (len < BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED_LEN) { return BLE_HS_ECONTROLLER; } evt.subevent_code = data[0]; evt.status = data[1]; evt.adv_handle = data[2]; evt.conn_handle = get_le16(data + 3); evt.completed_events = data[5]; if (evt.status == 0) { /* ignore return code as we need to terminate advertising set anyway */ ble_gap_rx_conn_complete(&pend_conn_complete, evt.adv_handle); } ble_gap_rx_adv_set_terminated(&evt); #endif return 0; } static int ble_hs_hci_evt_le_conn_upd_complete(uint8_t subevent, uint8_t *data, int len) { struct hci_le_conn_upd_complete evt; if (len < BLE_HCI_LE_CONN_UPD_LEN) { return BLE_HS_ECONTROLLER; } evt.subevent_code = data[0]; evt.status = data[1]; evt.connection_handle = get_le16(data + 2); evt.conn_itvl = get_le16(data + 4); evt.conn_latency = get_le16(data + 6); evt.supervision_timeout = get_le16(data + 8); if (evt.status == 0) { if (evt.conn_itvl < BLE_HCI_CONN_ITVL_MIN || evt.conn_itvl > BLE_HCI_CONN_ITVL_MAX) { return BLE_HS_EBADDATA; } if (evt.conn_latency < BLE_HCI_CONN_LATENCY_MIN || evt.conn_latency > BLE_HCI_CONN_LATENCY_MAX) { return BLE_HS_EBADDATA; } if (evt.supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN || evt.supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX) { return BLE_HS_EBADDATA; } } ble_gap_rx_update_complete(&evt); return 0; } static int ble_hs_hci_evt_le_lt_key_req(uint8_t subevent, uint8_t *data, int len) { struct hci_le_lt_key_req evt; if (len < BLE_HCI_LE_LT_KEY_REQ_LEN) { return BLE_HS_ECONTROLLER; } evt.subevent_code = data[0]; evt.connection_handle = get_le16(data + 1); evt.random_number = get_le64(data + 3); evt.encrypted_diversifier = get_le16(data + 11); ble_sm_ltk_req_rx(&evt); return 0; } static int ble_hs_hci_evt_le_conn_parm_req(uint8_t subevent, uint8_t *data, int len) { struct hci_le_conn_param_req evt; if (len < BLE_HCI_LE_REM_CONN_PARM_REQ_LEN) { return BLE_HS_ECONTROLLER; } evt.subevent_code = data[0]; evt.connection_handle = get_le16(data + 1); evt.itvl_min = get_le16(data + 3); evt.itvl_max = get_le16(data + 5); evt.latency = get_le16(data + 7); evt.timeout = get_le16(data + 9); if (evt.itvl_min < BLE_HCI_CONN_ITVL_MIN || evt.itvl_max > BLE_HCI_CONN_ITVL_MAX || evt.itvl_min > evt.itvl_max) { return BLE_HS_EBADDATA; } if (evt.latency < BLE_HCI_CONN_LATENCY_MIN || evt.latency > BLE_HCI_CONN_LATENCY_MAX) { return BLE_HS_EBADDATA; } if (evt.timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN || evt.timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX) { return BLE_HS_EBADDATA; } ble_gap_rx_param_req(&evt); return 0; } static int ble_hs_hci_evt_le_phy_update_complete(uint8_t subevent, uint8_t *data, int len) { struct hci_le_phy_upd_complete evt; if (len < BLE_HCI_LE_PHY_UPD_LEN) { return BLE_HS_ECONTROLLER; } evt.subevent_code = data[0]; evt.status = data[1]; evt.connection_handle = get_le16(data + 2); evt.tx_phy = data[4]; evt.rx_phy = data[5]; ble_gap_rx_phy_update_complete(&evt); return 0; } int ble_hs_hci_evt_process(uint8_t *data) { const struct ble_hs_hci_evt_dispatch_entry *entry; uint8_t event_code; uint8_t param_len; int event_len; int rc; /* Count events received */ STATS_INC(ble_hs_stats, hci_event); /* Display to console */ ble_hs_dbg_event_disp(data); /* Process the event */ event_code = data[0]; param_len = data[1]; event_len = param_len + 2; entry = ble_hs_hci_evt_dispatch_find(event_code); if (entry == NULL) { STATS_INC(ble_hs_stats, hci_unknown_event); rc = BLE_HS_ENOTSUP; } else { rc = entry->cb(event_code, data, event_len); } ble_hci_trans_buf_free(data); return rc; } /** * Called when a data packet is received from the controller. This function * consumes the supplied mbuf, regardless of the outcome. * * @param om The incoming data packet, beginning with the * HCI ACL data header. * * @return 0 on success; nonzero on failure. */ int ble_hs_hci_evt_acl_process(struct os_mbuf *om) { struct hci_data_hdr hci_hdr; struct ble_hs_conn *conn; ble_l2cap_rx_fn *rx_cb; uint16_t conn_handle; int reject_cid; int rc; rc = ble_hs_hci_util_data_hdr_strip(om, &hci_hdr); if (rc != 0) { goto err; } #if (BLETEST_THROUGHPUT_TEST == 0) #if !BLE_MONITOR BLE_HS_LOG(DEBUG, "ble_hs_hci_evt_acl_process(): conn_handle=%u pb=%x " "len=%u data=", BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc), BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc), hci_hdr.hdh_len); ble_hs_log_mbuf(om); BLE_HS_LOG(DEBUG, "\n"); #endif #endif if (hci_hdr.hdh_len != OS_MBUF_PKTHDR(om)->omp_len) { rc = BLE_HS_EBADDATA; goto err; } conn_handle = BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc); ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); if (conn == NULL) { /* Peer not connected; quietly discard packet. */ rc = BLE_HS_ENOTCONN; reject_cid = -1; } else { /* Forward ACL data to L2CAP. */ rc = ble_l2cap_rx(conn, &hci_hdr, om, &rx_cb, &reject_cid); om = NULL; } ble_hs_unlock(); switch (rc) { case 0: /* Final fragment received. */ BLE_HS_DBG_ASSERT(rx_cb != NULL); rc = rx_cb(conn->bhc_rx_chan); ble_l2cap_remove_rx(conn, conn->bhc_rx_chan); break; case BLE_HS_EAGAIN: /* More fragments on the way. */ break; default: if (reject_cid != -1) { ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, 0, 0, reject_cid); } goto err; } return 0; err: os_mbuf_free_chain(om); return rc; }