IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 11 BT配对流程[3] -> 正文阅读

[移动开发]Android 11 BT配对流程[3]

前面讲到btm_sec_bond_by_transport 这个接口,继续---->



/*******************************************************************************
 *
 * Function         btm_sec_bond_by_transport
 *
 * Description      this is the bond function that will start either SSP or SMP.
 *
 * Parameters:      bd_addr      - Address of the device to bond
 *                  pin_len      - length in bytes of the PIN Code
 *                  p_pin        - pointer to array with the PIN Code
 *                  trusted_mask - bitwise OR of trusted services
 *                                 (array of uint32_t)
 *
 *  Note: After 2.1 parameters are not used and preserved here not to change API
 ******************************************************************************/
tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr,
                                      tBT_TRANSPORT transport, uint8_t pin_len,
                                      uint8_t* p_pin, uint32_t trusted_mask[]) {
........
# 判断controller是否ready !

  if (!controller_get_interface()->get_is_ready()) {
    BTM_TRACE_ERROR("%s controller module is not ready", __func__);
    return (BTM_NO_RESOURCES);
  }

  BTM_TRACE_DEBUG("before update sec_flags=0x%x", p_dev_rec->sec_flags);

# 已配对返回 !
  /* Finished if connection is active and already paired */
  if (((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) &&
       transport == BT_TRANSPORT_BR_EDR &&
       (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) ||
      ((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) &&
       transport == BT_TRANSPORT_LE &&
       (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))) {
    BTM_TRACE_WARNING("BTM_SecBond -> Already Paired");
    return (BTM_SUCCESS);
  }

# 向Controller发送HCIC_PARAM_SIZE_DELETE_STORED_KEY 删除link key !

  /* Tell controller to get rid of the link key if it has one stored */
  if ((BTM_DeleteStoredLinkKey(&bd_addr, NULL)) != BTM_SUCCESS)
    return (BTM_NO_RESOURCES);

  /* Save the PIN code if we got a valid one */
  if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0)) {
    btm_cb.pin_code_len = pin_len;
    p_dev_rec->pin_code_length = pin_len;
    memcpy(btm_cb.pin_code, p_pin, PIN_CODE_LEN);
  }

  btm_cb.pairing_bda = bd_addr;

  btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD;

  p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE;
  p_dev_rec->is_originator = true;
  if (trusted_mask)
    BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);


  if (transport == BT_TRANSPORT_LE) {
    btm_ble_init_pseudo_addr(p_dev_rec, bd_addr);
    p_dev_rec->sec_flags &= ~BTM_SEC_LE_MASK;

    if (SMP_Pair(bd_addr) == SMP_STARTED) {
      btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
      p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
      btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
      return BTM_CMD_STARTED;
    }

    btm_cb.pairing_flags = 0;
    return (BTM_NO_RESOURCES);
  }

  p_dev_rec->sec_flags &=
      ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED |
        BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED);

# 判断是否支持简单安全配对SSP,以及对应的逻辑

  BTM_TRACE_DEBUG("after update sec_flags=0x%x", p_dev_rec->sec_flags);
  if (!controller_get_interface()->supports_simple_pairing()) {
    /* The special case when we authenticate keyboard.  Set pin type to fixed */
    /* It would be probably better to do it from the application, but it is */
    /* complicated */
    if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
         BTM_COD_MAJOR_PERIPHERAL) &&
        (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD) &&
        (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) {
      btm_cb.pin_type_changed = true;
      btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED);
    }
  }


