蓝牙配对过程分析(经典蓝牙)

打开手机/手表的蓝牙,就能在列表中看到扫描到的蓝牙,点击就可以实现配对功能。目前手表支持与所有设备的配对,但是仅支持与耳机类型的设备进行连接

安全简易配对SSP(Secure simple pairing),蓝牙2.0之后配对方式,简易安全配对一共有四种,其中Out of Band很少使用到,具体如下:
Numeric Comparison
配对双方都显示一个6位的数字,由用户来核对数字是否一致,并输入Yes/No,两端Yes表示一致即可配对,可以防止中间人攻击。
使用场景:两端设备可以弹出6位十进制数,并且有yes和no按钮。

Passkey Entry
配对目标输入一个在本地设备上显示的6位数字,输入正确即可配对,并可以防止中间人攻击。
使用场景:一端设备可以显示,另一端设备可以输入。

Just Works
不会进行鉴权,不能防止中间人攻击用于配对没有显示没有输入的设备,主动发起连接即可配对,用户看不到配对过程,不可以防止中间人攻击,例如连接蓝牙耳机。
使用场景:用于即不能显示6位随机数,也不能输入的设备。

Out of Band
两设备的通过别的途径交换配对信息,例如一些NFC蓝牙音箱。

一、原生应用设置界面的packages\Settings
目录:android\packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothDevicePreference.java

void onClicked() {
    int bondState = mCachedDevice.getBondState();

    if (mCachedDevice.isConnected()) {
        askDisconnect();//断开连接
    } else if (bondState == BluetoothDevice.BOND_BONDED) {
        mCachedDevice.connect(true);//已经配对了就连接
    } else if (bondState == BluetoothDevice.BOND_NONE) {
        pair();//没有配对的话就去配对
    }
}

private void pair() {
    if (!mCachedDevice.startPairing()) {
        Utils.showError(getContext(), mCachedDevice.getName(),
                R.string.bluetooth_pairing_error_message);
    } else {
        final Context context = getContext();

        SearchIndexableRaw data = new SearchIndexableRaw(context);
        data.className = BluetoothSettings.class.getName();
        data.title = mCachedDevice.getName();
        data.screenTitle = context.getResources().getString(R.string.bluetooth_settings);
        data.iconResId = R.drawable.ic_settings_bluetooth;
        data.enabled = true;

        Index.getInstance(context).updateFromSearchIndexableData(data);
    }
}

Y:\HLOS\frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth\CachedBluetoothDevice.java

public boolean startPairing() {
        // Pairing is unreliable while scanning, so cancel discovery
        if (mLocalAdapter.isDiscovering()) {
            mLocalAdapter.cancelDiscovery();//如果设备正在搜索,就取消搜索
        }

        if (!mDevice.createBond()) {//配对
            return false;
        }

        mConnectAfterPairing = true;  // auto-connect after pairing
        return true;
    }

二、framework层配对逻辑
Y:\HLOS\frameworks\base\core\java\android\bluetooth\BluetoothDevice.java

public boolean createBond() {
        if (sService == null) {
            Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
            return false;
        }
        try {
            Log.i(TAG, "createBond() for device " + getAddress() +
                    " called by pid: " + Process.myPid() +
                    " tid: " + Process.myTid());
            return sService.createBond(this, TRANSPORT_AUTO);//跨进程调用到AdapterService中的方法
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        return false;
    }

三、frameworks的aidl文件
private static IBluetooth sService;
1
HLOS\frameworks\base\core\java\android\bluetooth\IBluetooth.aidl
boolean createBond(in BluetoothDevice device);
这个是属于跨进程通信的方法,通过IBluetooth.aidl文件,调用到AdapterService.java中的createBond方法

四、从framework跨进程调到packages\Bluetooth
Y:\HLOS\packages\apps\Bluetooth\src\com\android\bluetooth\btservice\AdapterService.java

public boolean createBond(BluetoothDevice device, int transport) {
            if (!Utils.checkCallerAllowManagedProfiles(mService)) {
                Log.w(TAG, "createBond() - Not allowed for non-active user");
                return false;
            }

            AdapterService service = getService();
            if (service == null) return false;
            return service.createBond(device, transport, null);//调用本服务的createBond
        }

同在AdapterService文件下

boolean createBond(BluetoothDevice device, int transport, OobData oobData) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
            "Need BLUETOOTH ADMIN permission");
        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
        if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
            return false;
        }
        // Multicast: Do not allow bonding while multcast
        A2dpService a2dpService = A2dpService.getA2dpService();
        if (a2dpService != null &&
            a2dpService.isMulticastFeatureEnabled() &&
            a2dpService.isMulticastOngoing(null)) {
            Log.i(TAG,"A2dp Multicast is ongoing, ignore bonding");
            return false;
        }

        // Pairing is unreliable while scanning, so cancel discovery
        // Note, remove this when native stack improves
        cancelDiscoveryNative();//配对过程,取消扫描

        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
        msg.obj = device;
        msg.arg1 = transport;

        if (oobData != null) {
            Bundle oobDataBundle = new Bundle();
            oobDataBundle.putParcelable(BondStateMachine.OOBDATA, oobData);
            msg.setData(oobDataBundle);
        }
        mBondStateMachine.sendMessage(msg);//给配对的状态机发消息,创建创建了BondStateMachine.CREATE_BOND
        return true;
    }

