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: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
858cdc78be
commit
ef8efe4bf8
@ -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 {
|
|||||||
#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 {
|
|||||||
#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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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 = {
|
|||||||
.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)
|
|||||||
/* 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)
|
BT_DBG("chan %p", chan);
|
||||||
return;
|
|
||||||
|
|
||||||
BT_DBG("%s chan %p", hdev->name, 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)
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user