zoukankan      html  css  js  c++  java
  • 蓝牙speaker配对流程源码分析

    这篇文章简单分析一下 蓝牙音箱配对流程.现在的音箱基本都支持security simple pairing.所以这里的流程基本上就是ssp的代码流程.

    源码参考的是 Android 6.0 上面的bluedroid.这里先介绍一些bluedroid定义的概率.

    首先介绍一下 配对的几个状态:pairing_cb.state  ,这个定义在bluetooth.h里面.

     /** Bluetooth Bond state */
     typedef enum {
         BT_BOND_STATE_NONE,
         BT_BOND_STATE_BONDING,
         BT_BOND_STATE_BONDED
     } bt_bond_state_t;

     每次有配对状态发生改变的时候,通过bond_state_changed 来向上层汇报状态.

    bluetooth.c

    static int create_bond(const bt_bdaddr_t *bd_addr, int transport)
    {
        /* sanity check */
        if (interface_ready() == FALSE)
            return BT_STATUS_NOT_READY;
    
        return btif_dm_create_bond(bd_addr, transport);
    }

     btif_dm.c

    /*******************************************************************************
    **
    ** Function         btif_dm_create_bond
    **
    ** Description      Initiate bonding with the specified device
    **
    ** Returns          bt_status_t
    **
    *******************************************************************************/
    bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr, int transport)
    {
        btif_dm_create_bond_cb_t create_bond_cb;
        create_bond_cb.transport = transport;
        bdcpy(create_bond_cb.bdaddr.address, bd_addr->address);
    
        bdstr_t bdstr;
        BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __FUNCTION__, bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
        if (pairing_cb.state != BT_BOND_STATE_NONE)
            return BT_STATUS_BUSY;
    
        btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_CREATE_BOND,
                              (char *)&create_bond_cb, sizeof(btif_dm_create_bond_cb_t), NULL);
    
        return BT_STATUS_SUCCESS;
    }

    当前的配对状态是  BT_BOND_STATE_NONE,

     btif_dm.c:

    /*******************************************************************************
    **
    ** Function         btif_dm_generic_evt
    **
    ** Description      Executes non-BTA upstream events in BTIF context
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btif_dm_generic_evt(UINT16 event, char* p_param)
    {
        BTIF_TRACE_EVENT("%s: event=%d", __FUNCTION__, event);
        switch(event)
        {
            case BTIF_DM_CB_DISCOVERY_STARTED:
            {
                HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STARTED);
            }
            break;
    
            case BTIF_DM_CB_CREATE_BOND:
            {
                pairing_cb.timeout_retries = NUM_TIMEOUT_RETRIES;
                btif_dm_create_bond_cb_t *create_bond_cb = (btif_dm_create_bond_cb_t*)p_param;
                btif_dm_cb_create_bond(&create_bond_cb->bdaddr, create_bond_cb->transport);
            }
            break;

    继续看:

    /*******************************************************************************
    **
    ** Function         btif_dm_cb_create_bond
    **
    ** Description      Create bond initiated from the BTIF thread context
    **                  Special handling for HID devices
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr, tBTA_TRANSPORT transport)
    {
        BOOLEAN is_hid = check_cod(bd_addr, COD_HID_POINTING);
        bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
    
    #if BLE_INCLUDED == TRUE
        int device_type;
        int addr_type;
        bdstr_t bdstr;
        bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr));
        if (transport == BT_TRANSPORT_LE)
        {
    ...
        }
        if((btif_config_get_int((char const *)&bdstr,"DevType", &device_type) &&
           (btif_storage_get_remote_addr_type(bd_addr, &addr_type) == BT_STATUS_SUCCESS) &&
           (device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) || (transport == BT_TRANSPORT_LE))
        {
            BTA_DmAddBleDevice(bd_addr->address, addr_type, device_type);
        }
    #endif
    #if BLE_INCLUDED == TRUE
        if(is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0)
    #else
        if(is_hid)
    #endif
        {
            int status;
            status = btif_hh_connect(bd_addr);
            if(status != BT_STATUS_SUCCESS)
                bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);
        }
        else
        {
            BTA_DmBondByTransport((UINT8 *)bd_addr->address, transport); //非HID,继续进入到BTA
        }
        /*  Track  originator of bond creation  */
        pairing_cb.is_local_initiated = TRUE;
    
    }

    bta_dm_api.c

    /*******************************************************************************
    **
    ** Function         BTA_DmBondByTransports
    **
    ** Description      This function initiates a bonding procedure with a peer
    **                  device
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport)
    {
        tBTA_DM_API_BOND    *p_msg;
    
        if ((p_msg = (tBTA_DM_API_BOND *) GKI_getbuf(sizeof(tBTA_DM_API_BOND))) != NULL)
        {
            p_msg->hdr.event = BTA_DM_API_BOND_EVT;
            bdcpy(p_msg->bd_addr, bd_addr);
            p_msg->transport = transport;
            bta_sys_sendmsg(p_msg);
        }
    
    
    }

    关于消息的发送流程,这里就不讲了,直接分析所执行的函数:

    BTA_DM_API_BOND_EVT    // BTA got event 0x107

     bta_dm_main.c

    BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg)
    {
        UINT16  event = p_msg->event & 0x00ff;
    
        APPL_TRACE_EVENT("bta_dm_sm_execute event:0x%x", event);
    
        /* execute action functions */
        if(event < BTA_DM_NUM_ACTIONS)
        {
            (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg);
        }
    
        return TRUE;
    }
        bta_dm_bond,              /* 11  BTA_DM_API_BOND_EVT */

     到目前为止,transport = BTA_TRANSPORT_UNKNOWN  = 0

    bta_dm_act.c

    /*******************************************************************************
    **
    ** Function         bta_dm_bond
    **
    ** Description      Bonds with peer device
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    void bta_dm_bond (tBTA_DM_MSG *p_data)
    {
        tBTM_STATUS status;
        tBTA_DM_SEC sec_event;
        char        *p_name;
    
        if (p_data->bond.transport == BTA_TRANSPORT_UNKNOWN)
            status = BTM_SecBond ( p_data->bond.bd_addr, 0, NULL, 0 );//0 
        else
            status = BTM_SecBondByTransport ( p_data->bond.bd_addr, p_data->bond.transport, 0, NULL, 0 );
    
    
        if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED))
        {
           ...
         }
    
    }

    btm_sec.c  进入到stack/btm 了.

    /*******************************************************************************
    **
    ** Function         BTM_SecBond
    **
    ** Description      This function is called to perform bonding with peer device.
    **                  If the connection is already up, but not secure, pairing
    **                  is attempted.  If already paired BTM_SUCCESS is returned.
    **
    ** 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)
    **
    **  Note: After 2.1 parameters are not used and preserved here not to change API
    *******************************************************************************/
    tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
    {
        tBT_TRANSPORT   transport = BT_TRANSPORT_BR_EDR;
    #if BLE_INCLUDED == TRUE
        if (BTM_UseLeLink(bd_addr))
            transport = BT_TRANSPORT_LE;
    #endif
        return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask);
    }

    在btm 里面同样对于配对有相应的状态转换 btm_cb.pairing_state:

    定义在btm_int.h里面:

    /* Pairing State */
    enum
    {
        BTM_PAIR_STATE_IDLE,                        /* Idle                                         */
        BTM_PAIR_STATE_GET_REM_NAME,                /* Getting the remote name (to check for SM4)   */
        BTM_PAIR_STATE_WAIT_PIN_REQ,                /* Started authentication, waiting for PIN req (PIN is pre-fetched) */
        BTM_PAIR_STATE_WAIT_LOCAL_PIN,              /* Waiting for local PIN code                   */
        BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM,        /* Waiting user 'yes' to numeric confirmation   */
        BTM_PAIR_STATE_KEY_ENTRY,                   /* Key entry state (we are a keyboard)          */
        BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP,          /* Waiting for local response to peer OOB data  */
        BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS,           /* Waiting for local IO capabilities and OOB data */
        BTM_PAIR_STATE_INCOMING_SSP,                /* Incoming SSP (got peer IO caps when idle)    */
        BTM_PAIR_STATE_WAIT_AUTH_COMPLETE,          /* All done, waiting authentication cpmplete    */
        BTM_PAIR_STATE_WAIT_DISCONNECT              /* Waiting to disconnect the ACL                */
    };

    这里先 说一下一般的 btm_cb.pairing_state 里面的配对状态转换的流程:

    BTM_PAIR_STATE_IDLE -->BTM_PAIR_STATE_GET_REM_NAME -->BTM_PAIR_STATE_WAIT_PIN_REQ-->BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS(SSP)--->BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM(depends on IO)-->BTM_PAIR_STATE_WAIT_AUTH_COMPLETE-->BTM_PAIR_STATE_IDLE

    关于security 的flag 定义在btm_int.h:

    #define BTM_SEC_AUTHORIZED      BTM_SEC_FLAG_AUTHORIZED     /* 0x01 */
    #define BTM_SEC_AUTHENTICATED   BTM_SEC_FLAG_AUTHENTICATED  /* 0x02 */
    #define BTM_SEC_ENCRYPTED       BTM_SEC_FLAG_ENCRYPTED      /* 0x04 */
    #define BTM_SEC_NAME_KNOWN      0x08
    #define BTM_SEC_LINK_KEY_KNOWN  BTM_SEC_FLAG_LKEY_KNOWN /* 0x10 */
    #define BTM_SEC_LINK_KEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED    /* 0x20 */
    #define BTM_SEC_ROLE_SWITCHED   0x40
    #define BTM_SEC_IN_USE          0x80

    那么最终启动security的时候,就初始化为BTM_SEC_IN_USE    = 0x80 

    /*******************************************************************************
    **
    ** 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)
    **
    **  Note: After 2.1 parameters are not used and preserved here not to change API
    *******************************************************************************/
    tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport,
                                           UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
    {
        tBTM_SEC_DEV_REC *p_dev_rec;
        tBTM_STATUS      status;
        UINT8            *p_features;
        UINT8            ii;
        tACL_CONN        *p= btm_bda_to_acl(bd_addr, transport);
        BTM_TRACE_API ("btm_sec_bond_by_transport BDA: %02x:%02x:%02x:%02x:%02x:%02x",
                        bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
    
    
        /* Other security process is in progress */
        if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
        {
            BTM_TRACE_ERROR ("BTM_SecBond: already busy in state: %s", btm_pair_state_descr(btm_cb.pairing_state));
            return(BTM_WRONG_MODE);
        }
    
        if ((p_dev_rec = btm_find_or_alloc_dev (bd_addr)) == NULL)//find from btm_cb.sec_dev_rec 
        {
            return(BTM_NO_RESOURCES);
        }
    
        BTM_TRACE_DEBUG ("before update sec_flags=0x%x", p_dev_rec->sec_flags);//first time 0x80
    
        /* 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))
    #if (BLE_INCLUDED == TRUE)
            ||((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_LE
             &&  (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))
    #endif
    
             )
        {
            BTM_TRACE_WARNING("BTM_SecBond -> Already Paired");
            return(BTM_SUCCESS);
        }
    
        /* Tell controller to get rid of the link key if it has one stored */
        if ((BTM_DeleteStoredLinkKey (bd_addr, NULL)) != BTM_SUCCESS)//delete link key
            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)) //we have not got one valid
        {
    ...
        }
    
        memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);
    
        btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD;
    
        p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE;///* Outbound call requires authentication */ 0x10
        p_dev_rec->is_originator     = TRUE;
        if (trusted_mask)
            BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
    ...
    
        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);/*clear the all the flags*/
    
    
        BTM_TRACE_DEBUG ("after update sec_flags=0x%x", p_dev_rec->sec_flags);  //still in use  0x80
        if (!controller_get_interface()->supports_simple_pairing()) //local HCI_Read_Local_Extended_Features
        {
            /* 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);
            }
        }
    
        for (ii = 0; ii <= HCI_EXT_FEATURES_PAGE_MAX; ii++)
        {
            p_features = p_dev_rec->features[ii];
            BTM_TRACE_EVENT("  remote_features page[%1d] = %02x-%02x-%02x-%02x",
                             ii, p_features[0], p_features[1], p_features[2], p_features[3]);
            BTM_TRACE_EVENT("                              %02x-%02x-%02x-%02x",
                                 p_features[4], p_features[5], p_features[6], p_features[7]);
        }
    
        BTM_TRACE_EVENT ("BTM_SecBond: Remote sm4: 0x%x  HCI Handle: 0x%04x", p_dev_rec->sm4, p_dev_rec->hci_handle);//have not got remote feature
    
        /* If connection already exists... */
        if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE)/* then start authentication*/
        {
            if (!btm_sec_start_authentication (p_dev_rec))
                return(BTM_NO_RESOURCES);
    
            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);//local mode  = 4.
        if (!controller_get_interface()->supports_simple_pairing()
            || (p_dev_rec->sm4 == BTM_SM4_KNOWN))  // sm4 of remote is not known now
        {
            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);
                BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR);//begin to get rmt name
            }
            else
            {
                /* We are accepting connection request from peer */
                btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
            }
            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);
            return BTM_CMD_STARTED;
        }
    
        /* both local and peer are 2.1  */
        status = btm_sec_dd_create_conn(p_dev_rec);
    
        if (status != BTM_CMD_STARTED)
        {
            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
        }
    
        return status;
    }

     从这里的逻辑看出,如果我们的2.1 并且对方的feature还有获取到,那么我们就先进行remote name的获取.并且此刻btm_cb.pairing_state状态变为:BTM_PAIR_STATE_GET_REM_NAME

    下面我们看看RNR的流程:

    /*******************************************************************************
    **
    ** Function         BTM_ReadRemoteDeviceName
    **
    ** Description      This function initiates a remote device HCI command to the
    **                  controller and calls the callback when the process has completed.
    **
    ** Input Params:    remote_bda      - device address of name to retrieve
    **                  p_cb            - callback function called when BTM_CMD_STARTED
    **                                    is returned.
    **                                    A pointer to tBTM_REMOTE_DEV_NAME is passed to the
    **                                    callback.
    **
    ** Returns
    **                  BTM_CMD_STARTED is returned if the request was successfully sent
    **                                  to HCI.
    **                  BTM_BUSY if already in progress
    **                  BTM_UNKNOWN_ADDR if device address is bad
    **                  BTM_NO_RESOURCES if could not allocate resources to start the command
    **                  BTM_WRONG_MODE if the device is not up.
    **
    *******************************************************************************/
    tBTM_STATUS  BTM_ReadRemoteDeviceName (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb
                                                    ,tBT_TRANSPORT transport)
    {
        tBTM_INQ_INFO   *p_cur = NULL;
        tINQ_DB_ENT     *p_i;
    
        BTM_TRACE_API ("BTM_ReadRemoteDeviceName: bd addr [%02x%02x%02x%02x%02x%02x]",
                   remote_bda[0], remote_bda[1], remote_bda[2],
                   remote_bda[3], remote_bda[4], remote_bda[5]);
    
        /* Use the remote device's clock offset if it is in the local inquiry database */
        if ((p_i = btm_inq_db_find (remote_bda)) != NULL)
        {
            p_cur = &p_i->inq_info;
        }
        BTM_TRACE_API ("no device found in inquiry db");
        if (transport == BT_TRANSPORT_LE)
        {
            return btm_ble_read_remote_name(remote_bda, p_cur, p_cb);
        }
        else
        return (btm_initiate_rem_name (remote_bda, p_cur, BTM_RMT_NAME_EXT,
                                       BTM_EXT_RMT_NAME_TIMEOUT, p_cb));
    }

     从上面看 这个p_cb的回调是NULL.

    btm_inq.c

    /*******************************************************************************
    **
    ** Function         btm_initiate_rem_name
    **
    ** Description      This function looks initiates a remote name request.  It is called
    **                  either by GAP or by the API call BTM_ReadRemoteDeviceName.
    **
    ** Input Params:    p_cur         - pointer to an inquiry result structure (NULL if nonexistent)
    **                  p_cb            - callback function called when BTM_CMD_STARTED
    **                                    is returned.
    **                                    A pointer to tBTM_REMOTE_DEV_NAME is passed to the
    **                                    callback.
    **
    ** Returns
    **                  BTM_CMD_STARTED is returned if the request was sent to HCI.
    **                  BTM_BUSY if already in progress
    **                  BTM_NO_RESOURCES if could not allocate resources to start the command
    **                  BTM_WRONG_MODE if the device is not up.
    **
    *******************************************************************************/
    tBTM_STATUS  btm_initiate_rem_name (BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur,
                                        UINT8 origin, UINT32 timeout, tBTM_CMPL_CB *p_cb)
    {
        tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
        BOOLEAN              cmd_ok;
    ...
    
        if (origin == BTM_RMT_NAME_SEC)
        {
    ...
        }
        /* Make sure there are no two remote name requests from external API in progress */
        else if (origin == BTM_RMT_NAME_EXT)
        {
            if (p_inq->remname_active)
            {
                return (BTM_BUSY);
            }
            else
            {
                /* If there is no remote name request running,call the callback function and start timer */
                p_inq->p_remname_cmpl_cb = p_cb;//NULL
                memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
                btu_start_timer (&p_inq->rmt_name_timer_ent,
                                 BTU_TTYPE_BTM_RMT_NAME,
                                 timeout);
    
                /* If the database entry exists for the device, use its clock offset */
                if (p_cur)
                {
                    cmd_ok = btsnd_hcic_rmt_name_req (remote_bda,
                                             p_cur->results.page_scan_rep_mode,
                                             p_cur->results.page_scan_mode,
                                             (UINT16)(p_cur->results.clock_offset |
                                                      BTM_CLOCK_OFFSET_VALID));//start hci command
                }
                else /* Otherwise use defaults and mark the clock offset as invalid */
                {
                    cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
                                             HCI_MANDATARY_PAGE_SCAN_MODE, 0);
                }
                if (cmd_ok)
                {
                    p_inq->remname_active = TRUE;
                    return BTM_CMD_STARTED;
                }
                else
                    return BTM_NO_RESOURCES;
            }
        }
        else
        {
            return BTM_ILLEGAL_VALUE;
        }
    }

     从这里我们发现,其就已经开始了RNR流程了.

    这个cmd 其实不仅仅有获取名字的功能,当底层获取了remote 的feature,那么这个时候也会通过

    Event: HCI Remote Host Supported Features Notification

     上报.

    我们接下来看看这个事件的处理过程:

    btu_hcif.c

            case HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT:
                btu_hcif_host_support_evt (p);
                break;

    btm_Sec.c

    /*******************************************************************************
    **
    ** Function         btm_sec_rmt_host_support_feat_evt
    **
    ** Description      This function is called when the
    **                  HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is received
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_sec_rmt_host_support_feat_evt (UINT8 *p)
    {
        tBTM_SEC_DEV_REC *p_dev_rec;
        BD_ADDR         bd_addr;        /* peer address */
        BD_FEATURES     features;
    
        STREAM_TO_BDADDR (bd_addr, p);
        p_dev_rec = btm_find_or_alloc_dev (bd_addr);
    
    
        if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
        {
            p_dev_rec->sm4 = BTM_SM4_KNOWN;//now sm4 is known
            STREAM_TO_ARRAY(features, p, HCI_FEATURE_BYTES_PER_PAGE);
            int xx = 0;
            for(xx = 0;xx<HCI_FEATURE_BYTES_PER_PAGE;xx++)
                BTM_TRACE_EVENT("features[%d] = %d libs_liu",xx,features[xx]);
            if (HCI_SSP_HOST_SUPPORTED(features))
            {
                p_dev_rec->sm4 = BTM_SM4_TRUE;//0x11
        
            }
        }
    }

    现在就已经知道remote devices 的sm了.支持ssp的话,sm4 = 4

    下面我们看看controller 获取到名字之后host端的处理:

     btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_rmt_name_request_comp_evt
    **
    ** Description      Process event HCI_RMT_NAME_REQUEST_COMP_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_rmt_name_request_comp_evt (UINT8 *p, UINT16 evt_len)
    {
        UINT8   status;
        BD_ADDR bd_addr;
    
        STREAM_TO_UINT8 (status, p);
        STREAM_TO_BDADDR (bd_addr, p);
    
        evt_len -= (1 + BD_ADDR_LEN);
    
        btm_process_remote_name (bd_addr, p, evt_len, status);//获取名字,但是发现并没有去保存
    
        btm_sec_rmt_name_request_complete (bd_addr, p, status);//这里保存名字
    }

    我们先看看 上面那个处理名字的函数:

    btm_inq.c

    /*******************************************************************************
    **
    ** Function         btm_process_remote_name
    **
    ** Description      This function is called when a remote name is received from
    **                  the device. If remote names are cached, it updates the inquiry
    **                  database.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, UINT16 evt_len, UINT8 hci_status)
    {
        tBTM_REMOTE_DEV_NAME    rem_name;
        tBTM_INQUIRY_VAR_ST    *p_inq = &btm_cb.btm_inq_vars;
        tBTM_CMPL_CB           *p_cb = p_inq->p_remname_cmpl_cb;//NULL
        UINT8                  *p_n1;
    
        UINT16                 temp_evt_len;
    
        if (bda != NULL)
        {
            BTM_TRACE_EVENT("BDA %02x:%02x:%02x:%02x:%02x:%02x",bda[0], bda[1],
                     bda[2], bda[3],
                     bda[4], bda[5]);
        }
    
    ...
    
        /* If the inquire BDA and remote DBA are the same, then stop the timer and set the active to false */
        if ((p_inq->remname_active ==TRUE)&&
            (((bda != NULL) &&
            (memcmp(bda, p_inq->remname_bda,BD_ADDR_LEN)==0)) || bda == NULL))
    
        {
    #if BLE_INCLUDED == TRUE
            if (BTM_UseLeLink(p_inq->remname_bda))
            {
                if (hci_status == HCI_ERR_UNSPECIFIED)
                    btm_ble_cancel_remote_name(p_inq->remname_bda);
            }
    #endif
            btu_stop_timer (&p_inq->rmt_name_timer_ent);//停 timer
            p_inq->remname_active = FALSE;
             /* Clean up and return the status if the command was not successful */
             /* Note: If part of the inquiry, the name is not stored, and the    */
             /*       inquiry complete callback is called.                       */
    
            if (hci_status == HCI_SUCCESS)
            {
                /* Copy the name from the data stream into the return structure */
                /* Note that even if it is not being returned, it is used as a  */
                /*      temporary buffer.                                       */
                p_n1 = (UINT8 *)rem_name.remote_bd_name;
                rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN;
                rem_name.remote_bd_name[rem_name.length] = 0;
                rem_name.status = BTM_SUCCESS;
                temp_evt_len = rem_name.length;
    
                while (temp_evt_len > 0)
                {
                    *p_n1++ = *bdn++;
                    temp_evt_len--;
                }
                rem_name.remote_bd_name[rem_name.length] = 0;//temp struction 未返回
            }
    
    
            /* If processing a stand alone remote name then report the error in the callback */
            else
            {
                rem_name.status = BTM_BAD_VALUE_RET;
                rem_name.length = 0;
                rem_name.remote_bd_name[0] = 0;
            }
            /* Reset the remote BAD to zero and call callback if possible */
            memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
    
            p_inq->p_remname_cmpl_cb = NULL;
            if (p_cb)//null
                (p_cb)((tBTM_REMOTE_DEV_NAME *)&rem_name);
        }
    }

    我们再看看btm_sec_rmt_name_request_complete的实现:

    btm_Sec.c

    看名字,应该还是和配对流程相关.

     这里发现remote device的安全转换状态也是有一个状态转换的.其变量名是p_dev_rec->sec_state

    其可以取的值定义在btm_int.h里面:

    #define BTM_SEC_STATE_IDLE               0
    #define BTM_SEC_STATE_AUTHENTICATING     1
    #define BTM_SEC_STATE_ENCRYPTING         2
    #define BTM_SEC_STATE_GETTING_NAME       3
    #define BTM_SEC_STATE_AUTHORIZING        4
    #define BTM_SEC_STATE_SWITCHING_ROLE     5
    #define BTM_SEC_STATE_DISCONNECTING      6 /* disconnecting BR/EDR */
    #define BTM_SEC_STATE_DELAY_FOR_ENC      7 /* delay to check for encryption to work around */
                                               /* controller problems */
    #define BTM_SEC_STATE_DISCONNECTING_BLE  8 /* disconnecting BLE */
    #define BTM_SEC_STATE_DISCONNECTING_BOTH 9 /* disconnecting BR/EDR and BLE */

    btm_Sec.c

    /*******************************************************************************
    **
    ** Function         btm_sec_rmt_name_request_complete
    **
    ** Description      This function is called when remote name was obtained from
    **                  the peer device
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_sec_rmt_name_request_complete (UINT8 *p_bd_addr, UINT8 *p_bd_name, UINT8 status)
    {
        tBTM_SEC_DEV_REC *p_dev_rec;
        int              i;
        DEV_CLASS        dev_class;
        UINT8            old_sec_state;
    
        BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete");
        if (((p_bd_addr == NULL) && !BTM_ACL_IS_CONNECTED(btm_cb.connecting_bda))
            || ((p_bd_addr != NULL) && !BTM_ACL_IS_CONNECTED(p_bd_addr)))
        {
            btm_acl_resubmit_page();
        }
    
        /* If remote name request failed, p_bd_addr is null and we need to search */
        /* based on state assuming that we are doing 1 at a time */
        if (p_bd_addr)
            p_dev_rec = btm_find_dev (p_bd_addr);
        else
        {
    ...
        }
    ...
    
        if (p_dev_rec)
        {
            old_sec_state = p_dev_rec->sec_state;
            if (status == HCI_SUCCESS)
            {
                BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name), (char *)p_bd_name, BTM_MAX_REM_BD_NAME_LEN);//这里是保存名字的地方,名字从函数的第二个参数中来
                p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;// ++0x8 = 0x88
                BTM_TRACE_EVENT ("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x", p_dev_rec->sec_flags);
            }
            else
            {
                /* Notify all clients waiting for name to be resolved even if it failed so clients can continue */
                p_dev_rec->sec_bd_name[0] = 0;
            }
    
            if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME)//这里remote sec_state 是idle
                p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
    
            /* Notify all clients waiting for name to be resolved */
            for (i = 0;i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
            {
                if (btm_cb.p_rmt_name_callback[i] && p_bd_addr)
                    (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, p_dev_rec->dev_class,
                                                     p_dev_rec->sec_bd_name);
            }
        }
        else
        {
    ...
            return;
        }
    
        /* If we were delaying asking UI for a PIN because name was not resolved, ask now */
        if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) && p_bd_addr
             &&  (memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) )
        {
    ...
            return;
        }
    
        /* Check if we were delaying bonding because name was not resolved */
        if ( btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME)/*这里check 是否有配对流程需要继续*/
        {
            if (p_bd_addr && memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0)
            {
                BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete() continue bonding sm4: 0x%04x, status:0x%x", p_dev_rec->sm4, status);
                if(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_CANCEL_DD)//
                {
                    btm_sec_bond_cancel_complete();
                    return;
                }
    
                if (status != HCI_SUCCESS)
                {
                    btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
    
                    if (btm_cb.api.p_auth_complete_callback)
                        (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,  p_dev_rec->dev_class,
                                                                p_dev_rec->sec_bd_name, status);
                    return;
                }
    
                /* if peer is very old legacy devices, HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is not reported */
                if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
                {
                    /* set the KNOWN flag only if BTM_PAIR_FLAGS_REJECTED_CONNECT is not set.*/
                    /* If it is set, there may be a race condition */
                    BTM_TRACE_DEBUG ("btm_sec_rmt_name_request_complete  IS_SM4_UNKNOWN Flags:0x%04x",
                                       btm_cb.pairing_flags);
                    if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0)
                    {
                        p_dev_rec->sm4 |= BTM_SM4_KNOWN;
                    }
                }
    
                BTM_TRACE_DEBUG("%s, SM4 Value: %x, Legacy:%d,IS SM4:%d, Unknown:%d",__FUNCTION__,
                    p_dev_rec->sm4, BTM_SEC_IS_SM4_LEGACY(p_dev_rec->sm4),//sm4 = known这个变量就认为是legacy
                    BTM_SEC_IS_SM4(p_dev_rec->sm4),BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4));
    
                /* BT 2.1 or carkit, bring up the connection to force the peer to request PIN.
                ** Else prefetch (btm_sec_check_prefetch_pin will do the prefetching if needed)
                */
                if ((p_dev_rec->sm4 != BTM_SM4_KNOWN) || !btm_sec_check_prefetch_pin(p_dev_rec))  //一般走这里的流程,继续create connection
                {
                    /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */
                    /*  before originating  */
                    if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)
                    {
                        BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete: waiting HCI_Connection_Complete after rejecting connection");
                    }
                    /* Both we and the peer are 2.1 - continue to create connection */
                    else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED)//创建dd connection
                    {
                        BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete: failed to start connection");
    
                        btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
    
                        if (btm_cb.api.p_auth_complete_callback)
                        (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,  p_dev_rec->dev_class,
                                                                p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL);
                    }
                }
                return;
            }
    ....

    下面我们 在简单看下 btm_sec_dd_create_conn 的实现:

    btm_Sec.c

    /*******************************************************************************
    **
    ** 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)
    {
        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))/*Connection already exists */
        {
    ...
        }
    
        /* 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)
        {
    ...
            return(BTM_NO_RESOURCES);
        }
    
        /* set up the control block to indicated dedicated bonding */
        btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;//0x01 | 0x04 = 0x05
    
        if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == FALSE)
        {
            BTM_TRACE_WARNING ("Security Manager: failed create  [%02x%02x%02x%02x%02x%02x]",
                                p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
                                p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
    
            l2cu_release_lcb(p_lcb);
            return(BTM_NO_RESOURCES);
        }
    
        btm_acl_update_busy_level (BTM_BLI_PAGE_EVT);//update acl 
    
        BTM_TRACE_DEBUG ("Security Manager: btm_sec_dd_create_conn [%02x%02x%02x%02x%02x%02x]",
                          p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
                          p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
    
        btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);//更新 btm_cb.pairing_state = BTM_PAIR_STATE_WAIT_PIN_REQ
    
        return(BTM_CMD_STARTED);
    }

     接下来,当controller完成了物理link的建立,配对流程继续:

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_connection_comp_evt
    **
    ** Description      Process event HCI_CONNECTION_COMP_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_connection_comp_evt (UINT8 *p)
    {
        UINT8       status;
        UINT16      handle;
        BD_ADDR     bda;
        UINT8       link_type;
        UINT8       enc_mode;
    
        STREAM_TO_UINT8    (status, p);
        STREAM_TO_UINT16   (handle, p);
        STREAM_TO_BDADDR   (bda, p);
        STREAM_TO_UINT8    (link_type, p);
        STREAM_TO_UINT8    (enc_mode, p);
    
        handle = HCID_GET_HANDLE (handle);
    
        if (link_type == HCI_LINK_TYPE_ACL)
        {
            btm_sec_connected (bda, handle, status, enc_mode);
    
            l2c_link_hci_conn_comp (status, handle, bda);
        }...
    }

    这里还是两个函数,我们依次看一下:

     首先分析一下btm_sec_connected 

    /*******************************************************************************
    **
    ** Function         btm_sec_connected
    **
    ** Description      This function is when a connection to the peer device is
    **                  establsihed
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode)
    {
        tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
        UINT8            res;
        BOOLEAN          is_pairing_device = FALSE;
        tACL_CONN        *p_acl_cb;
        UINT8            bit_shift = 0;
    
        btm_acl_resubmit_page();
    
    
        if (!p_dev_rec)
        {
            ...
        }
        else    /* Update the timestamp for this device */
        {
    
    
            bit_shift = (handle == p_dev_rec->ble_hci_handle) ? 8 :0;
            p_dev_rec->timestamp = btm_cb.dev_rec_count++;
    
            if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND)
            {
                /* tell L2CAP it's a bonding connection. */
                if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
                     &&  (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
                     &&  (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) ){
                ...
                    }
                /* always clear the pending flag */
                p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
            }
        }
    
    #if BLE_INCLUDED == TRUE
        p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
    #endif
    
        p_dev_rec->rs_disc_pending   = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
    
        if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
             && (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0) )
        {
            /* if we rejected incoming connection from bonding device */
            if ((status == HCI_ERR_HOST_REJECT_DEVICE)
                &&(btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT))
            {
              ...
    
                return;
            }
            /* wait for incoming connection without resetting pairing state */
            else if (status == HCI_ERR_CONNECTION_EXISTS)
            {
                BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: Wait for incoming connection");
                return;
            }
    
            is_pairing_device = TRUE;
        }
    
        /* If connection was made to do bonding restore link security if changed */
        btm_restore_mode();
    
        /* if connection fails during pin request, notify application */
        if (status != HCI_SUCCESS)
        {
           ...
    
            return;
        }
    
        /* If initiated dedicated bonding, return the link key now, and initiate disconnect */
        /* If dedicated bonding, and we now have a link key, we are all done */
        if ( is_pairing_device
             && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) )
        {
        ...
                btm_send_link_key_notif(p_dev_rec);
    ...
            p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
    
    ...
    
            if (btm_cb.api.p_auth_complete_callback)
                (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
                                                        p_dev_rec->dev_class,
                                                        p_dev_rec->sec_bd_name, HCI_SUCCESS);
    
            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
            ...
            return;
        }
    
        p_dev_rec->hci_handle = handle;
    
        /* role may not be correct here, it will be updated by l2cap, but we need to */
        /* notify btm_acl that link is up, so starting of rmt name request will not */
        /* set paging flag up */
        p_acl_cb = btm_bda_to_acl(bda, BT_TRANSPORT_BR_EDR);
        if (p_acl_cb)
        {
            /* whatever is in btm_establish_continue() without reporting the BTM_BL_CONN_EVT event */
    #if (!defined(BTM_BYPASS_EXTRA_ACL_SETUP) || BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
            /* For now there are a some devices that do not like sending */
            /* commands events and data at the same time. */
            /* Set the packet types to the default allowed by the device */
            btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
    
            if (btm_cb.btm_def_link_policy)
                BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
    #endif
        }
        btm_acl_created (bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, handle, HCI_ROLE_SLAVE, BT_TRANSPORT_BR_EDR);
        /* Initialize security flags.  We need to do that because some            */
        /* authorization complete could have come after the connection is dropped */
        /* and that would set wrong flag that link has been authorized already    */
        p_dev_rec->sec_flags &= ~((BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED |
                                  BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED) << bit_shift);//first clear it
    
        if (enc_mode != HCI_ENCRYPT_MODE_DISABLED)
            p_dev_rec->sec_flags |= ((BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED) << bit_shift);
    
        if (btm_cb.security_mode == BTM_SEC_MODE_LINK)
            p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED << bit_shift);
    ...
    
        p_dev_rec->link_key_changed = FALSE;
    
        /* After connection is established we perform security if we do not know */
        /* the name, or if we are originator because some procedure can have */
        /* been scheduled while connection was down */
        BTM_TRACE_DEBUG ("is_originator:%d ", p_dev_rec->is_originator);
        if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator)
        {
            if ((res = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)//这里报包含 Start get name,Start authentication,Start encryption,一直到最后完成access granted
                btm_sec_dev_rec_cback_event (p_dev_rec, res, FALSE);
        }
        return;
    }

    简单说一下上面函数的要点:

    1. Allocate acl_db entry :p_acl_cb = btm_bda_to_acl(bda, BT_TRANSPORT_BR_EDR); 
      1. btsnd_hcic_read_rmt_clk_offset (p->hci_handle);//Command: HCI_Read_Clock_Offset
      2. btsnd_hcic_rmt_ver_req (p->hci_handle);//Command: HCI_Read_Remote_Version_Information
      3. btm_read_remote_features (p->hci_handle);//Command: HCI_Read_Remote_Supported_Features
    2.   btm_sec_execute_procedure (p_dev_rec)
      1. RNR 已经做过.
      2. Start authentication 即将要做
      3. Start encryption  后续要做
      4. Start authorization 可能要做  

    这里贴一下 btm_bda_to_acl 的代码,就不分析了.

    /*******************************************************************************
    **
    ** Function         btm_acl_created
    **
    ** Description      This function is called by L2CAP when an ACL connection
    **                  is created.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
                          UINT16 hci_handle, UINT8 link_role, tBT_TRANSPORT transport)
    {
        tBTM_SEC_DEV_REC *p_dev_rec = NULL;
        tACL_CONN        *p;
        UINT8             xx;
    
        BTM_TRACE_DEBUG ("btm_acl_created hci_handle=%d link_role=%d  transport=%d",
                          hci_handle,link_role, transport);
        /* Ensure we don't have duplicates */
        p = btm_bda_to_acl(bda, transport); //find btm_cb.acl_db ,if found then return .
        if (p != (tACL_CONN *)NULL)
        {
            p->hci_handle = hci_handle;
            p->link_role  = link_role;
    #if BLE_INCLUDED == TRUE
            p->transport = transport;
    #endif
            BTM_TRACE_DEBUG ("Duplicate btm_acl_created: RemBdAddr: %02x%02x%02x%02x%02x%02x",
                              bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
            BTM_SetLinkPolicy(p->remote_addr, &btm_cb.btm_def_link_policy);
            return;
        }
    
        /* Allocate acl_db entry */
        for (xx = 0, p = &btm_cb.acl_db[0]; xx < MAX_L2CAP_LINKS; xx++, p++)
        {
            if (!p->in_use)
            {
                p->in_use            = TRUE;
                p->hci_handle        = hci_handle;
                p->link_role         = link_role;
                p->link_up_issued    = FALSE;
                memcpy (p->remote_addr, bda, BD_ADDR_LEN);
    ...
    
                /* if BR/EDR do something more */
                if (transport == BT_TRANSPORT_BR_EDR)
                {
                    btsnd_hcic_read_rmt_clk_offset (p->hci_handle);//Command: HCI_Read_Clock_Offset
                }
                btsnd_hcic_rmt_ver_req (p->hci_handle);//Command: HCI_Read_Remote_Version_Information
                p_dev_rec = btm_find_dev_by_handle (hci_handle);
    ...
    
    #if (BLE_INCLUDED == TRUE)
                /* If here, features are not known yet */
                if (p_dev_rec && transport == BT_TRANSPORT_LE)
                {
    ...
                }
                else
    #endif
                {
                    BTM_TRACE_API("%s: begin to btm_read_remote_features", __FUNCTION__);
                    btm_read_remote_features (p->hci_handle);//Command: HCI_Read_Remote_Supported_Features
                }
    
                /* read page 1 - on rmt feature event for buffer reasons */
                return;
            }
        }
    }

    下面简单分析一下btm_sec_execute_procedure 的流程:

     btm_Sec.c

    /******************************************************************
    ** S T A T I C     F U N C T I O N S
    *******************************************************************/
    
    /*******************************************************************************
    **
    ** Function         btm_sec_execute_procedure
    **
    ** Description      This function is called to start required security
    **                  procedure.  There is a case when multiplexing protocol
    **                  calls this function on the originating side, connection to
    **                  the peer will not be established.  This function in this
    **                  case performs only authorization.
    **
    ** Returns          BTM_SUCCESS     - permission is granted
    **                  BTM_CMD_STARTED - in process
    **                  BTM_NO_RESOURCES  - permission declined
    **
    *******************************************************************************/
    static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec)
    {
        BTM_TRACE_EVENT ("btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
                          p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);//this time required = 0x10=BTM_SEC_OUT_AUTHENTICATE  p_dev_rec->sec_flags = 0x88--name known
    
        /* There is a chance that we are getting name.  Wait until done. */
        if (p_dev_rec->sec_state != 0)
            return(BTM_CMD_STARTED);
    
        /* If any security is required, get the name first */
        if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
            && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
        {
            BTM_TRACE_EVENT ("Security Manager: Start get name");
            if (!btm_sec_start_get_name (p_dev_rec))
            {
                return(BTM_NO_RESOURCES);
            }
            return(BTM_CMD_STARTED);
        }
    
        /* If connection is not authenticated and authentication is required */
        /* start authentication and return PENDING to the caller */
        if ((((!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
            && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE))
                || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHENTICATE))))
            || (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)
                && (!p_dev_rec->is_originator
                        && (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN))))
            && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
        {
            /*
             * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use,
             * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the
             * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM
             * authenticated connections, hence we cannot distinguish here.
             */
    
            BTM_TRACE_EVENT ("Security Manager: Start authentication");
    
            /*
             * If we do have a link-key, but we end up here because we need an
             * upgrade, then clear the link-key known and authenticated flag before
             * restarting authentication.
             * WARNING: If the controller has link-key, it is optional and
             * recommended for the controller to send a Link_Key_Request.
             * In case we need an upgrade, the only alternative would be to delete
             * the existing link-key. That could lead to very bad user experience
             * or even IOP issues, if a reconnect causes a new connection that
             * requires an upgrade.
             */
            if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
                    && (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)
                        && (!p_dev_rec->is_originator && (p_dev_rec->security_required
                                & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) {
                p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED
                        | BTM_SEC_AUTHENTICATED);//if BTM_SEC_LINK_KEY_KNOWN ,then clear the flag.
            }
    
            if (!btm_sec_start_authentication (p_dev_rec))//start authentication
            {
                return(BTM_NO_RESOURCES);
            }
            return(BTM_CMD_STARTED);
        }
    
        /* If connection is not encrypted and encryption is required */
        /* start encryption and return PENDING to the caller */
        if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
            && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT))
                || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT)))
            && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
        {
    
            BTM_TRACE_EVENT ("Security Manager: Start encryption");
    
            if (!btm_sec_start_encryption (p_dev_rec))
            {
                return(BTM_NO_RESOURCES);
            }
            return(BTM_CMD_STARTED);
        }
    
        if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
            (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
        {
            BTM_TRACE_EVENT("%s: Security Manager: SC only service, but link key type is 0x%02x -",
                            "security failure", __FUNCTION__, p_dev_rec->link_key_type);
            return (BTM_FAILED_ON_SECURITY);
        }
    
        /* If connection is not authorized and authorization is required */
        /* start authorization and return PENDING to the caller */
        if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)
            && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHORIZE))
                || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHORIZE))))
        {
            BTM_TRACE_EVENT ("service id:%d, is trusted:%d",
                              p_dev_rec->p_cur_service->service_id,
                              (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
                                                          p_dev_rec->p_cur_service->service_id)));
            if ((btm_sec_are_all_trusted(p_dev_rec->trusted_mask) == FALSE) &&
                (p_dev_rec->p_cur_service->service_id < BTM_SEC_MAX_SERVICES) &&
                (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
                                            p_dev_rec->p_cur_service->service_id) == FALSE))
            {
                BTM_TRACE_EVENT ("Security Manager: Start authorization");
                return(btm_sec_start_authorization (p_dev_rec));
            }
        }
    
        /* All required  security procedures already established */
        p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_IN_AUTHORIZE |
                                          BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |
                                          BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT |
                                          BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER |
                                          BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
    
        BTM_TRACE_EVENT ("Security Manager: trusted:0x%04x%04x", p_dev_rec->trusted_mask[1], p_dev_rec->trusted_mask[0]);
        BTM_TRACE_EVENT ("Security Manager: access granted");
    
        return(BTM_SUCCESS);
    }

        上面包含多个过程,但是当前就是执行start authentication 的流程.

     现在我们看看  btu_hcif_connection_comp_evt 中的另一个函数:

    l2c_link_hci_conn_comp (status, handle, bda);

    l2c_link.c

    /*******************************************************************************
    **
    ** Function         l2c_link_hci_conn_comp
    **
    ** Description      This function is called when an HCI Connection Complete
    **                  event is received.
    **
    ** Returns          void
    **
    *******************************************************************************/
    BOOLEAN l2c_link_hci_conn_comp (UINT8 status, UINT16 handle, BD_ADDR p_bda)
    {
        tL2C_CONN_INFO       ci;
        tL2C_LCB            *p_lcb;
        tL2C_CCB            *p_ccb;
        tBTM_SEC_DEV_REC    *p_dev_info = NULL;
        L2CAP_TRACE_WARNING ("enter l2c_link_hci_conn_comp libs_liu");
        btm_acl_update_busy_level (BTM_BLI_PAGE_DONE_EVT);
    
        /* Save the parameters */
        ci.status       = status;
        memcpy (ci.bd_addr, p_bda, BD_ADDR_LEN);
    
        /* See if we have a link control block for the remote device */
        p_lcb = l2cu_find_lcb_by_bd_addr (ci.bd_addr, BT_TRANSPORT_BR_EDR);
    
        /* If we don't have one, this is an error */
        if (!p_lcb)
        {
            L2CAP_TRACE_WARNING ("L2CAP got conn_comp for unknown BD_ADDR");
            return (FALSE);
        }
    
        if (p_lcb->link_state != LST_CONNECTING)
        {
            L2CAP_TRACE_ERROR ("L2CAP got conn_comp in bad state: %d  status: 0x%d", p_lcb->link_state, status);
    
            if (status != HCI_SUCCESS)
                l2c_link_hci_disc_comp (p_lcb->handle, status);
    
            return (FALSE);
        }
    
        /* Save the handle */
        p_lcb->handle = handle;
    
        if (ci.status == HCI_SUCCESS)
        {
            /* Connected OK. Change state to connected */
            p_lcb->link_state = LST_CONNECTED;
            counter_add("l2cap.conn.ok", 1);
    
            /* Get the peer information if the l2cap flow-control/rtrans is supported */
            l2cu_send_peer_info_req (p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE);//    Code: Information request   l2cap 
    
            /* Tell BTM Acl management about the link */
            if ((p_dev_info = btm_find_dev (p_bda)) != NULL)
                btm_acl_created (ci.bd_addr, p_dev_info->dev_class,
                                 p_dev_info->sec_bd_name, handle,
                                 p_lcb->link_role, BT_TRANSPORT_BR_EDR);//        Command: HCI_Write_Link_Policy_Settings
            else
                btm_acl_created (ci.bd_addr, NULL, NULL, handle, p_lcb->link_role, BT_TRANSPORT_BR_EDR);
    
            BTM_SetLinkSuperTout (ci.bd_addr, btm_cb.btm_def_link_super_tout);//        Command: HCI_Write_Link_Supervision_Timeout
    
            /* If dedicated bonding do not process any further */
            if (p_lcb->is_bonding)  //marked at start bonding: l2cu_update_lcb_4_bonding (bd_addr, TRUE); 
            {
                if (l2cu_start_post_bond_timer(handle))
                    /*start I2cap bonding timeout. the defaut idle:    l2cb.idle_timeout = L2CAP_LINK_INACTIVITY_TOUT = 4(l2c_main.c)
                     now set a new bonding timeout :#define L2CAP_BONDING_TIMEOUT       3  (bt_target.h)*/
                    return (TRUE);//return 
            }
      ...
        return (TRUE);
        }
    }

    上面函数做的主要的事情是:

    1. 设置link state:p_lcb->link_state = LST_CONNECTED; 
    2. Code: Information request   l2cap 
    3. Command: HCI_Write_Link_Policy_Settings
    4. Command: HCI_Write_Link_Supervision_Timeout
    5. l2cu_start_post_bond_timer   bonding timer

     当host端发起HCI_Authentication_Requested之后,往往contrller端还会请求Event: Link Key Request .

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_link_key_request_evt
    **
    ** Description      Process event HCI_LINK_KEY_REQUEST_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_link_key_request_evt (UINT8 *p)
    {
        BD_ADDR  bda;
    
        STREAM_TO_BDADDR (bda, p);
        btm_sec_link_key_request (bda);
    }

    对于该请求还是回到了btm_sec.c

    /*******************************************************************************
    **
    ** Function         btm_sec_link_key_request
    **
    ** Description      This function is called when controller requests link key
    **
    ** Returns          Pointer to the record or NULL
    **
    *******************************************************************************/
    void btm_sec_link_key_request (UINT8 *p_bda)
    {
        tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
    
        BTM_TRACE_EVENT ("btm_sec_link_key_request()  BDA: %02x:%02x:%02x:%02x:%02x:%02x",
                          p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
        if( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) &&
            (btm_cb.collision_start_time != 0) &&
            (memcmp (btm_cb.p_collided_dev_rec->bd_addr, p_bda, BD_ADDR_LEN) == 0) )
        {
            ...  /*collision */
            return;
        }
        if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
        {
            btsnd_hcic_link_key_req_reply (p_bda, p_dev_rec->link_key);/*if stored link key*/
            return;
        }
    
        /* Notify L2CAP to increase timeout */
        l2c_pin_code_request (p_bda);  /* increase link timeout to L2CAP_LINK_CONNECT_TOUT_EXT = 120 */
    
        /* The link key is not in the database and it is not known to the manager */
        btsnd_hcic_link_key_neg_reply (p_bda); //        Command: HCI_Link_Key_Request_Negative_Reply
    }

    这个处理很简单,有link key 就发送btsnd_hcic_link_key_req_reply  没有的话就HCI_Link_Key_Request_Negative_Reply 

    下面看一下 Event: Read Remote Version Information Complete 的处理:

    btm_acl.c

    /*******************************************************************************
    **
    ** Function         btm_read_remote_version_complete
    **
    ** Description      This function is called when the command complete message
    **                  is received from the HCI for the remote version info.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_read_remote_version_complete (UINT8 *p)
    {
        tACL_CONN        *p_acl_cb = &btm_cb.acl_db[0];
        UINT8             status;
        UINT16            handle;
        int               xx;
        BTM_TRACE_DEBUG ("btm_read_remote_version_complete");
        STREAM_TO_UINT8  (status, p);
        if (status == HCI_SUCCESS)
        {
            STREAM_TO_UINT16 (handle, p);
    
            /* Look up the connection by handle and copy features */
            for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
            {
                if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
                {
                    STREAM_TO_UINT8  (p_acl_cb->lmp_version, p);//btm_cb.acl_db[x].lmp_version
                    STREAM_TO_UINT16 (p_acl_cb->manufacturer, p);//btm_cb.acl_db[x].manufacturer
                    STREAM_TO_UINT16 (p_acl_cb->lmp_subversion, p);//btm_cb.acl_db[x].lmp_subversion
                    break;
                }
            }
        }
    }

    其就是将几个LMP 的version 保存到btm_cb.acl_db[x]结构中.

    接下来我们看看Event: Read Remote Supported Features Complete的处理:

    btm_acl.c

    /*******************************************************************************
    **
    ** Function         btm_read_remote_features_complete
    **
    ** Description      This function is called when the remote supported features
    **                  complete event is received from the HCI.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_read_remote_features_complete (UINT8 *p)
    {
        tACL_CONN        *p_acl_cb;
        UINT8             status;
        UINT16            handle;
        UINT8            acl_idx;
    
        BTM_TRACE_DEBUG ("btm_read_remote_features_complete");
        STREAM_TO_UINT8  (status, p);
    
        if (status != HCI_SUCCESS)
        {
            BTM_TRACE_ERROR ("btm_read_remote_features_complete failed (status 0x%02x)", status);
            return;
        }
    
            STREAM_TO_UINT16 (handle, p);
    
        if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
            {
            BTM_TRACE_ERROR("btm_read_remote_features_complete handle=%d invalid", handle);
            return;
                    }
    
        p_acl_cb = &btm_cb.acl_db[acl_idx];
    
        /* Copy the received features page */
        STREAM_TO_ARRAY(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0], p,
                        HCI_FEATURE_BYTES_PER_PAGE);//save remote feature in btm_cb.acl_db[acl_idx].peer_lmp_features
    
        if ((HCI_LMP_EXTENDED_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) &&
            (controller_get_interface()->supports_reading_remote_extended_features()))
        {
            /* if the remote controller has extended features and local controller supports
            ** HCI_Read_Remote_Extended_Features command then start reading these feature starting
            ** with extended features page 1 */
            BTM_TRACE_DEBUG ("Start reading remote extended features");
            btm_read_remote_ext_features(handle, HCI_EXT_FEATURES_PAGE_1);//        Command: HCI_Read_Remote_Extended_Features
            return;
        }
    
    ...
    }

    上面做了两件事:

    1. save remote feature in btm_cb.acl_db[acl_idx].peer_lmp_features  //临时
    2. Command: HCI_Read_Remote_Extended_Features (if support )

    下面我们继续看看对于Event: Read_Remote_Extended_Features_Complete的处理:

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_read_rmt_ext_features_comp_evt
    **
    ** Description      Process event HCI_READ_RMT_EXT_FEATURES_COMP_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_read_rmt_ext_features_comp_evt (UINT8 *p)
    {
        UINT8 *p_cur = p;
        UINT8 status;
        UINT16 handle;
    
        STREAM_TO_UINT8 (status, p_cur);
    
        if (status == HCI_SUCCESS)
            btm_read_remote_ext_features_complete(p);
        else
        {
            STREAM_TO_UINT16 (handle, p_cur);
            btm_read_remote_ext_features_failed(status, handle);
        }
    }

    btm_acl.c:

        
        
        /*******************************************************************************
        **
        ** Function         btm_read_remote_ext_features_complete
        **
        ** Description      This function is called when the remote extended features
        **                  complete event is received from the HCI.
        **
        ** Returns          void
        **
        *******************************************************************************/
        void btm_read_remote_ext_features_complete (UINT8 *p)
        {
            tACL_CONN   *p_acl_cb;
            UINT8       page_num, max_page;
            UINT16      handle;
            UINT8       acl_idx;
        
            ++p;
            STREAM_TO_UINT16 (handle, p);
            STREAM_TO_UINT8  (page_num, p);
            STREAM_TO_UINT8  (max_page, p);
        
            /* Validate parameters */
            if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
            {
                BTM_TRACE_ERROR("btm_read_remote_ext_features_complete handle=%d invalid", handle);
                return;
            }
        ...
        
            p_acl_cb = &btm_cb.acl_db[acl_idx];
        
            /* Copy the received features page */
            STREAM_TO_ARRAY(p_acl_cb->peer_lmp_features[page_num], p, HCI_FEATURE_BYTES_PER_PAGE);//store remote extend feature in btm_cb.acl_db[acl_idx].peer_lmp_features
        
            /* If there is the next remote features page and
             * we have space to keep this page data - read this page */
            if ((page_num < max_page) && (page_num < HCI_EXT_FEATURES_PAGE_MAX))
            {
                page_num++;
                BTM_TRACE_DEBUG("BTM reads next remote extended features page (%d)", page_num);
                btm_read_remote_ext_features (handle, page_num);//if there is .
                return;
            }
        
            /* Process the pages */
            btm_process_remote_ext_features (p_acl_cb, (UINT8) (page_num + 1));
        
            /* Continue with HCI connection establishment */
            btm_establish_continue (p_acl_cb);
        }

    上面做的事情:

    1. store remote extend feature in btm_cb.acl_db[acl_idx].peer_lmp_features
    2. btm_process_remote_ext_features
      1.  store remote feature in p_dev_rec->features 
      2.     p_dev_rec->sm4 = BTM_SM4_TRUE 
    3. btm_establish_continue
      1. Command: HCI_Change_Connection_Packet_Type
      2. Command: HCI_Write_Link_Policy_Settings
      3. update remote feature to upper layer:btm_cb.p_bl_changed_cb
      4. btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT);

    btm_acl.c

      
        /*******************************************************************************
        **
        ** Function         btm_process_remote_ext_features
        **
        ** Description      Local function called to process all extended features pages
        **                  read from a remote device.
        **
        ** Returns          void
        **
        *******************************************************************************/
        void btm_process_remote_ext_features (tACL_CONN *p_acl_cb, UINT8 num_read_pages)
        {
            UINT16              handle = p_acl_cb->hci_handle;
            tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_dev_by_handle (handle);
            UINT8               page_idx;
        
            BTM_TRACE_DEBUG ("btm_process_remote_ext_features");
        
            /* Make sure we have the record to save remote features information */
            if (p_dev_rec == NULL)
            {
                /* Get a new device; might be doing dedicated bonding */
                p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
            }
        
            p_acl_cb->num_read_pages = num_read_pages;
            p_dev_rec->num_read_pages = num_read_pages;
        
            /* Move the pages to placeholder */
            for (page_idx = 0; page_idx < num_read_pages; page_idx++)
            {
                if (page_idx > HCI_EXT_FEATURES_PAGE_MAX)
                {
                    BTM_TRACE_ERROR("%s: page=%d unexpected", __FUNCTION__, page_idx);
                    break;
                }
                memcpy (p_dev_rec->features[page_idx], p_acl_cb->peer_lmp_features[page_idx],
                        HCI_FEATURE_BYTES_PER_PAGE);//store remote feature in p_dev_rec->features
            }
      ...  
        
            /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
            btm_sec_set_peer_sec_caps(p_acl_cb, p_dev_rec);
            /*1.if remote device support ssp ,then set p_dev_rec->sm4 = BTM_SM4_TRUE
                **2. otherwise  set p_dev_rec->sm4 = BTM_SM4_KNOWN (means it does not support ssp)
                **3. do more if SC is supported.
                */
        
    ...
        }

    上面做了两件事:

    1. store remote feature in p_dev_rec->features 
    2. p_dev_rec->sm4 = BTM_SM4_TRUE (if support) .这个其实在之前btm_sec_rmt_host_support_feat_evt 就已经知晓了对方的相关feature

     当前分析的case, 是host端没有保存link key,那么配对的流程需要继续.下面我们看看

    Event: HCI IO Capability Request 的处理:

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_io_cap_request_evt
    **
    ** Description      Process event HCI_IO_CAPABILITY_REQUEST_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_io_cap_request_evt (UINT8 *p)
    {
        btm_io_capabilities_req(p);
    }

    btm_sec.c

        
        /*******************************************************************************
        **
        ** Function         btm_io_capabilities_req
        **
        ** Description      This function is called when LM request for the IO
        **                  capability of the local device and
        **                  if the OOB data is present for the device in the event
        **
        ** Returns          void
        **
        *******************************************************************************/
        void btm_io_capabilities_req (UINT8 *p)
        {
            tBTM_SP_IO_REQ  evt_data;
            UINT8           err_code = 0;
            tBTM_SEC_DEV_REC *p_dev_rec;
            BOOLEAN         is_orig = TRUE;
            UINT8           callback_rc = BTM_SUCCESS;
        
            STREAM_TO_BDADDR (evt_data.bd_addr, p);
        
            /* setup the default response according to compile options */
            /* assume that the local IO capability does not change
             * loc_io_caps is initialized with the default value */
            evt_data.io_cap = btm_cb.devcb.loc_io_caps;
            evt_data.oob_data = BTM_OOB_NONE;//none
            evt_data.auth_req = BTM_DEFAULT_AUTH_REQ;
        
        
            p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
        
            BTM_TRACE_DEBUG("%s:Security mode: %d, Num Read Remote Feat pages: %d", __FUNCTION__,
                              btm_cb.security_mode, p_dev_rec->num_read_pages);
       ...
        
            p_dev_rec->sm4 |= BTM_SM4_TRUE;//sm4  = 0x11 has updated before.
        
            BTM_TRACE_EVENT("%s: State: %s  Flags: 0x%04x  p_cur_service: 0x%08x p_dev_rec->sm4 = 0x%X libs_liu",
                             __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state),
                             btm_cb.pairing_flags, p_dev_rec->p_cur_service,p_dev_rec->sm4);
        
            if (p_dev_rec->p_cur_service)  //have not got one
            {
                BTM_TRACE_EVENT("%s: cur_service psm: 0x%04x, security_flags: 0x%04x",
                                 __FUNCTION__, p_dev_rec->p_cur_service->psm,
                                 p_dev_rec->p_cur_service->security_flags);
            }
        
            switch (btm_cb.pairing_state)
            {
    ...
        
                /* initiator, at this point it is expected to be dedicated bonding
                initiated by local device */
                case BTM_PAIR_STATE_WAIT_PIN_REQ:
                    if (!memcmp (evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN))
                    {
                        evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;//BTM_AUTH_AP_YES = 3
                    }
                    else
                    {
                        err_code = HCI_ERR_HOST_BUSY_PAIRING;
                    }
                    break;
        
                /* any other state is unexpected */
                default:
                    break;
            }
        ...
        
            evt_data.is_orig = is_orig;
        
    
            /* Notify L2CAP to increase timeout */
            l2c_pin_code_request (evt_data.bd_addr);//L2CAP_LINK_CONNECT_TOUT_EXT = 120
        
            memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
        
        /* coverity[uninit_use_in_call]
        Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
        False-positive: False-positive: evt_data.bd_addr is set at the beginning with:     STREAM_TO_BDADDR (evt_data.bd_addr, p);
        */
            if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
                memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
        
            btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS);//change btm_cb.pairing_state to BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS
        
            callback_rc = BTM_SUCCESS;
            if (p_dev_rec->sm4 & BTM_SM4_UPGRADE)//BTM_SM4_UPGRADE = 0x04
            {
                p_dev_rec->sm4 &= ~BTM_SM4_UPGRADE;
        
                /* link key upgrade: always use SPGB_YES - assuming we want to save the link key */
                evt_data.auth_req = BTM_AUTH_SPGB_YES;
            }
            else if (btm_cb.api.p_sp_callback)//bta_dm_sp_cback 
            {
                /* the callback function implementation may change the IO capability... */
                /*actually ,it is not changed */
                callback_rc = (*btm_cb.api.p_sp_callback) (BTM_SP_IO_REQ_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
            }
        
    
            if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != evt_data.oob_data))//the user does not indicate "reply later" by setting the oob_data to unknown
            {
                if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD))
                {
                    evt_data.auth_req = (BTM_AUTH_DD_BOND | (evt_data.auth_req & BTM_AUTH_YN_BIT));
                }
        ...
        
                /* if the user does not indicate "reply later" by setting the oob_data to unknown */
                /* send the response right now. Save the current IO capability in the control block */
                btm_cb.devcb.loc_auth_req   = evt_data.auth_req;
                btm_cb.devcb.loc_io_caps    = evt_data.io_cap;
        
                BTM_TRACE_EVENT("%s: State: %s  IO_CAP:%d oob_data:%d auth_req:%d",
                                 __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap,
                                 evt_data.oob_data, evt_data.auth_req);
        
                btsnd_hcic_io_cap_req_reply(evt_data.bd_addr, evt_data.io_cap,
                                            evt_data.oob_data, evt_data.auth_req);
            }
        }

    上面过程 主要就是

    1. 组建本端的IO capabilities  
    2. change btm_cb.pairing_state to BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS 
    3. Save the current IO capability in the control block: 
      1.   btm_cb.devcb.loc_auth_req   = evt_data.auth_req;
      2.        btm_cb.devcb.loc_io_caps    = evt_data.io_cap;
    4. btsnd_hcic_io_cap_req_reply

     IO的交互过程,本端已经将IO发送给对方,那么对方也会将其IO 发给我们,我们看下,对于对方IO的处理过程:

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_io_cap_response_evt
    **
    ** Description      Process event HCI_IO_CAPABILITY_RESPONSE_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_io_cap_response_evt (UINT8 *p)
    {
        btm_io_capabilities_rsp(p);
    }

    btm_sec.c

        
        /*******************************************************************************
        **
        ** Function         btm_io_capabilities_rsp
        **
        ** Description      This function is called when the IO capability of the
        **                  specified device is received
        **
        ** Returns          void
        **
        *******************************************************************************/
        void btm_io_capabilities_rsp (UINT8 *p)
        {
            tBTM_SEC_DEV_REC *p_dev_rec;
            tBTM_SP_IO_RSP evt_data;
        
            STREAM_TO_BDADDR (evt_data.bd_addr, p);
            STREAM_TO_UINT8 (evt_data.io_cap, p);
            STREAM_TO_UINT8 (evt_data.oob_data, p);
            STREAM_TO_UINT8 (evt_data.auth_req, p);
        
            /* Allocate a new device record or reuse the oldest one */
            p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
        
            /* If no security is in progress, this indicates incoming security */
            if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
            {
    ...
            }
        
            /* Notify L2CAP to increase timeout */
            l2c_pin_code_request (evt_data.bd_addr); //L2CAP_LINK_CONNECT_TOUT_EXT = 120
        
            /* We must have a device record here.
             * Use the connecting device's CoD for the connection */
        /* coverity[uninit_use_in_call]
        Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
        FALSE-POSITIVE error from Coverity test-tool. evt_data.bd_addr is set at the beginning with:     STREAM_TO_BDADDR (evt_data.bd_addr, p);
        */
            if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
                memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
    ...
        
            /* save the IO capability in the device record */
            p_dev_rec->rmt_io_caps  = evt_data.io_cap;
            p_dev_rec->rmt_auth_req = evt_data.auth_req;
        
            if (btm_cb.api.p_sp_callback)
                (*btm_cb.api.p_sp_callback) (BTM_SP_IO_RSP_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
        }

    上面函数做的事情:

    1.      保存remote IO  
      1. p_dev_rec->rmt_io_caps  = evt_data.io_cap;
      2. p_dev_rec->rmt_auth_req = evt_data.auth_req;
    2.   通知upper layer: p_sp_callback  : bta_dm_sp_cback ,保存IO
      1. pairing_cb.auth_req = auth_req;
      2. pairing_cb.io_cap = io_cap;

     接下来就走到了

    Event: HCI User Confirmation Request 的流程.

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_user_conf_request_evt
    **
    ** Description      Process event HCI_USER_CONFIRMATION_REQUEST_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_user_conf_request_evt (UINT8 *p)
    {
        btm_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p);
    }

     btm_sec.c

        
        /*******************************************************************************
        **
        ** Function         btm_proc_sp_req_evt
        **
        ** Description      This function is called to process/report
        **                  HCI_USER_CONFIRMATION_REQUEST_EVT
        **                  or HCI_USER_PASSKEY_REQUEST_EVT
        **                  or HCI_USER_PASSKEY_NOTIFY_EVT
        **
        ** Returns          void
        **
        *******************************************************************************/
        void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p)
        {
            tBTM_STATUS status = BTM_ERR_PROCESSING;
            tBTM_SP_EVT_DATA evt_data;
            UINT8               *p_bda = evt_data.cfm_req.bd_addr;
            tBTM_SEC_DEV_REC *p_dev_rec;
        
            /* All events start with bd_addr */
            STREAM_TO_BDADDR (p_bda, p);
        
            BTM_TRACE_EVENT ("btm_proc_sp_req_evt() BDA: %08x%04x event: 0x%x, State: %s",
                              (p_bda[0]<<24) + (p_bda[1]<<16) + (p_bda[2]<<8) + p_bda[3], (p_bda[4] << 8) + p_bda[5],
                              event, btm_pair_state_descr(btm_cb.pairing_state));
        
            if ( ((p_dev_rec = btm_find_dev (p_bda)) != NULL)
                 &&  (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
                 &&  (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) )
            {
                memcpy (evt_data.cfm_req.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
                memcpy (evt_data.cfm_req.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
        
                BCM_STRNCPY_S ((char *)evt_data.cfm_req.bd_name, sizeof(evt_data.cfm_req.bd_name), (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN);
        
                switch (event)
                {
                    case BTM_SP_CFM_REQ_EVT:
                        /* Numeric confirmation. Need user to conf the passkey */
                        btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM);
        
                        /* The device record must be allocated in the "IO cap exchange" step */
                        STREAM_TO_UINT32 (evt_data.cfm_req.num_val, p);
        
                        evt_data.cfm_req.just_works = TRUE;
        
                        /* process user confirm req in association with the auth_req param */
                        if ( (p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO)
                             &&  (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO)
                             &&  ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) || (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES)) )
                        {
                            /* Both devices are DisplayYesNo and one or both devices want to authenticate
                               -> use authenticated link key */    
                            evt_data.cfm_req.just_works = FALSE;
                        }
    
                        BTM_TRACE_DEBUG ("btm_proc_sp_req_evt()  just_works:%d, io loc:%d, rmt:%d, auth loc:%d, rmt:%d",
                                          evt_data.cfm_req.just_works, btm_cb.devcb.loc_io_caps, p_dev_rec->rmt_io_caps,
                                          btm_cb.devcb.loc_auth_req, p_dev_rec->rmt_auth_req);
        
                        evt_data.cfm_req.loc_auth_req   = btm_cb.devcb.loc_auth_req;
                        evt_data.cfm_req.rmt_auth_req   = p_dev_rec->rmt_auth_req;
                        evt_data.cfm_req.loc_io_caps    = btm_cb.devcb.loc_io_caps;
                        evt_data.cfm_req.rmt_io_caps    = p_dev_rec->rmt_io_caps;
                        break;
        
                    case BTM_SP_KEY_NOTIF_EVT:
                        /* Passkey notification (other side is a keyboard) */
                        ...
                        break;
        
                    case BTM_SP_KEY_REQ_EVT:
                        /* HCI_USER_PASSKEY_REQUEST_EVT */
                        btm_sec_change_pairing_state (BTM_PAIR_STATE_KEY_ENTRY);
                        break;
                }
        
                if (btm_cb.api.p_sp_callback)
                {
                    status = (*btm_cb.api.p_sp_callback) (event, (tBTM_SP_EVT_DATA *)&evt_data);
                    BTM_TRACE_DEBUG ("calling BTM_ConfirmReqReply with status: %d libs_liu", status);
                    if (status != BTM_NOT_AUTHORIZED)
                    {
                        BTM_TRACE_DEBUG(" return libs_liu");
                        return;
                    }
                    /* else BTM_NOT_AUTHORIZED means when the app wants to reject the req right now */
                }
    ...   
    
        }
            }

    上面函数做的事情:

    1. 设置btm_cb.pairing_state的状态为BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM 
    2.  evt_data.cfm_req.just_works = TRUE; 
    3. 将本端和对端的IO以及authentication req信息写进evt_data.cfm_req 
    4. 调用btm_cb.api.p_sp_callback(event (tBTM_SP_EVT_DATA *)&evt_data)  上报到upper layer. //bta_dm_sp_cback 

    下面看看bta_dm_sp_cback  对于该event 的实现:

    bta_dm_sp_cback
    
    
    
    
    /*******************************************************************************
    **
    ** Function         bta_dm_sp_cback
    **
    ** Description      simple pairing callback from BTM
    **
    ** Returns          void
    **
    *******************************************************************************/
    static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data)
    {
        tBTM_STATUS status = BTM_CMD_STARTED;
        tBTA_DM_SEC sec_event;
        tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT;
    
        APPL_TRACE_EVENT("bta_dm_sp_cback: %d", event);
        if (!bta_dm_cb.p_sec_cback){
            APPL_TRACE_EVENT("bta_dm_sp_cback:libs_liu BTM_NOT_AUTHORIZED");
            return BTM_NOT_AUTHORIZED;
            }
    
        /* TODO_SP */
        switch(event)
        {
        ...
        case BTM_SP_CFM_REQ_EVT:
            pin_evt = BTA_DM_SP_CFM_REQ_EVT;
            bta_dm_cb.just_works = sec_event.cfm_req.just_works = p_data->cfm_req.just_works;
            sec_event.cfm_req.loc_auth_req = p_data->cfm_req.loc_auth_req;
            sec_event.cfm_req.rmt_auth_req = p_data->cfm_req.rmt_auth_req;
            sec_event.cfm_req.loc_io_caps = p_data->cfm_req.loc_io_caps;
            sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps;
    
            /* continue to next case */
        /* Passkey entry mode, mobile device with output capability is very
            unlikely to receive key request, so skip this event */
        /*case BTM_SP_KEY_REQ_EVT: */
        case BTM_SP_KEY_NOTIF_EVT:
            if(BTM_SP_CFM_REQ_EVT == event)
            {
              /* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT,
                 call remote name request using values from cfm_req */
              if(p_data->cfm_req.bd_name[0] == 0)
              {
                ...
              }
              else
              {
                  /* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT,
                     copy these values into key_notif from cfm_req */
                  bdcpy(sec_event.key_notif.bd_addr, p_data->cfm_req.bd_addr);
                  BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class, p_data->cfm_req.dev_class);
                  BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME),
                       (char*)p_data->cfm_req.bd_name, (BD_NAME_LEN-1));
                  sec_event.key_notif.bd_name[BD_NAME_LEN-1] = 0;
               }
            }
    
            bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->key_notif.passkey;
            if (BTM_SP_KEY_NOTIF_EVT == event)
            {
            ...
            }
            bta_dm_cb.p_sec_cback(pin_evt, &sec_event);//p_sec_cback = bte_dm_evt
    
            break;
    
        default:
            status = BTM_NOT_AUTHORIZED;
            break;
        }
        APPL_TRACE_EVENT("dm status: %d", status);
        return status;
    }

    这里做的事情:

    1. 构建 sec_event.cfm_req 结构,保存本端和对端的IO以及authentication req
    2. 调用 bta_dm_cb.p_sec_cback(pin_evt, &sec_event)  来向上层 汇报:p_sec_cback = bte_dm_evt 

    下面看看回调做的事情:

     bte_dm_evt  -->btif_dm_upstreams_evt -->btif_dm_ssp_cfm_req_evt

    btif_dm.c

    /*******************************************************************************
    **
    ** Function         btif_dm_ssp_cfm_req_evt
    **
    ** Description      Executes SSP confirm request event in btif context
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ *p_ssp_cfm_req)
    {
        bt_bdaddr_t bd_addr;
        bt_bdname_t bd_name;
        UINT32 cod;
        BOOLEAN is_incoming = !(pairing_cb.state == BT_BOND_STATE_BONDING);
        int dev_type;
    
        BTIF_TRACE_DEBUG("%s", __FUNCTION__);
    
        /* Remote properties update */
        if (!btif_get_device_type(p_ssp_cfm_req->bd_addr, &dev_type))
        {
            dev_type = BT_DEVICE_TYPE_BREDR;
        }
        btif_update_remote_properties(p_ssp_cfm_req->bd_addr, p_ssp_cfm_req->bd_name,
                                      p_ssp_cfm_req->dev_class, (tBT_DEVICE_TYPE) dev_type);
    
        bdcpy(bd_addr.address, p_ssp_cfm_req->bd_addr);
        memcpy(bd_name.name, p_ssp_cfm_req->bd_name, BD_NAME_LEN);
    
        /* Set the pairing_cb based on the local & remote authentication requirements */
        bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING); /* has been update before .so the state will be updated this time  */
    
        /* if just_works and bonding bit is not set treat this as temporary */
    
        if (p_ssp_cfm_req->just_works && !(p_ssp_cfm_req->loc_auth_req & BTM_AUTH_BONDS) &&
            !(p_ssp_cfm_req->rmt_auth_req & BTM_AUTH_BONDS) &&
            !(check_cod((bt_bdaddr_t*)&p_ssp_cfm_req->bd_addr, COD_HID_POINTING)))
            pairing_cb.bond_type = BOND_TYPE_TEMPORARY;
        else
            pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
    
        btm_set_bond_type_dev(p_ssp_cfm_req->bd_addr, pairing_cb.bond_type);//save bond type :p_dev_rec->bond_type = BOND_TYPE_PERSISTENT
    
        pairing_cb.is_ssp = TRUE;
    
        /* If JustWorks auto-accept */
        if (p_ssp_cfm_req->just_works)
        {
            /// Don't show user confirm dialog if just work pairing request.
    
                BTIF_TRACE_EVENT("%s: User consent needed for incoming pairing request. bond_type: %d, loc_io_caps: %d, rmt_io_caps: %d",
                        __FUNCTION__, pairing_cb.bond_type , p_ssp_cfm_req->loc_io_caps, p_ssp_cfm_req->rmt_io_caps);
                BTIF_TRACE_EVENT("%s: Auto-accept JustWorks pairing", __FUNCTION__);
                btif_dm_ssp_reply(&bd_addr, BT_SSP_VARIANT_CONSENT, TRUE, 0);//        Command: HCI_User_Confirmation_Request_Reply
                return;
    ...
        }
    
        cod = devclass2uint(p_ssp_cfm_req->dev_class);
    
        if (cod == 0) {
            LOG_DEBUG("%s cod is 0, set as unclassified", __func__);
            cod = COD_UNCLASSIFIED;
        }
    
        pairing_cb.sdp_attempts = 0;
        /* notify upper level */
        HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
                         (p_ssp_cfm_req->just_works ? BT_SSP_VARIANT_CONSENT : BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
                         p_ssp_cfm_req->num_val);
    }

    上面函数主要做了如下的事情:

    1. btif_update_remote_properties  //看起来没什么需要更新 的.
    2. bond_state_changed ,因为之前已经更新过BT_BOND_STATE_BONDING,所以也不会真正的更新.
    3. pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
    4. btm_set_bond_type_dev(p_ssp_cfm_req->bd_addr, pairing_cb.bond_type);//save bond type :p_dev_rec->bond_type = BOND_TYPE_PERSISTENT 
    5. pairing_cb.is_ssp = TRUE;
    6. btif_dm_ssp_reply(&bd_addr, BT_SSP_VARIANT_CONSENT, TRUE, 0);// Command: HCI_User_Confirmation_Request_Reply 
      1.   btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); 改变btm_cb.pairing_state的状态为BTM_PAIR_STATE_WAIT_AUTH_COMPLETE

      接下去就是等待simple pairing的结束.

    我们看看

    Event: HCI Simple Pairing Complete 的处理:

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_simple_pair_complete_evt
    **
    ** Description      Process event HCI_SIMPLE_PAIRING_COMPLETE_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_simple_pair_complete_evt (UINT8 *p)
    {
        btm_simple_pair_complete(p);
    }

    btm_sec.c

    /*******************************************************************************
    **
    ** Function         btm_simple_pair_complete
    **
    ** Description      This function is called when simple pairing process is
    **                  complete
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_simple_pair_complete (UINT8 *p)
    {
        tBTM_SP_COMPLT  evt_data;
        tBTM_SEC_DEV_REC *p_dev_rec;
        UINT8           status;
        BOOLEAN         disc = FALSE;
    
        status = *p++;
        STREAM_TO_BDADDR (evt_data.bd_addr, p);
    
        if ((p_dev_rec = btm_find_dev (evt_data.bd_addr)) == NULL)
        {
            //error
            return;
        }
        BTM_TRACE_EVENT ("btm_simple_pair_complete()  Pair State: %s  Status:%d  sec_state: %u",
                          btm_pair_state_descr(btm_cb.pairing_state),  status, p_dev_rec->sec_state);
    
        evt_data.status = BTM_ERR_PROCESSING;
        if (status == HCI_SUCCESS)
        {
            evt_data.status = BTM_SUCCESS;
            p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;//0x88 | 0x02 = 0x8a
        }
    ...
    
        /* Let the pairing state stay active, p_auth_complete_callback will report the failure */
        memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
        memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
    
        if (btm_cb.api.p_sp_callback)//bta_dm_sp_cback 
            (*btm_cb.api.p_sp_callback) (BTM_SP_COMPLT_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
    ...
    }

    上面函数做的事情:

    1. 组建evt_data 结构
      1. evt_data.status = BTM_SUCCESS; (it depends)
      2. evt_data.bd_addr
      3. evt_data.dev_class
    2. (*btm_cb.api.p_sp_callback) (BTM_SP_COMPLT_EVT, (tBTM_SP_EVT_DATA *)&evt_data);//bta_dm_sp_cback   (do nothing about this event )
      1.    do not report this event - handled by link_key_callback or auth_complete_callback 

    "需要看看这个函数bta_dm_sp_cback (simple pairing)处理的event:"

    从上面可以看到,上层的回调bta_dm_sp_cback 并不会处理这个BTM_SP_COMPLT_EVT 事件,等到link key 上报或者authentication complete 再处理.

    接下来,我们继续看

    Event: Link Key Notification 的处理:

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_link_key_notification_evt
    **
    ** Description      Process event HCI_LINK_KEY_NOTIFICATION_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_link_key_notification_evt (UINT8 *p)
    {
        BD_ADDR  bda;
        LINK_KEY key;
        UINT8    key_type;
    
        STREAM_TO_BDADDR (bda, p);
        STREAM_TO_ARRAY16 (key, p);
        STREAM_TO_UINT8 (key_type, p);
    
        btm_sec_link_key_notification (bda, key, key_type);
    }

    btm_sec.c

    /*******************************************************************************
    **
    ** Function         btm_sec_link_key_notification
    **
    ** Description      This function is called when a new connection link key is
    **                  generated
    **
    ** Returns          Pointer to the record or NULL
    **
    *******************************************************************************/
    void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_type)
    {
        tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
        BOOLEAN         we_are_bonding = FALSE;
        BOOLEAN         ltk_derived_lk  = FALSE;
    
        BTM_TRACE_EVENT ("btm_sec_link_key_notification()  BDA:%04x%08x, TYPE: %d",
                          (p_bda[0]<<8)+p_bda[1], (p_bda[2]<<24)+(p_bda[3]<<16)+(p_bda[4]<<8)+p_bda[5],
                          key_type);
    
        if ((key_type >= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_COMBINATION) &&
            (key_type <= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_AUTH_COMB_P_256))
        {
            ltk_derived_lk = TRUE;
            key_type -= BTM_LTK_DERIVED_LKEY_OFFSET;
        }
        /* If connection was made to do bonding restore link security if changed */
        btm_restore_mode();
    
        if (key_type != BTM_LKEY_TYPE_CHANGED_COMB)
            p_dev_rec->link_key_type = key_type;
    
        p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;//0x8a | 0x10 = 0x9a
    
        /* BR/EDR connection, update the encryption key size to be 16 as always */
        p_dev_rec->enc_key_size = 16;
        memcpy (p_dev_rec->link_key, p_link_key, LINK_KEY_LEN);
    
        if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
             && (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) )
        {
            if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
                we_are_bonding = TRUE;
            ...
        }
    
        /* We will save link key only if the user authorized it - BTE report link key in all cases */
       
            if (btm_cb.api.p_link_key_callback)//bta_dm_new_link_key_cback 
            {
                if (ltk_derived_lk)
                {
                    BTM_TRACE_DEBUG ("btm_sec_link_key_notification()  LTK derived LK is saved already"
                                        " (key_type = %d)", p_dev_rec->link_key_type);
                }
                else
                {
                    (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class,
                                                       p_dev_rec->sec_bd_name,
                                                       p_link_key, p_dev_rec->link_key_type);
                }
            }
        
    }

    这个函数做的事情:

    1. p_dev_rec->link_key_type = key_type = 4
    2. p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;//0x8a | 0x10 = 0x9a
    3. p_dev_rec->enc_key_size = 16;
    4. memcpy (p_dev_rec->link_key, p_link_key, LINK_KEY_LEN);
    5. btm_cb.api.p_link_key_callback)//bta_dm_new_link_key_cback  上报upper layer (bta)

    关于btm_cb.api回调函数的注册是在蓝牙enable的时候 就已经注册了.BTM_SecRegister((tBTM_APPL_INFO*)&bta_security);

    我们看看bta_security的实现:

    bta_dm_act.c

    /* bta security callback */
    const tBTM_APPL_INFO bta_security =
    {
        &bta_dm_authorize_cback,
        &bta_dm_pin_cback,
        &bta_dm_new_link_key_cback,
        &bta_dm_authentication_complete_cback,
        &bta_dm_bond_cancel_complete_cback,
    #if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
        &bta_dm_sp_cback
    #else
        NULL
    #endif
    #if BLE_INCLUDED == TRUE
    #if SMP_INCLUDED == TRUE
        ,&bta_dm_ble_smp_cback
    #endif
        ,&bta_dm_ble_id_key_cback
    #endif
    
    }

     下面我们看看bta_dm_new_link_key_cback 的实现:

    /*******************************************************************************
    **
    ** Function         bta_dm_new_link_key_cback
    **
    ** Description      Callback from BTM to notify new link key
    **
    ** Returns          void
    **
    *******************************************************************************/
    static UINT8  bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
                                            BD_NAME bd_name, LINK_KEY key, UINT8 key_type)
    {
        tBTA_DM_SEC sec_event;
        tBTA_DM_AUTH_CMPL *p_auth_cmpl;
        UINT8             event;
        UNUSED(dev_class);
    
        memset (&sec_event, 0, sizeof(tBTA_DM_SEC));
    
        /* Not AMP Key type */
        if (key_type != HCI_LKEY_TYPE_AMP_WIFI && key_type != HCI_LKEY_TYPE_AMP_UWB)
        {
            event = BTA_DM_AUTH_CMPL_EVT;
            p_auth_cmpl = &sec_event.auth_cmpl;
    
            bdcpy(p_auth_cmpl->bd_addr, bd_addr);
    
            memcpy(p_auth_cmpl->bd_name, bd_name, (BD_NAME_LEN-1));
            p_auth_cmpl->bd_name[BD_NAME_LEN-1] = 0;
    
            p_auth_cmpl->key_present = TRUE;
            p_auth_cmpl->key_type = key_type;
            p_auth_cmpl->success = TRUE;
    
            memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN);//strore key in p_auth_cmpl->key
            sec_event.auth_cmpl.fail_reason = HCI_SUCCESS;
    
            // Report the BR link key based on the BR/EDR address and type
            BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type, &sec_event.auth_cmpl.addr_type);
            if(bta_dm_cb.p_sec_cback)//p_sec_cback = bte_dm_evt
                bta_dm_cb.p_sec_cback(event, &sec_event);
        }
    ...
        return BTM_CMD_STARTED;
    }

    上面函数做的事情:

    1.   组建sec_event.auth_cmpl 结构.并赋值
      1.   p_auth_cmpl->bd_addr
      2. p_auth_cmpl->bd_name
      3. p_auth_cmpl->key_present
      4. p_auth_cmpl->key_type
      5. p_auth_cmpl->success
      6. p_auth_cmpl->key //store link key
    2.   bta_dm_cb.p_sec_cback)//p_sec_cback = bte_dm_evt  ,event = BTA_DM_AUTH_CMPL_EVT  

     下面看看 bte_dm_evt对于BTA_DM_AUTH_CMPL_EVT  的处理:

     bte_dm_evt  -->btif_dm_upstreams_evt -->btif_dm_auth_cmpl_evt 

    btif_dm.c

    /*******************************************************************************
    **
    ** Function         btif_dm_auth_cmpl_evt
    **
    ** Description      Executes authentication complete event in btif context
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btif_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
    {
        /* Save link key, if not temporary */
        bt_bdaddr_t bd_addr;
        bt_status_t status = BT_STATUS_FAIL;
        bt_bond_state_t state = BT_BOND_STATE_NONE;
        BOOLEAN skip_sdp = FALSE;
    
        BTIF_TRACE_DEBUG("%s: bond state=%d", __func__, pairing_cb.state);
    
        bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
        if ( (p_auth_cmpl->success == TRUE) && (p_auth_cmpl->key_present) )
        {
            if ((p_auth_cmpl->key_type < HCI_LKEY_TYPE_DEBUG_COMB) ||
                (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) ||
                (p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) ||
                (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB_P_256) ||
                pairing_cb.bond_type == BOND_TYPE_PERSISTENT)
            {
                bt_status_t ret;
                BTIF_TRACE_DEBUG("%s: Storing link key. key_type=0x%x, bond_type=%d",
                    __FUNCTION__, p_auth_cmpl->key_type, pairing_cb.bond_type);
                ret = btif_storage_add_bonded_device(&bd_addr,
                                    p_auth_cmpl->key, p_auth_cmpl->key_type,
                                    pairing_cb.pin_code_len);//stote into  bt_config.conf
                ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret);
            }
            else
            {
                BTIF_TRACE_DEBUG("%s: Temporary key. Not storing. key_type=0x%x, bond_type=%d",
                    __FUNCTION__, p_auth_cmpl->key_type, pairing_cb.bond_type);
                if(pairing_cb.bond_type == BOND_TYPE_TEMPORARY)
                {
                    ...
                    return;
                }
            }
        }
    
        // Skip SDP for certain  HID Devices
        //because HID devices have do SDP before
        if (p_auth_cmpl->success)
        {
    
            btif_storage_set_remote_addr_type(&bd_addr, p_auth_cmpl->addr_type);
            btif_update_remote_properties(p_auth_cmpl->bd_addr,
                                          p_auth_cmpl->bd_name, NULL, p_auth_cmpl->dev_type);//update to upper layer :HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
            pairing_cb.timeout_retries = 0;
            status = BT_STATUS_SUCCESS;
            state = BT_BOND_STATE_BONDED;
            bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
    
            if (check_sdp_bl(&bd_addr) && check_cod_hid(&bd_addr, COD_HID_MAJOR))
            {
                LOG_WARN("%s:skip SDP", __FUNCTION__);
                skip_sdp = TRUE;
            }
            if(!pairing_cb.is_local_initiated && skip_sdp)
            {
                bond_state_changed(status, &bd_addr, state);
                ...
                /* Send the event to the BTIF */
                HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
                                 BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
            }
            else
            {
                /* Trigger SDP on the device */
                pairing_cb.sdp_attempts = 1;;
    
                /* If bonded due to cross-key, save the static address too*/
                if(pairing_cb.state == BT_BOND_STATE_BONDING &&
                  (bdcmp(p_auth_cmpl->bd_addr, pairing_cb.bd_addr) != 0))
                {
                    BTIF_TRACE_DEBUG("%s: bonding initiated due to cross key, adding static address",
                                     __func__);
                    bdcpy(pairing_cb.static_bdaddr.address, p_auth_cmpl->bd_addr);
                }
    
                if(btif_dm_inquiry_in_progress)
                    btif_dm_cancel_discovery();
    
                btif_dm_get_remote_services(&bd_addr);//BTA_DmDiscover begin to discovery
            }
            // Do not call bond_state_changed_cb yet. Wait until remote service discovery is complete
        }
        else
        ...
    }

    上面流程主要做的事情:

    1. btif_storage_add_bonded_device(&bd_addr,p_auth_cmpl->key, p_auth_cmpl->key_type,pairing_cb.pin_code_len);//stote into bt_config.conf

    2. btif_update_remote_properties(p_auth_cmpl->bd_addr,p_auth_cmpl->bd_name, NULL, p_auth_cmpl->dev_type);//update to upper layer :HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,

    3. btif_dm_get_remote_services(&bd_addr);//BTA_DmDiscover begin to discovery

    这里需要注意的是,当前并没有上报bond_state_changed_cb ,要等服务搜索完成之后才会做,(HID devices 有所不同)

    接下来在看看

    Event: Authentication Complete 的处理流程:

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_authentication_comp_evt
    **
    ** Description      Process event HCI_AUTHENTICATION_COMP_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_authentication_comp_evt (UINT8 *p)
    {
        UINT8   status;
        UINT16  handle;
    
        STREAM_TO_UINT8  (status, p);
        STREAM_TO_UINT16 (handle, p);
    
        btm_sec_auth_complete (handle, status);
    }

    btm_sec.c

    /*******************************************************************************
    **
    ** Function         btm_sec_auth_complete
    **
    ** Description      This function is when authentication of the connection is
    **                  completed by the LM
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_sec_auth_complete (UINT16 handle, UINT8 status)
    {
        UINT8            old_sm4;
        tBTM_PAIRING_STATE  old_state   = btm_cb.pairing_state;
        tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
        BOOLEAN             are_bonding = FALSE;
    ...
        btm_cb.collision_start_time = 0;
    
        btm_restore_mode();
    
    ...
        /* keep the old sm4 flag and clear the retry bit in control block */
        old_sm4 = p_dev_rec->sm4;
        p_dev_rec->sm4 &= ~BTM_SM4_RETRY;
    
        if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
             &&  (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
             &&  (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) )
            are_bonding = TRUE;
    
        if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
              &&  (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) )
            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);//change state to  BTM_PAIR_STATE_IDLE -->btm_cb.pairing_state
    
        //now p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING
    
    ...
        /* Currently we do not notify user if it is a keyboard which connects */
        /* User probably Disabled the keyboard while it was asleap.  Let her try */
        if (btm_cb.api.p_auth_complete_callback)
        {
            /* report the suthentication status */
            if (old_state != BTM_PAIR_STATE_IDLE)
                (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
                                                        p_dev_rec->dev_class,
                                                        p_dev_rec->sec_bd_name, status);//bta_dm_authentication_complete_cback
        }
    
        p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
    
        /* If this is a bonding procedure can disconnect the link now */
        if (are_bonding)
        {
            p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
    
            if (status != HCI_SUCCESS)
            {
                ...
            }
            else
            {
                BTM_TRACE_DEBUG ("TRYING TO DECIDE IF CAN USE SMP_BR_CHNL");
                ...
                l2cu_start_post_bond_timer (p_dev_rec->hci_handle);//after bonded ,the link timeout is set to BTU_TTYPE_L2CAP_LINK = 2s
            }
    
            return;
        }
        ...
    }

    上面函数做的事情主要是:

    1.         btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);//change state to  BTM_PAIR_STATE_IDLE -->btm_cb.pairing_state
    2. (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,p_dev_rec->dev_class,p_dev_rec->sec_bd_name, status);//bta_dm_authentication_complete_cback

    3.  p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; 从BTM_SEC_STATE_AUTHENTICATING(1)-->BTM_SEC_STATE_IDLE(0)
    4. l2cu_start_post_bond_timer (p_dev_rec->hci_handle);//after bonded ,the link timeout is set to BTU_TTYPE_L2CAP_LINK = 2s 创建定时器,2s

    下面我们看一下上面的回调:bta_dm_authentication_complete_cback

    bta_dm_act.c

        /*******************************************************************************
        **
        ** Function         bta_dm_authentication_complete_cback
        **
        ** Description      Authentication complete callback from BTM
        **
        ** Returns          void
        **
        *******************************************************************************/
        static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,BD_NAME bd_name, int result)
        {
            tBTA_DM_SEC sec_event;
            UNUSED(dev_class);
        
            if(result != BTM_SUCCESS)
            {
                ...
            }
        
            return BTM_SUCCESS;
        }

    仅仅进行错误处理.

    到此authentication 的流程就已经结束了.

     下面来看看encryption的流程.

    这里分析的case 是音箱,那么主要是看A2DP的security level.其level 定义如下:

    bta_api.h

    #define BTA_SEC_AUTHENTICATE    (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE)  //0x12

     这个在A2dp service 启动的时候,会初始化security level 

    btif_av.c

    /*******************************************************************************
    **
    ** Function         btif_av_execute_service
    **
    ** Description      Initializes/Shuts down the service
    **
    ** Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
    **
    *******************************************************************************/
    bt_status_t btif_av_execute_service(BOOLEAN b_enable)
    {
         if (b_enable)
         {
             /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
              * handle this request in order to allow incoming connections to succeed.
              * We need to put this back once support for this is added */
    
             /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
              * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
              * be initiated by the app/audioflinger layers */
    #if (AVRC_METADATA_INCLUDED == TRUE)
             BTA_AvEnable(BTA_SEC_AUTHENTICATE,
                 BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD
    #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
                 |BTA_AV_FEAT_RCCT
                 |BTA_AV_FEAT_ADV_CTRL
    #endif
                 ,bte_av_callback);
    ...
    #endif
             BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback);
         }
         else {
             BTA_AvDeregister(btif_av_cb.bta_handle);
             BTA_AvDisable();
         }
         return BT_STATUS_SUCCESS;
    }

    可以知道其初始化的level = BTA_SEC_AUTHENTICATE = 0x12

     A2dp 建立连接的过程中,需要在l2cap 上面建立AVDTP 的channel.这里面就会涉及到security 的问题.

    建立连接之前,有一个设置security level的步骤

    avdt_ccb_act.c

    /*******************************************************************************
    **
    ** Function         avdt_ccb_set_conn
    **
    ** Description      Set CCB variables associated with AVDT_ConnectReq().
    **
    **
    ** Returns          void.
    **
    *******************************************************************************/
    void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
    {
        /* save callback */
        p_ccb->p_conn_cback = p_data->connect.p_cback;//保存回调bta_av_stream0_cback
    
        /* set security level */
        BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_data->connect.sec_mask,
                             AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
    }

    BTM_SetSecurityLevel 会将0x3092 接下来执行:

    /*******************************************************************************
    **
    ** Function         avdt_ccb_chan_open
    **
    ** Description      This function calls avdt_ad_open_req() to
    **                  initiate a signaling channel connection.
    **
    **
    ** Returns          void.
    **
    *******************************************************************************/
    void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
    {
        UNUSED(p_data);
    
        BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG);
        avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT);
    }

    这里做的事情:

    1.   BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG);
      1. btm_cb.p_out_serv = p_serv_rec;
      2. p_dev_rec->p_cur_service = p_serv_rec;

    继续看 avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT);的实现:

    avdt_ad.c  (ad = adapter)

    /*******************************************************************************
    **
    ** Function         avdt_ad_open_req
    **
    ** Description      This function is called by a CCB or SCB to open a transport
    **                  channel.  This function allocates and initializes a
    **                  transport channel table entry.  The channel can be opened
    **                  in two roles:  as an initiator or acceptor.  When opened
    **                  as an initiator the function will start an L2CAP connection.
    **                  When opened as an acceptor the function simply configures
    **                  the table entry to listen for an incoming channel.
    **
    **
    ** Returns          Nothing.
    **
    *******************************************************************************/
    void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role)
    {
        tAVDT_TC_TBL    *p_tbl;
        UINT16          lcid;
    
        if((p_tbl = avdt_ad_tc_tbl_alloc(p_ccb)) == NULL)
        {
            AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl");
            return;
        }
    
    
        p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
        AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d",
            type, role, p_tbl->tcid);
    
        if (type == AVDT_CHAN_SIG)
        {
            /* if signaling, get mtu from registration control block */
            p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
            p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
        }
        else
        ...
    
        /* if we're acceptor, we're done; just sit back and listen */
        if (role == AVDT_ACP)
        {
            p_tbl->state = AVDT_AD_ST_ACP;
        }
        /* else we're inititator, start the L2CAP connection */
        else
        {
            p_tbl->state = AVDT_AD_ST_CONN;
    
            /* call l2cap connect req */
            if ((lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr)) != 0)//l2cap connection
            {
                /* if connect req ok, store tcid in lcid table  */
                avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
                AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d",
                    (lcid - L2CAP_BASE_APPL_CID), avdt_ad_tc_tbl_to_idx(p_tbl));
    
                avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
                AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
                    avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
                    lcid);
            }
            else
            {
                /* if connect req failed, call avdt_ad_tc_close_ind() */
                avdt_ad_tc_close_ind(p_tbl, 0);
            }
        }
    }

    这里的重点就是发起l2cap的连接.

    l2cap_api.c

    /*******************************************************************************
    **
    ** Function         L2CA_ConnectReq
    **
    ** Description      Higher layers call this function to create an L2CAP connection.
    **                  Note that the connection is not established at this time, but
    **                  connection establishment gets started. The callback function
    **                  will be invoked when connection establishes or fails.
    **
    ** Returns          the CID of the connection, or 0 if it failed to start
    **
    *******************************************************************************/
    UINT16 L2CA_ConnectReq (UINT16 psm, BD_ADDR p_bd_addr)
    {
        return L2CA_ErtmConnectReq (psm, p_bd_addr, NULL);
    }
    /*******************************************************************************
    **
    ** Function         L2CA_ErtmConnectReq
    **
    ** Description      Higher layers call this function to create an L2CAP connection.
    **                  Note that the connection is not established at this time, but
    **                  connection establishment gets started. The callback function
    **                  will be invoked when connection establishes or fails.
    **
    **  Parameters:       PSM: L2CAP PSM for the connection
    **                    BD address of the peer
    **                   Enhaced retransmission mode configurations
    
    ** Returns          the CID of the connection, or 0 if it failed to start
    **
    *******************************************************************************/
    UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_ertm_info)
    {
        tL2C_LCB        *p_lcb;
        tL2C_CCB        *p_ccb;
        tL2C_RCB        *p_rcb;
    
        counter_add("l2cap.conn.req", 1);
        L2CAP_TRACE_API ("L2CA_ErtmConnectReq()  PSM: 0x%04x  BDA: %08x%04x  p_ertm_info: 0x%08x allowed:0x%x preferred:%d", psm,
                          (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
                          (p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info,
                          (p_ertm_info) ? p_ertm_info->allowed_modes : 0,
                          (p_ertm_info) ? p_ertm_info->preferred_mode : 0);
    
    
        /* Fail if the PSM is not registered */
        if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
        {
            L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_conn_req, PSM: 0x%04x", psm);
            return (0);
        }
    
        /* First, see if we already have a link to the remote */
        /* assume all ERTM l2cap connection is going over BR/EDR for now */
        if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
        {
            ...
        }
    
        /* Allocate a channel control block */
        if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
        {
            L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_conn_req, PSM: 0x%04x", psm);
            return (0);
        }
    
        /* Save registration info */
        p_ccb->p_rcb = p_rcb;
    
    ...
        
        /* If link is up, start the L2CAP connection */
        if (p_lcb->link_state == LST_CONNECTED)
        {
            l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);//enter l2c_csm_execute   sm
        }
    ...
        /* Return the local CID as our handle */
        return (p_ccb->local_cid);
    }

    这里的重点 是进入到l2cap 的状态机来执行L2CEVT_L2CA_CONNECT_REQ  的事件.

    l2c_csm.c

    /*******************************************************************************
    **
    ** Function         l2c_csm_execute
    **
    ** Description      This function executes the state machine.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    {
        switch (p_ccb->chnl_state)
        {
        case CST_CLOSED:
            l2c_csm_closed (p_ccb, event, p_data);
            break;
    ...
        case L2CEVT_L2CA_CONNECT_REQ:                       /* API connect request  */
            /* Cancel sniff mode if needed */
            {
                tBTM_PM_PWR_MD settings;
    // btla-specific ++
                memset((void*)&settings, 0, sizeof(settings));
    // btla-specific --
                settings.mode = BTM_PM_MD_ACTIVE;
    /* COVERITY
    Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
    Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
    Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
    // FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
    // coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored
    */
                BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
            }
            L2CAP_TRACE_API ("L2CAP - after BTM_SetPowerMode libs_liu");
            /* If sec access does not result in started SEC_COM or COMP_NEG are already processed */
            if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
                                          p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED)
                p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
            break;

    这里的重点 是 建立符合安全等级的channel.从这里也可以看出来,建立channel的第一步就要检查security level.

    tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle,
                                          CONNECTION_TYPE conn_type,
                                          tBTM_SEC_CALLBACK *p_callback,
                                          void *p_ref_data)
    {
        tBTM_SEC_DEV_REC  *p_dev_rec;
        tBTM_SEC_SERV_REC *p_serv_rec;
        UINT16         security_required;
        UINT16         old_security_required;
        BOOLEAN       old_is_originator;
        tBTM_STATUS   rc = BTM_SUCCESS;
        BOOLEAN       chk_acp_auth_done = FALSE;
        BOOLEAN is_originator;
        BOOLEAN     transport = FALSE; /* should check PSM range in LE connection oriented L2CAP connection */
    
    
        is_originator = conn_type;
    
        BTM_TRACE_DEBUG ("%s() is_originator:%d, 0x%x psm  = %d ",__func__, is_originator, p_ref_data,psm);
    
        /* Find or get oldest record */
        p_dev_rec = btm_find_or_alloc_dev (bd_addr);
    
        p_dev_rec->hci_handle = handle;
    
        /* Find the service record for the PSM */
        p_serv_rec = btm_sec_find_first_serv (conn_type, psm);
    
    
        /* Services level0 by default have no security */
        if ((btm_sec_is_serv_level0(psm)) && (!btm_cb.devcb.secure_connections_only))
        {
            (*p_callback) (bd_addr,transport, p_ref_data, BTM_SUCCESS_NO_SECURITY);
            return(BTM_SUCCESS);
        }
        //delete something 
        {
            if (btm_cb.security_mode == BTM_SEC_MODE_SC)
            {
                security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags,
                                                                    is_originator);
            }
            else
            {
                security_required = p_serv_rec->security_flags;//  0x3092  update in :btm_sec_set_security_level
            }
        }
    
        BTM_TRACE_DEBUG("%s: security_required 0x%04x, is_originator 0x%02x, psm  0x%04x",
                        __FUNCTION__, security_required, is_originator, psm);
    
        if ((!is_originator) && (security_required & BTM_SEC_MODE4_LEVEL4))
            ...
        ...
    
        /* Save pointer to service record */
        p_dev_rec->p_cur_service = p_serv_rec;
    
        /* Modify security_required in btm_sec_l2cap_access_req for Lisbon */
        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)
        {
            if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
            {
                if (is_originator)
                {
                    /* SM4 to SM4 -> always authenticate & encrypt */
                    security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);//the security_required = 0x3092 | 0x20 = 0x30b2
                }
                else /* acceptor */
                {
                    /* SM4 to SM4: the acceptor needs to make sure the authentication is already done */
                    chk_acp_auth_done = TRUE;
                    /* SM4 to SM4 -> always authenticate & encrypt */
                    security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
               }
            }
            else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4))
            {
                ...
                return (BTM_CMD_STARTED);
            }
        }
    
        BTM_TRACE_DEBUG ("%s()  sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d", __func__,
                          p_dev_rec->sm4, p_dev_rec->sec_flags, security_required, chk_acp_auth_done);
    
        old_security_required        = p_dev_rec->security_required;
        old_is_originator            = p_dev_rec->is_originator;
        p_dev_rec->security_required = security_required;//update p_dev_rec->security_required
        p_dev_rec->p_ref_data        = p_ref_data;
        p_dev_rec->is_originator     = is_originator;
    
    
        /* If there are multiple service records used through the same PSM */
        /* leave security decision for the multiplexor on the top */
        ...
    
        /* if the originator is using dynamic PSM in legacy mode, do not start any security process now
         * The layer above L2CAP needs to carry out the security requirement after L2CAP connect
         * response is received */
    ...
    
        p_dev_rec->p_callback        = p_callback;//store callback  = l2c_link_sec_comp 
    
        if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID
            || p_dev_rec->last_author_service_id != p_dev_rec->p_cur_service->service_id)
        {
            /* Although authentication and encryption are per connection
            ** authorization is per access request.  For example when serial connection
            ** is up and authorized and client requests to read file (access to other
            ** scn), we need to request user's permission again.
            */
            p_dev_rec->sec_flags &= ~BTM_SEC_AUTHORIZED;//set it as non AUTHORIZED,actually ,the security_required does not conclude this one
        }
    
        if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
        {
            if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
                (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
            {
                /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */
                if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0)
                {
                    p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
                }
                p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
                                          BTM_SEC_AUTHENTICATED);
                BTM_TRACE_DEBUG ("%s: sec_flags:0x%x", __FUNCTION__, p_dev_rec->sec_flags);
            }
            else
            {
                /* If we already have a link key to the connected peer, is it secure enough? */
                btm_sec_check_upgrade(p_dev_rec, is_originator);//no need update.
            }
        }
    
        BTM_TRACE_EVENT ("%s() PSM:%d Handle:%d State:%d Flags: 0x%x Required: 0x%x Service ID:%d",
               __func__, psm, handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
               p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id);
    
        if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)//Start encryption
        {
            p_dev_rec->p_callback = NULL;
            (*p_callback) (bd_addr, transport, p_dev_rec->p_ref_data, (UINT8)rc);
        }
    
        return(rc);
    }

     这里做的事情:

    1.  security_required = p_serv_rec->security_flags;//  0x3092  update in :btm_sec_set_security_level 首先获取初始化(经过设置)的security level
    2. p_dev_rec->p_cur_service = p_serv_rec;  //Save pointer to service record   与security  device关联.
    3. security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);//the security_required = 0x3092 | 0x20 = 0x30b2   //重新规划 security_required
    4. p_dev_rec->security_required = security_required;//update p_dev_rec->security_required 
    5. p_dev_rec->p_callback        = p_callback;//store callback  = l2c_link_sec_comp   
    6. btm_sec_execute_procedure (p_dev_rec) //Start encryption 

    接下来 我们再次看看 btm_sec_execute_procedure 的流程,这里执行的就是encryption 流程

    btm_sec.c

    /******************************************************************
    ** S T A T I C     F U N C T I O N S
    *******************************************************************/
    
    /*******************************************************************************
    **
    ** Function         btm_sec_execute_procedure
    **
    ** Description      This function is called to start required security
    **                  procedure.  There is a case when multiplexing protocol
    **                  calls this function on the originating side, connection to
    **                  the peer will not be established.  This function in this
    **                  case performs only authorization.
    **
    ** Returns          BTM_SUCCESS     - permission is granted
    **                  BTM_CMD_STARTED - in process
    **                  BTM_NO_RESOURCES  - permission declined
    **
    *******************************************************************************/
    static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec)
    {
        BTM_TRACE_EVENT ("btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
                          p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);
    
    ...
    
        /* If any security is required, get the name first */
        if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
            && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
        {
        ...
        }
    
        /* If connection is not authenticated and authentication is required */
        /* start authentication and return PENDING to the caller */
            ...
        
    
        /* If connection is not encrypted and encryption is required */
        /* start encryption and return PENDING to the caller */
        if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
            && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT))
                || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT)))
            && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
        {
    
            BTM_TRACE_EVENT ("Security Manager: Start encryption");
    
            if (!btm_sec_start_encryption (p_dev_rec))//p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
            {
                return(BTM_NO_RESOURCES);
            }
            return(BTM_CMD_STARTED);
        }
        ...
    
        /* If connection is not authorized and authorization is required */
        /* start authorization and return PENDING to the caller */
        ...
        /* All required  security procedures already established */
        p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_IN_AUTHORIZE |
                                          BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |
                                          BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT |
                                          BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER |
                                          BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);//clear all flag
    
        BTM_TRACE_EVENT ("Security Manager: trusted:0x%04x%04x", p_dev_rec->trusted_mask[1], p_dev_rec->trusted_mask[0]);
        BTM_TRACE_EVENT ("Security Manager: access granted");
    
        return(BTM_SUCCESS);
    }

     上面走的流程就是btm_sec_start_encryption .这里还是设置了 p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;

    接下来我们看看

    Event: Encryption Change 的处理:

    btu_hcif.c

    /*******************************************************************************
    **
    ** Function         btu_hcif_encryption_change_evt
    **
    ** Description      Process event HCI_ENCRYPTION_CHANGE_EVT
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void btu_hcif_encryption_change_evt (UINT8 *p)
    {
        UINT8   status;
        UINT16  handle;
        UINT8   encr_enable;
    
        STREAM_TO_UINT8  (status, p);
        STREAM_TO_UINT16 (handle, p);
        STREAM_TO_UINT8  (encr_enable, p);
    
        btm_acl_encrypt_change (handle, status, encr_enable);
        btm_sec_encrypt_change (handle, status, encr_enable);
    }

    btm_acl_encrypt_change 主要是处理role switch 相关,略去.

    btm_sec.c

    /*******************************************************************************
    **
    ** Function         btm_sec_encrypt_change
    **
    ** Description      This function is when encryption of the connection is
    **                  completed by the LM
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable)
    {
        tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev_by_handle (handle);
    #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
        tACL_CONN       *p_acl = NULL;
        UINT8           acl_idx = btm_handle_to_acl_index(handle);
    #endif
        BTM_TRACE_EVENT ("Security Manager: encrypt_change status:%d State:%d, encr_enable = %d",
                          status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable);
        BTM_TRACE_DEBUG ("before update p_dev_rec->sec_flags=0x%x", (p_dev_rec) ? p_dev_rec->sec_flags : 0 );
    ...
    
        if ((status == HCI_SUCCESS) && encr_enable)
        {
            if (p_dev_rec->hci_handle == handle) {
                p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED);
                if (p_dev_rec->pin_code_length >= 16 ||
                    p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
                    p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
                    p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
                }
            }
            else
            {
                p_dev_rec->sec_flags |= (BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED);
            }
        }
    ...
    
        BTM_TRACE_DEBUG ("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags );
    
    #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
        if (acl_idx != MAX_L2CAP_LINKS)
            p_acl = &btm_cb.acl_db[acl_idx];
    
        if (p_acl != NULL)
            btm_sec_check_pending_enc_req(p_dev_rec, p_acl->transport, encr_enable);
    
        if (p_acl && p_acl->transport == BT_TRANSPORT_LE)
            ...
        else
        {
            /* BR/EDR connection, update the encryption key size to be 16 as always */
            p_dev_rec->enc_key_size = 16;
        }
    
         BTM_TRACE_DEBUG ("in %s new_encr_key_256 is %d",
                           __func__, p_dev_rec->new_encryption_key_is_p256);
    
        if ((status == HCI_SUCCESS) && encr_enable && (p_dev_rec->hci_handle == handle))
            ...
    #else
        btm_sec_check_pending_enc_req (p_dev_rec, BT_TRANSPORT_BR_EDR, encr_enable);
    #endif /* BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE */
    
        /* If this encryption was started by peer do not need to do anything */
        ...
    
        p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;//set p_dev_rec->sec_state
        /* If encryption setup failed, notify the waiting layer */
        ...
    
        /* Encryption setup succeeded, execute the next security procedure, if any */
        status = (UINT8)btm_sec_execute_procedure (p_dev_rec);
        /* If there is no next procedure, or procedure failed to start, notify the caller */
        if (status != BTM_CMD_STARTED)
            btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE);
    }

    上面函数要点:

    1. p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED);  //更新 sec_flag
    2.  p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;//set p_dev_rec->sec_state
    3. status = (UINT8)btm_sec_execute_procedure (p_dev_rec);
    4. btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE);//notify the caller  

    这里简单看一下这个回调的内容:

    /*******************************************************************************
    **
    ** Function         btm_sec_dev_rec_cback_event
    **
    ** Description      This function calls the callback function with the given
    **                  result and clear the callback function.
    **
    ** Parameters:      void
    **
    *******************************************************************************/
    void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res, BOOLEAN is_le_transport)
    {
        tBTM_SEC_CALLBACK   *p_callback = p_dev_rec->p_callback;//l2c_link_sec_comp  
    
        if (p_dev_rec->p_callback)
        {
            p_dev_rec->p_callback = NULL;
    
    #if BLE_INCLUDED == TRUE
            if (is_le_transport)
               (*p_callback) (p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE, p_dev_rec->p_ref_data, res);
            else
    #endif
               (*p_callback) (p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, p_dev_rec->p_ref_data, res);
        }
    
        btm_sec_check_pending_reqs();
    }

    这里就是调用l2c_link_sec_comp   继续去执行connection request以下的流程,并且把 p_dev_rec->p_callback 清掉.

    到这里关于security 的流程就都已经结束了.

  • 相关阅读:
    使用Powershell开机启动隐藏窗口的程序
    使用鼠标左键事件实现VR中的Eye Gaze Input
    在github网站上更新fork的repo
    零Web知识个性化Blog
    C#中的Attribute
    ConsoleWindow中的双击日志定位
    Hackintosh Issues 10.13.x
    开启macOS的原生写入Ntfs的功能
    Install macOS High Sierra on Any Supported Intel-based PC
    DSDT/SSDT
  • 原文地址:https://www.cnblogs.com/libs-liu/p/10175949.html
Copyright © 2011-2022 走看看