提交 ef8efe4b 编写于 作者: J Johan Hedberg 提交者: Marcel Holtmann

Bluetooth: Add skeleton for BR/EDR SMP channel

This patch adds the very basic code for creating and destroying SMP
L2CAP channels for BR/EDR connections.
Signed-off-by: NJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: NMarcel Holtmann <marcel@holtmann.org>
上级 858cdc78
...@@ -306,6 +306,7 @@ struct hci_dev { ...@@ -306,6 +306,7 @@ struct hci_dev {
__u32 req_result; __u32 req_result;
void *smp_data; void *smp_data;
void *smp_bredr_data;
struct discovery_state discovery; struct discovery_state discovery;
struct hci_conn_hash conn_hash; struct hci_conn_hash conn_hash;
......
...@@ -141,6 +141,7 @@ struct l2cap_conninfo { ...@@ -141,6 +141,7 @@ struct l2cap_conninfo {
#define L2CAP_FC_ATT 0x10 #define L2CAP_FC_ATT 0x10
#define L2CAP_FC_SIG_LE 0x20 #define L2CAP_FC_SIG_LE 0x20
#define L2CAP_FC_SMP_LE 0x40 #define L2CAP_FC_SMP_LE 0x40
#define L2CAP_FC_SMP_BREDR 0x80
/* L2CAP Control Field bit masks */ /* L2CAP Control Field bit masks */
#define L2CAP_CTRL_SAR 0xC000 #define L2CAP_CTRL_SAR 0xC000
...@@ -255,6 +256,7 @@ struct l2cap_conn_rsp { ...@@ -255,6 +256,7 @@ struct l2cap_conn_rsp {
#define L2CAP_CID_ATT 0x0004 #define L2CAP_CID_ATT 0x0004
#define L2CAP_CID_LE_SIGNALING 0x0005 #define L2CAP_CID_LE_SIGNALING 0x0005
#define L2CAP_CID_SMP 0x0006 #define L2CAP_CID_SMP 0x0006
#define L2CAP_CID_SMP_BREDR 0x0007
#define L2CAP_CID_DYN_START 0x0040 #define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_DYN_END 0xffff #define L2CAP_CID_DYN_END 0xffff
#define L2CAP_CID_LE_DYN_END 0x007f #define L2CAP_CID_LE_DYN_END 0x007f
......
...@@ -2504,6 +2504,9 @@ static void smp_resume_cb(struct l2cap_chan *chan) ...@@ -2504,6 +2504,9 @@ static void smp_resume_cb(struct l2cap_chan *chan)
BT_DBG("chan %p", chan); BT_DBG("chan %p", chan);
if (hcon->type == ACL_LINK)
return;
if (!smp) if (!smp)
return; return;
...@@ -2527,10 +2530,14 @@ static void smp_ready_cb(struct l2cap_chan *chan) ...@@ -2527,10 +2530,14 @@ static void smp_ready_cb(struct l2cap_chan *chan)
static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
{ {
struct hci_conn *hcon = chan->conn->hcon;
int err; int err;
BT_DBG("chan %p", chan); BT_DBG("chan %p", chan);
if (hcon->type == ACL_LINK)
return -EOPNOTSUPP;
err = smp_sig_channel(chan, skb); err = smp_sig_channel(chan, skb);
if (err) { if (err) {
struct smp_chan *smp = chan->data; struct smp_chan *smp = chan->data;
...@@ -2627,34 +2634,40 @@ static const struct l2cap_ops smp_root_chan_ops = { ...@@ -2627,34 +2634,40 @@ static const struct l2cap_ops smp_root_chan_ops = {
.memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
}; };
int smp_register(struct hci_dev *hdev) static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
{ {
struct l2cap_chan *chan; struct l2cap_chan *chan;
struct crypto_blkcipher *tfm_aes; struct crypto_blkcipher *tfm_aes;
BT_DBG("%s", hdev->name); if (cid == L2CAP_CID_SMP_BREDR) {
tfm_aes = NULL;
goto create_chan;
}
tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0); tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0);
if (IS_ERR(tfm_aes)) { if (IS_ERR(tfm_aes)) {
int err = PTR_ERR(tfm_aes);
BT_ERR("Unable to create crypto context"); BT_ERR("Unable to create crypto context");
return err; return ERR_PTR(PTR_ERR(tfm_aes));
} }
create_chan:
chan = l2cap_chan_create(); chan = l2cap_chan_create();
if (!chan) { if (!chan) {
crypto_free_blkcipher(tfm_aes); crypto_free_blkcipher(tfm_aes);
return -ENOMEM; return ERR_PTR(-ENOMEM);
} }
chan->data = tfm_aes; chan->data = tfm_aes;
l2cap_add_scid(chan, L2CAP_CID_SMP); l2cap_add_scid(chan, cid);
l2cap_chan_set_defaults(chan); l2cap_chan_set_defaults(chan);
bacpy(&chan->src, &hdev->bdaddr); bacpy(&chan->src, &hdev->bdaddr);
chan->src_type = BDADDR_LE_PUBLIC; if (cid == L2CAP_CID_SMP)
chan->src_type = BDADDR_LE_PUBLIC;
else
chan->src_type = BDADDR_BREDR;
chan->state = BT_LISTEN; chan->state = BT_LISTEN;
chan->mode = L2CAP_MODE_BASIC; chan->mode = L2CAP_MODE_BASIC;
chan->imtu = L2CAP_DEFAULT_MTU; chan->imtu = L2CAP_DEFAULT_MTU;
...@@ -2663,20 +2676,14 @@ int smp_register(struct hci_dev *hdev) ...@@ -2663,20 +2676,14 @@ int smp_register(struct hci_dev *hdev)
/* Set correct nesting level for a parent/listening channel */ /* Set correct nesting level for a parent/listening channel */
atomic_set(&chan->nesting, L2CAP_NESTING_PARENT); atomic_set(&chan->nesting, L2CAP_NESTING_PARENT);
hdev->smp_data = chan; return chan;
return 0;
} }
void smp_unregister(struct hci_dev *hdev) static void smp_del_chan(struct l2cap_chan *chan)
{ {
struct l2cap_chan *chan = hdev->smp_data; struct crypto_blkcipher *tfm_aes;
struct crypto_blkcipher *tfm_aes;
if (!chan)
return;
BT_DBG("%s chan %p", hdev->name, chan); BT_DBG("chan %p", chan);
tfm_aes = chan->data; tfm_aes = chan->data;
if (tfm_aes) { if (tfm_aes) {
...@@ -2684,6 +2691,52 @@ void smp_unregister(struct hci_dev *hdev) ...@@ -2684,6 +2691,52 @@ void smp_unregister(struct hci_dev *hdev)
crypto_free_blkcipher(tfm_aes); crypto_free_blkcipher(tfm_aes);
} }
hdev->smp_data = NULL;
l2cap_chan_put(chan); l2cap_chan_put(chan);
} }
int smp_register(struct hci_dev *hdev)
{
struct l2cap_chan *chan;
BT_DBG("%s", hdev->name);
chan = smp_add_cid(hdev, L2CAP_CID_SMP);
if (IS_ERR(chan))
return PTR_ERR(chan);
hdev->smp_data = chan;
if (!lmp_sc_capable(hdev) &&
!test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
return 0;
chan = smp_add_cid(hdev, L2CAP_CID_SMP_BREDR);
if (IS_ERR(chan)) {
int err = PTR_ERR(chan);
chan = hdev->smp_data;
hdev->smp_data = NULL;
smp_del_chan(chan);
return err;
}
hdev->smp_bredr_data = chan;
return 0;
}
void smp_unregister(struct hci_dev *hdev)
{
struct l2cap_chan *chan;
if (hdev->smp_bredr_data) {
chan = hdev->smp_bredr_data;
hdev->smp_bredr_data = NULL;
smp_del_chan(chan);
}
if (hdev->smp_data) {
chan = hdev->smp_data;
hdev->smp_data = NULL;
smp_del_chan(chan);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册