.......

  /* If connection already exists... */
  if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE) {
    btm_sec_start_authentication(p_dev_rec);

    btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);

    /* Mark lcb as bonding */
    l2cu_update_lcb_4_bonding(bd_addr, true);
    return (BTM_CMD_STARTED);
  }

  BTM_TRACE_DEBUG("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4);
  if (!controller_get_interface()->supports_simple_pairing() ||
      (p_dev_rec->sm4 == BTM_SM4_KNOWN)) {
    if (btm_sec_check_prefetch_pin(p_dev_rec)) return (BTM_CMD_STARTED);
  }
  if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
       btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
       btm_cb.security_mode == BTM_SEC_MODE_SC) &&
      BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
    /* local is 2.1 and peer is unknown */
    if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) {
      /* we are not accepting connection request from peer
       * -> RNR (to learn if peer is 2.1)
       * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
      btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME);
      status = BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR);
    } else {
      /* We are accepting connection request from peer */


      btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
      status = BTM_CMD_STARTED;
    }
    BTM_TRACE_DEBUG("State:%s sm4: 0x%x sec_state:%d",
                    btm_pair_state_descr(btm_cb.pairing_state), p_dev_rec->sm4,
                    p_dev_rec->sec_state);
  } else {

# 我这边看的是BR/EDR 流程,走到这里 !

    /* both local and peer are 2.1  */
    status = btm_sec_dd_create_conn(p_dev_rec);
  }

  if (status != BTM_CMD_STARTED) {
    BTM_TRACE_ERROR(
        "%s BTM_ReadRemoteDeviceName or btm_sec_dd_create_conn error: 0x%x",
        __func__, (int)status);
    btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
  }

  return status;
}

这个接口很长,后面有发现学到的细节继续补充

下面实现建立ACL连接【ACL(AsynchronousConnectionless),和另一种链路是SCO(Synchronous Connection Oriented)。SCO主要用于同步话音传送,ACL主要用于分组数据传送】

ACL细节参考ACL&SCO链路介绍

system/bt/stack/btm/btm_sec.cc


/*******************************************************************************
 *
 * Function         btm_sec_dd_create_conn
 *
 * Description      This function is called to create the ACL connection for
 *                  the dedicated boding process
 *
 * Returns          void
 *
 ******************************************************************************/
static tBTM_STATUS btm_sec_dd_create_conn(tBTM_SEC_DEV_REC* p_dev_rec) {

# Step1 找到一个lcb(link control block)
  tL2C_LCB* p_lcb =
      l2cu_find_lcb_by_bd_addr(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
  if (p_lcb && (p_lcb->link_state == LST_CONNECTED ||
                p_lcb->link_state == LST_CONNECTING)) {
    BTM_TRACE_WARNING("%s Connection already exists", __func__);
    btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
    return BTM_CMD_STARTED;
  }

# Step2 确保l2cap lcb空闲

  /* Make sure an L2cap link control block is available */
  if (!p_lcb && (p_lcb = l2cu_allocate_lcb(p_dev_rec->bd_addr, true,
                                           BT_TRANSPORT_BR_EDR)) == NULL) {
    LOG(WARNING) << "Security Manager: failed allocate LCB "
                 << p_dev_rec->bd_addr;

    return (BTM_NO_RESOURCES);
  }

  /* set up the control block to indicated dedicated bonding */
  btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;

# Step3 通过HCI创建一个与经典蓝牙设备的ACL链接

  if (!l2cu_create_conn_br_edr(p_lcb)) {
    LOG(WARNING) << "Security Manager: failed create allocate LCB "
                 << p_dev_rec->bd_addr;

    l2cu_release_lcb(p_lcb);
    return (BTM_NO_RESOURCES);
  }

  btm_acl_update_busy_level(BTM_BLI_PAGE_EVT);

  VLOG(1) << "Security Manager: " << p_dev_rec->bd_addr;

  btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);

  return (BTM_CMD_STARTED);
}

system/bt/stack/l2cap/l2c_utils.cc
----------------------------------------------

/* This function initiates an acl connection to a Classic device via HCI.
 * Returns true on success, false otherwise. */