在Y:\HLOS\packages\apps\Bluetooth\src\com\android\bluetooth\btservice\BondStateMachine.java
处理服务发送过来的消息

@Override
        public boolean processMessage(Message msg) {

            BluetoothDevice dev = (BluetoothDevice)msg.obj;
            DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev);
            boolean result = false;
             if (mDevices.contains(dev) && msg.what != CANCEL_BOND &&
                   msg.what != BONDING_STATE_CHANGE && msg.what != SSP_REQUEST &&
                   msg.what != PIN_REQUEST) {
                 deferMessage(msg);
                 return true;
             }

            Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);

            switch (msg.what) {
                case CREATE_BOND:
                    OobData oobData = null;
                    if (msg.getData() != null)
                        oobData = msg.getData().getParcelable(OOBDATA);

                    result = createBond(dev, msg.arg1, oobData, false);
                    break;
                    、、、
                    }
            }

private boolean createBond(BluetoothDevice dev, int transport, OobData oobData,
                               boolean transition) {
        if(mAdapterService == null) return false;
        if (dev.getBondState() == BluetoothDevice.BOND_NONE) {
            infoLog("Bond address is:" + dev);
            byte[] addr = Utils.getBytesFromAddress(dev.getAddress());
            boolean result;
            if (oobData != null) {//判读是否借助其他硬件进行无绑定配对
                result = mAdapterService.createBondOutOfBandNative(addr, transport, oobData);
            } else {
                result = mAdapterService.createBondNative(addr, transport);//调用到JNI层,进行配对
            }

            if (!result) {
                sendIntent(dev, BluetoothDevice.BOND_NONE,
                           BluetoothDevice.UNBOND_REASON_REMOVED);
                return false;
            } else if (transition) {
                transitionTo(mPendingCommandState);
            }
            return true;
        }
        return false;
    }

五、packages\Bluetooth的java层调到jini层的cpp文件
Y:\HLOS\packages\apps\Bluetooth\jni\com_android_bluetooth_btservice_AdapterService.cpp

static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address, jint transport) {
    ALOGV("%s:",__FUNCTION__);

    jbyte *addr;
    jboolean result = JNI_FALSE;

    if (!sBluetoothInterface) return result;

    addr = env->GetByteArrayElements(address, NULL);
    if (addr == NULL) {
        jniThrowIOException(env, EINVAL);
        return result;
    }

    int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr, transport);//该接口调用到hal层的配对函数
    env->ReleaseByteArrayElements(address, addr, 0);
    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;

    return result;
}

六、hal层createBond的调用
Y:\HLOS\system\bt\btif\src\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);
}

Y:\HLOS\system\bt\btif\src\btif_dm.c

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_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND, pairing_cb.state);//添加了绑定事件

    btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_CREATE_BOND,
                          (char *)&create_bond_cb, sizeof(btif_dm_create_bond_cb_t), NULL);//cotext是开辟了上下文的意思,这里create_bond_cb已经包含了要绑定的蓝牙地址,会分别发送给底层两部分,最后会调用btif_dm_generic_evt

    return BT_STATUS_SUCCESS;
}

Y:\HLOS\system\bt\btif\src\btif_dm.c

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;

        case BTIF_DM_CB_REMOVE_BOND:
        {
            btif_dm_cb_remove_bond((bt_bdaddr_t *)p_param);
        }
        break;
        、、、
    }
    、、、
}

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_config_set_int(bdstr, "DevType", BT_DEVICE_TYPE_BLE);
        }
        if (btif_storage_get_remote_addr_type(bd_addr, &addr_type) != BT_STATUS_SUCCESS)
        {
            btif_storage_set_remote_addr_type(bd_addr, BLE_ADDR_PUBLIC);
        }
    }
    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);//第一次调用会走这里
    }
    /*  Track  originator of bond creation  */
    pairing_cb.is_local_initiated = TRUE;

}


