diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2014-08-13 08:12:32 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-12-03 10:51:20 -0500 |
commit | ef8efe4bf8b5fe1a9342ae964c428aed1be7863b (patch) | |
tree | fa5ed6ec8be7f501c12d9ca6376bbfdb8a248146 /net | |
parent | 858cdc78be8be19b7176cafe06d3db3acfb345d4 (diff) |
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/smp.c | 89 |
1 files changed, 71 insertions, 18 deletions
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 779160485a50..135e725119c5 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
@@ -2504,6 +2504,9 @@ static void smp_resume_cb(struct l2cap_chan *chan) | |||
2504 | 2504 | ||
2505 | BT_DBG("chan %p", chan); | 2505 | BT_DBG("chan %p", chan); |
2506 | 2506 | ||
2507 | if (hcon->type == ACL_LINK) | ||
2508 | return; | ||
2509 | |||
2507 | if (!smp) | 2510 | if (!smp) |
2508 | return; | 2511 | return; |
2509 | 2512 | ||
@@ -2527,10 +2530,14 @@ static void smp_ready_cb(struct l2cap_chan *chan) | |||
2527 | 2530 | ||
2528 | static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) | 2531 | static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) |
2529 | { | 2532 | { |
2533 | struct hci_conn *hcon = chan->conn->hcon; | ||
2530 | int err; | 2534 | int err; |
2531 | 2535 | ||
2532 | BT_DBG("chan %p", chan); | 2536 | BT_DBG("chan %p", chan); |
2533 | 2537 | ||
2538 | if (hcon->type == ACL_LINK) | ||
2539 | return -EOPNOTSUPP; | ||
2540 | |||
2534 | err = smp_sig_channel(chan, skb); | 2541 | err = smp_sig_channel(chan, skb); |
2535 | if (err) { | 2542 | if (err) { |
2536 | struct smp_chan *smp = chan->data; | 2543 | struct smp_chan *smp = chan->data; |
@@ -2627,34 +2634,40 @@ static const struct l2cap_ops smp_root_chan_ops = { | |||
2627 | .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, | 2634 | .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, |
2628 | }; | 2635 | }; |
2629 | 2636 | ||
2630 | int smp_register(struct hci_dev *hdev) | 2637 | static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) |
2631 | { | 2638 | { |
2632 | struct l2cap_chan *chan; | 2639 | struct l2cap_chan *chan; |
2633 | struct crypto_blkcipher *tfm_aes; | 2640 | struct crypto_blkcipher *tfm_aes; |
2634 | 2641 | ||
2635 | BT_DBG("%s", hdev->name); | 2642 | if (cid == L2CAP_CID_SMP_BREDR) { |
2643 | tfm_aes = NULL; | ||
2644 | goto create_chan; | ||
2645 | } | ||
2636 | 2646 | ||
2637 | tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0); | 2647 | tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0); |
2638 | if (IS_ERR(tfm_aes)) { | 2648 | if (IS_ERR(tfm_aes)) { |
2639 | int err = PTR_ERR(tfm_aes); | ||
2640 | BT_ERR("Unable to create crypto context"); | 2649 | BT_ERR("Unable to create crypto context"); |
2641 | return err; | 2650 | return ERR_PTR(PTR_ERR(tfm_aes)); |
2642 | } | 2651 | } |
2643 | 2652 | ||
2653 | create_chan: | ||
2644 | chan = l2cap_chan_create(); | 2654 | chan = l2cap_chan_create(); |
2645 | if (!chan) { | 2655 | if (!chan) { |
2646 | crypto_free_blkcipher(tfm_aes); | 2656 | crypto_free_blkcipher(tfm_aes); |
2647 | return -ENOMEM; | 2657 | return ERR_PTR(-ENOMEM); |
2648 | } | 2658 | } |
2649 | 2659 | ||
2650 | chan->data = tfm_aes; | 2660 | chan->data = tfm_aes; |
2651 | 2661 | ||
2652 | l2cap_add_scid(chan, L2CAP_CID_SMP); | 2662 | l2cap_add_scid(chan, cid); |
2653 | 2663 | ||
2654 | l2cap_chan_set_defaults(chan); | 2664 | l2cap_chan_set_defaults(chan); |
2655 | 2665 | ||
2656 | bacpy(&chan->src, &hdev->bdaddr); | 2666 | bacpy(&chan->src, &hdev->bdaddr); |
2657 | chan->src_type = BDADDR_LE_PUBLIC; | 2667 | if (cid == L2CAP_CID_SMP) |
2668 | chan->src_type = BDADDR_LE_PUBLIC; | ||
2669 | else | ||
2670 | chan->src_type = BDADDR_BREDR; | ||
2658 | chan->state = BT_LISTEN; | 2671 | chan->state = BT_LISTEN; |
2659 | chan->mode = L2CAP_MODE_BASIC; | 2672 | chan->mode = L2CAP_MODE_BASIC; |
2660 | chan->imtu = L2CAP_DEFAULT_MTU; | 2673 | chan->imtu = L2CAP_DEFAULT_MTU; |
@@ -2663,20 +2676,14 @@ int smp_register(struct hci_dev *hdev) | |||
2663 | /* Set correct nesting level for a parent/listening channel */ | 2676 | /* Set correct nesting level for a parent/listening channel */ |
2664 | atomic_set(&chan->nesting, L2CAP_NESTING_PARENT); | 2677 | atomic_set(&chan->nesting, L2CAP_NESTING_PARENT); |
2665 | 2678 | ||
2666 | hdev->smp_data = chan; | 2679 | return chan; |
2667 | |||
2668 | return 0; | ||
2669 | } | 2680 | } |
2670 | 2681 | ||
2671 | void smp_unregister(struct hci_dev *hdev) | 2682 | static void smp_del_chan(struct l2cap_chan *chan) |
2672 | { | 2683 | { |
2673 | struct l2cap_chan *chan = hdev->smp_data; | 2684 | struct crypto_blkcipher *tfm_aes; |
2674 | struct crypto_blkcipher *tfm_aes; | ||
2675 | |||
2676 | if (!chan) | ||
2677 | return; | ||
2678 | 2685 | ||
2679 | BT_DBG("%s chan %p", hdev->name, chan); | 2686 | BT_DBG("chan %p", chan); |
2680 | 2687 | ||
2681 | tfm_aes = chan->data; | 2688 | tfm_aes = chan->data; |
2682 | if (tfm_aes) { | 2689 | if (tfm_aes) { |
@@ -2684,6 +2691,52 @@ void smp_unregister(struct hci_dev *hdev) | |||
2684 | crypto_free_blkcipher(tfm_aes); | 2691 | crypto_free_blkcipher(tfm_aes); |
2685 | } | 2692 | } |
2686 | 2693 | ||
2687 | hdev->smp_data = NULL; | ||
2688 | l2cap_chan_put(chan); | 2694 | l2cap_chan_put(chan); |
2689 | } | 2695 | } |
2696 | |||
2697 | int smp_register(struct hci_dev *hdev) | ||
2698 | { | ||
2699 | struct l2cap_chan *chan; | ||
2700 | |||
2701 | BT_DBG("%s", hdev->name); | ||
2702 | |||
2703 | chan = smp_add_cid(hdev, L2CAP_CID_SMP); | ||
2704 | if (IS_ERR(chan)) | ||
2705 | return PTR_ERR(chan); | ||
2706 | |||
2707 | hdev->smp_data = chan; | ||
2708 | |||
2709 | if (!lmp_sc_capable(hdev) && | ||
2710 | !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags)) | ||
2711 | return 0; | ||
2712 | |||
2713 | chan = smp_add_cid(hdev, L2CAP_CID_SMP_BREDR); | ||
2714 | if (IS_ERR(chan)) { | ||
2715 | int err = PTR_ERR(chan); | ||
2716 | chan = hdev->smp_data; | ||
2717 | hdev->smp_data = NULL; | ||
2718 | smp_del_chan(chan); | ||
2719 | return err; | ||
2720 | } | ||
2721 | |||
2722 | hdev->smp_bredr_data = chan; | ||
2723 | |||
2724 | return 0; | ||
2725 | } | ||
2726 | |||
2727 | void smp_unregister(struct hci_dev *hdev) | ||
2728 | { | ||
2729 | struct l2cap_chan *chan; | ||
2730 | |||
2731 | if (hdev->smp_bredr_data) { | ||
2732 | chan = hdev->smp_bredr_data; | ||
2733 | hdev->smp_bredr_data = NULL; | ||
2734 | smp_del_chan(chan); | ||
2735 | } | ||
2736 | |||
2737 | if (hdev->smp_data) { | ||
2738 | chan = hdev->smp_data; | ||
2739 | hdev->smp_data = NULL; | ||
2740 | smp_del_chan(chan); | ||
2741 | } | ||
2742 | } | ||