bool l2cu_create_conn_br_edr(tL2C_LCB* p_lcb) {
  int xx;
  tL2C_LCB* p_lcb_cur = &l2cb.lcb_pool[0];
  bool is_sco_active;

  /* If there is a connection where we perform as a slave, try to switch roles
     for this connection */
  for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS;
       xx++, p_lcb_cur++) {
    if (p_lcb_cur == p_lcb) continue;

    if ((p_lcb_cur->in_use) && (p_lcb_cur->link_role == HCI_ROLE_SLAVE)) {
      /* The LMP_switch_req shall be sent only if the ACL logical transport
      is in active mode, when encryption is disabled, and all synchronous
      logical transports on the same physical link are disabled." */

      /* Check if there is any SCO Active on this BD Address */
      is_sco_active = btm_is_sco_active_by_bdaddr(p_lcb_cur->remote_bd_addr);

      L2CAP_TRACE_API(
          "l2cu_create_conn - btm_is_sco_active_by_bdaddr() is_sco_active = %s",
          (is_sco_active) ? "true" : "false");

      if (is_sco_active)
        continue; /* No Master Slave switch not allowed when SCO Active */
      /*4_1_TODO check  if btm_cb.devcb.local_features to be used instead */
      if (HCI_SWITCH_SUPPORTED(BTM_ReadLocalFeatures())) {
        /* mark this lcb waiting for switch to be completed and
           start switch on the other one */
        p_lcb->link_state = LST_CONNECTING_WAIT_SWITCH;
        p_lcb->link_role = HCI_ROLE_MASTER;

        if (BTM_SwitchRole(p_lcb_cur->remote_bd_addr, HCI_ROLE_MASTER, NULL) ==
            BTM_CMD_STARTED) {
          alarm_set_on_mloop(p_lcb->l2c_lcb_timer,
                             L2CAP_LINK_ROLE_SWITCH_TIMEOUT_MS,
                             l2c_lcb_timer_timeout, p_lcb);
          return (true);
        }
      }
    }
  }

  p_lcb->link_state = LST_CONNECTING;

  return (l2cu_create_conn_after_switch(p_lcb));
}



/*******************************************************************************
 *
 * Function         l2cu_create_conn_after_switch
 *
 * Description      This function initiates an acl connection via HCI
 *                  If switch required to create connection it is already done.
 *
 * Returns          true if successful, false if get buffer fails.
 *
 ******************************************************************************/

bool l2cu_create_conn_after_switch(tL2C_LCB* p_lcb) {
  uint8_t allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
  tBTM_INQ_INFO* p_inq_info;
  uint8_t page_scan_rep_mode;
  uint8_t page_scan_mode;
  uint16_t clock_offset;
  uint8_t* p_features;
  uint16_t num_acl = BTM_GetNumAclLinks();
  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_lcb->remote_bd_addr);
  uint8_t no_hi_prio_chs = l2cu_get_num_hi_priority();

  p_features = BTM_ReadLocalFeatures();

  L2CAP_TRACE_DEBUG(
      "l2cu_create_conn_after_switch :%d num_acl:%d no_hi: %d is_bonding:%d",
      l2cb.disallow_switch, num_acl, no_hi_prio_chs, p_lcb->is_bonding);
  /* FW team says that we can participant in 4 piconets
   * typically 3 piconet + 1 for scanning.
   * We can enhance the code to count the number of piconets later. */
  if (((!l2cb.disallow_switch && (num_acl < 3)) ||
       (p_lcb->is_bonding && (no_hi_prio_chs == 0))) &&
      HCI_SWITCH_SUPPORTED(p_features))
    allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
  else
    allow_switch = HCI_CR_CONN_NOT_ALLOW_SWITCH;

  p_lcb->link_state = LST_CONNECTING;

  /* Check with the BT manager if details about remote device are known */
  p_inq_info = BTM_InqDbRead(p_lcb->remote_bd_addr);
  if ((p_inq_info != NULL) &&
      (p_inq_info->results.inq_result_type & BTM_INQ_RESULT_BR)) {
    page_scan_rep_mode = p_inq_info->results.page_scan_rep_mode;
    page_scan_mode = p_inq_info->results.page_scan_mode;
    clock_offset = (uint16_t)(p_inq_info->results.clock_offset);
  } else {
    /* No info known. Use default settings */
    page_scan_rep_mode = HCI_PAGE_SCAN_REP_MODE_R1;
    page_scan_mode = HCI_MANDATARY_PAGE_SCAN_MODE;

    clock_offset = (p_dev_rec) ? p_dev_rec->clock_offset : 0;
  }
# 发起连接
  btsnd_hcic_create_conn(
      p_lcb->remote_bd_addr, (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1 |
                              HCI_PKT_TYPES_MASK_DM3 | HCI_PKT_TYPES_MASK_DH3 |
                              HCI_PKT_TYPES_MASK_DM5 | HCI_PKT_TYPES_MASK_DH5),
      page_scan_rep_mode, page_scan_mode, clock_offset, allow_switch);

  btm_acl_update_busy_level(BTM_BLI_PAGE_EVT);

