aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-10-23 18:24:12 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-10-23 22:15:03 -0400
commit5f3847a4788e7205a6ad2ac363f968c9618074f1 (patch)
treed8cc36ebccf19691c10311f0661fe59fcedbea47
parent32b32735ca1439e2ead658dd63234c0c380af8ac (diff)
Bluetooth: Add move channel confirm handling
After sending a move channel response, a move responder waits for a move channel confirm command. If the received command has a "confirmed" result the move is proceeding, and "unconfirmed" means the move has failed and the channel will not change controllers. Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Acked-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
-rw-r--r--net/bluetooth/l2cap_core.c58
1 files changed, 55 insertions, 3 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b9a91bf3d95e..fef0394add18 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1037,6 +1037,28 @@ static void l2cap_move_setup(struct l2cap_chan *chan)
1037 set_bit(CONN_REMOTE_BUSY, &chan->conn_state); 1037 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
1038} 1038}
1039 1039
1040static void l2cap_move_done(struct l2cap_chan *chan)
1041{
1042 u8 move_role = chan->move_role;
1043 BT_DBG("chan %p", chan);
1044
1045 chan->move_state = L2CAP_MOVE_STABLE;
1046 chan->move_role = L2CAP_MOVE_ROLE_NONE;
1047
1048 if (chan->mode != L2CAP_MODE_ERTM)
1049 return;
1050
1051 switch (move_role) {
1052 case L2CAP_MOVE_ROLE_INITIATOR:
1053 l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL);
1054 chan->rx_state = L2CAP_RX_STATE_WAIT_F;
1055 break;
1056 case L2CAP_MOVE_ROLE_RESPONDER:
1057 chan->rx_state = L2CAP_RX_STATE_WAIT_P;
1058 break;
1059 }
1060}
1061
1040static void l2cap_chan_ready(struct l2cap_chan *chan) 1062static void l2cap_chan_ready(struct l2cap_chan *chan)
1041{ 1063{
1042 /* This clears all conf flags, including CONF_NOT_COMPLETE */ 1064 /* This clears all conf flags, including CONF_NOT_COMPLETE */
@@ -4193,6 +4215,14 @@ static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
4193 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); 4215 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
4194} 4216}
4195 4217
4218static void __release_logical_link(struct l2cap_chan *chan)
4219{
4220 chan->hs_hchan = NULL;
4221 chan->hs_hcon = NULL;
4222
4223 /* Placeholder - release the logical link */
4224}
4225
4196static inline int l2cap_move_channel_req(struct l2cap_conn *conn, 4226static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
4197 struct l2cap_cmd_hdr *cmd, 4227 struct l2cap_cmd_hdr *cmd,
4198 u16 cmd_len, void *data) 4228 u16 cmd_len, void *data)
@@ -4308,11 +4338,12 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
4308 return 0; 4338 return 0;
4309} 4339}
4310 4340
4311static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, 4341static int l2cap_move_channel_confirm(struct l2cap_conn *conn,
4312 struct l2cap_cmd_hdr *cmd, 4342 struct l2cap_cmd_hdr *cmd,
4313 u16 cmd_len, void *data) 4343 u16 cmd_len, void *data)
4314{ 4344{
4315 struct l2cap_move_chan_cfm *cfm = data; 4345 struct l2cap_move_chan_cfm *cfm = data;
4346 struct l2cap_chan *chan;
4316 u16 icid, result; 4347 u16 icid, result;
4317 4348
4318 if (cmd_len != sizeof(*cfm)) 4349 if (cmd_len != sizeof(*cfm))
@@ -4323,8 +4354,29 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
4323 4354
4324 BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); 4355 BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
4325 4356
4357 chan = l2cap_get_chan_by_dcid(conn, icid);
4358 if (!chan) {
4359 /* Spec requires a response even if the icid was not found */
4360 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
4361 return 0;
4362 }
4363
4364 if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) {
4365 if (result == L2CAP_MC_CONFIRMED) {
4366 chan->local_amp_id = chan->move_id;
4367 if (!chan->local_amp_id)
4368 __release_logical_link(chan);
4369 } else {
4370 chan->move_id = chan->local_amp_id;
4371 }
4372
4373 l2cap_move_done(chan);
4374 }
4375
4326 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); 4376 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
4327 4377
4378 l2cap_chan_unlock(chan);
4379
4328 return 0; 4380 return 0;
4329} 4381}
4330 4382