text: /*
   * 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 <stdint.h>
  #include <assert.h>
  #include <string.h>
  #include "syscfg/syscfg.h"
  #include "nimble/ble.h"
  #include "nimble/hci_common.h"
  #include "nimble/ble_hci_trans.h"
  #include "controller/ble_ll.h"
  #include "controller/ble_ll_hci.h"
  #include "controller/ble_ll_ctrl.h"
  #include "ble_ll_conn_priv.h"
  
  #if (BLETEST_CONCURRENT_CONN_TEST == 1)
  extern void bletest_ltk_req_reply(uint16_t handle);
  #endif
  
  /**
   * 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 = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          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;
              put_le16(evbuf + 3, connsm->conn_handle);
              put_le16(evbuf + 5, connsm->eff_max_tx_octets);
              put_le16(evbuf + 7, connsm->eff_max_tx_time);
              put_le16(evbuf + 9, connsm->eff_max_rx_octets);
              put_le16(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 = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          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;
              put_le16(evbuf + 3, connsm->conn_handle);
              put_le16(evbuf + 5, cp->interval_min);
              put_le16(evbuf + 7, cp->interval_max);
              put_le16(evbuf + 9, cp->latency);
              put_le16(evbuf + 11, cp->timeout);
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  
  /**
   * Send a connection update event.
   *
   * @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 = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          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;
              put_le16(evbuf + 4, connsm->conn_handle);
              put_le16(evbuf + 6, connsm->conn_itvl);
              put_le16(evbuf + 8, connsm->slave_latency);
              put_le16(evbuf + 10, connsm->supervision_tmo);
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  
  #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
  void
  ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status)
  {
      uint8_t evcode;
      uint8_t *evbuf;
      uint8_t evlen;
  
      if (CONN_F_ENC_CHANGE_SENT(connsm) == 0) {
          evcode = BLE_HCI_EVCODE_ENCRYPT_CHG;
          evlen = BLE_HCI_EVENT_ENCRYPT_CHG_LEN;
      } else {
          evcode = BLE_HCI_EVCODE_ENC_KEY_REFRESH;
          evlen = BLE_HCI_EVENT_ENC_KEY_REFRESH_LEN;
      }
  
      if (ble_ll_hci_is_event_enabled(evcode)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = evcode;
              evbuf[1] = evlen;
              evbuf[2] = status;
              put_le16(evbuf + 3, connsm->conn_handle);
              if (evcode == BLE_HCI_EVCODE_ENCRYPT_CHG) {
                  if (status == BLE_ERR_SUCCESS) {
                      evbuf[5] = 0x01;
                  } else {
                      evbuf[5] = 0;
                  }
              }
              ble_ll_hci_event_send(evbuf);
          }
      }
      CONN_F_ENC_CHANGE_SENT(connsm) = 1;
  }
  
  /**
   * Send a long term key request event for a connection to the host.
   *
   * @param connsm Pointer to connection state machine
   */
  int
  ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm)
  {
      int rc;
      uint8_t *evbuf;
  
      if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_LT_KEY_REQ)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_LE_META;
              evbuf[1] = BLE_HCI_LE_LT_KEY_REQ_LEN;
              evbuf[2] = BLE_HCI_LE_SUBEV_LT_KEY_REQ;
              put_le16(evbuf + 3, connsm->conn_handle);
              put_le64(evbuf + 5, connsm->enc_data.host_rand_num);
              put_le16(evbuf + 13, connsm->enc_data.enc_div);
              ble_ll_hci_event_send(evbuf);
          }
          rc = 0;
      } else {
          rc = -1;
      }
  
  #if (BLETEST_CONCURRENT_CONN_TEST == 1)
      if (rc == 0) {
          bletest_ltk_req_reply(connsm->conn_handle);
      }
  #endif
      return rc;
  }
  #endif
  
  void
  ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status)
  {
      uint8_t *evbuf;
  
      if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_LE_META;
              evbuf[1] = BLE_HCI_LE_RD_REM_USED_FEAT_LEN;
              evbuf[2] = BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT;
              evbuf[3] = status;
              put_le16(evbuf + 4, connsm->conn_handle);
              memset(evbuf + 6, 0, BLE_HCI_RD_LOC_SUPP_FEAT_RSPLEN);
              evbuf[6] = connsm->conn_features;
              memcpy(evbuf + 7, connsm->remote_features, 7);
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  
  void
  ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status)
  {
      uint8_t *evbuf;
  
      if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP;
              evbuf[1] = BLE_HCI_EVENT_RD_RM_VER_LEN;
              evbuf[2] = status;
              put_le16(evbuf + 3, connsm->conn_handle);
              evbuf[5] = connsm->vers_nr;
              put_le16(evbuf + 6, connsm->comp_id);
              put_le16(evbuf + 8, connsm->sub_vers_nr);
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  
  /**
   * Send a HW error to the host.
   *
   * @param hw_err
   *
   * @return int 0: event masked or event sent, -1 otherwise
   */
  int
  ble_ll_hci_ev_hw_err(uint8_t hw_err)
  {
      int rc;
      uint8_t *evbuf;
  
      rc = 0;
      if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_HW_ERROR)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_HW_ERROR;
              evbuf[1] = BLE_HCI_EVENT_HW_ERROR_LEN;
              evbuf[2] = hw_err;
              ble_ll_hci_event_send(evbuf);
          } else {
              rc = -1;
          }
      }
      return rc;
  }
  
  void
  ble_ll_hci_ev_databuf_overflow(void)
  {
      uint8_t *evbuf;
  
      if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DATA_BUF_OVERFLOW)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_DATA_BUF_OVERFLOW;
              evbuf[1] = BLE_HCI_EVENT_DATABUF_OVERFLOW_LEN;
              evbuf[2] = BLE_HCI_EVENT_ACL_BUF_OVERFLOW;
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  
  /**
   * Send a LE Channel Selection Algorithm event.
   *
   * @param connsm Pointer to connection state machine
   */
  #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
  void
  ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm)
  {
      uint8_t *evbuf;
  
      if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CHAN_SEL_ALG)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_LE_META;
              evbuf[1] = BLE_HCI_LE_SUBEV_CHAN_SEL_ALG_LEN;
              evbuf[2] = BLE_HCI_LE_SUBEV_CHAN_SEL_ALG;
              put_le16(evbuf + 3, connsm->conn_handle);
              evbuf[5] = connsm->csmflags.cfbit.csa2_supp ? 0x01 : 0x00;
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  #endif
  
  /**
   * Sends the LE Scan Request Received event
   *
   */
  #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
  void
  ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer,
                                   uint8_t peer_addr_type)
  {
      uint8_t *evbuf;
  
      if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_LE_META;
              evbuf[1] = BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD_LEN;
              evbuf[2] = BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD;
              evbuf[3] = adv_handle;
              evbuf[4] = peer_addr_type;
              memcpy(&evbuf[5], peer, BLE_DEV_ADDR_LEN);
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  #endif
  
  /**
   * Sends the  LE Scan Timeout Event
   *
   */
  #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
  void
  ble_ll_hci_ev_send_scan_timeout(void)
  {
      uint8_t *evbuf;
  
      if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_TIMEOUT)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_LE_META;
              evbuf[1] = BLE_HCI_LE_SUBEV_SCAN_TIMEOUT_LEN;
              evbuf[2] = BLE_HCI_LE_SUBEV_SCAN_TIMEOUT;
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  #endif
  
  /**
   * Sends the LE Advertising Set Terminated event
   *
   */
  #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
  void
  ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle,
                                        uint16_t conn_handle, uint8_t events)
  {
      uint8_t *evbuf;
  
      if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_LE_META;
              evbuf[1] = BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED_LEN;
              evbuf[2] = BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED;
              evbuf[3] = status;
              evbuf[4] = adv_handle;
              put_le16(evbuf + 5, conn_handle);
              evbuf[7] = events;
              ble_ll_hci_event_send(evbuf);
          }
      }
  }
  #endif
  
  /**
   * Send a PHY update complete event
   *
   * @param connsm Pointer to connection state machine
   * @param status error status of event
   */
  #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
  int
  ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status)
  {
      int rc;
      uint8_t *evbuf;
  
      rc = 0;
      if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE)) {
          evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
          if (evbuf) {
              evbuf[0] = BLE_HCI_EVCODE_LE_META;
              evbuf[1] = BLE_HCI_LE_PHY_UPD_LEN;
              evbuf[2] = BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE;
              evbuf[3] = status;
              put_le16(evbuf + 4, connsm->conn_handle);
              evbuf[6] = connsm->phy_data.cur_tx_phy;
              evbuf[7] = connsm->phy_data.cur_rx_phy;
              ble_ll_hci_event_send(evbuf);
          } else {
              rc = BLE_ERR_MEM_CAPACITY;
          }
      }
      return rc;
  }
  #endif
  
  void
  ble_ll_hci_ev_send_vendor_err(char *file, uint32_t line)
  {
      uint8_t *evbuf;
      uint8_t file_len = strlen(file);
  
      evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
      if (!evbuf) {
          return;
      }
  
      evbuf[0] = BLE_HCI_EVCODE_VENDOR_DEBUG;
      evbuf[1] = file_len + sizeof(line) + 1;
      /* Debug id for future use */
      evbuf[2] = 0x00;
      memcpy(&evbuf[3], file, file_len);
      put_le32(&evbuf[3] + file_len, line);
      ble_ll_hci_event_send(evbuf);
  }
  