diff options
-rw-r--r-- | include/net/bluetooth/a2mp.h | 2 | ||||
-rw-r--r-- | include/net/bluetooth/l2cap.h | 1 | ||||
-rw-r--r-- | net/bluetooth/a2mp.c | 34 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 33 |
4 files changed, 60 insertions, 10 deletions
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h index 99c7389b9189..9fda7c94913f 100644 --- a/include/net/bluetooth/a2mp.h +++ b/include/net/bluetooth/a2mp.h | |||
@@ -28,6 +28,7 @@ struct amp_mgr { | |||
28 | struct list_head list; | 28 | struct list_head list; |
29 | struct l2cap_conn *l2cap_conn; | 29 | struct l2cap_conn *l2cap_conn; |
30 | struct l2cap_chan *a2mp_chan; | 30 | struct l2cap_chan *a2mp_chan; |
31 | struct l2cap_chan *bredr_chan; | ||
31 | struct kref kref; | 32 | struct kref kref; |
32 | __u8 ident; | 33 | __u8 ident; |
33 | __u8 handle; | 34 | __u8 handle; |
@@ -137,6 +138,7 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, | |||
137 | struct sk_buff *skb); | 138 | struct sk_buff *skb); |
138 | struct amp_mgr *amp_mgr_lookup_by_state(u8 state); | 139 | struct amp_mgr *amp_mgr_lookup_by_state(u8 state); |
139 | void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data); | 140 | void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data); |
141 | void a2mp_discover_amp(struct l2cap_chan *chan); | ||
140 | void a2mp_send_getinfo_rsp(struct hci_dev *hdev); | 142 | void a2mp_send_getinfo_rsp(struct hci_dev *hdev); |
141 | void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); | 143 | void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); |
142 | 144 | ||
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7ed8e356425a..aba830fc762f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -767,6 +767,7 @@ int l2cap_chan_check_security(struct l2cap_chan *chan); | |||
767 | void l2cap_chan_set_defaults(struct l2cap_chan *chan); | 767 | void l2cap_chan_set_defaults(struct l2cap_chan *chan); |
768 | int l2cap_ertm_init(struct l2cap_chan *chan); | 768 | int l2cap_ertm_init(struct l2cap_chan *chan); |
769 | void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); | 769 | void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); |
770 | void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); | ||
770 | void l2cap_chan_del(struct l2cap_chan *chan, int err); | 771 | void l2cap_chan_del(struct l2cap_chan *chan, int err); |
771 | 772 | ||
772 | #endif /* __L2CAP_H */ | 773 | #endif /* __L2CAP_H */ |
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index d0fde05e8b17..93adaad782ed 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
@@ -638,7 +638,7 @@ static struct l2cap_ops a2mp_chan_ops = { | |||
638 | .ready = l2cap_chan_no_ready, | 638 | .ready = l2cap_chan_no_ready, |
639 | }; | 639 | }; |
640 | 640 | ||
641 | static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn) | 641 | static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) |
642 | { | 642 | { |
643 | struct l2cap_chan *chan; | 643 | struct l2cap_chan *chan; |
644 | int err; | 644 | int err; |
@@ -673,7 +673,10 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn) | |||
673 | 673 | ||
674 | chan->conf_state = 0; | 674 | chan->conf_state = 0; |
675 | 675 | ||
676 | l2cap_chan_add(conn, chan); | 676 | if (locked) |
677 | __l2cap_chan_add(conn, chan); | ||
678 | else | ||
679 | l2cap_chan_add(conn, chan); | ||
677 | 680 | ||
678 | chan->remote_mps = chan->omtu; | 681 | chan->remote_mps = chan->omtu; |
679 | chan->mps = chan->omtu; | 682 | chan->mps = chan->omtu; |
@@ -712,7 +715,7 @@ int amp_mgr_put(struct amp_mgr *mgr) | |||
712 | return kref_put(&mgr->kref, &_mgr_destroy); | 715 | return kref_put(&mgr->kref, &_mgr_destroy); |
713 | } | 716 | } |
714 | 717 | ||
715 | static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn) | 718 | static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked) |
716 | { | 719 | { |
717 | struct amp_mgr *mgr; | 720 | struct amp_mgr *mgr; |
718 | struct l2cap_chan *chan; | 721 | struct l2cap_chan *chan; |
@@ -725,7 +728,7 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn) | |||
725 | 728 | ||
726 | mgr->l2cap_conn = conn; | 729 | mgr->l2cap_conn = conn; |
727 | 730 | ||
728 | chan = a2mp_chan_open(conn); | 731 | chan = a2mp_chan_open(conn, locked); |
729 | if (!chan) { | 732 | if (!chan) { |
730 | kfree(mgr); | 733 | kfree(mgr); |
731 | return NULL; | 734 | return NULL; |
@@ -754,7 +757,7 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, | |||
754 | { | 757 | { |
755 | struct amp_mgr *mgr; | 758 | struct amp_mgr *mgr; |
756 | 759 | ||
757 | mgr = amp_mgr_create(conn); | 760 | mgr = amp_mgr_create(conn, false); |
758 | if (!mgr) { | 761 | if (!mgr) { |
759 | BT_ERR("Could not create AMP manager"); | 762 | BT_ERR("Could not create AMP manager"); |
760 | return NULL; | 763 | return NULL; |
@@ -842,3 +845,24 @@ void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status) | |||
842 | amp_mgr_put(mgr); | 845 | amp_mgr_put(mgr); |
843 | kfree(rsp); | 846 | kfree(rsp); |
844 | } | 847 | } |
848 | |||
849 | void a2mp_discover_amp(struct l2cap_chan *chan) | ||
850 | { | ||
851 | struct l2cap_conn *conn = chan->conn; | ||
852 | struct amp_mgr *mgr = conn->hcon->amp_mgr; | ||
853 | struct a2mp_discov_req req; | ||
854 | |||
855 | BT_DBG("chan %p conn %p mgr %p", chan, conn, mgr); | ||
856 | |||
857 | if (!mgr) { | ||
858 | mgr = amp_mgr_create(conn, true); | ||
859 | if (!mgr) | ||
860 | return; | ||
861 | } | ||
862 | |||
863 | mgr->bredr_chan = chan; | ||
864 | |||
865 | req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); | ||
866 | req.ext_feat = 0; | ||
867 | a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req); | ||
868 | } | ||
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7a59e929febc..781a085ae5bc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -455,7 +455,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) | |||
455 | set_bit(FLAG_FORCE_ACTIVE, &chan->flags); | 455 | set_bit(FLAG_FORCE_ACTIVE, &chan->flags); |
456 | } | 456 | } |
457 | 457 | ||
458 | static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) | 458 | void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) |
459 | { | 459 | { |
460 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, | 460 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, |
461 | __le16_to_cpu(chan->psm), chan->dcid); | 461 | __le16_to_cpu(chan->psm), chan->dcid); |
@@ -946,6 +946,18 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) | |||
946 | return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); | 946 | return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); |
947 | } | 947 | } |
948 | 948 | ||
949 | static bool __amp_capable(struct l2cap_chan *chan) | ||
950 | { | ||
951 | struct l2cap_conn *conn = chan->conn; | ||
952 | |||
953 | if (enable_hs && | ||
954 | chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED && | ||
955 | conn->fixed_chan_mask & L2CAP_FC_A2MP) | ||
956 | return true; | ||
957 | else | ||
958 | return false; | ||
959 | } | ||
960 | |||
949 | static void l2cap_send_conn_req(struct l2cap_chan *chan) | 961 | static void l2cap_send_conn_req(struct l2cap_chan *chan) |
950 | { | 962 | { |
951 | struct l2cap_conn *conn = chan->conn; | 963 | struct l2cap_conn *conn = chan->conn; |
@@ -972,6 +984,16 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) | |||
972 | chan->ops->ready(chan); | 984 | chan->ops->ready(chan); |
973 | } | 985 | } |
974 | 986 | ||
987 | static void l2cap_start_connection(struct l2cap_chan *chan) | ||
988 | { | ||
989 | if (__amp_capable(chan)) { | ||
990 | BT_DBG("chan %p AMP capable: discover AMPs", chan); | ||
991 | a2mp_discover_amp(chan); | ||
992 | } else { | ||
993 | l2cap_send_conn_req(chan); | ||
994 | } | ||
995 | } | ||
996 | |||
975 | static void l2cap_do_start(struct l2cap_chan *chan) | 997 | static void l2cap_do_start(struct l2cap_chan *chan) |
976 | { | 998 | { |
977 | struct l2cap_conn *conn = chan->conn; | 999 | struct l2cap_conn *conn = chan->conn; |
@@ -986,8 +1008,9 @@ static void l2cap_do_start(struct l2cap_chan *chan) | |||
986 | return; | 1008 | return; |
987 | 1009 | ||
988 | if (l2cap_chan_check_security(chan) && | 1010 | if (l2cap_chan_check_security(chan) && |
989 | __l2cap_no_conn_pending(chan)) | 1011 | __l2cap_no_conn_pending(chan)) { |
990 | l2cap_send_conn_req(chan); | 1012 | l2cap_start_connection(chan); |
1013 | } | ||
991 | } else { | 1014 | } else { |
992 | struct l2cap_info_req req; | 1015 | struct l2cap_info_req req; |
993 | req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK); | 1016 | req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK); |
@@ -1082,7 +1105,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
1082 | continue; | 1105 | continue; |
1083 | } | 1106 | } |
1084 | 1107 | ||
1085 | l2cap_send_conn_req(chan); | 1108 | l2cap_start_connection(chan); |
1086 | 1109 | ||
1087 | } else if (chan->state == BT_CONNECT2) { | 1110 | } else if (chan->state == BT_CONNECT2) { |
1088 | struct l2cap_conn_rsp rsp; | 1111 | struct l2cap_conn_rsp rsp; |
@@ -5456,7 +5479,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) | |||
5456 | 5479 | ||
5457 | if (chan->state == BT_CONNECT) { | 5480 | if (chan->state == BT_CONNECT) { |
5458 | if (!status) { | 5481 | if (!status) { |
5459 | l2cap_send_conn_req(chan); | 5482 | l2cap_start_connection(chan); |
5460 | } else { | 5483 | } else { |
5461 | __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); | 5484 | __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); |
5462 | } | 5485 | } |