Y:\HLOS\system\bt\bta\dm\bta_dm_api.c

void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport)
{
    tBTA_DM_API_BOND *p_msg =
        (tBTA_DM_API_BOND *)osi_malloc(sizeof(tBTA_DM_API_BOND));

    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_sys_sendmsg这是蓝牙协议栈的进程间收发消息的机制,不是三言两语能说清楚的,若想了解,可以参考android bluedroid协议栈里面的各个组件之间的消息处理机制
根据BTA_DM_API_BOND_EVT这个类型,可以找到消息接收的地方
Y:\HLOS\system\bt\bta\dm\bta_dm_main.c

const tBTA_DM_ACTION bta_dm_action[] =
{

    /* device manager local device API events */
    bta_dm_enable,            /* 0  BTA_DM_API_ENABLE_EVT */
    bta_dm_disable,           /* 1  BTA_DM_API_DISABLE_EVT */
    bta_dm_set_dev_name,      /* 2  BTA_DM_API_SET_NAME_EVT */
    bta_dm_set_visibility,    /* 3  BTA_DM_API_SET_VISIBILITY_EVT */
    bta_dm_acl_change,        /* 8  BTA_DM_ACL_CHANGE_EVT */
    bta_dm_add_device,        /* 9  BTA_DM_API_ADD_DEVICE_EVT */
    bta_dm_close_acl,        /* 10  BTA_DM_API_ADD_DEVICE_EVT */

    /* security API events */
    bta_dm_bond,              /* 11  BTA_DM_API_BOND_EVT */
    bta_dm_bond_cancel,       /* 12  BTA_DM_API_BOND_CANCEL_EVT */
    bta_dm_pin_reply,         /* 13 BTA_DM_API_PIN_REPLY_EVT */

    /* power manger events */
    bta_dm_pm_btm_status,     /* 16 BTA_DM_PM_BTM_STATUS_EVT */
    bta_dm_pm_timer,          /* 17 BTA_DM_PM_TIMER_EVT*/

    /* simple pairing events */
    bta_dm_confirm,           /* 18 BTA_DM_API_CONFIRM_EVT */

    bta_dm_set_encryption,    /* BTA_DM_API_SET_ENCRYPTION_EVT */

    /* out of band pairing events */
    bta_dm_loc_oob,           /* 20 BTA_DM_API_LOC_OOB_EVT */
    bta_dm_ci_io_req_act,     /* 21 BTA_DM_CI_IO_REQ_EVT */
    bta_dm_ci_rmt_oob_act,    /* 22 BTA_DM_CI_RMT_OOB_EVT */
、、、
}

Y:\HLOS\system\bt\bta\dm\bta_dm_act.c

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)//这里看transport类型,走不通渠道
        status = BTM_SecBond ( p_data->bond.bd_addr, 0, NULL, 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))
    {

        memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
        bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr);
        p_name = BTM_SecReadDevName(p_data->bond.bd_addr);
        if (p_name != NULL)
        {
            memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN-1));
            sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 0;
        }

/*      taken care of by memset [above]
        sec_event.auth_cmpl.key_present = FALSE;
        sec_event.auth_cmpl.success = FALSE;
*/
        sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND;
        if (status == BTM_SUCCESS)
        {
            sec_event.auth_cmpl.success = TRUE;
        }
        else
        {
            /* delete this device entry from Sec Dev DB */
            bta_dm_remove_sec_dev_entry(p_data->bond.bd_addr);
        }
        bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
    }

}

Y:\HLOS\system\bt\stack\btm\btm_sec.c

tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport,
                                    UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
{
#if SMP_INCLUDED == TRUE
    tBT_DEVICE_TYPE     dev_type;
    tBLE_ADDR_TYPE      addr_type;

    BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
    /* LE device, do SMP pairing */
    if ((transport == BT_TRANSPORT_LE && (dev_type & BT_DEVICE_TYPE_BLE) == 0) ||
        (transport == BT_TRANSPORT_BR_EDR && (dev_type & BT_DEVICE_TYPE_BREDR) == 0))
    {
        return BTM_ILLEGAL_ACTION;
    }
#endif
    return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask);
}