# 设置定时器,l2c_lcb_timer_timeout进行超时处理;
  alarm_set_on_mloop(p_lcb->l2c_lcb_timer, L2CAP_LINK_CONNECT_TIMEOUT_MS,
                     l2c_lcb_timer_timeout, p_lcb);

  return (true);
}

void btsnd_hcic_create_conn(const RawAddress& dest, uint16_t packet_types,
                            uint8_t page_scan_rep_mode, uint8_t page_scan_mode,
                            uint16_t clock_offset, uint8_t allow_switch) {
  BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
  uint8_t* pp = (uint8_t*)(p + 1);

#ifndef BT_10A
  p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN;
#else
  p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN - 1;
#endif
  p->offset = 0;

  UINT16_TO_STREAM(pp, HCI_CREATE_CONNECTION);
#ifndef BT_10A
  UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CREATE_CONN);
#else
  UINT8_TO_STREAM(pp, (HCIC_PARAM_SIZE_CREATE_CONN - 1));
#endif
  BDADDR_TO_STREAM(pp, dest);
  UINT16_TO_STREAM(pp, packet_types);
  UINT8_TO_STREAM(pp, page_scan_rep_mode);
  UINT8_TO_STREAM(pp, page_scan_mode);
  UINT16_TO_STREAM(pp, clock_offset);
#if !defined(BT_10A)
  UINT8_TO_STREAM(pp, allow_switch);
#endif
  btm_acl_paging(p, dest);
}



/*******************************************************************************
 *
 * Function         btm_acl_paging
 *
 * Description      send a paging command or queue it in btm_cb
 *
 ******************************************************************************/
void btm_acl_paging(BT_HDR* p, const RawAddress& bda) {
  tBTM_SEC_DEV_REC* p_dev_rec;

  VLOG(2) << __func__ << ":" << btm_cb.discing << " , paging:" << btm_cb.paging
          << " BDA: " << bda;

  if (btm_cb.discing) {
    btm_cb.paging = true;
    fixed_queue_enqueue(btm_cb.page_queue, p);
  } else {
    if (!BTM_ACL_IS_CONNECTED(bda)) {
      VLOG(1) << "connecting_bda: " << btm_cb.connecting_bda;
      if (btm_cb.paging && bda == btm_cb.connecting_bda) {
        fixed_queue_enqueue(btm_cb.page_queue, p);
      } else {
        p_dev_rec = btm_find_or_alloc_dev(bda);
        btm_cb.connecting_bda = p_dev_rec->bd_addr;
        memcpy(btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);

        btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
      }

      btm_cb.paging = true;
    } else /* ACL is already up */
    {
 # 发送了 HCIC_PARAM_SIZE_CREATE_CONN 命令
      btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
    }
  }
}



/*******************************************************************************
 *
 * Function         btu_hcif_send_cmd
 *
 * Description      This function is called to send commands to the Host
 *                  Controller.
 *
 * Returns          void
 *
 ******************************************************************************/
void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_buf) {
  if (!p_buf) return;

  uint16_t opcode;
  uint8_t* stream = p_buf->data + p_buf->offset;
  void* vsc_callback = NULL;

  STREAM_TO_UINT16(opcode, stream);

  // Eww...horrible hackery here
  /* If command was a VSC, then extract command_complete callback */
  if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC ||
      (opcode == HCI_BLE_RAND) || (opcode == HCI_BLE_ENCRYPT)) {
    vsc_callback = *((void**)(p_buf + 1));
  }

  // Skip parameter length before logging
  stream++;
  btu_hcif_log_command_metrics(opcode, stream,
                               android::bluetooth::hci::STATUS_UNKNOWN, false);

# 通过HCI向controller发送指令
  hci_layer_get_interface()->transmit_command(
      p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt,
      vsc_callback);
}


transmit_comman发送机制参考[init_layer_interface]

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-27 12:56:47  更:2021-10-27 12:57:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:40:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码