A2DP SOURCE CONNECT
简单总结:
struct l2cap_chan :一个表示应用层socket PSM,比如SDP/AVDTP/AVCTP struct hci_conn :表示kernel底层是唯一的实际物理连接MAC地址为区分
struct hci_conn *conn; 状态机: hci_acl_create_connection conn->state = BT_CONNECT; hci_conn_complete_evt conn->state = BT_CONFIG; hci_remote_ext_features_evt hci_remote_ext_features_evt conn->state = BT_CONNECTED; ///建立底层连接通道后: hci_connect_cfm //反馈给L2CAP进行处理 l2cap_connect_cfm struct l2cap_conn *conn; 指向 struct hci_conn *conn; /* Find fixed channels and notify them of the new connection.*/ //给l2cap_conn 找一个 fix chn 的 l2cap_chan ,主要用来做smp相关的 __l2cap_chan_add(conn, chan); chan->conn = conn; l2cap_conn_ready(conn); //[l2cap_state_change] chan 00000000950c1207 BT_BOUND -> BT_CONNECT //l2cap chan的状态机 l2cap_conn_ready //先做一个l2cap info 交互 if (hcon->type == ACL_LINK) l2cap_request_info(conn); [l2cap_conn_ready] fix chan [7, 4, 2, 4] state: BT_OPEN [l2cap_conn_ready] co chan [64, 3, 5, 4] state: BT_CONNECT //l2cap chan的状态机 if (chan->state == BT_CONNECT) l2cap_do_start(chan); //由于L2CAP_INFO_REQ没有完成,所以什么也没做, if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
return;
//l2cap info 交互完成
l2cap_information_rsp
case L2CAP_IT_FEAT_MASK:
case L2CAP_IT_FIXED_CHAN:
l2cap_conn_start(conn);
//开始建立l2cap conn
l2cap_conn_start(struct l2cap_conn *conn)
//便利挂在l2cap_conn上面的所有的l2cap_chan
list_for_each_entry_safe(chan, tmp, &conn->chan_l, list)
//fix chan
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
l2cap_chan_ready(chan);
chan->state = BT_CONNECTED; //fix chan connected
smp_ready_cb
conn->smp = chan;
if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
bredr_pairing(chan); //如果满足条件,进行smp
//conn oriented
if (chan->state == BT_CONNECT)
l2cap_chan_check_security
hci_conn_security //由于是SDP,无需加密
l2cap_start_connection(chan);//启动l2cap连接
l2cap_connect_create_rsp
l2cap_state_change(chan, BT_CONFIG); //l2cap chan的状态机
//连接成功后,发起配置请求
l2cap_send_cmd(L2CAP_CONF_REQ)
//对端回应配置请求
l2cap_config_rsp
//我们回应对方的配置请求
l2cap_config_req
CONF_OUTPUT_DONE
CONF_INPUT_DONE
l2cap_chan_ready(chan);
//l2cap_chan 就绪的前提是l2cap conf 配置完成
l2cap_chan_ready
chan->state = BT_CONNECTED;//l2cap chan的状态机
chan->ops->ready(chan);
l2cap_sock_ready_cb
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
sk->sk_state = BT_CONNECTED;
//至此,完成了一次上层的SDP的 socket connect 操作,包括两个状态机,由于SDP无需加密,所以比较简单
//下面相同的流程再走一遍,这次是AVDTP socket connect操作,不同点用红色表示,相比SDP而已
[l2cap_chan_create] chan 00000000db3a6a9d
[l2cap_chan_connect] 4d:11:f2:1e:3c:c9 -> f0:13:c3:50:ff:26 (type 0) psm 0x19 (3, 0 3) //PSM 0X19 AVDTP
//对应同一个ACL连接而已,这两个结构体都是对所有的L2CAP共用!
struct l2cap_conn *conn;
struct hci_conn *hcon;
//把新建立的l2cap_chan 挂到 l2cap_conn上面
[__l2cap_chan_add] conn 0000000080dc1834, psm 0x19, dcid 0x0000, scid 0x0041, ct: 3, flags: 0x2
list_add(&chan->list, &conn->chan_l);
//AVDTP chan的状态机
l2cap_state_change(chan, BT_CONNECT);
//struct hci_conn *hcon; ACL连接再SDP阶段已经完成,所有是connected!
if (hcon->state == BT_CONNECTED)
l2cap_do_start(chan);
l2cap_do_start
//重点:发起l2cap conn之前,要检查安全级别
l2cap_chan_check_security(chan, true)
//由于是AVDTP,则加密级别提高为:BT_SECURITY_MEDIUM -> HCI_AT_GENERAL_BONDING
[l2cap_get_auth_type] sl: 2, psm: 25, ct: 3
//ACL LINK, BT_SECURITY_MEDIUM HCI_AT_GENERAL_BONDING
[hci_conn_security] hcon 000000007c312d12, te: 1, sl: 2, at: 4, ir: 1, kt: 0xff, flags: 0x4c0
/* For other security levels we need the link key. */
if (!test_bit(HCI_CONN_AUTH, &conn->flags))
//如果此ACL链路没有认证过
hci_conn_auth(conn, sec_level, auth_type)
//发起认证
[hci_send_cmd] hci0 opcode 0x0411 plen 2
//并且设置加密等待
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
//下面开始一个认证流程
//首先LMP会向host询问是否有配对过的有效的LINK KEY
[hci_link_key_request_evt] hci0 link key not found for f0:13:c3:50:ff:26
//没有,则询问host的io capa
[hci_io_capa_request_evt] 0x10ca18030, 0x204c5, 0xff, 0x3
[hci_io_capa_request_evt] capa: 0x3, authentication: 0x4
//reply给LMP
hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
sizeof(cp), &cp);
//LMP给的反馈
[hci_io_capa_reply_evt] hci0, 0x3, 0x4
conn->remote_cap = ev->capability; 0x3
conn->remote_auth = ev->authentication; 0x4
[hci_user_confirm_request_evt] hci0 0x4, 0x4, flags: 0x204c5
[hci_user_confirm_request_evt] hci0 lm: 0, rm: 0, psl: 0x2, rcap: 0x3
[hci_user_confirm_request_evt] Auto-accept of user confirmation with 0ms delay
/* If no side requires MITM protection; auto-accept */
HCI_IO_NO_INPUT_OUTPUT 无需 MITM,自动接收确认
hci_send_cmd: HCI_OP_USER_CONFIRM_REPLY
//Event Code Simple Pairing Complete
hci_simple_pair_complete_evt
//HCI Link Key Notification (F0:13:C3:50:FF:26, Key=4B120A2E:0E5F443D:145E8660:F851DF75, Type=Unauthenticated-192)
hci_link_key_notify_evt
hci_add_link_key(hdev, conn, &ev->bdaddr, ev->link_key,
ev->key_type, pin_len, &persistent);
mgmt_new_link_key(hdev, key, persistent);
[hci_auth_complete_evt] hci0 status 0x00 state 1
//完成认证
set_bit(HCI_CONN_AUTH, &conn->flags);
conn->sec_level = conn->pending_sec_level;
//开始加密相关
hci_encrypt_change_evt
hci_auth_cfm(conn, ev->status);
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
return; //认证还没有完成,需要去加密
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)
hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT
[hci_send_cmd] hci0 opcode 0x0413 plen 3 //发起加密
hci_encrypt_change_evt
Encryption Enabled On (BR/EDR E0, LE AES-CCM)
/* Encryption implies authentication */
set_bit(HCI_CONN_AUTH, &conn->flags);
set_bit(HCI_CONN_ENCRYPT, &conn->flags);
conn->sec_level = conn->pending_sec_level;
//sec_level: 2, conn->flags: 0x1234c4
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
/* Try reading the encryption key size for encrypted ACL links */
if (!ev->status && ev->encrypt && conn->type == ACL_LINK)
hci_req_add(&req, HCI_OP_READ_ENC_KEY_SIZE
[hci_req_add_ev] hci0 opcode 0x1408 plen 2
read_enc_key_size_complete
hci_encrypt_cfm(conn, 0);
list_for_each_entry(cb, &hci_cb_list, list)
cb->security_cfm(conn, status, encrypt);
l2cap_security_cfm
//遍历l2cap_conn上面的所有l2cap_chan (PSM的代码表示)
list_for_each_entry(chan, &conn->chan_l, list)
[l2cap_security_cfm] conn 0000000080dc1834 status 0x00 encrypt 1
[l2cap_security_cfm] chan 00000000db3a6a9d AVDTP scid 0x0041 state BT_CONNECT
if (chan->state == BT_CONNECT)
l2cap_start_connection(chan); //至此,AVDTP的安全机制已完成,则现在可以开始L2CAP CONN!!!,流程参考上面的SDP
[l2cap_security_cfm] chan 0000000061cd910d SMP OVER BR/EDR scid 0x0007 state BT_CONNECTED
[l2cap_security_cfm] chan 00000000ee31465e SDP scid 0x0040 state BT_CONNECTED
l2cap_start_connection
l2cap_connect_create_rsp
[l2cap_connect_create_rsp] dcid 0x0601 scid 0x0041 result 0x01 status 0x02
[l2cap_connect_create_rsp] dcid 0x0601 scid 0x0041 result 0x00 status 0x00
l2cap_state_change(chan, BT_CONFIG);
[l2cap_state_change] chan 00000000db3a6a9d BT_CONNECT -> BT_CONFIG
l2cap_send_cmd L2CAP_CONF_REQ
//对端回应配置请求
l2cap_config_rsp
//我们回应对方的配置请求
l2cap_config_req
CONF_OUTPUT_DONE
CONF_INPUT_DONE
l2cap_chan_ready(chan);
l2cap_chan_ready
[l2cap_chan_ready] chan: 00000000db3a6a9d
[l2cap_chan_ready] [00000000db3a6a9d] chan->state = BT_CONNECTED
sk->sk_state = BT_CONNECTED;
//至此,完成了AVDTP的 socket connect 操作,包括两个状态机,由于AVDTP需要加密,所以比较复杂!
疑问:为什么AVDTP没有触发FIXED CHAN 的 SMP机制?
//一 只有下面的case才能跑到SMP,但l2cap_information_req/rsp只有在ACL建立后仅执行一次,所以第二次无法跑到这里!
l2cap_information_rsp
l2cap_conn_start
list_for_each_entry_safe(chan, tmp, &conn->chan_l, list)
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_ready(chan);
l2cap_chan_unlock(chan);
continue;
}
//二
hci_encrypt_cfm
if (conn->state == BT_CONFIG) {
if (!status)
conn->state = BT_CONNECTED;
hci_connect_cfm(conn, status);
hci_conn_drop(conn);
return;
}
//接下来第三次AVDTP TRANSPORT,上面那个是AVDTP SIG通道,一个传输控制数据,另一个传输音频数据(两个L2CAP的连接,L2CAP的作用)
//类比:TCP/UDP 层
//L2CAP的SCID/DCID,就是端口的概念!!!
//ACL链路类比 数据链路层!!!,蓝牙没有IP层的类比,它不想以太网有IP地址及MAC地址!
[l2cap_chan_create] chan 00000000a34acb53
[l2cap_sock_bind] sk 000000004f83a7ce, l2_cid: 0, l2_psm: 0, sl: 1, ct: 3, mode: 0
[l2cap_chan_connect] 4d:11:f2:1e:3c:c9 -> f0:13:c3:50:ff:26 (type 0) psm 0x19 (3, 0 3)
[l2cap_get_auth_type] sl: 2, psm: 25, ct: 3
[l2cap_state_change] chan 00000000a34acb53 BT_BOUND -> BT_CONNECT
[l2cap_chan_connect] hcon->state: 1
[l2cap_chan_connect] l2cap_do_start
l2cap_do_start
[l2cap_get_auth_type] sl: 2, psm: 25, ct: 3
[hci_conn_security] hcon 000000007c312d12, te: 1, sl: 2, at: 4, ir: 1, kt: 0x4, flags: 0x1234c0
HCI_CONN_AUTH 已经置位
//这是之前的link key
HCI Link Key Notification (F0:13:C3:50:FF:26, Key=4B120A2E:0E5F443D:145E8660:F851DF75, Type=Unauthenticated-192)
/* An unauthenticated combination key has sufficient security for security level 1 and 2. */
if ((conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 ||
conn->key_type == HCI_LK_UNAUTH_COMBINATION_P256) &&
(sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW))
goto encrypt;
encrypt:
//之前已经加密完成!
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
if (!conn->enc_key_size)
return 0;
/* Nothing else needed, all requirements are met */
return 1;
if (l2cap_check_enc_key_size(conn->hcon)) //检查下enc key
l2cap_start_connection(chan);
... ...
SPP 被动监听
SPP
被动连接:
hci_cs_create_conn
conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr, HCI_ROLE_MASTER);
struct hci_conn *conn = kzalloc(sizeof(*conn), GFP_KERNEL);
conn->state = BT_OPEN;
conn->role = HCI_ROLE_MASTER;
conn->auth_type = HCI_AT_GENERAL_BONDING;
if (conn->role == HCI_ROLE_MASTER)
conn->out = true;
case ACL_LINK:
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
hci_conn_hash_add(hdev, conn);
hci_conn_complete_evt
[hci_conn_complete_evt] flags: 0x1d, cflags: 0x400, at: 4, out: 0, 0x5,0xd,0x6,0xc
/* Get remote features */
hci_send_cmd HCI_OP_READ_REMOTE_FEATURES
hci_remote_features_evt
hci_send_cmd HCI_OP_READ_REMOTE_EXT_FEATURES
hci_remote_ext_features_evt
[hci_remote_ext_features_evt] flags: 0x580, 0x8,0x7
set_bit(HCI_CONN_SC_ENABLED, &conn->flags);
set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ,
//[hci_outgoing_auth_needed] flags: 0x580, 0x7,0x0,0x0,0x4.
if (!hci_outgoing_auth_needed(hdev, conn))
conn->state = BT_CONNECTED;
BT_INFO(" %d BT_CONNECTED to hci_connect_cfm", __LINE__);
hci_connect_cfm(conn, ev->status);
hci_connect_cfm
l2cap_connect_cfm
[l2cap_connect_cfm] hcon 000000001cf0a359 bdaddr 94:87:e0:b6:6d:ae status 0
[l2cap_connect_cfm] hcon flags: 0x580, 0x1,0x0,0x0,0x4
struct hci_conn *hcon
struct l2cap_conn *conn;
//这里仅创建l2cap_conn/hci_chan,并没有l2cap_chan
conn = l2cap_conn_add(hcon);
hchan = hci_chan_create(hcon);
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
hcon->l2cap_data = conn;
conn->hcon = hci_conn_get(hcon);
conn->hchan = hchan;
struct l2cap_chan *pchan;
//找到smp root
pchan = l2cap_global_fixed_chan(NULL, hcon);
chan = pchan->ops->new_connection(pchan);
smp_new_conn_cb
//创建l2cap_chan
__l2cap_chan_add(conn, chan);
l2cap_conn_ready
if (hcon->type == ACL_LINK)
l2cap_request_info(conn); //发起L2CAP初始的INFO交互
list_for_each_entry(chan, &conn->chan_l, list)
[l2cap_conn_ready] chan SMP 00000000cee8bdf1 [7, 4, 2, 4]
l2cap_information_rsp
[l2cap_information_rsp] type 0x0002 result 0x00
[l2cap_information_rsp] type 0x0003 result 0x00
l2cap_conn_start
list_for_each_entry_safe(chan, tmp, &conn->chan_l, list)
[l2cap_conn_start] chan 00000000cee8bdf1, type: 4, state: 2
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_ready(chan);
l2cap_chan_ready
[l2cap_chan_ready] SMP [00000000cee8bdf1] chan->state = BT_CONNECTED
chan->ops->ready(chan);
[smp_ready_cb] chan 00000000cee8bdf1
//
hci_io_capa_reply_evt
[hci_io_capa_reply_evt] hci0, 0x1, 0x5
//手机侧发来它的io capa
//HCI IO Capability Response (94:87:E0:B6:6D:AE, IoCapability=Yes/No, RemoteOobDataPresent=None, Auth=MITM+General)
conn->remote_cap = ev->capability;
conn->remote_auth = ev->authentication;
//手机侧询问我们的io
[hci_io_capa_request_evt] 0x10cb18030, 0x5c0, 0x5, 0x3
[hci_get_auth_req] 0x5, 0x4, 0x1, 0x3
[hci_io_capa_request_evt] capa: 0x3, authentication: 0x4
//HCI IO Capability Request Reply (94:87:E0:B6:6D:AE, IoCapability=None, HostOobDataPresent=None, Auth=!MITM+General)
[hci_user_confirm_request_evt] hci0 0x4, 0x5, flags: 0x5c0
[hci_user_confirm_request_evt] hci0 lm: 0, rm: 1, psl: 0x0, rcap: 0x1
[hci_user_confirm_request_evt] Auto-accept of user confirmation with 0ms delay
[hci_simple_pair_complete_evt] hci0
[hci_link_key_notify_evt] hci0
[hci_add_link_key] hci0 key for 94:87:e0:b6:6d:ae type 7
[hci_encrypt_change_evt] 2878, sec_level: 2, conn->flags: 0x1035c0
/* Encryption implies authentication */
set_bit(HCI_CONN_AUTH, &conn->flags);
set_bit(HCI_CONN_ENCRYPT, &conn->flags);
[read_enc_key_size_complete] hci0 status 0x00
read_enc_key_size_complete
if (conn->state == BT_CONFIG) {
//这就是为什么单独SPP连接可以进SMP流程的原因!!!
if (!status)
conn->state = BT_CONNECTED;
hci_connect_cfm(conn, status);
hci_conn_drop(conn);
return;
}
[hci_encrypt_cfm] 1297, conn->state: 1, conn->sec_level: 2
list_for_each_entry(cb, &hci_cb_list, list) {
if (cb->security_cfm)
cb->security_cfm(conn, status, encrypt);
}
[l2cap_security_cfm] conn 00000000ee457177 status 0x00 encrypt 2
[l2cap_security_cfm] chan 00000000cee8bdf1 scid 0x0007 state BT_CONNECTED
if (!status && (chan->state == BT_CONNECTED ||
chan->state == BT_CONFIG)) {
chan->ops->resume(chan);
smp_resume_cb
}
[rfcomm_security_cfm] conn 000000001cf0a359 status 0x00 encrypt 0x02
smp_resume_cb
if (hcon->type == ACL_LINK) {
bredr_pairing(chan);
return;
}
bredr_pairing
... ...
l2cap_connect_req
l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
/* Check if we have socket listening on psm */
//rfcomm_run 创建l2cap_chan
pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, &conn->hcon->dst, ACL_LINK);
//创建新的sock 及 l2cap_chan
chan = pchan->ops->new_connection(pchan);
//.name = "L2CAP Socket Interface",
//.new_connection = l2cap_sock_new_connection_cb,
l2cap_sock_new_connection_cb
sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC, 0);
l2cap_sock_init(sk, parent);
bt_accept_enqueue(parent, sk, false);
list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
bt_sk(sk)->parent = parent;
return l2cap_pi(sk)->chan;
bacpy(&chan->src, &conn->hcon->src);
bacpy(&chan->dst, &conn->hcon->dst);
chan->src_type = bdaddr_src_type(conn->hcon);
chan->dst_type = bdaddr_dst_type(conn->hcon);
chan->psm = psm;
chan->dcid = scid;
__l2cap_chan_add(conn, chan);
l2cap_state_change(chan, BT_CONFIG);
result = L2CAP_CR_SUCCESS;
l2cap_config_rsp
[l2cap_chan_ready] [00000000bef51779] chan->state = BT_CONNECTED
chan->state = BT_CONNECTED;//l2cap chan的状态机
chan->ops->ready(chan);
l2cap_sock_ready_cb
l2cap_sock_ready_cb
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
if (parent)
parent->sk_data_ready(parent);
sk_data_ready
rfcomm_l2data_ready
... ...