aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-10-23 18:24:07 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-10-23 21:58:52 -0400
commit1700915fef115b13c43fe3974d0dbb619e6a187d (patch)
treed129e4c36259e4e4a7fddca19db3916e091ec7c0 /net/bluetooth
parent08333283a7347c33589f31c9b1d1b7a4f3c3f7a3 (diff)
Bluetooth: Add L2CAP create channel request handling
The L2CAP create channel request is very similar to an L2CAP connect request, but it has an additional parameter for the controller ID. If the controller id is 0, the channel is set up on the BR/EDR controller (just like a connect request). Using a valid high speed controller ID will cause the channel to be initially created on that high speed controller. While the L2CAP data will be initially routed over the AMP controller, the L2CAP fixed signaling channel only uses BR/EDR. When a create channel request is received for a high speed controller, a pending response is always sent first. After the high speed physical and logical links are complete a success response will be sent. Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap_core.c63
1 files changed, 48 insertions, 15 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c1b169f3ae0d..2b3eef706899 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3400,8 +3400,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
3400 return 0; 3400 return 0;
3401} 3401}
3402 3402
3403static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, 3403static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
3404 u8 *data, u8 rsp_code, u8 amp_id) 3404 struct l2cap_cmd_hdr *cmd,
3405 u8 *data, u8 rsp_code, u8 amp_id)
3405{ 3406{
3406 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; 3407 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
3407 struct l2cap_conn_rsp rsp; 3408 struct l2cap_conn_rsp rsp;
@@ -3452,6 +3453,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
3452 bacpy(&bt_sk(sk)->dst, conn->dst); 3453 bacpy(&bt_sk(sk)->dst, conn->dst);
3453 chan->psm = psm; 3454 chan->psm = psm;
3454 chan->dcid = scid; 3455 chan->dcid = scid;
3456 chan->local_amp_id = amp_id;
3455 3457
3456 __l2cap_chan_add(conn, chan); 3458 __l2cap_chan_add(conn, chan);
3457 3459
@@ -3469,8 +3471,17 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
3469 status = L2CAP_CS_AUTHOR_PEND; 3471 status = L2CAP_CS_AUTHOR_PEND;
3470 chan->ops->defer(chan); 3472 chan->ops->defer(chan);
3471 } else { 3473 } else {
3472 __l2cap_state_change(chan, BT_CONFIG); 3474 /* Force pending result for AMP controllers.
3473 result = L2CAP_CR_SUCCESS; 3475 * The connection will succeed after the
3476 * physical link is up.
3477 */
3478 if (amp_id) {
3479 __l2cap_state_change(chan, BT_CONNECT2);
3480 result = L2CAP_CR_PEND;
3481 } else {
3482 __l2cap_state_change(chan, BT_CONFIG);
3483 result = L2CAP_CR_SUCCESS;
3484 }
3474 status = L2CAP_CS_NO_INFO; 3485 status = L2CAP_CS_NO_INFO;
3475 } 3486 }
3476 } else { 3487 } else {
@@ -3516,6 +3527,8 @@ sendresp:
3516 l2cap_build_conf_req(chan, buf), buf); 3527 l2cap_build_conf_req(chan, buf), buf);
3517 chan->num_conf_req++; 3528 chan->num_conf_req++;
3518 } 3529 }
3530
3531 return chan;
3519} 3532}
3520 3533
3521static int l2cap_connect_req(struct l2cap_conn *conn, 3534static int l2cap_connect_req(struct l2cap_conn *conn,
@@ -4028,12 +4041,12 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
4028 return 0; 4041 return 0;
4029} 4042}
4030 4043
4031static inline int l2cap_create_channel_req(struct l2cap_conn *conn, 4044static int l2cap_create_channel_req(struct l2cap_conn *conn,
4032 struct l2cap_cmd_hdr *cmd, 4045 struct l2cap_cmd_hdr *cmd,
4033 u16 cmd_len, void *data) 4046 u16 cmd_len, void *data)
4034{ 4047{
4035 struct l2cap_create_chan_req *req = data; 4048 struct l2cap_create_chan_req *req = data;
4036 struct l2cap_create_chan_rsp rsp; 4049 struct l2cap_chan *chan;
4037 u16 psm, scid; 4050 u16 psm, scid;
4038 4051
4039 if (cmd_len != sizeof(*req)) 4052 if (cmd_len != sizeof(*req))
@@ -4047,14 +4060,34 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
4047 4060
4048 BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id); 4061 BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id);
4049 4062
4050 /* Placeholder: Always reject */ 4063 if (req->amp_id) {
4051 rsp.dcid = 0; 4064 struct hci_dev *hdev;
4052 rsp.scid = cpu_to_le16(scid);
4053 rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
4054 rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
4055 4065
4056 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, 4066 /* Validate AMP controller id */
4057 sizeof(rsp), &rsp); 4067 hdev = hci_dev_get(req->amp_id);
4068 if (!hdev || hdev->dev_type != HCI_AMP ||
4069 !test_bit(HCI_UP, &hdev->flags)) {
4070 struct l2cap_create_chan_rsp rsp;
4071
4072 rsp.dcid = 0;
4073 rsp.scid = cpu_to_le16(scid);
4074 rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP);
4075 rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
4076
4077 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
4078 sizeof(rsp), &rsp);
4079
4080 if (hdev)
4081 hci_dev_put(hdev);
4082
4083 return 0;
4084 }
4085
4086 hci_dev_put(hdev);
4087 }
4088
4089 chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
4090 req->amp_id);
4058 4091
4059 return 0; 4092 return 0;
4060} 4093}