1. 程式人生 > >藍芽speaker配對流程原始碼分析

藍芽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
**