Y:\HLOS\system\bt\stack\btm\btm_sec.c

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]);

    BTM_TRACE_DEBUG("btm_sec_bond_by_transport: Transport used %d" , transport);

    /* 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)
    {
        return(BTM_NO_RESOURCES);
    }
    if (!controller_get_interface()->get_is_ready())
    {
        BTM_TRACE_ERROR ("%s controller module is not ready", __func__);
        return(BTM_NO_RESOURCES);
    }
    BTM_TRACE_DEBUG ("before update sec_flags=0x%x", p_dev_rec->sec_flags);

    /* Finished if connection is active and already paired */
    if ( ((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_BR_EDR
         &&  (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
#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)
        return(BTM_NO_RESOURCES);

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

    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;
    p_dev_rec->is_originator     = TRUE;
    if (trusted_mask)
        BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);

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

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

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

    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);

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

    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);

#if BTM_SEC_FORCE_RNR_FOR_DBOND == TRUE
    p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN;
#endif

    /* If connection already exists... */
    if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE)
    {
        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);
    if (!controller_get_interface()->supports_simple_pairing()
        || (p_dev_rec->sm4 == BTM_SM4_KNOWN))
    {
        if ( btm_sec_check_prefetch_pin (p_dev_rec) )
            return (BTM_CMD_STARTED);
    }
    if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
         btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
         btm_cb.security_mode == BTM_SEC_MODE_SC) &&
         BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
    {
        /* local is 2.1 and peer is unknown */
        if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0)
        {
            /* we are not accepting connection request from peer
             * -> RNR (to learn if peer is 2.1)
             * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
            btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
            BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR);
        }
        else
        {
            /* We are accepting connection request from peer */
            btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
        }
        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;
}

这里代码很多,每一句都看懂不现实,现摘出重要的一段看

 if (!controller_get_interface()->supports_simple_pairing())//这里做一个判断,看是否支持简单配对方式
    {
        /* The special case when we authenticate keyboard.  Set pin type to fixed */
        /* It would be probably better to do it from the application, but it is */
        /* complicated */
        if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL)
            && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD)
            && (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED))
        {
            btm_cb.pin_type_changed = TRUE;
            btsnd_hcic_write_pin_type (HCI_PIN_TYPE_FIXED);//这里就可以看到在和hci层打交道了
        }
    }

八、通过HCI向底层发送命令进行控制
BOOLEAN btsnd_hcic_write_pin_type (UINT8 type)
{
    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
    UINT8 *pp = (UINT8 *)(p + 1);

    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
    p->offset = 0;

    UINT16_TO_STREAM (pp, HCI_WRITE_PIN_TYPE);
    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);

    UINT8_TO_STREAM (pp, type);

    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);//这里是向hci层发命令,
    return (TRUE);
}

可以看出,这里是通过和hci层的通信,host告诉controlor蓝牙地址、数据、命令等,从而控制其底层硬件发起配对操作
————————————————
版权声明:本文为CSDN博主「跳舞的蘑菇」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/w1107845086/article/details/79636090

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝牙配对流程源码分析在CSDN上可以找到相关的技术博文和开源项目,以下是大致的分析过程: 首先,在CSDN中搜索蓝牙配对流程的关键词,可以找到一些作者分享的源码分析文章。这些文章通常包括了蓝牙配对流程的基本知识介绍、配对过程的技术原理以及相关代码的解析。 其次,阅读这些源码分析文章,可以了解蓝牙配对流程在底层的实现细节。这些文章通常会讲解配对流程的各个步骤,例如配对方式的选择、密钥生成的过程配对请求和回应的交互等。 同时,可以跟踪并分析开源项目中的相关代码。在CSDN上,一些开发者可能会分享他们自己实现的或者对开源项目进行的蓝牙配对流程源码分析。通过分析这些代码,可以更深入地了解蓝牙配对流程的实现细节和相关的算法。 最后,结合文献和博客中的技术理论与代码分析,我们可以对蓝牙配对流程的源码有一个整体的认识,了解不同实现中的差异和特点。需要注意的是,虽然CSDN上的文章和博客可以提供一些指导,但最好通过多个来源的阅读和对比,以获得更全面和准确的理解。 需要注意的是,由于CSDN是一个开发者分享技术经验的平台,文章和博客的质量、深度和准确性可能有所不同。因此,在阅读这些内容时,应当保持批判性思维,结合官方文档和其他权威来源进行综合分析和验证。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值